/* ==========================================================================
   WooCommerce re-skin.
   We never touch WooCommerce's PHP templates — this file styles the
   markup WooCommerce already renders (shop loop, single product, cart,
   checkout, my-account) using ToyVibe's design tokens from style.css.
   ========================================================================== */

.tv-shop {
  min-height: 40vh;
}

.tv-breadcrumb {
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
  padding-block: var(--space-4);
}

.tv-breadcrumb a:hover {
  color: var(--tv-primary-dark);
}

/* Page/archive titles */
.woocommerce-products-header__title.page-title,
.tv-shop .page-title {
  font-size: var(--fs-2xl);
  margin-bottom: var(--space-2);
}

.woocommerce-result-count,
.woocommerce-ordering {
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
}

.woocommerce-ordering select {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3);
  background: var(--color-surface);
  font-family: inherit;
}

/* ---- Shop loop / category archive ---- */

.woocommerce ul.products {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-5);
  list-style: none;
  margin: var(--space-6) 0 0;
  padding: 0;
}

@media (min-width: 700px) {
  .woocommerce ul.products {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 1100px) {
  .woocommerce ul.products {
    grid-template-columns: repeat(4, 1fr);
  }
}

.woocommerce ul.products li.product {
  /* WooCommerce's own bundled stylesheet still ships a legacy float-based
     grid (width ~22%, float:left) at the exact same selector specificity
     as this rule, so without !important here it wins on load order alone
     and squashes every card into a narrow column with a huge empty gap. */
  width: 100% !important;
  float: none !important;
  margin: 0 !important;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 0;
  overflow: hidden;
  position: relative;
  transition: box-shadow 180ms ease, transform 180ms ease;
  /* Cards in a row share the grid's row height (grid default stretch),
     but title/price text can wrap to a different number of lines per
     product — without flex + margin-top:auto on the button below, that
     pushes the "افزودن به سبد خرید" button to a different vertical
     offset in every card instead of a single lined-up row. */
  display: flex;
  flex-direction: column;
}

.woocommerce ul.products::before,
.woocommerce ul.products::after {
  content: none !important;
}

.woocommerce ul.products li.product:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-3px);
}

/* Shop and category archives: same reasoning as the product grid — square photos
   are unaffected, portrait box shots stop losing their titles. */
.woocommerce ul.products li.product a img {
  aspect-ratio: 1;
  object-fit: contain;
  width: 100%;
  margin: 0 0 var(--space-3);
  border-radius: 0;
}

/* toyvibe_product_image_webp() wraps the loop thumbnail in a <picture> so the WebP
   copy can be offered alongside the JPEG. <picture> is an inline element, and an
   inline box between the <a> and the <img> is enough to change what the img's
   width:100% resolves against — the grid would still render, just subtly wrong.
   Making it block keeps the layout byte-identical to before the wrapper existed.
   The rule above still applies either way: "a img" is a descendant selector. */
.woocommerce ul.products li.product a picture {
  display: block;
}

.woocommerce ul.products li.product .woocommerce-loop-product__title {
  font-size: var(--fs-sm);
  font-weight: 700;
  padding: 0 var(--space-5);
  margin: 0 0 var(--space-2);
  line-height: 1.5;
}

.woocommerce ul.products li.product .price {
  padding: 0 var(--space-5);
  display: block;
  font-weight: 800;
  font-family: var(--font-display);
  color: var(--tv-primary-dark);
}

.woocommerce ul.products li.product .price del {
  color: var(--color-text-muted);
  font-weight: 400;
  opacity: 0.8;
  margin-inline-end: var(--space-2);
}

.woocommerce ul.products li.product .price ins {
  text-decoration: none;
}

.woocommerce ul.products li.product .button {
  display: block;
  text-align: center;
  margin: auto var(--space-5) var(--space-5);
  width: calc(100% - 2 * var(--space-5));
}

/* WooCommerce's AJAX add-to-cart injects this second link right after the
   "افزودن به سبد خرید" button once the item is in the cart. It only matches
   the generic `.woocommerce a.button` rule (pill, inline), not the block-width
   rule above, so left alone it renders as a small loose fragment of text
   under the first button instead of a matching second action. Style it as an
   outline twin, same width, stacked directly below with a small gap. */
.woocommerce ul.products li.product .added_to_cart.wc-forward {
  display: block;
  width: calc(100% - 2 * var(--space-5));
  margin: var(--space-2) var(--space-5) var(--space-5);
  background: transparent;
  border-color: var(--tv-ink);
  color: var(--tv-ink);
}

.woocommerce ul.products li.product .added_to_cart.wc-forward:hover {
  background: var(--tv-ink);
  color: var(--tv-white);
}

.woocommerce span.onsale {
  position: absolute;
  top: var(--space-3);
  inset-inline-start: var(--space-3);
  background: var(--color-primary);
  color: var(--tv-white);
  font-size: var(--fs-xs);
  font-weight: 800;
  min-height: 0;
  min-width: 0;
  border-radius: var(--radius-pill);
  padding: 0.3rem 0.65rem;
  line-height: 1;
  margin: 0;
  z-index: 2;
}

.tv-badge {
  z-index: 3;
}

/* ---- Buttons (add to cart, checkout, etc.) share ToyVibe's button system ---- */

.woocommerce a.button,
.woocommerce button.button,
.woocommerce input.button,
.woocommerce #respond input#submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--space-2);
  background: var(--color-primary);
  color: var(--tv-ink);
  border: 2px solid transparent;
  border-radius: var(--radius-pill);
  padding: 0.75rem 1.5rem;
  font-weight: 700;
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: background-color 150ms ease, box-shadow 150ms ease;
}

.woocommerce a.button:hover,
.woocommerce button.button:hover,
.woocommerce input.button:hover {
  background: var(--color-primary-hover);
  color: var(--tv-white);
}

.woocommerce a.button.loading,
.woocommerce button.button.loading {
  opacity: 0.7;
}

/* ---- Notices ---- */

.woocommerce-message,
.woocommerce-info,
.woocommerce-error,
.woocommerce-noreviews,
p.no-comments {
  background: var(--color-success-tint);
  border: 1px solid var(--tv-sage);
  color: var(--tv-ink);
  border-radius: var(--radius-md);
  padding: var(--space-4) var(--space-5);
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin: 0 0 var(--space-5);
}

