/* DUNEUS · Product card
 * ---------------------------------------------------------------------------
 * The card component emits the official Soft Theme class names (.product-item,
 * .box-1-1, .product-title, .add-to-wishlist …) because those carry the
 * commerce hooks. This file styles exactly those names.
 *
 * It exists because the ported reference stylesheet sized `.duneus-product-card`
 * — a class the component never renders — so cards received no width at all and
 * overflowed their row.
 * ------------------------------------------------------------------------ */

/* ===========================================================================
 * 1 · Card shell
 * ======================================================================== */
.product-item {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: transparent;
  border: 0;
}

/* ===========================================================================
 * 2 · Media frame — a fixed ratio is what keeps a row of cards aligned
 * ======================================================================== */
.product-item .d-card-media {
  position: relative;
  overflow: hidden;
  background: var(--pc-bg, #FFFFFF);
  border: var(--pc-border-width, 0) solid var(--pc-border, transparent);
  border-radius: var(--pc-radius, 0);
}

.product-item .box-1-1 {
  display: block;
  position: relative;
  aspect-ratio: var(--pc-aspect-ratio, 2 / 3) !important;
  overflow: hidden;
}
/* Soft Theme's base `.box-1-1::before { padding-top:100% }` forces a square and
   fights the aspect-ratio above, leaving cards at the wrong height. Remove it so
   --pc-aspect-ratio (2:3) is the single source of truth — a true 2:3 photo then
   fills edge-to-edge under object-fit:cover with no crop and no empty frame. */
.product-item .box-1-1::before { content: none !important; padding-top: 0 !important; }
.product-item .box-1-1 > .content,
.product-item .box-1-1 > .content > div {
  width: 100%;
  height: 100%;
}

.product-item .box-1-1 img {
  width: 100%;
  height: 100%;
  object-fit: var(--pc-image-fit, cover);
  padding: var(--pc-image-padding, 0);
  display: block;
  transition: transform 0.6s cubic-bezier(0.2, 0.7, 0.2, 1), opacity 0.3s ease;
}
.product-item:hover .box-1-1 img { transform: scale(1.03); }

/* Second image crossfade when the product has one. */
.product-item .d-card-img--alt {
  position: absolute;
  inset: 0;
  opacity: 0;
  z-index: 1;
}
.product-item:hover .d-card-img--alt { opacity: 1; }

/* ===========================================================================
 * 3 · Badges — top-start, on a light plate as in the reference
 * ======================================================================== */
.product-item .product-badge,
.product-item .preorder-badge--product-card {
  position: absolute;
  top: 10px;
  inset-inline-start: 10px;
  z-index: 3;
  padding: 5px 10px;
  border-radius: var(--pc-radius, 0);
  font-family: var(--duneus-font-en-heading, 'Montserrat'), sans-serif;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1;
  white-space: nowrap;
}
[dir='rtl'] .product-item .product-badge,
[dir='rtl'] .product-item .preorder-badge--product-card { letter-spacing: 0; text-transform: none; }

/* ===========================================================================
 * 4 · Wishlist — top-end, above the media, never colliding with the CTA
 * ======================================================================== */

/* ===========================================================================
 * 5 · Quick add — hidden until hover on pointer devices
 * This is what was overflowing: the CTA had no width rule, so it spilled past
 * the card and sat on top of the wishlist control.
 * ======================================================================== */
.product-item .d-card-action {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  z-index: 2;
  padding: 8px;
}
.product-item .d-card-action .btn,
.product-item .product-card-add-to-cart,
.product-item .btn-product-card-select-variant,
.product-item .btn-product-card-out-of-stock {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  width: 100%;
  min-height: 42px;
  margin: 0;
  padding: 0 0.75rem;
  border-radius: var(--pc-radius, 0);
  font-family: var(--duneus-font-en-heading, 'Montserrat'), sans-serif;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
[dir='rtl'] .product-item .d-card-action .btn { letter-spacing: 0; text-transform: none; }

@media (hover: hover) and (min-width: 768px) {
  .product-item .d-card-action {
    opacity: 0;
    transform: translateY(100%);
    transition: opacity 0.24s ease, transform 0.24s cubic-bezier(0.2, 0.7, 0.2, 1);
    pointer-events: none;
  }
  .product-item:hover .d-card-action,
  .product-item:focus-within .d-card-action {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }
}
/* Touch has no hover, so the CTA sits under the image instead of over it. */
@media (hover: none), (max-width: 767.98px) {
  .product-item .d-card-action { position: static; padding: 8px 0 0; }
}

/* ===========================================================================
 * 6 · Body — title, rating, price
 * ======================================================================== */
.product-item .d-card-body {
  display: block;
  padding-block-start: 0.85rem;
  text-align: var(--pc-text-align, start);
}

.product-item .product-card-rating-wrapper {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  margin-bottom: 0.3rem;
}
.product-item .product-card-rating-count { font-size: 0.75rem; color: var(--pc-compare-color, #8a8a8a); }

.product-item .product-crd-spec { display: flex; flex-direction: column; gap: 0.25rem; }

.product-item .section-product-price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.product-item .product-price {
  font-family: var(--duneus-font-en-body, 'Montserrat'), sans-serif;
  font-size: var(--pc-price-size, 15px);
  font-weight: var(--pc-price-weight, 600);
  color: var(--pc-price-color, #111);
}
.product-item .product-prev-price {
  font-size: 0.8125rem;
  font-weight: 400;
  color: var(--pc-compare-color, #8a8a8a);
  text-decoration: line-through;
}
.product-item .d-card-discount {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--duneus-accent, #FF5100);
}
.product-item .product-crd-spec small {
  font-size: 0.75rem;
  color: var(--pc-compare-color, #8a8a8a);
}

/* Out of stock recedes rather than disappears. */
.product-item-out-of-stock .box-1-1 img { opacity: 0.45; filter: grayscale(1); }

/* ===========================================================================
 * 7 · Row layouts — the width rules that were missing entirely
 * ======================================================================== */

/* Horizontal slider */
.duneus-scroller {
  display: flex;
  gap: var(--pc-gap, 12px);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: 0;
  scrollbar-width: none;
  padding-bottom: 0.25rem;
}
.duneus-scroller::-webkit-scrollbar { display: none; }

.duneus-scroller > .product-item {
  /* A fractional value (1.5, 2.5) lets the next card peek, which is what tells
     a shopper the row scrolls. The gap term uses ceil-ish rounding via the same
     fraction, which is close enough visually and avoids a second variable. */
  flex: 0 0 calc((100% - (var(--bs-cards-m, 1.5) - 1) * var(--pc-gap, 12px)) / var(--bs-cards-m, 1.5));
  scroll-snap-align: start;
}
@media (min-width: 768px) {
  .duneus-scroller > .product-item {
    flex: 0 0 calc((100% - (var(--bs-cards-d, 4) - 1) * var(--pc-gap, 12px)) / var(--bs-cards-d, 4));
  }
}

/* ---------------------------------------------------------------------------
 * RELATED PRODUCTS ("You may also like") — mobile
 * Soft's official JS unslicks this row below 768px, leaving an inline-block
 * scroller where .prod-col has no fixed width — so each card sized to its own
 * image and the rows came out staggered (badges aligned at the top, but the
 * button/title/price fell wherever each image happened to end). Give every
 * card one fixed width so the aspect-ratio image box resolves to a single
 * consistent height, matching the rest of the store's scrollers. Scoped to the
 * related row by its id; the official desktop slick (>=768px) is untouched. */
@media (max-width: 767.98px) {
  #related-products.products-slider {
    display: flex;
    gap: var(--pc-gap, 12px);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    white-space: normal;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  #related-products.products-slider::-webkit-scrollbar { display: none; }
  #related-products.products-slider .prod-col {
    display: block;
    flex: 0 0 calc((100% - (var(--bs-cards-m, 1.5) - 1) * var(--pc-gap, 12px)) / var(--bs-cards-m, 1.5));
    width: auto;
    padding-left: 0;
    padding-right: 0;
    white-space: normal;
    vertical-align: top;
    scroll-snap-align: start;
  }
}

/* Static grid */
.dn-pgrid {
  display: grid;
  grid-template-columns: repeat(var(--pg-cols-m, 2), minmax(0, 1fr));
  gap: var(--pc-gap, 12px);
}
@media (min-width: 768px) {
  .dn-pgrid { grid-template-columns: repeat(var(--pg-cols-d, 4), minmax(0, 1fr)); }
}

@media (prefers-reduced-motion: reduce) {
  .product-item .box-1-1 img,
  .product-item .d-card-action,
  .product-item .d-card-img--alt { transition: none; }
  .product-item:hover .box-1-1 img { transform: none; }
}

/* Add-to-cart spinner and the bundle-offer slot the component renders. */
.product-item .add-to-cart-progress { width: 18px; height: 18px; display: inline-block; }
/* The bundle-offer slot is filled by Zid's JS with the offer name and rendered
   as a large orange block that overlays the card photo. The bundle offer has a
   proper, tidy section on the product page, so on the listing CARD we suppress
   this slot entirely — the card stays clean and the offer is unaffected. */
.product-item .product-card-bundle-offer,
.product-item .product-card-bundle-offer.bundle-offer-product-tag,
.product-item .box-1-1 .product-card-bundle-offer { display: none !important; }

/* ===========================================================================
 * 8 · TOKEN-DRIVEN APPEARANCE
 * Every declaration below reads a token emitted by the Products section, so
 * each element on the card is controllable from the Theme Editor and two
 * sections on one page can look entirely different.
 * ======================================================================== */

/* ---- Card shell ---- */
.product-item .d-card-media {
  background: var(--pc-image-bg, #fff);
  border: var(--pc-border-width, 0) solid var(--pc-border, transparent);
  border-radius: var(--pc-radius, 0);
}
.product-item .d-card-body { padding-block-start: var(--pc-body-gap, 14px); }

body.pc-shadow-soft .product-item .d-card-media { box-shadow: 0 8px 20px -14px rgba(0,0,0,.9); }
body.pc-shadow-strong .product-item .d-card-media { box-shadow: 0 18px 40px -20px rgba(0,0,0,1); }

/* ---- Image ---- */
.product-item .box-1-1 { border-radius: var(--pc-image-radius, 0); }
.product-item .box-1-1 img { padding: var(--pc-image-padding, 0); }

body.pc-hover-none .product-item:hover .box-1-1 img { transform: none; }
body.pc-hover-zoom .product-item:hover .box-1-1 img { transform: scale(1.04); }
body.pc-hover-lift .product-item { transition: transform .28s cubic-bezier(.2,.7,.2,1); }
body.pc-hover-lift .product-item:hover { transform: translateY(-6px); }
body.pc-hover-lift .product-item:hover .box-1-1 img { transform: none; }
body.pc-hover-fade .product-item:hover .box-1-1 img { transform: none; }
body.pc-hover-fade .product-item:hover .d-card-img--alt { opacity: 1; }

/* ---- Badge (platform markup, so target every plausible wrapper) ---- */
.product-item .d-card-media > .product-badge,
.product-item .d-card-media > .badge,
.product-item .d-card-media > span[class*='badge'],
.product-item .d-card-media > div[class*='badge'],
.product-item .product-badge {
  position: absolute;
  top: var(--pc-badge-offset, 10px);
  inset-inline-start: var(--pc-badge-offset, 10px);
  inset-inline-end: auto;
  bottom: auto;
  z-index: 3;
  margin: 0;
  padding: .45em .8em;
  background: var(--pc-badge-bg, #FF5100) !important;
  color: var(--pc-badge-text, #fff) !important;
  border: 0;
  border-radius: var(--pc-badge-radius, 0);
  font-family: var(--duneus-font-en-heading, 'Montserrat'), sans-serif;
  font-size: var(--pc-badge-size, 10px);
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  line-height: 1;
  white-space: nowrap;
  box-shadow: none;
}
[dir='rtl'] .product-item .product-badge { letter-spacing: 0; text-transform: none; }

body.pc-badge-top-end .product-item .d-card-media > .product-badge,
body.pc-badge-top-end .product-item .product-badge {
  inset-inline-start: auto; inset-inline-end: var(--pc-badge-offset, 10px);
}
body.pc-badge-bottom-start .product-item .d-card-media > .product-badge,
body.pc-badge-bottom-start .product-item .product-badge {
  top: auto; bottom: var(--pc-badge-offset, 10px);
}
body.pc-no-badge .product-item .d-card-media > .product-badge,
body.pc-no-badge .product-item .product-badge { display: none; }

.product-item-out-of-stock .d-card-media > .product-badge {
  background: var(--pc-oos-badge-bg, #2A2A2A) !important;
  color: var(--pc-oos-badge-text, #B3B3B3) !important;
}

/* ---- Wishlist ---- */
body.pc-no-plate body.pc-no-wish 

/* ---- Add to cart ---- */
.product-item .d-card-action {
  position: absolute;
  inset-inline: var(--pc-cta-inset, 14px);
  bottom: var(--pc-cta-bottom, 26px);
  z-index: 4;
  padding: 0;
}
.product-item .d-card-action .btn,
.product-item .product-card-add-to-cart,
.product-item .btn-product-card-select-variant,
.product-item .btn-product-card-out-of-stock {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  width: 100%;
  min-height: var(--pc-cta-height, 44px);
  margin: 0;
  padding: 0 .75rem;
  background: var(--pc-cta-bg, #FF5100);
  border: 1px solid var(--pc-cta-bg, #FF5100);
  border-radius: var(--pc-cta-radius, 0);
  color: var(--pc-cta-text, #fff);
  font-family: var(--duneus-font-en-heading, 'Montserrat'), sans-serif;
  font-size: var(--pc-cta-size, 11px);
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background-color .35s cubic-bezier(.2,.7,.2,1), color .35s cubic-bezier(.2,.7,.2,1), border-color .35s cubic-bezier(.2,.7,.2,1), transform .35s cubic-bezier(.2,.7,.2,1), box-shadow .35s cubic-bezier(.2,.7,.2,1);
}
[dir='rtl'] .product-item .d-card-action .btn { letter-spacing: 0; text-transform: none; }
.product-item .d-card-action .btn:hover,
.product-item .product-card-add-to-cart:hover {
  background: var(--pc-cta-bg-hover, #fff);
  border-color: var(--pc-cta-bg-hover, #fff);
  color: var(--pc-cta-text-hover, #000);
  transform: translateY(-2px);
  box-shadow: 0 8px 22px rgba(0,0,0,.28);
}
body.pc-no-cta .product-item .d-card-action { display: none; }

@media (hover: hover) and (min-width: 768px) {
  body.pc-cta-hover .product-item .d-card-action {
    opacity: 0;
    transform: translateY(120%);
    transition: opacity .24s ease, transform .24s cubic-bezier(.2,.7,.2,1);
    pointer-events: none;
  }
  body.pc-cta-hover .product-item:hover .d-card-action,
  body.pc-cta-hover .product-item:focus-within .d-card-action {
    opacity: 1; transform: translateY(0); pointer-events: auto;
  }
}
@media (hover: none), (max-width: 767.98px) {
  .product-item .d-card-action { position: static; padding-block-start: 8px; }
}

/* ---- Title ---- */
.product-item .d-card-body { text-align: var(--pc-text-align, start); }
.product-item .d-card-body .product-title,
.product-item .d-card-body .product-title span {
  color: var(--pc-title-color, #111);
}
.product-item .product-title {
  margin: 0 0 var(--pc-title-spacing, 6px);
  font-family: var(--duneus-font-en-body, 'Montserrat'), sans-serif;
  font-size: var(--pc-title-size, 16px);
  font-weight: var(--pc-title-weight, 600);
  line-height: 1.35;
  text-transform: var(--pc-title-transform, none);
  display: -webkit-box;
  -webkit-line-clamp: var(--pc-title-lines, 2);
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ---- Rating ---- */
.product-item .product-card-rating-wrapper { display: flex; align-items: center; gap: .3rem; margin-bottom: .35rem; }
body.pc-no-rating .product-item .product-card-rating-wrapper { display: none; }
.product-item .product-card-rating-wrapper svg,
.product-item .product-card-rating-wrapper i,
.product-item .product-card-rating-wrapper span[class*='star'] {
  color: var(--pc-star, #E8B93B);
  fill: var(--pc-star, #E8B93B);
  font-size: var(--pc-star-size, 14px);
}
.product-item .product-card-rating-count { color: var(--pc-rating-count, #6A6A6A); font-size: calc(var(--pc-star-size, 14px) - 2px); }

/* ---- Price ---- */
.product-item .section-product-price { display: flex; align-items: baseline; flex-wrap: wrap; gap: .5rem; }
body.pc-cta-always .product-item .section-product-price { justify-content: inherit; }
.product-item .d-card-body .product-price {
  color: var(--pc-price-color, #111);
  font-size: var(--pc-price-size, 17px);
  font-weight: var(--pc-price-weight, 700);
}
.product-item .d-card-body .product-prev-price {
  color: var(--pc-compare-color, #6A6A6A);
  font-size: var(--pc-compare-size, 13px);
  text-decoration: line-through;
}
.product-item .d-card-body .d-card-discount { color: var(--pc-discount-color, #FF5100); font-size: var(--pc-compare-size, 13px); font-weight: 600; }

/* ---- Options note ---- */
.product-item .product-crd-spec small,
.product-item .product-crd-spec > span:last-child:not([class]) {
  color: var(--pc-note-color, #6A6A6A);
  font-size: var(--pc-note-size, 13px);
}
body.pc-no-note .product-item .product-crd-spec small { display: none; }

/* ---- Out of stock ---- */
.product-item-out-of-stock .box-1-1 img { opacity: .45; filter: grayscale(1); }
.product-item .btn-product-card-out-of-stock {
  background: var(--pc-oos-badge-bg, #2A2A2A) !important;
  border-color: var(--pc-oos-badge-bg, #2A2A2A) !important;
  color: var(--pc-oos-badge-text, #B3B3B3) !important;
}

/* ---- Row layouts ---- */

.dn-pgrid { display: grid; grid-template-columns: repeat(var(--pg-cols-m, 2), minmax(0,1fr)); gap: var(--pc-gap, 12px); }
@media (min-width: 768px) { .dn-pgrid { grid-template-columns: repeat(var(--pg-cols-d, 4), minmax(0,1fr)); } }

@media (prefers-reduced-motion: reduce) {
  .product-item, .product-item .box-1-1 img, .product-item .d-card-action,
  .product-item .add-to-wishlist, .product-item .d-card-action .btn { transition: none; }
}

/* ===========================================================================
 * 9 · WISHLIST — the control IS the heart
 * The markup renders <button class="icon-heart-mask"> directly, so the button
 * itself is the masked element. Resetting it (all: unset) wiped the mask, the
 * size and the colour that custom.css provides, which is why nothing showed.
 * Style it in place instead.
 * ======================================================================== */
.product-item .add-to-wishlist > span,

/* ===========================================================================
 * 10 · RATING STARS — drawn by an icon font through ::before
 * main.css colours `.product-card-rating .icon-star1:before` at (0,4,0), so a
 * rule on the span never reaches them. These match that shape and clear it.
 * ======================================================================== */
.product-item .product-card-rating .icon-star1:before,
.product-item .product-card-rating .icon-half-star:before,
.product-item .product-card-rating .icon-star1,
.product-item .product-card-rating .icon-half-star {
  color: var(--pc-star, #E8B93B);
  font-size: var(--pc-star-size, 14px);
}
/* Empty stars keep a muted tone so the score stays readable. */
.product-item .product-card-rating .icon-star1.deactive:before,
.product-item .product-card-rating .icon-star1.deactive {
  color: var(--pc-star-empty, rgba(255, 255, 255, 0.22));
}
.product-item .product-card-rating-count {
  color: var(--pc-rating-count, #6A6A6A);
  font-size: calc(var(--pc-star-size, 14px) - 2px);
}

/* ===========================================================================
 * 11 · SLIDER ARROWS
 * Two placements. `edge` floats them over the row's outer edges; `header` puts
 * a tidy pair beside the section title. Both fade out when the row cannot
 * scroll any further, so a dead control is never offered.
 * ======================================================================== */
.dn-prod__row { position: relative; }

.dn-prod__arrow {
  all: unset;
  box-sizing: border-box;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 1px solid var(--dn-arrow-border, rgba(255, 255, 255, 0.22));
  border-radius: var(--dn-arrow-radius, 999px);
  background: var(--dn-arrow-bg, transparent);
  color: var(--dn-arrow-fg, #fff);
  transition: background-color .2s ease, border-color .2s ease, color .2s ease, opacity .2s ease;
}
.dn-prod__arrow svg {
  width: 18px; height: 18px;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
[dir='rtl'] .dn-prod__arrow svg { transform: scaleX(-1); }

.dn-prod__arrow:hover {
  background: var(--dn-arrow-bg-hover, #fff);
  border-color: var(--dn-arrow-bg-hover, #fff);
  color: var(--dn-arrow-fg-hover, #000);
}
/* Disabled rather than hidden, so the row does not jump as you scroll. */
.dn-prod__arrow[disabled] { opacity: .25; pointer-events: none; }

/* --- edge placement --- */
.dn-prod__row--arrows > .dn-prod__arrow--prev,
.dn-prod__row--arrows > .dn-prod__arrow--next {
  position: absolute;
  top: calc(50% - 40px);
  z-index: 5;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  background: var(--dn-arrow-bg, rgba(0, 0, 0, .35));
}
.dn-prod__row--arrows > .dn-prod__arrow--prev { inset-inline-start: -8px; }
.dn-prod__row--arrows > .dn-prod__arrow--next { inset-inline-end: -8px; }

@media (max-width: 767.98px) {
  /* On touch the row is swipeable, so floating arrows only cover product art. */
  .dn-prod__row--arrows > .dn-prod__arrow--prev,
  .dn-prod__row--arrows > .dn-prod__arrow--next { display: none; }
}

/* --- header placement --- */
.dn-sec-head__end { display: flex; align-items: center; gap: 1rem; }
.dn-prod__navpair { display: inline-flex; gap: .5rem; }
.dn-prod__navpair .dn-prod__arrow { width: 36px; height: 36px; }

/* ===========================================================================
 * 12 · CARD WIDTH
 * main.css caps every card at `max-width: 200px`, which fought the row's own
 * width calculation and left cards small with gaps beside them. The row (grid
 * or slider) already decides how wide a card should be, so the cap is removed
 * and the card simply fills the track it is given.
 * ======================================================================== */
.duneus-scroller > .product-item,
.dn-pgrid > .product-item,
.product-item {
  max-width: none;
  width: 100%;
}

/* The image element must fill its frame rather than sit at intrinsic size. */
.product-item .box-1-1 .content,
.product-item .box-1-1 .content > div { width: 100%; height: 100%; }
.product-item .box-1-1 img {
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: var(--pc-image-fit, cover);
}

/* ===========================================================================
 * 13 · TITLE CLAMP AND SPACING — the real owners
 * main.css clamps the INNER <span>, not the title div:
 *     .product-item .product-title > span { height:48px; -webkit-line-clamp:2 }
 * and fixes the block with `.product-item .product-title { min-height:46px }`.
 * A fixed height plus a hardcoded clamp override anything set on the parent,
 * which is why the line-count and spacing settings appeared to do nothing.
 * The clamp is moved onto the span where it belongs, and the fixed heights are
 * replaced by ones derived from the settings.
 * ======================================================================== */
.product-item .d-card-body .product-title {
  min-height: 0;
  display: block;
  margin: 0 0 var(--pc-title-spacing, 6px);
  overflow: visible;
}

.product-item .d-card-body .product-title > span {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--pc-title-lines, 2);
  overflow: hidden;
  text-overflow: ellipsis;
  /* Reserve exactly the chosen number of lines so rows stay aligned even when
     one product name is shorter than the rest. */
  height: auto;
  min-height: calc(var(--pc-title-size, 16px) * 1.35 * var(--pc-title-lines, 2));
  font-size: var(--pc-title-size, 16px);
  font-weight: var(--pc-title-weight, 600);
  line-height: 1.35;
  text-transform: var(--pc-title-transform, none);
  color: var(--pc-title-color, #111);
}

body.pc-no-reserve .product-item .d-card-body .product-title > span { min-height: 0; }

/* ===========================================================================
 * 14 · PRODUCTS WITH SIDE BANNER (.dn-pb)
 * A banner pinned to the start of the row with products scrolling beside it.
 * Cards are the shared component, so they inherit every Product Card token —
 * only the arrangement and two optional flourishes live here.
 * ======================================================================== */
.dn-pb { position: relative; overflow-x: clip; }
/* `clip` rather than `hidden` so a sticky header above is unaffected. */
@supports not (overflow: clip) { .dn-pb { overflow-x: hidden; } }

.dn-pb__wrap { display: flex; gap: var(--pb-gap, 2px); align-items: flex-start; }

/* ---- Banner ---- */
.dn-pb__banner {
  position: relative;
  flex: 0 0 auto;
  overflow: hidden;
  display: none;                       /* stacked above the row on mobile */
  aspect-ratio: var(--pb-ratio, 3/4);
  background: var(--duneus-bg-secondary, #0C0C0C);
}
.dn-pb__img, .dn-pb__video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: var(--pb-fit, cover); object-position: center; }
.dn-pb__img--d, .dn-pb__video--d { display: none; }
.dn-pb__img--m, .dn-pb__video--m { display: block; }
.dn-pb__scrim {
  position: absolute; inset: 0;
  background: linear-gradient(0deg, rgba(0,0,0,var(--pb-overlay,.35)), rgba(0,0,0,calc(var(--pb-overlay,.35) * .3)));
}
.dn-pb__copy {
  position: absolute;
  inset-inline: 0;
  top: 50%;
  transform: translateY(-50%);
  padding: clamp(1rem, 3vw, 2rem);
  text-align: center;
}
.dn-pb__title {
  margin: 0 0 1.25rem;
  font-family: var(--duneus-font-en-heading, 'Montserrat'), sans-serif;
  font-weight: 500;
  font-size: var(--pb-title-m, 24px);
  line-height: 1.1;
  letter-spacing: .01em;
  color: var(--pb-title-color, #fff);
}
.dn-pb__text { margin: -.75rem 0 1.25rem; color: rgba(255,255,255,.82); font-size: .875rem; line-height: 1.6; }
.dn-pb__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: 0 2.25rem;
  background: var(--pb-cta-bg, #fff);
  color: var(--pb-cta-text, #000);
  font-family: var(--duneus-font-en-heading, 'Montserrat'), sans-serif;
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  transition: background-color .22s ease, color .22s ease;
}
[dir='rtl'] .dn-pb__cta { letter-spacing: 0; text-transform: none; }
.dn-pb__cta:hover { background: var(--pb-cta-bg-hover, #FF5100); color: var(--pb-cta-text-hover, #fff); }

/* ---- Row ---- */
.dn-pb__rowwrap { position: relative; flex: 1 1 auto; min-width: 0; }
.dn-pb__row { gap: var(--pb-gap, 2px); }
/* Higher specificity (.dn-pb__row.duneus-scroller) so these win over the
   generic .duneus-scroller > .product-item sizing — otherwise the banner
   cards took the generic/huge width. */
.dn-pb .dn-pb__row.duneus-scroller > .product-item {
  flex: 0 0 calc((100% - (var(--bs-cards-m, 1.5) - 1) * var(--pb-gap, 2px)) / var(--bs-cards-m, 1.5)) !important;
}
@media (min-width: 768px) {
  .dn-pb .dn-pb__row.duneus-scroller > .product-item {
    flex: 0 0 calc((100% - (var(--bs-cards-d, 3) - 1) * var(--pb-gap, 2px)) / var(--bs-cards-d, 3)) !important;
  }
}
.dn-pb .product-item .d-card-media { aspect-ratio: auto; }
.dn-pb .product-item .box-1-1 { aspect-ratio: var(--pb-ratio, 3/4); }

@media (min-width: 768px) {
  .dn-pb__banner {
    display: block;
    flex: 0 0 var(--pb-banner-w, 25%);
    /* Same ratio as the product images so the two line up exactly. Stretching
       to the column height made the banner taller than the images, because a
       product column is image + meta while the banner is image only. */
    aspect-ratio: var(--pb-ratio, 3/4);
  }
  .dn-pb__img--d, .dn-pb__video--d { display: block; }
  .dn-pb__img--m, .dn-pb__video--m { display: none; }
  .dn-pb__title { font-size: var(--pb-title-d, 34px); }
  .dn-pb__row > .product-item {
    flex: 0 0 calc((100% - (var(--bs-cards-d, 3) - 1) * var(--pb-gap, 2px)) / var(--bs-cards-d, 3));
  }
}
@media (max-width: 767.98px) {
  .dn-pb__wrap { flex-direction: column; }
  /* Banner stacks on top of the products. Its height on mobile is driven by a
     merchant setting (--pb-mobile-ratio) so a video or image can be sized to
     taste, with an optional cap (--pb-mobile-maxh) to stop it dominating the
     screen. object-fit (--pb-fit) chooses crop (cover) vs full-frame (contain). */
  .dn-pb__banner {
    display: block;
    width: 100%;
    flex: 0 0 auto;
    aspect-ratio: var(--pb-mobile-ratio, 16 / 10) !important;
    max-height: var(--pb-mobile-maxh, 60vh);
  }
  /* Prefer the mobile image; fall back to the desktop image so the banner is
     never blank. (Desktop img is first in markup, mobile second — so when a
     mobile img exists it sits on top and we hide the desktop one.) */
  .dn-pb__img--d, .dn-pb__video--d { display: block; }
  .dn-pb__img--d:has(~ .dn-pb__img--m) { display: none; }
  .dn-pb__video--d:has(~ .dn-pb__video--m) { display: none; }
  .dn-pb__img--m, .dn-pb__video--m { display: block; }
  .dn-pb__title { font-size: var(--pb-title-m, 24px); }
}

/* ---- Arrows: circular, straddling the row edges ---- */
.dn-pb__arrow {
  all: unset;
  box-sizing: border-box;
  cursor: pointer;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 6;
  width: 52px; height: 52px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px;
  background: var(--pb-arrow-bg, #fff);
  color: var(--pb-arrow-fg, #000);
  box-shadow: 0 6px 18px -10px rgba(0,0,0,.7);
  transition: opacity .2s ease, transform .2s ease;
}
.dn-pb__arrow svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
[dir='rtl'] .dn-pb__arrow svg { transform: scaleX(-1); }
.dn-pb__arrow--prev { inset-inline-start: 14px; }
.dn-pb__arrow--next { inset-inline-end: 14px; }
.dn-pb__arrow:hover { transform: translateY(-50%) scale(1.06); }
.dn-pb__arrow[disabled] { opacity: 0; pointer-events: none; }
@media (max-width: 767.98px) { .dn-pb__arrow { display: none; } }

@media (prefers-reduced-motion: reduce) {
  .dn-pb__arrow, .dn-pb__cta { transition: none; }
  .dn-pb__arrow:hover { transform: translateY(-50%); }
}

/* ===========================================================================
 * 15 · CARD TEMPLATES
 * Five arrangements of the same markup, selected in
 * Theme settings -> Product Card -> Card template.
 *
 * Every template reorders with flex rather than changing the markup, so all
 * commerce hooks (wishlist attributes, add-to-cart handler, badge include)
 * stay exactly where Zid expects them.
 * ======================================================================== */
.product-item { display: flex; flex-direction: column; }

/* ---- meta-top: title and price above the image (Parel) ---- */
body.pc-tpl-meta-top .product-item .d-card-body {
  order: -1;
  padding: 0 0 .85rem;
  padding-block-start: 0;
}
body.pc-tpl-meta-top .product-item .product-card-rating-wrapper,
body.pc-tpl-meta-top .product-item .product-crd-spec small { display: none; }
body.pc-tpl-meta-top .product-item .product-title { margin-bottom: .1rem; }
body.pc-tpl-meta-top .product-item .product-price { font-weight: 400; opacity: .72; }

/* ---- split-row: title start, price end, one line under the image ---- */
body.pc-tpl-split-row .product-item .d-card-body {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}
body.pc-tpl-split-row .product-item .product-title {
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
  -webkit-line-clamp: 1;
}
body.pc-tpl-split-row .product-item .d-card-body .product-title > span { min-height: 0; -webkit-line-clamp: 1; }
body.pc-tpl-split-row .product-item .product-crd-spec { flex: 0 0 auto; }
body.pc-tpl-split-row .product-item .product-card-rating-wrapper,
body.pc-tpl-split-row .product-item .product-crd-spec small { display: none; }

/* ---- overlay: meta sits on the image, bottom aligned ---- */
body.pc-tpl-overlay .product-item { position: relative; }
body.pc-tpl-overlay .product-item .d-card-media { position: relative; }
body.pc-tpl-overlay .product-item .d-card-body {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  z-index: 3;
  padding: clamp(.75rem, 2vw, 1.15rem);
  background: linear-gradient(0deg, rgba(0,0,0,.72), transparent);
  pointer-events: none;
}
body.pc-tpl-overlay .product-item .d-card-body a { pointer-events: auto; }
body.pc-tpl-overlay .product-item .product-title,
body.pc-tpl-overlay .product-item .product-price { color: #fff; }
body.pc-tpl-overlay .product-item .product-card-rating-wrapper,
body.pc-tpl-overlay .product-item .product-crd-spec small { display: none; }

/* ---- minimal: image and title only ---- */
body.pc-tpl-minimal .product-item .product-crd-spec,
body.pc-tpl-minimal .product-item .product-card-rating-wrapper { display: none; }

/* ===========================================================================
 * 16 · BADGE STYLES
 * ======================================================================== */
/* pill — rounded light chip, as in the House-of reference */
body.pc-bstyle-pill .product-item .d-card-media > .product-badge,
body.pc-bstyle-pill .product-item .product-badge {
  border-radius: 999px;
  padding: .55em 1em;
  letter-spacing: .04em;
}

/* vertical — rides the trailing edge (Parel) */
body.pc-bstyle-vertical .product-item .d-card-media > .product-badge,
body.pc-bstyle-vertical .product-item .product-badge {
  inset-inline-start: auto;
  inset-inline-end: 0;
  top: var(--pc-badge-offset, 10px);
  writing-mode: vertical-rl;
  padding: .9em .45em;
  letter-spacing: .14em;
  border-radius: 0;
}

/* underline — text with a rule beneath, no fill */
body.pc-bstyle-underline .product-item .d-card-media > .product-badge,
body.pc-bstyle-underline .product-item .product-badge {
  background: transparent !important;
  color: var(--pc-badge-bg, #FF5100) !important;
  padding: 0 0 3px;
  border-bottom: 2px solid currentColor;
  border-radius: 0;
}

@media (prefers-reduced-motion: reduce) {
  .dn-pb__arrow, .dn-pb__cta { transition: none; }
  .dn-pb__arrow:hover { transform: translateY(-50%); }
}

/* ===========================================================================
 * 17 · SPLIT-ROW SPACING
 * `justify-content: space-between` pushes the title to the card's leading edge
 * and the price to its trailing edge. With cards nearly touching, the price of
 * one card ended up beside the title of the next and the two read as one line.
 * Insetting the meta row from the card edges keeps each pair visually owned by
 * its own card.
 * ======================================================================== */
body.pc-tpl-split-row .product-item .d-card-body,
body.pc-tpl-meta-top .product-item .d-card-body {
  padding-inline: var(--pc-meta-inset, 14px);
}
body.pc-tpl-split-row .product-item .product-price,
body.pc-tpl-split-row .product-item .section-product-price { white-space: nowrap; }

/* A hairline between cards makes the ownership unambiguous when the gap is
   small, which is the look in the reference. */
/* Opt-in per section (Layout -> Divider line between cards), with its own
   colour — reusing the card border made a black rule appear unbidden. */
.dn-pb--sep .dn-pb__row > .product-item + .product-item {
  border-inline-start: 1px solid var(--pb-sep, #E5E5E5);
}

/* Section width: contained keeps the page gutter on both sides; full bleeds. */
.dn-pb--contained .dn-pb__wrap {
  max-width: var(--d-max, 1440px);
  margin-inline: auto;
  padding-inline: var(--d-gutter, 2rem);
}
/* The section heading must sit in the SAME box as the content below it, so the
   title lines up with the banner/products on both edges — not flush to the
   page edge (the old `.edge` padding didn't match the contained wrap). */
.dn-pb--contained .dn-sec-head {
  max-width: var(--d-max, 1440px);
  margin-inline: auto;
  padding-inline: var(--d-gutter, 2rem);
}
.dn-pb--full .dn-sec-head { padding-inline: var(--d-gutter, 2rem); }
.dn-pb--contained .dn-pb__arrow--prev { inset-inline-start: calc(var(--d-gutter, 2rem) + 14px); }
.dn-pb--contained .dn-pb__arrow--next { inset-inline-end: calc(var(--d-gutter, 2rem) + 14px); }

/* ===========================================================================
 * 18 · IN-CARD GALLERY
 * Every product image is a stacked slide, so a shopper can look through the
 * product without leaving the grid. Controls stop their own events, because
 * the card is wrapped in a link and a swipe must never navigate.
 * ======================================================================== */
.dn-card-gallery {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

/* Declaring that this area does not pan horizontally is what stops the parent
   product row from stealing a sideways swipe. Vertical panning is left to the
   page, so scrolling still works over a card. */
.dn-card-gallery[data-dn-gallery] { touch-action: pan-y; }

.dn-card-track {
  display: flex;
  width: 100%;
  height: 100%;
  will-change: transform;
  /* Force LTR flow so slide 0 is always at offset 0. On RTL pages the flex row
     reversed and left the first slide off-screen (blank/white panel until a
     swipe). The JS positions the track LTR to match. */
  direction: ltr;
}

.dn-card-slide {
  flex: 0 0 100%;
  width: 100%;
  height: 100%;
  object-fit: var(--pc-image-fit, cover);
  /* Dragging photos should feel physical, so nothing fades. */
  opacity: 1;
  pointer-events: none;
}

.dn-card-gnav {
  all: unset;
  box-sizing: border-box;
  cursor: pointer;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 4;
  width: 30px;
  height: 30px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.9);
  color: #111;
  opacity: 0;
  transition: opacity 0.2s ease, background-color 0.2s ease;
}
.dn-card-gnav--prev { inset-inline-start: 8px; }
.dn-card-gnav--next { inset-inline-end: 8px; }
.dn-card-gnav svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
[dir='rtl'] .dn-card-gnav svg { transform: scaleX(-1); }
.product-item:hover .dn-card-gnav { opacity: 1; }
.dn-card-gnav:hover { background: #fff; }
/* Touch has swipe, so floating arrows only cover the garment. */
@media (hover: none) { .dn-card-gnav { display: none; } }

.dn-card-gdots {
  position: absolute;
  inset-inline: 0;
  bottom: 10px;
  z-index: 3;
  display: flex;
  justify-content: center;
  gap: 4px;
  pointer-events: none;
}
.dn-card-gdots i {
  width: 5px;
  height: 5px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.55);
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.35);
  transition: width 0.22s ease, background-color 0.22s ease;
}
.dn-card-gdots i.is-on { width: 14px; background: #fff; }

/* ===========================================================================
 * 19 · WISHLIST — the DUNEUS mark, bottom end
 * Matches the header's icon so the control reads as one thing across the
 * store. The mask that custom.css applies is cleared, since the shape is now
 * a real SVG rather than a masked box.
 * ======================================================================== */

@media (prefers-reduced-motion: reduce) {
  .dn-card-slide, .dn-card-gnav, .dn-card-gdots i, .dn-wl-icon { transition: none; }
}

/* ===========================================================================
 * 20 · WISHLIST — one rule, no leftovers
 * custom.css styles .icon-heart-mask as a MASKED BOX (width/height + a
 * background colour showing through a mask). The mark is a real SVG now, so
 * that box must be fully neutralised — a leftover background is what painted a
 * solid rectangle over the icon.
 * ======================================================================== */

/* Image dots — a long strip of dots is noise, so the count is capped by the
   slide limit and the dots themselves can be hidden or shown only on hover. */
body.pc-dots-hide .dn-card-gdots { display: none; }
body.pc-dots-auto .dn-card-gdots { opacity: 0; transition: opacity 0.2s ease; }
body.pc-dots-auto .product-item:hover .dn-card-gdots { opacity: 1; }
/* Touch has no hover, so they stay visible there. */
@media (hover: none) { body.pc-dots-auto .dn-card-gdots { opacity: 1; } }

body.pc-gal-off .dn-card-gnav,
body.pc-gal-off .dn-card-gdots { display: none; }

/* ===========================================================================
 * 21 · WISHLIST POSITION
 * Top-end by default. The bottom edge already belongs to the quick-add button,
 * so anchoring the heart there put two controls on the same spot.
 * ======================================================================== */
/* The heart is levelled with the badge by sharing its offset, so the two
   corners of the frame stay symmetrical whatever the merchant sets. The plate
   is taller than the badge, so it is nudged up by half the difference to align
   their optical centres rather than just their top edges. */
/* Without a plate the mark is small, so it lines up with the badge directly. */
body.pc-no-plate 
body.pc-wish-top-start /* Offered, but it shares the row with quick-add — the offset lifts it clear. */
body.pc-wish-bottom-end 
/* ===========================================================================
 * WISHLIST — stated once, in full
 * Earlier passes appended rules instead of replacing them, so several
 * declarations for the same element sat in this file and the winner depended
 * on file order. This is the single source for the control.
 *
 * custom.css treats .icon-heart-mask as a masked box (size + a background
 * showing through a mask). The mark is a real SVG now, so that box is fully
 * neutralised — a leftover background is what painted a solid rectangle.
 * ======================================================================== */
.product-item .add-to-wishlist {
  position: absolute;
  z-index: 4;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--pc-wish-plate-size, 38px);
  height: var(--pc-wish-plate-size, 38px);
  background: var(--pc-wish-plate, #fff);
  border-radius: var(--pc-wish-plate-radius, 30px);
  transition: transform 0.18s ease;

  /* Levelled with the badge by sharing its offset, then nudged so the two
     optical centres line up — the plate is taller than the badge, so matching
     top edges alone would still look off. */
  top: calc(var(--pc-badge-offset, 10px) - ((var(--pc-wish-plate-size, 38px) - var(--pc-badge-h, 22px)) / 2));
  bottom: auto;
  inset-inline-end: var(--pc-wish-offset, 10px);
  inset-inline-start: auto;
}
.product-item .add-to-wishlist:hover { transform: scale(1.06); }

/* Without a plate the mark is small enough to sit at the badge line directly. */
body.pc-no-plate .product-item .add-to-wishlist {
  background: transparent;
  top: var(--pc-badge-offset, 10px);
}
body.pc-no-wish .product-item .add-to-wishlist { display: none; }

body.pc-wish-top-start .product-item .add-to-wishlist {
  inset-inline-start: var(--pc-wish-offset, 10px);
  inset-inline-end: auto;
}
body.pc-wish-bottom-end .product-item .add-to-wishlist {
  top: auto;
  bottom: calc(var(--pc-wish-offset, 10px) + var(--pc-cta-height, 44px) + 8px);
}

.product-item .add-to-wishlist .icon-heart-mask {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: auto;
  height: auto;
  padding: 0;
  border: 0;
  cursor: pointer;
  background: none !important;
  background-color: transparent !important;
  -webkit-mask-image: none !important;
          mask-image: none !important;
}
.product-item .add-to-wishlist .loader { width: 16px; height: 16px; }

.product-item .dn-wl-icon {
  display: block;
  width: var(--pc-wish-size, 22px);
  /* Derived from the 58x50 viewBox — `auto` is not resolved reliably on an
     inline SVG. */
  height: calc(var(--pc-wish-size, 22px) * 0.862);
  fill: none;
  stroke: var(--pc-wish, #111);
  stroke-width: 3;
  transition: fill 0.18s ease, stroke 0.18s ease;
}
.product-item .dn-wl-icon.is-filled {
  fill: var(--pc-wish-active, #FF5100);
  stroke: var(--pc-wish-active, #FF5100);
}

@media (prefers-reduced-motion: reduce) {
  .product-item .add-to-wishlist, .product-item .dn-wl-icon { transition: none; }
}

/* ===========================================================================
 * PRODUCT LISTING FIXES (2026-09-27)
 * =========================================================================== */

/* (1) Card "Add to cart" button height above the dots — nudged back down a
   little (was too high at 40px). Sits just clear of the dots. */
.product-item .d-card-action { bottom: var(--pc-cta-bottom, 22px) !important; }

/* (2) Price filter FROM / TO — align both fields on one baseline.
   Confirmed via DOM inspection the real structure is:
   .attribute-price-body > .form-row > .form-group.col-md-6 (Bootstrap grid).
   The "To" column carries a <label> while the "From" one differs, so they
   drifted. Force both columns to identical column-flex and bottom-align. */
.attribute-price-body .form-row {
  display: flex !important;
  align-items: flex-end !important;
  flex-wrap: nowrap !important;
  gap: 10px !important;
  margin: 0 !important;
}
.attribute-price-body .form-row > .form-group {
  display: flex !important;
  flex-direction: column !important;
  justify-content: flex-end !important;
  padding: 0 !important;
  margin: 0 !important;
  flex: 1 1 0 !important;
  max-width: 50% !important;
}
.attribute-price-body .form-row > .form-group > label {
  margin: 0 0 6px !important;
  line-height: 1.2 !important;
  min-height: 1.2em !important;
  display: block !important;
  text-align: start !important;
}
.attribute-price-body .form-row > .form-group > .form-control {
  width: 100% !important;
  margin: 0 !important;
}
/* The "To" column had text-right which pushed its label out of line. */
.attribute-price-body .form-row > .form-group.text-right { text-align: start !important; }
.attribute-price-body .form-row > .form-group.text-right > label { text-align: start !important; }

/* ===========================================================================
 * CATEGORY / PRODUCTS GRID — SquatWolf-style large 2-up layout (2026-09-29)
 * PART 1: product display. Big images, 2 columns, minimal gaps. Scoped to the
 * listing grid only (#products-list) so nothing else is affected.
 * =========================================================================== */
/* Desktop: with OR without the filter sidebar, use a clean 2-column grid with
   large imagery, edge-to-edge feel (very small gutters). */
#products-list.products-list {
  display: grid !important;
  /* minmax(0,1fr) — NOT plain 1fr. Plain 1fr lets a column grow to its content's
     min width, so a card with a wider image stretched its own column and the two
     columns came out unequal (one image big, one small). minmax(0,…) forces
     every track to the same width regardless of content. */
  grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  gap: 2px !important;
  margin: 0 !important;
  align-items: start !important;
}
#products-list.products-list .prod-col,
#products-list.products-list .prod-col-attr,
#products-list.products-list .prod-col-tb {
  width: 100% !important;
  max-width: 100% !important;
  padding: 0 !important;
  margin: 0 !important;
  flex: none !important;
}
/* Larger product image inside each card — full 2:3 portrait, shows the
   complete studio shot the way it was uploaded (no square crop). */
#products-list .product-item .product-image-wrapper,
#products-list .product-item .box-1-1 {
  aspect-ratio: var(--pc-aspect-ratio, 2/3) !important;
}
#products-list .product-item .box-1-1 img,
#products-list .product-item .dn-card-slide,
#products-list .product-item .carousel-img {
  width: 100% !important;
  height: 100% !important;
  object-fit: var(--pc-image-fit, cover) !important;
  object-position: center !important;
}

/* On wide desktops allow 3 across so images stay a sensible size; keep 2 on
   tablet/medium. */
@media (min-width: 1200px) {
  #products-list.products-list { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; }
}
/* Mobile: exactly 2 large columns like the reference. */
@media (max-width: 767px) {
  #products-list.products-list { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 2px !important; }
}

/* ===========================================================================
 * CARD INFO — mobile stacking like the reference (2026-09-29)
 * Name on top, then price, then the discount line on its own row (red).
 * Applies to the listing grid on mobile.
 * =========================================================================== */
@media (max-width: 767px) {
  #products-list .product-item .d-card-body { text-align: start; }
  /* Name first (already first in markup) — ensure it's block and above. */
  #products-list .product-item .product-title { display: block; margin-bottom: 4px; }
  /* Price + previous price on one line, discount drops below. */
  #products-list .product-item .section-product-price {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.4rem 0.5rem;
  }
  /* Discount forced onto its own full-width line under the price. */
  #products-list .product-item .d-card-discount {
    flex: 0 0 100%;
    display: block;
    margin-top: 2px;
  }
}

/* ===========================================================================
 * UNIFORM CARD IMAGE + SOLD-OUT BADGE  (v6.9.12)
 * ---------------------------------------------------------------------------
 * (1) Every product card photo must render at the SAME size. The 2:3 frame is
 *     already fixed, but some cards showed the image at natural size (small)
 *     while others filled — because a slide/img wasn't stretched to the frame.
 *     Force the whole fill chain so the photo covers the frame identically on
 *     every card and every state (in-stock, out-of-stock, home rows, grid).
 * (2) A clean, legible SOLD OUT badge on out-of-stock cards.
 * ======================================================================== */
.product-item .box-1-1 { position: relative; overflow: hidden !important; }
.product-item .box-1-1 > .content {
  position: absolute !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
}
.product-item .box-1-1 .content > .d-flex,
.product-item .dn-card-gallery {
  width: 100% !important;
  height: 100% !important;
  overflow: hidden;
}
.product-item .dn-card-track {
  display: flex !important;
  width: 100% !important;
  height: 100% !important;
}
.product-item .box-1-1 img,
.product-item .dn-card-slide,
.product-item .dn-card-track > img,
.product-item .carousel-img {
  flex: 0 0 100% !important;
  width: 100% !important;
  height: 100% !important;
  max-width: none !important;
  object-fit: var(--pc-image-fit, cover) !important;
  object-position: center !important;
}
/* The editorial side-banner section keeps its own ratio. */
.dn-pb .product-item .box-1-1 { aspect-ratio: var(--pb-ratio, 2/3) !important; }

/* ---- SOLD OUT badge ---- */
.product-item .dn-soldout {
  position: absolute;
  top: 10px;
  inset-inline-start: 10px;
  z-index: 4;
  display: inline-block;
  padding: 6px 12px;
  background: #111111;
  color: #FFFFFF;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  line-height: 1;
  border-radius: 2px;
  pointer-events: none;
}

/* ===========================================================================
 * ZID NAME-BADGE (e.g. "Best Seller") · clean placement  (v6.9.17)
 * ---------------------------------------------------------------------------
 * Zid injects a product name-badge absolutely at the TOP-RIGHT (right:28px),
 * exactly where the wishlist heart sits — so they overlap, and on the narrow
 * side-banner scroller cards it crowds/overflows the corner. Move it to the
 * TOP-LEFT as a compact, premium pill (keeping the merchant's chosen colour),
 * clear of the heart, with an ellipsis so a long label never overflows.
 * ======================================================================== */
.product-item .badge-name.badge-name-product-card {
  position: absolute !important;
  top: 10px !important;
  inset-inline-start: 10px !important;
  inset-inline-end: auto !important;
  left: auto !important;
  right: auto !important;
  margin: 0 !important;
  z-index: 5 !important;
  max-width: calc(100% - 20px);
  padding: 5px 10px !important;
  border: 0 !important;
  border-radius: 2px !important;
  font-size: 10px !important;
  font-weight: 800 !important;
  letter-spacing: 0.08em !important;
  text-transform: uppercase !important;
  line-height: 1 !important;
  white-space: nowrap !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
  box-shadow: 0 2px 8px -4px rgba(0,0,0,.4);
}
/* If a product is BOTH sold out and badged, drop the name-badge below the
   SOLD OUT chip so they stack instead of overlapping. */
.product-item.product-item-out-of-stock .badge-name.badge-name-product-card {
  top: 44px !important;
}