/* WooCommerce's own stylesheet injects a legacy icon-font glyph before
   these notices (::before, font-family: WooCommerce) reserved via extra
   padding we don't add — without that padding the glyph overlaps the
   first word instead of sitting in its own space, so we drop it entirely
   and rely on our flex layout + colored border for the "info" meaning. */
.woocommerce-info::before,
.woocommerce-error::before,
.woocommerce-message::before,
.woocommerce-noreviews::before {
  display: none;
}

.woocommerce-error {
  background: var(--color-danger-tint);
  border-color: var(--color-danger);
}

.woocommerce-message .button,
.woocommerce-info .button {
  order: 2;
}

/* ---- Single product ---- */

.woocommerce div.product {
  display: grid;
  gap: var(--space-8);
  padding-block: var(--space-6);
}

@media (min-width: 900px) {
  .woocommerce div.product {
    grid-template-columns: 11fr 9fr;
    align-items: start;
  }
}

/* WooCommerce's own bundled stylesheet (woocommerce-layout-rtl.css) still
   ships the legacy float layout's exact sizing for this markup —
   .woocommerce div.product div.images/div.summary { float; width:48% } —
   and since our grid rules above never declared a competing `width` on
   either one, that legacy 48% simply applied uncontested: both columns
   sat at 48% of their own grid track instead of stretching to fill it,
   which is why the gallery (and the text column) looked far smaller than
   the space actually reserved for them. Neutralizing both here is the
   same fix already used elsewhere in this file for identical WC legacy-
   CSS conflicts (the shop-loop grid, the account addresses grid). */
.woocommerce div.product div.images {
  width: 95% !important;
  float: none !important;
  margin: 0 !important;
}

.woocommerce div.product .summary {
  width: 100% !important;
  float: none !important;
  margin: 0 !important;
}

/* Everything after the image/summary row (tabs, specs, related
   products) is wrapped in this single div (see functions.php) and must
   span both grid columns — otherwise WooCommerce's own grid placement
   would put it beside the summary as a 3rd/4th cell instead of below
   both, full width. */
.woocommerce div.product .tv-product-below {
  grid-column: 1 / -1;
}

.woocommerce div.product div.images {
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: #f7e8f6;
}

.woocommerce div.product div.images img {
  width: 100%;
  height: auto;
  object-fit: cover;
}

/* Thin card frame around the text column only (not the gallery) —
   matches the reference site: a subtle 1px border and light padding,
   no shadow/background tint, so it reads as a light frame rather than a
   heavy boxed card. */
.woocommerce div.product .summary {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-5);
}

/* Wraps .flex-control-thumbs (added by main.js) so prev/next arrows can be
   positioned over the strip without touching WooCommerce's own template. */
.tv-gallery-thumbs-wrap {
  position: relative;
}

/* WooCommerce's own bundled stylesheet (woocommerce-rtl.css) styles this
   exact markup at .woocommerce div.product div.images .flex-control-thumbs
   (and ...li, ...li img) — identical class/type count to a shorter selector
   here, so a shorter selector loses even though our stylesheet loads after
   it. Matching WC's selector chain exactly wins the tie via source order
   instead (already fixed once for the shop-loop grid the same way). */
.woocommerce div.product div.images .flex-control-thumbs {
  display: flex;
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  gap: var(--space-4);
  list-style: none;
  margin: 0;
  padding: var(--space-3);
  background: var(--color-surface);
  scroll-behavior: smooth;
}

.woocommerce div.product div.images .flex-control-thumbs::-webkit-scrollbar {
  display: none;
}

.woocommerce div.product div.images .flex-control-thumbs li {
  width: 84px;
  flex-shrink: 0;
  margin: 0;
}

/* Zoom trigger dropped entirely — its position never rendered correctly
   across attempts and wasn't worth further debugging time. */
.woocommerce-product-gallery__trigger {
  display: none !important;
}

.woocommerce div.product div.images .flex-control-thumbs li img {
  aspect-ratio: 1;
  object-fit: contain;
  border-radius: var(--radius-sm);
  border: 2px solid transparent;
  cursor: pointer;
  opacity: 1;
  transition: border-color 150ms ease;
}

.woocommerce div.product div.images .flex-control-thumbs li img:hover,
.woocommerce div.product div.images .flex-control-thumbs li.flex-active-slide img {
  border-color: var(--tv-primary);
}

/* Prev/next arrows for the thumbnail strip, injected by main.js and only
   shown once it actually overflows (see .has-scroll toggle there). Reuses
   the same look as the homepage carousel arrows, just smaller. */
.tv-gallery-thumbs-arrow {
  display: none;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1px solid var(--color-border);
  background: var(--tv-white);
  box-shadow: var(--shadow-md);
  align-items: center;
  justify-content: center;
  color: var(--tv-ink);
  cursor: pointer;
  z-index: 2;
}

.tv-gallery-thumbs-wrap.has-scroll .tv-gallery-thumbs-arrow {
  display: flex;
}

.tv-gallery-thumbs-arrow:hover {
  color: var(--tv-primary-dark);
}

.tv-gallery-thumbs-arrow.tv-gallery-thumbs-prev {
  inset-inline-start: -4px;
}

.tv-gallery-thumbs-arrow.tv-gallery-thumbs-next {
  inset-inline-end: -4px;
}

.woocommerce div.product .summary {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.woocommerce div.product .product_title {
  margin-bottom: 0;
  font-size: 19px;
  font-weight: 800;
}

.woocommerce div.product p.price,
.woocommerce div.product span.price {
  font-size: 1.15rem;
  font-weight: 800;
  font-family: var(--font-display);
  color: var(--tv-primary-dark);
}

.woocommerce div.product .woocommerce-product-details__short-description {
  color: var(--color-text-muted);
}

.woocommerce div.product form.cart {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-top: var(--space-3);
}

@media (min-width: 480px) {
  .woocommerce div.product form.cart .single_add_to_cart_button {
    flex-shrink: 0;
  }
}

/* WooCommerce's own bundled CSS floats .single_variation_wrap (same legacy
   float layout already fought elsewhere in this file for .images/.summary
   and the thumbnail strip) — with nothing here clearing/neutralizing it,
   the quantity+button row detached from normal block flow and floated
   out to the side, landing outside the card entirely instead of stacking
   below the color swatches/reset link like every other block on the
   page. */
.woocommerce div.product .single_variation_wrap {
  float: none !important;
  clear: both;
  width: 100%;
  margin-top: var(--space-3);
}

/* Variable products (with color/attribute swatches) wrap the quantity box
   and the add-to-cart button together in an extra
   .woocommerce-variation-add-to-cart div, which isn't a direct child of
   form.cart — so the flex/gap rules above never reach it, and the two just
   stack as plain blocks touching each other with a squashed button. Mirror
   the same treatment here so variable products line up identically to
   simple ones. */
.woocommerce div.product .woocommerce-variation-add-to-cart {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  float: none !important;
  width: 100%;
}

/* No forced `flex-wrap: nowrap` here (unlike earlier attempts) — with the
   card's own padding eating into the available width, the quantity
   stepper + button combined don't always fit on one line at every
   viewport in between mobile and the 900px two-column breakpoint. Nowrap
   plus flex-shrink:0 (needed so the stepper doesn't collapse thin — see
   .tv-qty-stepper above) had nowhere to put the excess width but overflow
   past the card's edge. Letting it wrap keeps both rules' intent (never
   thin, never overflowing) without the two fighting each other. */
@media (min-width: 480px) {
  .woocommerce div.product .woocommerce-variation-add-to-cart .single_add_to_cart_button {
    flex-shrink: 0;
  }
}

.woocommerce div.product .quantity {
  display: inline-flex;
}

.woocommerce div.product .quantity .qty {
  width: 70px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-family: inherit;
  text-align: center;
}

/* Native number-input spin arrows — hidden everywhere on .qty fields as a
   safety net for the moment before (or in case) main.js's +/- buttons
   attach, so the raw browser control never shows through. */
.woocommerce input.qty {
  -moz-appearance: textfield;
}

.woocommerce input.qty::-webkit-outer-spin-button,
.woocommerce input.qty::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.woocommerce-tabs ul.tabs {
  display: flex;
  gap: var(--space-2);
  list-style: none;
  padding: 0;
  margin: var(--space-8) 0 0;
  border-bottom: 1px solid var(--color-border);
}

.woocommerce-tabs ul.tabs li {
  margin: 0;
}

.woocommerce-tabs ul.tabs li a {
  display: inline-block;
  padding: var(--space-3) var(--space-4);
  font-weight: 700;
  font-size: var(--fs-sm);
  border-bottom: 3px solid transparent;
}

.woocommerce-tabs ul.tabs li.active a {
  border-color: var(--tv-primary);
  color: var(--tv-primary-dark);
}

.woocommerce-tabs .panel {
  padding-block: var(--space-6);
  color: var(--color-text-muted);
}

/* Bullet lists inside the product summary/description read as a proper
   feature checklist (matches reference stores) instead of plain bullets. */
.woocommerce div.product .summary ul li,
.woocommerce-tabs .panel ul li {
  list-style: none;
  position: relative;
  padding-inline-start: var(--space-5);
  margin-bottom: var(--space-2);
}

.woocommerce div.product .summary ul,
.woocommerce-tabs .panel ul {
  padding-inline-start: 0;
  margin: 0 0 var(--space-4);
}

.woocommerce div.product .summary ul li::before,
.woocommerce-tabs .panel ul li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 0.35em;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--color-success-tint);
  box-shadow: inset 0 0 0 1px var(--tv-sage);
}

.woocommerce div.product .summary ul li::after,
.woocommerce-tabs .panel ul li::after {
  content: "";
  position: absolute;
  inset-inline-start: 4px;
  top: 0.55em;
  width: 8px;
  height: 5px;
  border-inline-start: 2px solid var(--tv-sage);
  border-block-end: 2px solid var(--tv-sage);
  transform: rotate(-45deg);
}

/* A bold, standalone paragraph ("ویژگی‌های بازی", "اقلام همراه", …) acts
   as a section label inside product description content. */
.woocommerce-tabs .panel p > strong:only-child,
.woocommerce div.product .summary p > strong:only-child {
  display: inline-block;
  font-size: var(--fs-md);
  color: var(--tv-primary-dark);
  margin-top: var(--space-3);
}

/* ---- Specifications table (from WooCommerce product attributes) ---- */

.woocommerce div.product .summary .tv-product-features {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.woocommerce div.product .summary .tv-product-features li {
  position: relative;
  padding-inline-start: var(--space-4);
  padding-inline-end: 0;
  margin-bottom: 0;
  font-size: var(--fs-sm);
  color: var(--color-text);
}

.woocommerce div.product .summary .tv-product-features li::before {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  top: 0.6em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--tv-primary-dark);
  box-shadow: none;
}

.woocommerce div.product .summary .tv-product-features li::after {
  content: none;
}

/* The description tab's spec list used to be a plain <ul><li> (typed
   straight into the product's description field, e.g. ابعاد/وزن/جنس) that
   rendered with an unexplained green marker no CSS in this file or
   WooCommerce core accounted for, on every browser/device, cache or not —
   proven by blanking a product's description entirely (icon gone), then
   re-adding the same list (icon back), then replacing the <ul><li> with
   plain <br>-separated text (icon gone again, for good). So every
   product's spec list was converted server-side from <ul><li> to a
   <div class="tv-spec-plain"><p> per line — no <li> left anywhere for
   whatever that was to attach to. This ::before icon targets those <p>
   tags instead; top:50%/translateY keeps it centered regardless of the
   icon's size, unlike guessing a fixed top offset in em units. */
.woocommerce div.product #tab-description .tv-spec-plain {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: var(--space-3) 0;
}

.woocommerce div.product #tab-description .tv-spec-plain p {
  position: relative;
  margin: 0;
  padding-inline-start: var(--space-5);
  padding-inline-end: 0;
}

.woocommerce div.product #tab-description .tv-spec-plain p::before {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 15px;
  height: 15px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='%239b3b95'%3E%3Cellipse cx='12' cy='6.5' rx='3.4' ry='5.2' transform='rotate(0 12 12)'/%3E%3Cellipse cx='12' cy='6.5' rx='3.4' ry='5.2' transform='rotate(72 12 12)'/%3E%3Cellipse cx='12' cy='6.5' rx='3.4' ry='5.2' transform='rotate(144 12 12)'/%3E%3Cellipse cx='12' cy='6.5' rx='3.4' ry='5.2' transform='rotate(216 12 12)'/%3E%3Cellipse cx='12' cy='6.5' rx='3.4' ry='5.2' transform='rotate(288 12 12)'/%3E%3C/g%3E%3Ccircle cx='12' cy='12' r='2.6' fill='%23f6ffdc'/%3E%3C/svg%3E");
  background-size: contain;
  background-repeat: no-repeat;
}

.related.products {
  margin-top: var(--space-10);
}

.related.products > h2 {
  margin-bottom: var(--space-5);
}

/* 6 related products are fetched (see functions.php), so this grid
   scales further than the general shop/category grid to actually fill
   a row on wide screens instead of leaving gaps. */
@media (min-width: 900px) {
  .related.products ul.products {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 1300px) {
  .related.products ul.products {
    grid-template-columns: repeat(6, 1fr);
  }
}

/* ---- Cart ---- */

/* Wraps the cart table (via woocommerce_before/after_cart_table hooks in
   functions.php, not a template override) so wide tables scroll inside
   themselves on phones instead of breaking the page's horizontal width. */
.tv-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  margin-bottom: var(--space-6);
}

.tv-table-scroll table.shop_table {
  min-width: 560px;
  margin-bottom: 0;
  border: none;
  border-radius: 0;
}

.woocommerce table.shop_table {
  width: 100%;
  border-collapse: collapse;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
  margin-bottom: var(--space-6);
}

.woocommerce table.shop_table th,
.woocommerce table.shop_table td {
  padding: var(--space-4);
  border-bottom: 1px solid var(--color-border);
  text-align: right;
}

.woocommerce table.shop_table thead th {
  background: var(--color-surface-alt);
  font-size: var(--fs-sm);
}

@media (max-width: 599px) {
  .woocommerce table.shop_table th,
  .woocommerce table.shop_table td {
    padding: var(--space-3);
    font-size: var(--fs-sm);
  }
}

/* Below 640px the cart table can't fit its 6 columns (thumbnail, name,
   price, quantity, subtotal, remove) without horizontal scrolling, which
   left the product itself scrolled out of view. Replace it with a stacked
   card per line item instead of scrolling the wide table sideways — this
   also removes the horizontal overflow that was dragging the fixed bottom
   nav out of place on phones. Wins over WooCommerce's own bundled mobile
   table CSS (data-title labels + narrower cells) with !important. */
@media (max-width: 640px) {
  .tv-table-scroll {
    overflow-x: visible !important;
  }

  .tv-table-scroll table.shop_table.cart {
    min-width: 0 !important;
  }

  .woocommerce table.shop_table.cart thead {
    display: none !important;
  }

  .woocommerce table.shop_table.cart tr.cart_item {
    display: grid !important;
    grid-template-columns: 60px 1fr auto;
    grid-template-areas:
      "thumb name remove"
      "thumb price price"
      "thumb qty subtotal";
    column-gap: var(--space-3);
    row-gap: var(--space-1);
    align-items: center;
    padding: var(--space-3) !important;
    border: none !important;
    border-bottom: 1px solid var(--color-border) !important;
  }

  .woocommerce table.shop_table.cart tr.cart_item:last-child {
    border-bottom: none !important;
  }

  .woocommerce table.shop_table.cart tr.cart_item td {
    display: block;
    border: none !important;
    padding: 0 !important;
    width: auto;
  }

  .woocommerce table.shop_table.cart tr.cart_item td::before {
    content: none !important;
  }

  .woocommerce table.shop_table.cart td.product-thumbnail {
    grid-area: thumb;
  }

  .woocommerce table.shop_table.cart td.product-thumbnail img {
    width: 60px;
    height: 60px;
    object-fit: contain;
    border-radius: var(--radius-sm);
    display: block;
  }

  .woocommerce table.shop_table.cart td.product-name {
    grid-area: name;
    font-weight: 600;
    font-size: var(--fs-sm);
  }

  .woocommerce table.shop_table.cart td.product-remove {
    grid-area: remove;
  }

  .woocommerce table.shop_table.cart td.product-price {
    grid-area: price;
    color: var(--tv-ink-soft);
    font-size: var(--fs-xs);
  }

  .woocommerce table.shop_table.cart td.product-quantity {
    grid-area: qty;
  }

  .woocommerce table.shop_table.cart td.product-subtotal {
    grid-area: subtotal;
    font-weight: 700;
    text-align: left;
  }
}

.woocommerce table.shop_table td.product-remove a.remove {
  display: inline-grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--color-danger-tint);
  color: var(--color-danger) !important;
  font-weight: 900;
}

.woocommerce-cart .cart-collaterals .cart_totals {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
}

.woocommerce-cart .cart-collaterals .cart_totals h2 {
  margin-top: 0;
}

/* ---- Checkout ---- */

/* "کد تخفیف دارید؟" toggle line: drop the shared .woocommerce-info notice's
   colored background/border/padding here specifically (that styling is still
   used as-is for real info notices elsewhere) so this reads as a plain line
   of text with an inline link, matching other Iranian storefronts (e.g.
   Lemor) instead of a big green banner. */
.woocommerce-form-coupon-toggle .woocommerce-info {
  background: none;
  border: none;
  padding: 0 0 var(--space-4);
  color: var(--color-text-muted);
  justify-content: flex-start;
  gap: var(--space-2);
}

.woocommerce-form-coupon-toggle .woocommerce-info .showcoupon {
  color: var(--tv-primary-dark);
  font-weight: 700;
  text-decoration: underline;
}

/* Coupon form: WooCommerce's default markup floats a wide input + a
   full-width button on their own rows with no card around them at all —
   restyle to a single compact white card (input + small pill button side
   by side), closer to other Iranian storefronts (e.g. Lemor) than the
   default. */
.woocommerce-form-coupon {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  margin: 0 0 var(--space-5);
}

.woocommerce-form-coupon .form-row {
  margin: 0;
  float: none;
  width: auto;
}

.woocommerce-form-coupon .form-row-first {
  flex: 1;
}

.woocommerce-form-coupon .form-row-first .input-text {
  width: 100%;
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-family: inherit;
  background: var(--color-surface);
  color: var(--tv-ink);
}

.woocommerce-form-coupon .form-row-first .input-text:focus {
  border-color: var(--tv-primary);
}

.woocommerce-form-coupon .form-row-last {
  flex: 0 0 auto;
}

.woocommerce-form-coupon .form-row-last .button {
  white-space: nowrap;
}

.woocommerce-form-coupon .clear {
  display: none;
}

@media (max-width: 480px) {
  .woocommerce-form-coupon {
    flex-wrap: wrap;
  }
  .woocommerce-form-coupon .form-row-first {
    flex-basis: 100%;
  }
  .woocommerce-form-coupon .form-row-last .button {
    width: 100%;
  }
}

/* Two-column checkout: form fields (billing/shipping/notes) on one side,
   order summary + payment sticky on the other, so the total and the "پرداخت"
   button are visible without scrolling past the whole form first — matches
   how other Iranian storefronts (e.g. Lemor) lay this page out. core markup is
   <form class="checkout"> > .col2-set#customer_details (billing+shipping) then
   #order_review (summary table + #payment); grid-template-areas reorders them
   visually (summary first, i.e. right-hand side in RTL) without touching PHP. */
/* The checkout page is a normal WordPress page (page-id-706) rendering the
   [woocommerce_checkout] shortcode through page.php — its .tv-container
   wrapper already sits at the site's normal 1240px (same as every other
   page), which is wide enough here, so no override is needed on it. */

/* .tv-content itself (style.css) caps at max-width:820px — sized for plain
   text pages (about/contact/blog), which is what actually kept the checkout
   form narrow even after widening its .tv-container parent above. Lift that
   cap specifically when it's wrapping the checkout form. */
.tv-content:has(.woocommerce-checkout) {
  max-width: none;
  width: 100%;
}

.woocommerce-checkout form.checkout {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
}

@media (min-width: 900px) {
  .woocommerce-checkout form.checkout {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas: "fields summary";
    align-items: start;
  }

  .woocommerce-checkout #customer_details {
    grid-area: fields;
  }

  .woocommerce-checkout #order_review_heading,
  .woocommerce-checkout #order_review {
    grid-area: summary;
  }

  /* #order_review_heading and #order_review share grid-area:summary, so they
     stack directly on top of each other in the same grid cell rather than
     flowing one after another — margin-top on just one of them only shifts
     that element within the shared cell, not the other. Both need the same
     margin-top to move down together as one visual unit. */
  .woocommerce-checkout #order_review_heading {
    position: sticky;
    top: var(--space-4);
    margin-top: calc(var(--space-3) * 3 - 5px);
  }

  .woocommerce-checkout #order_review {
    position: sticky;
    top: calc(var(--space-4) + 2.4em);
    margin-top: calc(var(--space-3) * 3 - 5px);
    max-height: calc(100vh - var(--space-8));
    overflow-y: auto;
  }
}

/* On this site col-1 holds only the billing card, while col-2 bundles
   shipping + order notes together (checked directly against the live
   markup), so a side-by-side 2-column split never made sense *within*
   customer_details: it left billing alone on one side and everything else
   crammed onto the other. Stack those two full-width in DOM order instead.
   WooCommerce's own core CSS still sizes .col-1/.col-2 at width:47% with a
   float for its default layout; reset both so the grid track decides width. */
.woocommerce-checkout .col2-set {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
}

.woocommerce-checkout .col2-set .col-1,
.woocommerce-checkout .col2-set .col-2 {
  width: auto;
  float: none;
}

.woocommerce form .form-row label {
  font-weight: 600;
  font-size: var(--fs-sm);
  margin-bottom: var(--space-1);
  display: block;
}

.woocommerce form .form-row input.input-text,
.woocommerce form .form-row textarea,
.woocommerce form .form-row select {
  width: 100%;
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-family: inherit;
  background: var(--color-surface);
  color: var(--color-text);
}

.woocommerce form .form-row input.input-text:focus,
.woocommerce form .form-row textarea:focus,
.woocommerce form .form-row select:focus {
  border-color: var(--tv-primary);
}

#order_review,
.woocommerce-checkout-review-order {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
}

.woocommerce-checkout #payment {
  background: var(--color-surface-alt);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  margin-top: var(--space-4);
}

.woocommerce-checkout #payment ul.payment_methods {
  list-style: none;
  padding: 0;
  margin: 0;
}

.woocommerce-checkout #payment .payment_box {
  background: var(--color-surface);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  margin-top: var(--space-2);
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
}

/* Billing/shipping/order-notes read as a loose pile of fields with no
   visual grouping — give each the same card language used elsewhere on
   the site (border + radius + padding). */
.woocommerce-billing-fields,
.woocommerce-additional-fields {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  margin-bottom: var(--space-6);
}

/* Single billing address only — the "ship to a different address?" toggle
   and the order-notes textarea are both dropped from checkout per client
   request. */
.woocommerce-checkout .woocommerce-shipping-fields,
.woocommerce-checkout .woocommerce-additional-fields {
  display: none;
}

.woocommerce-billing-fields h3,
.woocommerce-shipping-fields > h3 {
  margin-top: 0;
  font-size: var(--fs-md);
}

.woocommerce-shipping-fields .shipping_address {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  margin-top: var(--space-4);
}

.woocommerce form .form-row {
  margin-bottom: var(--space-4);
}

.woocommerce form .form-row:last-child {
  margin-bottom: 0;
}

/* Below ~600px the checkout's own col2-set already stacks to a single
   column (see @media (min-width: 900px) above), but WooCommerce's core
   CSS still splits name/family (and any other form-row-first/-last pair)
   50/50 inside that single narrow column, squeezing each input down to
   a near-square box. Stack those to full width instead, and trim the
   card's own padding so the narrow width goes to the fields, not the
   frame around them. */
@media (max-width: 599px) {
  .woocommerce-billing-fields,
  .woocommerce-additional-fields,
  .woocommerce-shipping-fields .shipping_address {
    padding: var(--space-4);
  }

  .woocommerce-billing-fields__field-wrapper .form-row-first,
  .woocommerce-billing-fields__field-wrapper .form-row-last,
  .woocommerce-shipping-fields__field-wrapper .form-row-first,
  .woocommerce-shipping-fields__field-wrapper .form-row-last {
    width: 100%;
    float: none;
  }
}

.woocommerce form .form-row .woocommerce-invalid-required-field-message {
  display: block;
  margin-top: var(--space-1);
  font-size: var(--fs-xs);
  color: var(--color-danger);
}

#order_comments {
  min-height: 90px;
  resize: vertical;
}

/* Checkout page only: swap the shared cream tint (--color-surface-alt,
   used by cards across the whole site) for plain white on the payment
   box and order-review table header. Scoped to .woocommerce-checkout so
   nothing outside this page changes. */
.woocommerce-checkout #payment,
.woocommerce-checkout table.shop_table thead th {
  background: var(--color-surface);
}

/* Email is now shown as an optional registration field (toyvibe_make_registration_email_optional
   in functions.php clears the `required` attribute) — if the customer leaves it blank, a
   placeholder is generated behind the scenes (see toyvibe_fill_placeholder_email). */

.tv-form-error {
  background: var(--color-danger-tint);
  border: 1px solid var(--color-danger);
  color: var(--tv-ink);
  border-radius: var(--radius-sm);
  padding: var(--space-3) var(--space-4);
  font-weight: 600;
  margin-bottom: var(--space-4);
}

/* ---- My account ---- */

.woocommerce-account .woocommerce {
  display: block;
  width: 100%;
}

.woocommerce-account .woocommerce-MyAccount-navigation,
.woocommerce-account .woocommerce-MyAccount-content {
  width: 100%;
  box-sizing: border-box;
}

.woocommerce-account .woocommerce-MyAccount-content {
  margin-top: var(--space-6);
}

@media (min-width: 800px) {
  .woocommerce-account .woocommerce {
    display: flex;
    align-items: flex-start;
    gap: var(--space-6);
  }
  .woocommerce-account .woocommerce-MyAccount-navigation {
    flex: 0 0 220px;
    width: 220px;
  }
  .woocommerce-account .woocommerce-MyAccount-content {
    flex: 1 1 0%;
    min-width: 0;
    margin-top: 0;
  }
}

.woocommerce-account .woocommerce-MyAccount-navigation ul {
  list-style: none;
  padding: var(--space-2);
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
}

.woocommerce-account .woocommerce-MyAccount-navigation a {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-3);
  border-radius: var(--radius-sm);
  font-weight: 600;
  font-size: var(--fs-sm);
  color: var(--color-text);
}

.woocommerce-account .woocommerce-MyAccount-navigation a::before {
  content: "";
  display: inline-block;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  background-color: var(--tv-ink-soft);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

.woocommerce-account .woocommerce-MyAccount-navigation a:hover {
  background: var(--color-surface-alt);
}

.woocommerce-account .woocommerce-MyAccount-navigation li.is-active a {
  background: var(--tv-primary-tint);
  color: var(--tv-primary-dark);
}

.woocommerce-account .woocommerce-MyAccount-navigation li.is-active a::before {
  background-color: var(--tv-primary-dark);
}

.woocommerce-MyAccount-navigation-link--dashboard a::before {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M3 11.5 12 4l9 7.5'/%3E%3Cpath d='M5.5 10v9a1 1 0 0 0 1 1H9a1 1 0 0 0 1-1v-4a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v4a1 1 0 0 0 1 1h2.5a1 1 0 0 0 1-1v-9'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M3 11.5 12 4l9 7.5'/%3E%3Cpath d='M5.5 10v9a1 1 0 0 0 1 1H9a1 1 0 0 0 1-1v-4a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v4a1 1 0 0 0 1 1h2.5a1 1 0 0 0 1-1v-9'/%3E%3C/svg%3E");
}

.woocommerce-MyAccount-navigation-link--orders a::before {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M3 4h2l2.4 12.4a2 2 0 0 0 2 1.6h7.7a2 2 0 0 0 2-1.6L21 8H6'/%3E%3Ccircle cx='9.5' cy='20.5' r='1.4'/%3E%3Ccircle cx='17.5' cy='20.5' r='1.4'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M3 4h2l2.4 12.4a2 2 0 0 0 2 1.6h7.7a2 2 0 0 0 2-1.6L21 8H6'/%3E%3Ccircle cx='9.5' cy='20.5' r='1.4'/%3E%3Ccircle cx='17.5' cy='20.5' r='1.4'/%3E%3C/svg%3E");
}

.woocommerce-MyAccount-navigation-link--edit-address a::before {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M12 21s-7-6.2-7-11a7 7 0 0 1 14 0c0 4.8-7 11-7 11Z'/%3E%3Ccircle cx='12' cy='10' r='2.4'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M12 21s-7-6.2-7-11a7 7 0 0 1 14 0c0 4.8-7 11-7 11Z'/%3E%3Ccircle cx='12' cy='10' r='2.4'/%3E%3C/svg%3E");
}

.woocommerce-MyAccount-navigation-link--edit-account a::before {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Ccircle cx='12' cy='8' r='3.6'/%3E%3Cpath d='M4.5 20c1.2-4 4-6 7.5-6s6.3 2 7.5 6'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Ccircle cx='12' cy='8' r='3.6'/%3E%3Cpath d='M4.5 20c1.2-4 4-6 7.5-6s6.3 2 7.5 6'/%3E%3C/svg%3E");
}

.woocommerce-MyAccount-navigation-link--customer-logout {
  margin-top: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px solid var(--color-border);
}

.woocommerce-MyAccount-navigation-link--customer-logout a {
  color: var(--color-danger);
  font-weight: 700;
}

.woocommerce-MyAccount-navigation-link--customer-logout a::before {
  background-color: var(--color-danger);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4'/%3E%3Cpath d='M16 17l5-5-5-5'/%3E%3Cpath d='M21 12H9'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2'%3E%3Cpath d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4'/%3E%3Cpath d='M16 17l5-5-5-5'/%3E%3Cpath d='M21 12H9'/%3E%3C/svg%3E");
}

.woocommerce-MyAccount-navigation-link--customer-logout a:hover {
  background: var(--color-danger-tint);
}

/* Greeting line ("Hello X, not you? Log out") — the account content's
   first paragraph, styled as a card instead of plain text. The second,
   more verbose explanatory paragraph is redundant once the stat cards
   below exist, so it's hidden rather than kept as clutter. */
.woocommerce-MyAccount-content > p:first-of-type {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-5);
  margin-bottom: var(--space-5);
  color: #000;
}

.woocommerce-MyAccount-content > p:first-of-type a {
  color: #000;
  font-weight: 700;
}

.woocommerce-MyAccount-content > p:nth-of-type(2) {
  display: none;
}

.tv-account-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-4);
  margin-bottom: var(--space-6);
}

@media (max-width: 560px) {
  .tv-account-stats {
    grid-template-columns: 1fr;
  }
}

.tv-account-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  text-align: center;
  padding: var(--space-5) var(--space-3);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

.tv-account-stat-icon {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.6);
}

.tv-account-stat-value {
  font-size: var(--fs-lg);
  font-weight: 800;
  font-family: var(--font-display);
}

.tv-account-stat-label {
  font-size: var(--fs-xs);
  font-weight: 600;
  opacity: 0.85;
}

.tv-account-stat-orders {
  background: var(--tv-primary-tint);
  color: var(--tv-primary-dark);
}

.tv-account-stat-spent {
  background: var(--tv-sage-tint);
  color: var(--tv-sage);
}

.tv-account-stat-products {
  background: var(--tv-cream);
  color: var(--tv-peach-dark);
}

/* WooCommerce's own bundled CSS still styles this exact markup as a
   legacy float-based 2-column layout — the wrapper can carry either/both
   of .addresses / .col2-set / .u-columns depending on version, and each
   card either/both of .woocommerce-Address / .col-1 / .col-2 / .u-column1
   / .u-column2 — at the same selector specificity as the rules below, so
   without !important on every alias it wins on load order alone (same
   category of bug found and fixed on the checkout page's col2-set).
   Requested as always single-column/stacked, so no 2-column breakpoint
   here at all (unlike the shop-loop product grid this comment used to
   describe). */
.woocommerce-account .addresses,
.woocommerce-account .woocommerce-Addresses,
.woocommerce-account .col2-set,
.woocommerce-account .u-columns {
  display: grid !important;
  gap: var(--space-4);
  grid-template-columns: 1fr !important;
  width: 100% !important;
  float: none !important;
}

.woocommerce-account .woocommerce-Address,
.woocommerce-account .col-1,
.woocommerce-account .col-2,
.woocommerce-account .u-column1,
.woocommerce-account .u-column2 {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  float: none !important;
  width: 100% !important;
  margin: 0 !important;
}

.woocommerce-account .woocommerce-Address-title {
  display: flex !important;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
  overflow: visible !important;
}

.woocommerce-account .woocommerce-Address-title h2 {
  font-size: var(--fs-md);
  margin: 0;
  float: none !important;
}

.woocommerce-account .woocommerce-Address-title .edit {
  float: none !important;
}

.woocommerce-account .addresses .title .edit {
  color: var(--tv-primary-dark);
  font-weight: 700;
  font-size: var(--fs-sm);
}

.woocommerce-account address {
  font-style: normal;
  color: var(--color-text-muted);
  line-height: 1.8;
}

/* ---- Color swatches (replaces the native <select> for variations,
   injected by main.js) ---- */

.tv-color-select-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.tv-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-block: var(--space-2);
}

.tv-swatch {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 2px solid var(--color-surface);
  box-shadow: 0 0 0 1px var(--color-border);
  cursor: pointer;
  padding: 0;
  position: relative;
  transition: box-shadow 120ms ease, transform 120ms ease;
}

.tv-swatch.tv-swatch-light {
  box-shadow: 0 0 0 1px var(--color-border), inset 0 0 0 1px var(--color-border);
}

.tv-swatch:hover {
  transform: translateY(-2px);
}

.tv-swatch.is-active {
  box-shadow: 0 0 0 2px var(--color-surface), 0 0 0 4px var(--tv-primary);
}

.tv-swatch.is-active::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.15);
}

/* A colour with nothing in stock behind it. Marked before the buyer clicks
   rather than after: the old behaviour let someone pick the black flask and
   only then told them it was gone, which spends a click to deliver bad news.
   ::before because ::after already carries the selected ring above. */
.tv-swatch.tv-swatch-oos {
  cursor: not-allowed;
}

/* The wash and the line are BOTH drawn on ::before, and the button itself keeps
   full opacity. The first attempt faded the whole button with opacity: 0.5 —
   which faded the strike along with it, which is why the line read as a faint
   grey smudge. Red now, with a white halo under it so it stays visible on a
   black swatch and on a white one alike. */
.tv-swatch.tv-swatch-oos::before {
  content: "";
  position: absolute;
  inset: -2px;
  border-radius: 50%;
  background:
    linear-gradient(
      to top left,
      transparent calc(50% - 1.5px),
      #dc2626 calc(50% - 1.5px),
      #dc2626 calc(50% + 1.5px),
      transparent calc(50% + 1.5px)
    ),
    linear-gradient(
      to top left,
      transparent calc(50% - 3px),
      rgba(255, 255, 255, 0.9) calc(50% - 3px),
      rgba(255, 255, 255, 0.9) calc(50% + 3px),
      transparent calc(50% + 3px)
    ),
    rgba(255, 255, 255, 0.55);
}

/* No lift on hover — a sold-out swatch should not feel like the others. */
.tv-swatch.tv-swatch-oos:hover {
  transform: none;
}

.tv-swatch-label {
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
  margin: 0 0 var(--space-3);
}

.tv-swatch-label strong {
  color: var(--color-text);
  font-weight: 700;
}

/* ---- Star rating ---- */

.woocommerce .star-rating {
  color: var(--tv-peach-dark);
}

/* ---- Quantity increment/decrement buttons injected by main.js ---- */

.tv-qty-stepper {
  /* Locked to LTR so the −/+ order stays put regardless of which RTL
     context this renders inside (product page vs. cart table row) —
     otherwise the same DOM order visually flips depending on ancestor
     direction. */
  direction: ltr;
  display: inline-flex;
  align-items: center;
  /* overflow:hidden below (needed to clip the buttons to the pill's rounded
     corners) has a side effect per spec: it makes this element's automatic
     min-width resolve to 0 instead of hugging its content. As a flex item
     next to the add-to-cart button, that let the flex algorithm crush this
     down to a sliver instead of wrapping to a new line. flex-shrink:0 keeps
     it at its natural size no matter how tight the row gets. */
  flex-shrink: 0;
  border: 1px solid #dcdcdc;
  border-radius: var(--radius-pill);
  overflow: hidden;
}

.tv-qty-stepper button {
  border: none;
  background: var(--color-surface);
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  font-size: var(--fs-sm);
  line-height: 1;
  cursor: pointer;
}

/* .woocommerce div.product .quantity .qty (width:70px + visible border) is
   more specific than a plain ".tv-qty-stepper .qty", so it was winning the
   cascade and the "shrink it down" rule below never actually applied —
   !important is the simplest reliable way to guarantee this wins regardless
   of which page/context the stepper renders in. */
.tv-qty-stepper .qty {
  border: none !important;
  background: var(--color-surface) !important;
  width: 30px !important;
  height: 28px !important;
  padding: 0 !important;
  margin: 0 !important;
  text-align: center !important;
  font-size: var(--fs-sm) !important;
  line-height: 28px !important;
}

@media (max-width: 699px) {
  .woocommerce ul.products li.product .woocommerce-loop-product__title {
    font-size: var(--fs-xs);
  }
}

/* ---- Pagination (shop / category archive) ---- */

.woocommerce nav.woocommerce-pagination {
  margin-top: var(--space-8);
}

.woocommerce nav.woocommerce-pagination ul {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
  border: none !important;
  background: none !important;
}

.woocommerce nav.woocommerce-pagination ul li {
  border: none !important;
}

/* The `li` in these three selectors is load-bearing, not decoration.
   WooCommerce puts the class "page-numbers" on BOTH the individual links and
   the <ul> that wraps them. Without the `li`, the pill styling below also hit
   the <ul> — handing the container a fixed height:40px and display:inline-flex.
   Once there were enough pages to wrap onto a second row (page 5+ on a phone),
   the container stayed one row tall while its contents spilled out the bottom
   and over the footer. Scoping to links inside a list item leaves the <ul>
   free to grow with its rows. */
.woocommerce nav.woocommerce-pagination li .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  height: 40px;
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  font-weight: 700;
  font-size: var(--fs-sm);
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
}

.woocommerce nav.woocommerce-pagination li .page-numbers.dots {
  background: none;
  border-color: transparent;
}

.woocommerce nav.woocommerce-pagination li .page-numbers.current {
  background: var(--color-primary);
  color: var(--tv-ink);
  border-color: transparent;
}

.woocommerce nav.woocommerce-pagination a.page-numbers:hover {
  border-color: var(--tv-primary);
  color: var(--tv-primary-dark);
}

/* ---- Touch targets on phones and tablets ----
   The stepper's -/+ buttons render at 28px and the add-to-cart button at
   42px tall, both under the 44px minimum tap target. Enlarged below the
   theme's mobile breakpoint only; on desktop a mouse makes the compact
   pill's smaller hit area a non-issue, so the design there is unchanged.
   The .qty overrides need !important to match the specificity of the
   existing .tv-qty-stepper .qty rule above. */

@media (max-width: 959px) {
  .tv-qty-stepper button {
    width: 44px;
    height: 44px;
    font-size: var(--fs-md);
  }

  .tv-qty-stepper .qty {
    width: 46px !important;
    height: 44px !important;
    line-height: 44px !important;
    font-size: var(--fs-base) !important;
  }

  /* The wider stepper no longer leaves room for the button on the same row,
     so it wraps. Rather than sit at its content width with dead space beside
     it, let it fill the row — the full-width CTA is the usual mobile
     storefront pattern and makes the primary action easier to hit. */
  .woocommerce div.product form.cart .single_add_to_cart_button,
  .woocommerce div.product .woocommerce-variation-add-to-cart .single_add_to_cart_button {
    min-height: 44px;
    flex: 1 1 100%;
  }
}


/* ---------------------------------------------------------------------------
   Product gallery: hold the column at its final height while it is still hidden

   WooCommerce ships the gallery with an inline `opacity: 0` and clears it only
   once FlexSlider has finished. In between, the column is laid out at three very
   different heights. Traced in a real browser on 2026-08-22, 3-image product,
   412px viewport:

       pre-JS, images stacked in normal flow ................  458px
       .flex-viewport built, slides NOT yet positioned ....... 2823px
       slides positioned, thumbnail strip built .............   469px  <- final

   On mobile the summary column sits BELOW the gallery, so each of those heights
   drags the title, price and add-to-cart button with it. On the 18-image product
   the middle state reaches 29,385px. On desktop the two columns sit side by side,
   which is why desktop CLS was always near zero and mobile was not.

   THE TRAP, and why the previous attempt made this worse (0.189 -> 0.298):
   it keyed on `.flex-viewport` existing. That element is created at the START of
   the middle state, so the images were revealed at the exact moment they were
   stacked and unpositioned. The only marker that spans all three states is
   WooCommerce's own inline `opacity: 0`, which is what these rules use.
   ("transition: opacity 0.25s" cannot false-match: no colon after `opacity`.)

   Two measured facts make the arithmetic exact:
     - every product image on this site is square, so one slide is exactly as
       tall as the column is wide;
     - the thumbnail strip is a single 108px row at BOTH 361px and 598px column
       widths, so it does not scale and 108px is a constant, not a guess.

   `aspect-ratio` is used rather than `padding-bottom: 100%` on purpose: percentage
   padding resolves against the PARENT's width, and this column is 48% of its
   parent on desktop, which would have over-reserved by roughly 2x.

   Single-image products are excluded by the `:nth-child(2)` test. FlexSlider
   disables itself at one image, builds no strip, and those pages already measure
   a flat 361px from first paint to reveal - adding a 108px reserve would create
   a shift where none exists. Browsers without `:has()` drop these rules entirely
   and get exactly today's behaviour.
   --------------------------------------------------------------------------- */
.woocommerce div.product div.images.woocommerce-product-gallery[style*="opacity: 0"]:has(.woocommerce-product-gallery__image:nth-child(2)) > .woocommerce-product-gallery__wrapper,
.woocommerce div.product div.images.woocommerce-product-gallery[style*="opacity: 0"]:has(.woocommerce-product-gallery__image:nth-child(2)) > .flex-viewport {
  aspect-ratio: 1 / 1;
  overflow: hidden;
}

/* Before FlexSlider builds the strip there is nothing to occupy its 108px, so the
   container reserves it. Once `.flex-control-thumbs` exists the real strip takes
   over and this stops applying, which is what keeps the total at 469px in every
   state instead of double-counting to 577px. */
.woocommerce div.product div.images.woocommerce-product-gallery[style*="opacity: 0"]:has(.woocommerce-product-gallery__image:nth-child(2)):not(:has(.flex-control-thumbs)) {
  padding-bottom: 108px;
}
