/*
 Theme Name:     Niswah Boutique
 Theme URI:      https://niswahboutique.com/
 Description:    Custom Divi child theme for Niswah Boutique — modest fashion & hijab store, Qatar. Brand tokens, global typography and the Theme Builder starter templates ship with this theme.
 Author:         Built for Niswah Boutique
 Template:       Divi
 Version:        0.10.17
 Text Domain:    niswah-boutique
*/

/* =========================================================================
   1. BRAND TOKENS
   Palette derived from the Niswah Boutique logo.
   Type scale + spacing measured from the design reference (see 03-DESIGN-SPEC.md).
   ========================================================================= */

:root {
  /* Colour */
  --nb-burgundy:   #6E1423;  /* primary — logo wordmark */
  --nb-gold:       #C6A15B;  /* accent — logo gradient */
  --nb-terracotta: #B24D2E;  /* secondary accent / hover */
  --nb-ivory:      #FAF3EA;  /* editorial background */
  --nb-espresso:   #241512;  /* text / dark surfaces */
  --nb-white:      #FFFFFF;
  --nb-line:       #E8E2D9;  /* hairline rules, input borders */

  /* Type */
  --nb-font-head: "Marcellus", Georgia, "Times New Roman", serif;
  --nb-font-body: "Jost", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  --nb-body-size: 16px;
  --nb-body-weight: 300;
  --nb-body-lh: 1.8;
  --nb-body-ls: 0.6px;

  --nb-h2-size: 36px;
  --nb-h2-lh: 1.3;
  --nb-h2-ls: 0.54px;

  /* Layout */
  --nb-content-width: 1600px;
  --nb-gutter: 50px;
  --nb-grid-col-gap: 20px;
  --nb-grid-row-gap: 55px;

  /* Header */
  --nb-ticker-h: 40px;
}

/* =========================================================================
   2. GLOBAL TYPOGRAPHY
   Mirrors the Divi Customizer settings so the values live in one readable
   place. Divi's own settings still win in the builder UI — these are the
   safety net for anything Divi does not cover.
   ========================================================================= */

body,
.et_pb_module,
input,
textarea,
select,
button {
  font-family: var(--nb-font-body);
  letter-spacing: var(--nb-body-ls);
}

body {
  font-size: var(--nb-body-size);
  font-weight: var(--nb-body-weight);
  line-height: var(--nb-body-lh);
  color: var(--nb-espresso);
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--nb-font-head);
  color: var(--nb-espresso);
  letter-spacing: var(--nb-h2-ls);
}

h2 {
  font-size: var(--nb-h2-size);
  line-height: var(--nb-h2-lh);
}

a {
  color: var(--nb-burgundy);
  transition: color 0.2s ease;
}

a:hover {
  color: var(--nb-terracotta);
}

/* =========================================================================
   3. LAYOUT WIDTH
   Reference container is 1600px with a 50px gutter.
   ========================================================================= */

.et_pb_row {
  max-width: var(--nb-content-width);
}

@media (min-width: 981px) {
  .et_pb_row {
    padding-left: var(--nb-gutter);
    padding-right: var(--nb-gutter);
  }
}

/* =========================================================================
   4. HEADER
   Ticker sits at a fixed 40px. Nothing here should introduce a horizontal
   scrollbar, so the page container is clipped.
   ========================================================================= */

#page-container {
  overflow-x: hidden;
}

/* -------------------------------------------------------------------------
   Header geometry.

   The reference header is 128px (40px ticker + 88px brand band). We cannot hit
   88px honestly: their logo is a flat text wordmark at roughly 8.2:1, ours is a
   stacked lockup (Arabic over Latin, plus the emblem) at 1161x516 = 2.25:1.
   Constraining ours to the reference's ~44px logo height forces it to 99px
   wide, at which point the wordmark is unreadable. So the logo is held at 56px
   and the band lands near 150px. Matching 128px exactly needs a horizontal
   logo variant (emblem left, wordmark right) — a design asset, not a CSS fix.

   !important is required on the logo height: Divi emits per-module CSS for
   et_pb_menu_0_tb_header AFTER this stylesheet, and at equal specificity the
   later rule wins. This is the one place we cannot win on cascade order.
   ------------------------------------------------------------------------- */

.nb-header .et_pb_menu__logo img {
  max-height: 56px !important;
  width: auto !important;
}

.nb-header .et_pb_menu__logo,
.nb-header .et_pb_menu__logo-wrap {
  height: auto !important;
}

/* Icons ride on the logo line, hard right, rather than taking a third row.
   Divi renders them as direct children of .et_pb_menu__wrap — there is no
   .et_pb_menu__icons wrapper, which is why an earlier attempt did nothing. */
@media (min-width: 981px) {
  .nb-header .et_pb_menu_inner_container { position: relative; }

  .nb-header .et_pb_menu__wrap { justify-content: center; }

  /* Offsets resolve against .et_pb_menu_inner_container (the nearest positioned
     ancestor), whose top edge is the top of the logo band — not against
     .et_pb_menu__wrap. A negative offset therefore pushed the icons up into the
     ticker. Centring them on the 56px logo band means (56 - 25) / 2 ~= 15px. */
  .nb-header .et_pb_menu__wrap > .et_pb_menu__icon {
    position: absolute;
    top: 15px;
    height: auto;
    margin: 0;
  }

  .nb-header .et_pb_menu__wrap > .et_pb_menu__cart-button { right: 0; }
  .nb-header .et_pb_menu__wrap > .et_pb_menu__search-button { right: 92px; }

  .nb-header .et_pb_menu__menu > nav > ul { justify-content: center; }

  /* Nav row: tighten from Divi's 69px to ~40px. */
  .nb-header .et_pb_menu__menu > nav > ul > li > a {
    padding-top: 4px;
    padding-bottom: 8px;
    line-height: 1.6em;
  }
}

/* Underline grows from the centre on hover. */
.nb-header .et_pb_menu__menu > nav > ul > li > a { position: relative; }

.nb-header .et_pb_menu__menu > nav > ul > li > a::after {
  content: "";
  position: absolute;
  left: 50%;

  /* Anchored to the CENTRE OF THE TEXT, not to the bottom of the link box.
     -----------------------------------------------------------------------
     Two separate things forced this, both measured on the live site:

     1. A parent-theme rule sets top:50% + translateY(-50%) on this pseudo-
        element, which centred the line on the label like a strikethrough.
        When `top` and `bottom` are both set the box is over-constrained and
        `top` wins, so a plain `bottom` never took effect. That rule also
        outranks ours on `transform`, hence the !important on these two.

     2. The link box is NOT the same height on every template — measured
        40.8px on the home page (padding 4/8) but 94.4px on a category
        archive (padding 31/31). Anything anchored to the box bottom
        therefore sits at a different distance from the text per page.

     The links are display:flex + align-items:center, so the text centre is
     the box centre on every template. Offsetting from there is stable:
     0.78em = 14px at the 18px nav size, which clears the descenders
     (~9px below centre) by the 5px gap the design calls for. Being in `em`,
     it stays proportional if the nav size ever changes. */
  top: 50% !important;
  bottom: auto !important;
  transform: translateY(0.78em) !important;

  width: 0;
  height: 1px;
  background: var(--nb-burgundy);
  transition: width 0.28s ease, left 0.28s ease;
}

.nb-header .et_pb_menu__menu > nav > ul > li > a:hover::after {
  left: 0;
  width: 100%;
}

/* Mobile: hamburger left, logo centred, cart right — one compact row.
   -------------------------------------------------------------------------
   Divi's own responsive rules for the menu module are NOT reliably present on
   this site: measured at a 400px viewport the desktop nav computed to
   display:block, the closed mobile menu computed to display:block, and the
   search container rendered despite carrying Divi's own --disabled class. The
   result was a 655px header showing the whole nav twice as a plain bulleted
   list. So the mobile state is enforced here rather than inherited. */
@media (max-width: 980px) {
  .nb-header .et_pb_menu__logo img { max-height: 38px !important; }

  .nb-header .et_pb_menu_inner_container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: nowrap;
  }

  .nb-header .et_pb_menu__logo-wrap { order: 2; margin: 0 auto; flex: 0 1 auto; }
  .nb-header .et_pb_menu__wrap { order: 3; width: auto; flex: 0 0 auto; }
  .nb-header .et_mobile_nav_menu { order: 1; flex: 0 0 auto; display: block; }

  /* The desktop nav must not render at all below 980px. */
  .nb-header .et_pb_menu__menu { display: none !important; }

  /* A closed mobile menu stays closed. Divi toggles .opened on tap. */
  .nb-header .mobile_nav.closed .et_mobile_menu { display: none !important; }
  .nb-header .mobile_nav.opened .et_mobile_menu { display: block !important; }

  /* Search panel only appears when Divi opens it. */
  .nb-header .et_pb_menu__search-container--disabled,
  .nb-header .et_pb_menu__search-container:not(.et_pb_menu__search-container--visible) {
    display: none !important;
  }

  /* Hamburger stays visible and tappable. */
  .nb-header .mobile_menu_bar { display: block; position: relative; }

  /* The dropdown panel spans the header rather than the hamburger's own width,
     which is what made it a 129px-wide column of wrapped links. */
  /* Both the extra class in this selector and the !important are required.
     Divi's Theme Builder emits, in a stylesheet that loads AFTER this one:
       .et_pb_menu_0_tb_header.et_pb_menu .et_mobile_menu
       { background-color: rgba(255,255,255,0) !important }
     That is (0,3,0) + !important. The obvious override here,
     `.nb-header .et_mobile_nav_menu .et_mobile_menu`, is also (0,3,0), so it
     lost on source order and the open panel rendered fully transparent with
     the page text showing straight through it. Verified by placing the
     3-class rule FIRST in the document and watching it still lose; adding
     `.et_pb_menu` takes it to (0,4,1) and it wins on specificity alone,
     independent of load order. Not keyed to `et_pb_menu_0_tb_header` on
     purpose — that index changes if the header template is rebuilt. */
  .nb-header .et_pb_menu .et_mobile_nav_menu ul.et_mobile_menu {
    position: absolute;
    left: 0;
    right: 0;
    width: 100%;
    z-index: 999;
    background-color: var(--nb-white) !important;
    box-shadow: 0 14px 28px rgba(0, 0, 0, 0.16);
    border-top: 1px solid var(--nb-line, #E8E2D9);
    padding: 6px 0;
  }

  .nb-header .et_pb_menu .et_mobile_nav_menu ul.et_mobile_menu li a {
    background-color: transparent !important;
  }

  .nb-header .et_mobile_nav_menu .et_mobile_menu li a {
    padding: 12px 18px;
    font-size: 15px;
    letter-spacing: 0.4px;
  }
}

/* Ticker bar — dense, letterspaced, always legible on the deep background. */
.nb-ticker .et_pb_text {
  font-size: 13px;
  font-weight: 300;
  letter-spacing: 0.78px;
  line-height: 1.25;
  color: var(--nb-white);
  margin: 0;
}

/* Primary nav — 18px / 300 / 0.6px, per the measured reference. */
.et_pb_menu .et-menu > li > a {
  font-size: 18px;
  font-weight: 300;
  letter-spacing: 0.6px;
  color: var(--nb-espresso);
}

.et_pb_menu .et-menu > li > a:hover {
  color: var(--nb-burgundy);
  opacity: 1;
}

/* Header icons (search / cart) share the body text colour. */
.et_pb_menu .et_pb_menu__icon {
  color: var(--nb-espresso);
}

/* =========================================================================
   5. WOOCOMMERCE — product card
   Measured from the reference on 2026-08-26:
     card image 460x690  -> 2:3 portrait, object-fit cover
     two images per card -> second crossfades in on hover
     title 14.4px / 400 / ls 0.54px / serif, sentence case (NOT uppercase)
     grid gaps 20px column, 55px row, borderless
   ========================================================================= */

.woocommerce ul.products,
ul.products {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  column-gap: var(--nb-grid-col-gap);
  row-gap: var(--nb-grid-row-gap);
  margin: 0;
}

/* WooCommerce clears its float layout with ::before/::after on ul.products.
   In a grid container those pseudo-elements are GRID ITEMS, so ::before
   silently consumed the first cell and shunted every card one place along —
   leaving an empty top-left slot and wrapping the last card onto a new row.
   The float layout they exist for is gone, so they can go too. */
.woocommerce ul.products::before,
.woocommerce ul.products::after,
ul.products::before,
ul.products::after {
  display: none !important;
  content: none !important;
}

/* Divi's shop module emits per-instance CSS AFTER this stylesheet that gives
   li.product a fixed percentage width for its own float layout. In a grid that
   leaves each card sitting at ~140px inside a 460px cell. Since we cannot load
   later than Divi's generated CSS, this is one of the few places !important is
   the right tool rather than a shortcut. */
.woocommerce ul.products li.product,
.et_pb_shop ul.products li.product,
ul.products li.product {
  position: relative;      /* anchors the sale badge and slide-up button */
  width: 100% !important;
  max-width: 100% !important;
  margin: 0 !important;
  float: none !important;
  clear: none !important;
  padding: 0;
  border: 0;
  box-shadow: none;
  background: none;
  text-align: center;
}

/* Fixed-ratio frame: a catalogue with mixed photo ratios still forms a tidy
   grid, which is the single biggest reason the reference grid reads cleanly. */
/* overflow stays VISIBLE so the button can hang 26px below the image, the way
   the reference does. The zoom is clipped by the two inner layers instead,
   each of which is already absolutely positioned to fill this box. */
.nb-card__media {
  position: relative;
  display: block;
  overflow: visible;
  aspect-ratio: 2 / 3;
  background: var(--nb-ivory);
  /* No bottom margin: it inflates the card's first grid row past the image,
     and the button is anchored to the end of that row. A 16px margin here put
     the button 16px lower than the reference's 26px overhang. The gap under
     the image is provided by the title's margin-top instead. */
  margin-bottom: 0;
}

.nb-card__media .et_shop_image,
.nb-card__media .nb-card__hover {
  overflow: hidden;
}

/* Divi's shop module does not output a bare <img>: it wraps it in
   span.et_shop_image, which computes to zero height and absolutely positions
   the <img> inside itself. Left alone the wrapper collapses, the image escapes
   the 2:3 frame, and the frame's background shows through as a blank block.
   The wrapper has to be stretched to fill the frame before the image can. */
.nb-card__media .et_shop_image {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
}

.nb-card__media img {
  position: absolute !important;
  inset: 0;
  width: 100% !important;
  height: 100% !important;
  max-width: none;
  object-fit: cover;
  display: block;
  margin: 0;
  transition: opacity 0.55s ease, transform 0.9s cubic-bezier(0.2, 0.6, 0.2, 1);
}

/* Divi paints its own hover overlay over the thumbnail, which competes with
   the image swap and the slide-up button. */
.nb-card__media .et_overlay { display: none !important; }

/* Second image sits over the first at zero opacity and fades in. */
.nb-card__hover {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.55s ease;
}

li.product:hover .nb-card__hover { opacity: 1; }

/* Slow zoom applies to whichever image is currently visible, so single-image
   products still get a hover response. */
li.product:hover .nb-card__media img { transform: scale(1.06); }

/* Touch devices never hover: drop the swap rather than leave it stuck. */
@media (hover: none) {
  .nb-card__hover { display: none; }
}

/* Title sits on a single line, as the reference does. Clipping with an ellipsis
   rather than wrapping is what keeps every card in the row exactly the same
   height — a two-line title on one card otherwise shunts its neighbours' prices
   out of alignment. */
.woocommerce ul.products li.product .woocommerce-loop-product__title,
ul.products li.product .woocommerce-loop-product__title {
  font-family: var(--nb-font-head);
  font-size: 15px;
  font-weight: 400;
  letter-spacing: 0.54px;
  line-height: 1.5;
  text-transform: none;
  color: var(--nb-espresso);
  padding: 0 4px 6px;
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Currency mark is set smaller and lighter than the figure, so the number
   carries the line — the treatment the reference uses. */
.woocommerce ul.products li.product .woocommerce-Price-currencySymbol {
  font-size: 0.72em;
  opacity: 0.75;
  margin-right: 2px;
}

.woocommerce ul.products li.product .price,
ul.products li.product .price {
  font-family: var(--nb-font-body);
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 1px;
  color: var(--nb-espresso);
}

.woocommerce ul.products li.product .price del { opacity: 0.5; margin-right: 6px; }

.woocommerce ul.products li.product .price ins {
  text-decoration: none;
  color: var(--nb-burgundy);
}

/* Sale badge — square, brand colour, top-left. Divi ships a circle. */
.woocommerce ul.products li.product .onsale,
.woocommerce span.onsale {
  position: absolute;
  top: 12px;
  left: 12px;
  right: auto;
  min-height: 0;
  min-width: 0;
  padding: 5px 12px;
  border-radius: 0;
  background: var(--nb-burgundy);
  color: var(--nb-white);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  line-height: 1.6;
  margin: 0;
  z-index: 2;
}

/* Add-to-cart / choose-options, matched to the reference's measured values:
   430px wide in a 460px card (15px inset), 40px tall, sitting 26px below the
   image, black, 12px/600/2.4px letter-spacing, 4px radius. Hidden state is
   opacity 0 + translateY(40px), revealed on hover over 0.25s.

   The button cannot be nested inside the image: Divi closes the product link
   before any hook we can attach to, so the button is always a sibling of it.
   Instead the card becomes a grid and the button is assigned to the SAME grid
   cell as the link — which is exactly the image box — then aligned to its
   bottom edge. That anchors it to the image regardless of how tall the title
   and price render, which is what the reference's offsets are relative to. */
.woocommerce ul.products li.product,
ul.products li.product {
  display: grid;
  grid-template-columns: 100%;
  grid-template-rows: auto auto auto;
}

li.product > a.woocommerce-LoopProduct-link { grid-area: 1 / 1; }
li.product > h2.woocommerce-loop-product__title { grid-row: 2; }
li.product > .price { grid-row: 3; }
li.product > .screen-reader-text { display: none; }

.woocommerce ul.products li.product > .button,
ul.products li.product > .button {
  grid-area: 1 / 1;
  align-self: end;
  margin: 0 15px -26px;
  padding: 6px 20px;
  min-height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;

  background: #000000;
  color: var(--nb-white);
  border: 0;
  border-radius: 4px;

  font-family: var(--nb-font-body);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 2.4px;
  line-height: 1.2;
  text-transform: uppercase;
  white-space: nowrap;

  opacity: 0;
  transform: translateY(40px);
  transition: transform 0.25s ease, opacity 0.25s ease, background-color 0.25s ease;
  z-index: 3;
}

/* The hover selector MUST carry at least the specificity of the base rule
   above. Written as plain `li.product:hover > .button` it scores (0,3,1)
   against the base rule's (0,4,2), so `opacity: 0` kept winning and the button
   never appeared even though the hover was firing correctly. */
.woocommerce ul.products li.product:hover > .button,
ul.products li.product:hover > .button,
.woocommerce ul.products li.product:focus-within > .button,
ul.products li.product:focus-within > .button {
  opacity: 1;
  transform: translateY(0);
}

.woocommerce ul.products li.product > .button:hover,
ul.products li.product > .button:hover { background: var(--nb-burgundy); }

/* Title clears the button's 26px overhang with a little breathing room, and
   supplies the gap under the image that .nb-card__media no longer carries. */
.woocommerce ul.products li.product .woocommerce-loop-product__title,
ul.products li.product .woocommerce-loop-product__title {
  margin-top: 34px;
}

/* Reference sets the minor units small and raised. */
.nb-price-decimals {
  font-size: 0.62em;
  vertical-align: super;
  letter-spacing: 0.4px;
  margin-left: 1px;
}

/* Top-right control (quick view / wishlist), revealed with the rest of the
   hover state. Kept visible on touch, where there is no hover to reveal it. */
.nb-card__action {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 4;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--nb-white);
  border-radius: 50%;
  box-shadow: 0 1px 6px rgba(36, 21, 18, 0.14);
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity 0.3s ease, transform 0.3s ease;
}

li.product:hover .nb-card__action { opacity: 1; transform: translateY(0); }

.nb-card__action a,
.nb-card__action button { color: var(--nb-espresso); line-height: 1; }

@media (hover: none) {
  .nb-card__action { opacity: 1; transform: none; }
}

/* =========================================================================
   5b. FEATURED TRIO — full-bleed three-up under the hero
   Measured on the reference at a 1536 viewport:
     row  x=50  w=1421   -> full width minus a 50px gutter, no max-width cap
     card 460 x 747, image 460 x 690 -> 2:3, object-fit cover
     gaps 20px column / 55px row
   The image height is NOT hardcoded: 2:3 at a wider container is what produces
   the ~850px the reference shows on a large screen, and it keeps scaling.
   ========================================================================= */

/* Lift the site-wide 1600px cap for this row only. */
.nb-featured .et_pb_row {
  max-width: 100%;
  width: 100%;
}

.nb-featured ul.products {
  grid-template-columns: repeat(3, 1fr);
  column-gap: 20px;
  row-gap: 55px;
}

/* Slightly larger type than the standard grid, per the reference. */
.nb-featured ul.products li.product .woocommerce-loop-product__title {
  font-size: 17px;
  padding-top: 4px;
}

.nb-featured ul.products li.product .price { font-size: 16px; }

/* Featured cards use the same button geometry as the rest of the grid — the
   reference measurement was taken from this very row, so no override needed. */

@media (max-width: 980px) {
  /* Two up on tablet, one up on phone: at three across the 2:3 images become
     too small to read, which is the opposite of what this section is for. */
  .nb-featured ul.products { grid-template-columns: repeat(2, 1fr); }

  .nb-featured ul.products li.product .woocommerce-loop-product__title { font-size: 15px; }
  .nb-featured ul.products li.product .price { font-size: 14px; }
}

@media (max-width: 600px) {
  /* `body` prefix is load-bearing. `.nb-featured ul.products` and the generic
     `.woocommerce ul.products` are both (0,2,1), and the generic rule sits
     LATER in this file, so at equal specificity it won and the featured row
     stayed two-up. Raising this to (0,2,2) settles it by specificity instead
     of by source order. */
  body .nb-featured ul.products { grid-template-columns: minmax(0, 1fr); row-gap: 34px; }
}

/* =========================================================================
   5c. CATEGORY TILES
   Measured on the reference: tile 506 x 820, three across, edge to edge with
   NO gaps, photo at object-fit cover with no tint or scrim, and the text block
   pinned bottom-LEFT — 30px in, heading baseline 10px off the tile bottom.
   Divi's column controls cannot pin content to the bottom, so the column is
   made a flex container here.
   ========================================================================= */

.nb-cat-tile {
  position: relative;
  display: flex !important;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 820px;
  padding: 0 30px 10px !important;
  margin: 0 !important;
  overflow: hidden;
}

.nb-cat-tile .et_pb_text { margin: 0; }

.nb-cat-tile a {
  color: var(--nb-white);
  text-decoration: none;
}

/* The whole tile is the click target, not just the words. */
.nb-cat-tile a::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
}

/* 1.5px separator between tiles.
   Done as a border rather than a gap or margin so the three tiles still add up
   to the full viewport width — a real gap would either overflow the row or
   shrink the photos. box-sizing keeps each tile at its measured width. */
.nb-cat-tile + .nb-cat-tile {
  border-left: 1.5px solid var(--nb-white);
  box-sizing: border-box;
}

/* Hover: a plain translucent veil, nothing moves.
   An earlier version animated background-size from `cover` to `106% auto`,
   which on a 507x820 tile is far smaller than `cover` needs — so the photo
   snapped down in size instead of pushing in. Fading a flat overlay cannot
   shift the image at all, which is the point. */
.nb-cat-tile::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, 0.16);
  opacity: 0;
  transition: opacity 0.3s ease;
  pointer-events: none;
  z-index: 1;
}

.nb-cat-tile:hover::before,
.nb-cat-tile:focus-within::before { opacity: 1; }

/* Type sits above the veil; the full-tile click target sits between them. */
.nb-cat-tile .et_pb_text {
  position: relative;
  z-index: 3;
}

@media (max-width: 980px) {
  /* Three 820px tiles side by side become unreadable slivers on a tablet, so
     they stack. Height drops with them — a full 820px per tile would make the
     section three screens tall on a phone. */
  .nb-cat-tile {
    min-height: 460px;
    padding: 0 24px 14px !important;
  }

  .nb-cat-tile .et_pb_text:last-child { font-size: 28px !important; }
}

@media (max-width: 600px) {
  .nb-cat-tile {
    min-height: 380px;
    padding: 0 18px 14px !important;
  }
}

/* =========================================================================
   5e. EDITORIAL BANNER
   The copy column is centred against the photo. Divi stacks column content
   from the top, so a short block of copy beside a tall image left the lower
   half of the column empty.
   ========================================================================= */

@media (min-width: 981px) {
  .nb-editorial__copy {
    display: flex !important;
    flex-direction: column;
    justify-content: center;
  }

  /* Divi gives the last module in a column a bottom margin, which throws the
     optical centring off by that amount. */
  .nb-editorial__copy > .et_pb_module:last-child { margin-bottom: 0; }
}

/* =========================================================================
   5d. TRUST BADGES
   Reference: 32x32 line icon, heading 18px serif, subtext 16px at 75% opacity.
   ========================================================================= */

.nb-badge__icon { line-height: 0; }

.nb-badge__icon svg {
  width: 32px;
  height: 32px;
  color: var(--nb-espresso);
  display: inline-block;
  vertical-align: middle;
}

/* =========================================================================
   5g. FULL-WIDTH SHOP / CATEGORY ARCHIVES
   The body class swap in functions.php does the real work; these rules are the
   belt-and-braces for Divi builds that still print the sidebar markup.
   ========================================================================= */

.nb-full-width #sidebar { display: none !important; }

.nb-full-width #left-area {
  width: 100% !important;
  padding-right: 0 !important;
  float: none !important;
}

.nb-full-width #main-content .container::before { display: none; }

/* =========================================================================
   5f. COLLECTIONS PAGE
   Measured on the reference's /collections/ listing:
     H1 36px serif weight 400, centred
     grid 3 cols at x = 50 / 530 / 1010, 20px gaps
     card 460 x 460 SQUARE, overflow hidden, image fills it
     title OVERLAID inside the card, bottom-left, 30px in, 21px up, 16px sans
   Note the card is 1:1 here, NOT the 2:3 used for product cards, so the
   shared card rules have to be overridden rather than inherited.
   ========================================================================= */

.nb-collections ul.products {
  grid-template-columns: repeat(3, 1fr);
  column-gap: 20px;
  row-gap: 20px;
}

.nb-collections ul.products li.product-category {
  position: relative;
  width: 100% !important;
  margin: 0 !important;
  text-align: left;
}

.nb-collections li.product-category > a {
  position: relative;
  display: block;
  aspect-ratio: 1 / 1;      /* square, unlike the 2:3 product card */
  overflow: hidden;
  background: var(--nb-ivory);
}

.nb-collections li.product-category img {
  position: absolute;
  inset: 0;
  width: 100% !important;
  height: 100% !important;
  object-fit: cover;
  margin: 0 !important;
  transition: transform 0.9s cubic-bezier(0.2, 0.6, 0.2, 1);
}

.nb-collections li.product-category:hover img { transform: scale(1.04); }

/* Title sits over the photo at the bottom-left, not underneath it. */
.nb-collections li.product-category .woocommerce-loop-category__title {
  position: absolute;
  left: 30px;
  right: 30px;
  bottom: 21px;
  z-index: 2;
  margin: 0;
  padding: 0;
  font-family: var(--nb-font-body);
  font-size: 16px;
  font-weight: 400;
  letter-spacing: 0.6px;
  line-height: 1.4;
  text-align: left;
  text-transform: none;
  color: var(--nb-white);
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.55);
}

/* WooCommerce appends a product count in a <mark>; the reference shows none. */
.nb-collections li.product-category .woocommerce-loop-category__title .count {
  display: none;
}

/* A soft bottom scrim. The reference relies on its own light promo artwork and
   uses dark text, but our category thumbnails are real photography of every
   possible tone — without this the title is unreadable on the darker ones. */
.nb-collections li.product-category > a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 45%;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  z-index: 1;
  pointer-events: none;
}

@media (max-width: 980px) {
  .nb-collections ul.products { grid-template-columns: repeat(2, 1fr); }
  .nb-collections li.product-category .woocommerce-loop-category__title {
    left: 20px;
    right: 20px;
    bottom: 16px;
    font-size: 15px;
  }
}

@media (max-width: 600px) {
  .nb-collections ul.products { grid-template-columns: repeat(2, 1fr); column-gap: 12px; row-gap: 12px; }
  .nb-collections li.product-category .woocommerce-loop-category__title { font-size: 13px; left: 14px; right: 14px; bottom: 12px; }
}

/* =========================================================================
   5h. SINGLE PRODUCT PAGE
   Measured on the reference product page at a 1521 viewport:
     two equal columns — gallery x=50 w=710, info x=760 w=710
     info content inset 70px -> 640px
     gallery images STACKED vertically, first 710x1064 = 2:3
     title 25.2px serif weight 400
     add to cart 500x50, #000, white, radius 4px, 13px / 600 / ls 2.6px
   Order in the info column: title+price, rating, variants, qty + cart,
   stock notice, description.
   ========================================================================= */

/* Divi caps #main-content .container at 1080px, which is narrower than the
   1600px the rest of the site uses and squeezed the product page badly. */
.nb-full-width #main-content .container {
  width: 90%;
  max-width: var(--nb-content-width);
}

/* IMPORTANT — which element to grid.
   There are TWO elements matching `div.product` on this page. Divi puts its own
   class on the builder wrapper (`et_builder_inner_content et_pb_gutters3
   product`), whose children are et_pb_sections, not the gallery. Gridding that
   one splits Divi's own layout in half and does nothing to the product.
   The real one is `div.product.type-product`, and the gallery and summary sit
   inside an unnamed `.clearfix` within it. That wrapper is the grid. */
.nb-single-product div.product.type-product > .clearfix {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 0;
  align-items: start;
  width: 100%;
}

/* --- Gallery: a plain vertical stack, no slider, no thumbnail strip ------- */
.nb-single-product .woocommerce-product-gallery {
  grid-column: 1;
  width: 100% !important;
  float: none !important;
  margin: 0 !important;
  padding-right: 50px;
}

/* Sticky media column, matching the reference.
   -------------------------------------------------------------------------
   niswafashion.com pins <media-gallery class="product__media-gallery"> with
   position:sticky; top:0 at a measured 710px wide, so the summary scrolls
   past a held image. Ours is worth pinning for the same reason: measured on
   the live page the gallery is 1048px tall against a 2095px summary, so the
   left column would otherwise leave half a screen of dead space.

   Two things are load-bearing here:

   1. Divi sets overflow-x:hidden on #page-container. Per spec a hidden value
      on one axis forces the other to compute to `auto`, which makes the
      element a scroll container and silently breaks every descendant sticky.
      `clip` does the same horizontal clipping WITHOUT establishing one, so
      the sticky resolves against the viewport again. Scoped to this template
      so no other page's layout is touched.

   2. `position` needs the full grid-child selector to outrank the
      `position:relative` WooCommerce sets on the gallery. */
.nb-single-product #page-container {
  overflow-x: clip;
  overflow-y: visible;
}

@media (min-width: 981px) {
  .nb-single-product div.product.type-product > .clearfix > .woocommerce-product-gallery {
    position: sticky !important;
    top: 24px;
    align-self: start;
  }
}

/* One slide visible at a time, 2:3, with the thumbnail rail beneath. */
.nb-single-product .woocommerce-product-gallery__image {
  aspect-ratio: 2 / 3;
  overflow: hidden;
  background: var(--nb-ivory);
  margin: 0;
}

.nb-single-product .woocommerce-product-gallery__image img {
  width: 100% !important;
  height: 100% !important;
  object-fit: cover;
  display: block;
}

/* Thumbnail rail — reference measures 710x83 directly under the main image. */
.nb-single-product .flex-control-thumbs {
  display: flex !important;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: flex-start;
  margin: 12px 0 0 !important;
  padding: 0 !important;
  list-style: none;
}

.nb-single-product .flex-control-thumbs li {
  width: 84px !important;
  height: 84px;
  margin: 0 !important;
  padding: 0;
  list-style: none;
  float: none !important;
}

.nb-single-product .flex-control-thumbs li img {
  width: 100% !important;
  height: 100% !important;
  object-fit: cover;
  opacity: 0.55;
  border: 1px solid transparent;
  border-radius: 3px;
  cursor: pointer;
  transition: opacity 0.2s ease, border-color 0.2s ease;
}

.nb-single-product .flex-control-thumbs li img:hover,
.nb-single-product .flex-control-thumbs li img.flex-active {
  opacity: 1;
  border-color: var(--nb-espresso);
}

/* --- Info column --------------------------------------------------------- */
.nb-single-product div.product.type-product > .clearfix > .summary,
.nb-single-product div.product .summary,
.nb-single-product div.product .entry-summary {
  grid-column: 2;
  width: 100% !important;
  float: none !important;
  margin: 0 !important;
  padding: 0 0 0 70px;
}

.nb-single-product .summary .product_title {
  font-family: var(--nb-font-head);
  font-size: 25px;
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: 0.4px;
  color: var(--nb-espresso);
  margin: 0 0 10px;
  padding: 0;
}

/* Divi paints WooCommerce prices in its accent blue (#2EA3F2) from CSS that
   loads after this file, so the colour has to be forced. */
.nb-single-product .summary .price,
.nb-single-product .summary .price .amount,
.nb-single-product .summary .price bdi {
  font-family: var(--nb-font-body);
  font-size: 18px;
  font-weight: 400;
  letter-spacing: 0.8px;
  color: var(--nb-espresso) !important;
}

.nb-single-product .summary .price { margin: 0 0 22px; }

.nb-single-product .summary .price del,
.nb-single-product .summary .price del .amount,
.nb-single-product .summary .price del bdi { opacity: 0.5; }

.nb-single-product .summary .price del { margin-right: 8px; }

.nb-single-product .summary .price ins,
.nb-single-product .summary .price ins .amount,
.nb-single-product .summary .price ins bdi {
  text-decoration: none;
  color: var(--nb-burgundy) !important;
}

/* WooCommerce appends a screen-reader "Price range:" label that Divi renders
   visibly on the variable-product price. */
.nb-single-product .summary .price .screen-reader-text { display: none; }

.nb-single-product .woocommerce-product-rating { margin: 0 0 20px; }

/* --- Variations ---------------------------------------------------------- */
.nb-single-product .variations {
  margin: 0 0 18px;
  border: 0;
}

/* Divi styles table cells with generous line-height and padding, which made a
   one-word "LENGTH" label 88px tall and left a chasm between each label and its
   options. Everything here is reset to a tight block rhythm. */
.nb-single-product .variations tbody,
.nb-single-product table.variations tr {
  display: block;
  width: 100%;
  /* Divi pads table ROWS (12px 8px), not just cells — resetting th/td alone
     left 24px of vertical air and an 8px left indent on every option row. */
  padding: 0 !important;
  margin: 0;
  border: 0 !important;
}

.nb-single-product .variations th,
.nb-single-product .variations td {
  display: block;
  width: 100%;
  padding: 0 !important;
  border: 0 !important;
  text-align: left;
  line-height: 1.4 !important;
  background: none !important;
}

.nb-single-product .variations tr + tr { margin-top: 18px; }

.nb-single-product .variations th.label,
.nb-single-product .variations th.label label {
  font-family: var(--nb-font-body);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--nb-espresso);
  margin: 0 0 8px !important;
  display: block;
  line-height: 1.4 !important;
}

/* The swatch plugin keeps a 20px bottom pad on the value cell from CSS that
   loads after ours, so this needs the extra table selector to outrank it. */
.nb-single-product table.variations td.value,
.nb-single-product .variations td.value {
  margin: 0 !important;
  padding: 0 !important;
  height: auto !important;
}

.nb-single-product table.variations th.label,
.nb-single-product .variations th.label {
  height: auto !important;
  padding: 0 !important;
}

/* The swatch plugin adds its own 23px bottom pad and a 14px left indent, which
   pushed the options away from their label and out of line with everything
   else in the column. */
.nb-single-product .variable-items-wrapper {
  padding: 0 !important;
  margin: 0 !important;
  gap: 8px;
  flex-wrap: wrap;
}

.nb-single-product .variable-items-wrapper .variable-item {
  margin: 0 !important;
}

.nb-single-product .woocommerce-variation-add-to-cart,
.nb-single-product .single_variation_wrap { margin-top: 4px; }

/* Divi renders the "clear" link on its own line with heavy spacing. */
.nb-single-product .reset_variations { display: inline-block; margin-top: 6px; }

.nb-single-product .variations select {
  width: 100%;
  max-width: 320px;
  padding: 12px 14px;
  border: 1px solid var(--nb-line, #E8E2D9);
  border-radius: 4px;
  background-color: var(--nb-white);
  font-size: 14px;
  letter-spacing: 0.4px;
}

.nb-single-product .reset_variations {
  font-size: 12px;
  letter-spacing: 0.6px;
}

/* Round colour swatches, matching the reference. Applies when the Variation
   Swatches plugin is active; harmless when it is not. */
.nb-single-product .variable-items-wrapper .variable-item.color-variable-item,
.nb-single-product .woo-variation-swatches .variable-item.color-variable-item {
  border-radius: 50% !important;
  width: 32px !important;
  height: 32px !important;
  box-shadow: 0 0 0 1px rgba(36, 21, 18, 0.18);
}

/* The plugin puts the colour on an INNER span, not on the item itself — the
   outer element stays white. Sizing only the outer therefore produced a row of
   white circles with the real colour hidden underneath. */
.nb-single-product .color-variable-item span,
.nb-single-product .color-variable-item .variable-item-span,
.nb-single-product .color-variable-item .variable-item-span-color {
  display: block !important;
  width: 100% !important;
  height: 100% !important;
  border-radius: 50% !important;
  margin: 0 !important;
}

.nb-single-product .variable-item.color-variable-item.selected,
.nb-single-product .variable-item.color-variable-item:hover {
  box-shadow: 0 0 0 2px var(--nb-espresso);
}

/* Square size buttons. They rendered at 33x30 with no visible border, which is
   why the row read as faint floating text rather than as choices. */
.nb-single-product .variable-item.button-variable-item {
  min-width: 52px !important;
  height: 44px !important;
  padding: 0 12px !important;
  display: inline-flex !important;
  align-items: center;
  justify-content: center;

  border: 1px solid var(--nb-line) !important;
  border-radius: 4px !important;
  background: var(--nb-white) !important;
  box-shadow: none !important;

  font-family: var(--nb-font-body);
  font-size: 14px !important;
  font-weight: 400;
  letter-spacing: 0.8px;
  color: var(--nb-espresso) !important;
  transition: border-color 0.2s ease, background-color 0.2s ease, color 0.2s ease;
}

.nb-single-product .variable-item.button-variable-item:hover {
  border-color: var(--nb-espresso) !important;
}

.nb-single-product .variable-item.button-variable-item.selected {
  background: var(--nb-espresso) !important;
  border-color: var(--nb-espresso) !important;
  color: var(--nb-white) !important;
}

/* An unavailable combination should read as unavailable, not just fail. */
.nb-single-product .variable-item.disabled,
.nb-single-product .variable-item[disabled] {
  opacity: 0.35 !important;
  cursor: not-allowed;
  text-decoration: line-through;
}

/* --- Quantity + add to cart ---------------------------------------------- */
.nb-single-product form.cart {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin: 0 0 18px;
}

.nb-single-product form.cart .quantity { margin: 0; }

.nb-single-product form.cart .quantity input.qty {
  width: 92px;
  height: 50px;
  padding: 0 8px;
  border: 1px solid var(--nb-line, #E8E2D9);
  border-radius: 4px;
  background: var(--nb-white);
  font-size: 15px;
  text-align: center;
}

.nb-single-product .single_add_to_cart_button {
  flex: 1 1 300px;
  max-width: 500px;
  min-height: 50px;
  padding: 0 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;

  background: #000000 !important;
  color: var(--nb-white) !important;
  border: 0 !important;
  border-radius: 4px !important;

  font-family: var(--nb-font-body);
  /* Divi styles WooCommerce buttons at 20px/1.2px from its own generated CSS,
     which loads after this stylesheet — these three cannot win on order. */
  font-size: 13px !important;
  font-weight: 600 !important;
  letter-spacing: 2.6px !important;
  line-height: 1.2 !important;
  text-transform: uppercase;
  transition: background-color 0.25s ease;
}

.nb-single-product .single_add_to_cart_button:hover {
  background: var(--nb-burgundy) !important;
}

/* Divi appends an arrow glyph to buttons on hover; the reference has none. */
.nb-single-product .single_add_to_cart_button::after { display: none !important; }

/* Variable products render the button disabled until options are chosen. */
.nb-single-product .single_add_to_cart_button.disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* --- Stock notice -------------------------------------------------------- */
.nb-product__stock {
  margin: 0 0 20px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--nb-terracotta);
}

/* --- Description in the column ------------------------------------------- */
.nb-product__description {
  margin: 24px 0 0;
  padding-top: 24px;
  border-top: 1px solid var(--nb-line, #E8E2D9);
  font-size: 15px;
  line-height: 1.85;
  color: rgba(36, 21, 18, 0.85);
}

.nb-product__description p { margin: 0 0 14px; }
.nb-product__description :is(h2, h3, h4) { font-size: 18px; margin: 20px 0 8px; }

/* --- Tabs below, as a quiet strip ---------------------------------------- */
.nb-single-product .woocommerce-tabs {
  grid-column: 1 / -1;
  margin-top: 60px;
}

.nb-single-product .woocommerce-tabs ul.tabs {
  padding: 0;
  margin: 0 0 24px;
  border-bottom: 1px solid var(--nb-line, #E8E2D9);
}

.nb-single-product .woocommerce-tabs ul.tabs::before { display: none; }

.nb-single-product .woocommerce-tabs ul.tabs li {
  background: none;
  border: 0;
  border-radius: 0;
  margin: 0 28px 0 0;
  padding: 0;
}

.nb-single-product .woocommerce-tabs ul.tabs li::before,
.nb-single-product .woocommerce-tabs ul.tabs li::after { display: none; }

.nb-single-product .woocommerce-tabs ul.tabs li a {
  padding: 0 0 12px;
  font-family: var(--nb-font-body);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: rgba(36, 21, 18, 0.6);
}

.nb-single-product .woocommerce-tabs ul.tabs li.active a {
  color: var(--nb-espresso);
  box-shadow: inset 0 -2px 0 var(--nb-burgundy);
}

/* Related products use the shared card, so they need the grid width back. */
.nb-single-product .related.products,
.nb-single-product .upsells.products { grid-column: 1 / -1; margin-top: 70px; }

.nb-single-product .related.products > h2,
.nb-single-product .upsells.products > h2 {
  font-size: 28px;
  text-align: center;
  margin-bottom: 34px;
}

/* Single product below 981px: one column, gallery above the summary.
   -------------------------------------------------------------------------
   This block existed but did not work, and the reason was specificity, not
   the media query. The desktop rule that places the summary is

     .nb-single-product div.product.type-product > .clearfix > .summary
     { grid-column: 2 }                                        -- (0,5,2)

   while the release below was written as `.nb-single-product div.product
   .summary` -- only (0,3,1). So on a phone the column count dropped to one
   but the summary kept `grid-column: 2`, which forced an IMPLICIT second
   track sized to its max-content. Measured at a 400px viewport: the tracks
   came out `84px 481px`, squashing the gallery to 84px and pushing the
   summary past the viewport edge. The full-length selector is repeated here
   so the release actually outranks the desktop placement.

   minmax(0, 1fr) rather than 1fr for the same automatic-minimum reason as
   the product grid: a bare 1fr cannot shrink below the item's min-content. */
@media (max-width: 980px) {
  .nb-single-product div.product.type-product > .clearfix {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 0;
  }

  .nb-single-product .woocommerce-product-gallery {
    grid-column: 1;
    padding-right: 0;
    margin-bottom: 28px !important;
    position: static !important;
  }

  .nb-single-product div.product.type-product > .clearfix > .summary,
  .nb-single-product div.product .summary,
  .nb-single-product div.product .entry-summary {
    grid-column: 1;
    padding: 0 !important;
  }

  .nb-single-product .flex-control-thumbs li {
    width: 64px !important;
    height: 64px;
  }

  .nb-single-product .single_add_to_cart_button { flex: 1 1 100%; max-width: none; }

  /* Size-guide tables ship from a plugin at a fixed width and overflowed the
     viewport. Scroll them rather than let them widen the page. */
  .esc-size-guide--table-wrap {
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
}

/* =========================================================================
   6. BUTTONS
   ========================================================================= */

.et_pb_button,
.woocommerce a.button,
.woocommerce button.button,
.woocommerce input.button {
  font-family: var(--nb-font-body);
  font-weight: 400;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  border-radius: 0;
  background-color: var(--nb-burgundy);
  border-color: var(--nb-burgundy);
  color: var(--nb-white);
}

.et_pb_button:hover,
.woocommerce a.button:hover,
.woocommerce button.button:hover,
.woocommerce input.button:hover {
  background-color: var(--nb-terracotta);
  border-color: var(--nb-terracotta);
  color: var(--nb-white);
}

/* =========================================================================
   7. FOOTER
   ========================================================================= */

.nb-footer,
.nb-footer .et_pb_text {
  color: var(--nb-white);
}

.nb-footer a {
  color: var(--nb-white);
}

.nb-footer a:hover {
  color: var(--nb-gold);
}

/* =========================================================================
   8. RESPONSIVE
   ========================================================================= */

/* Grid steps 4 -> 3 -> 2. It never drops to 1: single-column product grids on
   phones make the page enormously long and read as a broken layout. */
@media (max-width: 1280px) {
  :root { --nb-gutter: 32px; }

  .woocommerce ul.products,
  ul.products { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 980px) {
  :root {
    --nb-gutter: 24px;
    --nb-h2-size: 28px;
  }

  /* minmax(0, 1fr), NOT 1fr. A bare `1fr` track carries an automatic minimum
     of the item's min-content width, and the card's min-content measured
     190px against a 364px container — so two tracks came to 380px and the
     grid overflowed its own row. minmax(0, ...) lets the track shrink. */
  .woocommerce ul.products,
  ul.products {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 16px;
    row-gap: 38px;
  }

  /* Cards must fill their grid cell.
     WooCommerce and Divi still ship the old float layout's percentage widths,
     and Divi's dynamic CSS carries the most specific one:
       @media (max-width: 980px) .et_pb_shop ul.products.columns-3 li.product
       { width: 48% !important }   -- specificity (0,4,2), !important
     Inside a grid cell that 48% is measured against the CELL, so every card
     rendered at roughly half its column — 91px inside a 190px track. The
     `body` prefix here outranks that rule; the attribute selector covers
     every columns-N variant Woo emits. */
  body .et_pb_shop ul.products[class*="columns-"] li.product,
  body .woocommerce ul.products[class*="columns-"] li.product,
  body .woocommerce ul.products li.product,
  body ul.products li.product {
    width: 100% !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
    float: none !important;
  }

  /* No hover on touch, so the button must be permanently visible rather than
     waiting for a hover that never comes. Pulled back inside the image, since
     the 26px overhang only makes sense while it is a hover reveal. */
  .woocommerce ul.products li.product > .button,
  ul.products li.product > .button {
    margin: 0 10px 10px;
    opacity: 1;
    transform: none;
    letter-spacing: 1.6px;
    min-height: 36px;
  }

  .woocommerce ul.products li.product .woocommerce-loop-product__title,
  ul.products li.product .woocommerce-loop-product__title {
    margin-top: 0;
  }

  /* Footer: stack the columns and centre them. */
  .nb-footer .et_pb_column {
    width: 100% !important;
    margin-bottom: 30px !important;
    text-align: center;
  }

  .nb-footer .et_pb_column:last-child { margin-bottom: 0 !important; }

  .nb-footer .et_pb_social_media_follow { text-align: center; }
}

@media (max-width: 480px) {
  :root {
    --nb-gutter: 18px;
    --nb-h2-size: 24px;
    --nb-grid-row-gap: 34px;
  }

  .nb-ticker .et_pb_text {
    font-size: 11px;
    letter-spacing: 0.5px;
  }

  .woocommerce ul.products,
  ul.products {
    column-gap: 12px;
    row-gap: 28px;
  }

  .woocommerce ul.products li.product .woocommerce-loop-product__title { font-size: 13px; }
  .woocommerce ul.products li.product .price { font-size: 13px; }

  .et_pb_button,
  .woocommerce a.button { padding: 12px 24px; font-size: 12px; }
}

/* =========================================================================
   9. CART
   Measured on the reference's populated /cart (1521px viewport):
     H1 "Cart" 36px serif, CENTRED
     content full-bleed 1421 wide at x=50 — not the 1080 Divi container
     column widths  media 70 | details 472 | price 236 | qty 406 | total 236
     row height 170px, NO borders on thead or rows
     thumb 70x105 (2:3), object-fit cover, square corners
     title serif 16px weight 300; variation lines sans, muted
     column headers 10px uppercase, letter-spacing 1.3px, weight 600, pb 16px
     qty stepper 120x36
     remove control 40x40 at the FAR RIGHT of the row, past the total
     totals block right-aligned, 360 wide; button 360x50 uppercase ls 2.6px

   The reference's black button is not carried over: every button on this site
   is burgundy and the client has signed that off. The geometry is copied, the
   colour stays ours.
   ========================================================================= */

.nb-cart #main-content h1.entry-title,
.nb-cart .entry-title {
  text-align: center;
  font-size: var(--nb-h2-size);
  font-weight: 400;
  margin-bottom: 46px;
}

/* --- line-item table ---------------------------------------------------- */

.nb-cart .woocommerce table.shop_table {
  border: 0;
  border-radius: 0;
  margin: 0 0 40px;
  width: 100%;
}

.nb-cart .woocommerce table.shop_table th,
.nb-cart .woocommerce table.shop_table td {
  border: 0;
  background: none;
}

/* Turning the rows into grids is what lets the remove control sit at the far
   right. It is the last column visually but the FIRST cell in WooCommerce's
   markup, and table cells ignore `order` — grid items do not. Scoped to
   thead tr and tr.cart_item so the trailing colspan="6" actions row, which is
   a single full-width cell, keeps its normal table behaviour. */
/* Column widths are fixed px rather than the reference's percentages because
   the table no longer owns the full page — it shares the row with the totals
   panel, so percentages of a ~950px track left the name column too narrow for
   a two-line product title. */
.nb-cart .woocommerce table.shop_table thead tr,
.nb-cart .woocommerce table.shop_table tr.cart_item {
  display: grid;
  grid-template-columns: 70px minmax(0, 1fr) 92px 120px 100px 36px;
  column-gap: 16px;
  align-items: center;
}

.nb-cart .woocommerce table.shop_table .product-thumbnail { order: 1; }
.nb-cart .woocommerce table.shop_table .product-name      { order: 2; }
.nb-cart .woocommerce table.shop_table .product-price     { order: 3; }
.nb-cart .woocommerce table.shop_table .product-quantity  { order: 4; }
.nb-cart .woocommerce table.shop_table .product-subtotal  { order: 5; }
.nb-cart .woocommerce table.shop_table .product-remove    { order: 6; }

.nb-cart .woocommerce table.shop_table thead th {
  font-family: var(--nb-font-head);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 1.3px;
  text-transform: uppercase;
  color: var(--nb-espresso);
  text-align: left;
  padding: 0 0 16px;
}

.nb-cart .woocommerce table.shop_table thead th.product-price,
.nb-cart .woocommerce table.shop_table thead th.product-subtotal,
.nb-cart .woocommerce table.shop_table td.product-price,
.nb-cart .woocommerce table.shop_table td.product-subtotal {
  text-align: right;
}

.nb-cart .woocommerce table.shop_table tr.cart_item {
  min-height: 170px;
  padding: 16px 0;
}

.nb-cart .woocommerce table.shop_table tr.cart_item td {
  padding: 0;
}

/* --- thumbnail ----------------------------------------------------------
   WooCommerce's own stylesheet carries `.woocommerce table.cart img {
   width: 32px }`, which is (0,2,2). The obvious `.nb-cart .product-thumbnail
   img` is only (0,2,1) and lost to it — measured 32x48 on the live page
   instead of 70x105. Matching table.cart explicitly takes this to (0,4,2),
   and the size is flagged because Divi emits per-module CSS after the child
   stylesheet and cannot be beaten on cascade order alone.
   ------------------------------------------------------------------------ */

.nb-cart .woocommerce table.cart .product-thumbnail img,
.nb-cart .woocommerce table.shop_table .product-thumbnail img {
  width: 70px !important;
  height: 105px !important;
  object-fit: cover;
  border-radius: 0;
  display: block;
  max-width: none;
}

/* --- product name + variation lines ------------------------------------- */

.nb-cart .product-name a {
  font-family: var(--nb-font-head);
  font-size: 16px;
  font-weight: 300;
  line-height: 1.5;
  color: var(--nb-espresso);
  text-decoration: none;
}

.nb-cart .product-name a:hover {
  color: var(--nb-burgundy);
}

.nb-cart .product-name .variation {
  margin: 8px 0 0;
  font-family: var(--nb-font-body);
  font-size: 14px;
  line-height: 1.7;
  color: var(--nb-espresso);
  opacity: 0.75;
}

.nb-cart .product-name .variation dt,
.nb-cart .product-name .variation dd {
  display: inline;
  margin: 0;
  font-weight: inherit;
}

/* Each attribute on its own line, the way the reference lists them. */
.nb-cart .product-name .variation dd::after {
  content: "";
  display: block;
}

.nb-cart .product-name .variation p { margin: 0; }

/* --- price / subtotal --------------------------------------------------- */

.nb-cart .product-price,
.nb-cart .product-subtotal {
  font-family: var(--nb-font-body);
  font-size: 14px;
  color: var(--nb-espresso);
}

.nb-cart .product-subtotal { font-weight: 400; }

/* --- quantity stepper --------------------------------------------------- */

.nb-cart .product-quantity .quantity {
  display: inline-flex;
  align-items: center;
  width: 120px;
  height: 36px;
  border: 1px solid var(--nb-line);
}

.nb-cart .product-quantity .quantity input.qty {
  width: 100%;
  height: 34px;
  border: 0;
  background: none;
  text-align: center;
  font-family: var(--nb-font-body);
  font-size: 14px;
  color: var(--nb-espresso);
  padding: 0;
  box-shadow: none;
}

/* --- remove control ----------------------------------------------------- */

.nb-cart .product-remove {
  text-align: right;
}

.nb-cart .product-remove a.remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  font-size: 22px;
  line-height: 1;
  color: var(--nb-espresso);
  background: none;
  border-radius: 0;
  text-decoration: none;
}

.nb-cart .product-remove a.remove:hover {
  color: var(--nb-burgundy);
  background: none;
}

/* --- coupon + update row ------------------------------------------------ */

.nb-cart .woocommerce table.shop_table td.actions {
  padding: 24px 0 0;
  border-top: 1px solid var(--nb-line);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.nb-cart .woocommerce table.shop_table td.actions .coupon {
  display: flex;
  align-items: center;
  gap: 10px;
  float: none;
}

.nb-cart .woocommerce table.shop_table td.actions .coupon label {
  display: none;
}

.nb-cart .woocommerce table.shop_table td.actions .input-text {
  width: 220px;
  height: 46px;
  padding: 0 14px;
  border: 1px solid var(--nb-line);
  border-radius: 0;
  font-family: var(--nb-font-body);
  font-size: 14px;
}

.nb-cart .woocommerce table.shop_table td.actions .button {
  height: 46px;
  padding: 0 24px;
  font-size: 11px;
  letter-spacing: 1.2px;
}

/* --- two-column shell: items left, totals right -------------------------
   The reference stacks these — full-bleed table, totals beneath it on the
   right — but the client asked for them side by side, the way a stock
   WooCommerce cart reads. So the .woocommerce wrapper becomes the grid and
   its two children take a column each.

   Notices are children of the same wrapper, so they would otherwise be
   placed into the item track and end up squeezed under the table. They are
   spanned across both columns explicitly.
   ------------------------------------------------------------------------ */

.nb-cart .woocommerce {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  column-gap: 60px;
  align-items: start;
}

.nb-cart .woocommerce > form.woocommerce-cart-form { grid-column: 1; }
.nb-cart .woocommerce > .cart-collaterals { grid-column: 2; }

.nb-cart .woocommerce > .woocommerce-notices-wrapper,
.nb-cart .woocommerce > .woocommerce-message,
.nb-cart .woocommerce > .woocommerce-error,
.nb-cart .woocommerce > .woocommerce-info,
.nb-cart .woocommerce > .cart-empty,
.nb-cart .woocommerce > .return-to-shop {
  grid-column: 1 / -1;
}

/* --- totals block ------------------------------------------------------- */

.nb-cart .cart-collaterals {
  display: block;
  width: 100%;
}

/* Sitting beside the table rather than under it, the totals need an edge of
   their own or they read as a stray column of text. Ivory matches the
   checkout's order-review panel, so the two pages stay of a piece. */
.nb-cart .cart-collaterals .cart_totals {
  width: 100%;
  max-width: 100%;
  float: none;
  background: var(--nb-ivory);
  padding: 26px 28px;
}

.nb-cart .woocommerce table.shop_table {
  margin-bottom: 0;
}

.nb-cart .cart_totals h2 {
  font-family: var(--nb-font-head);
  font-size: 16px;
  font-weight: 400;
  letter-spacing: 0.54px;
  text-transform: none;
  margin: 0 0 12px;
  padding: 0;
  text-align: left;
}

.nb-cart .cart_totals table.shop_table {
  margin: 0 0 4px;
}

.nb-cart .cart_totals table.shop_table th,
.nb-cart .cart_totals table.shop_table td {
  padding: 6px 0;
  border: 0;
  font-family: var(--nb-font-head);
  font-size: 16px;
  font-weight: 400;
  color: var(--nb-espresso);
}

.nb-cart .cart_totals table.shop_table td { text-align: right; }

/* The reference sets expectations before the customer commits: shipping and
   tax are not final until the checkout address is known. */
.nb-cart .cart_totals::after {
  content: "Taxes and shipping calculated at checkout";
  display: block;
  margin: 2px 0 20px;
  font-family: var(--nb-font-body);
  font-size: 13px;
  letter-spacing: 0.4px;
  color: var(--nb-espresso);
  opacity: 0.65;
}

.nb-cart .wc-proceed-to-checkout {
  padding: 0;
}

.nb-cart .wc-proceed-to-checkout a.checkout-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 360px;
  max-width: 100%;
  height: 50px;
  margin: 0;
  padding: 0;
  font-family: var(--nb-font-body);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 2.6px;
  text-transform: uppercase;
  border-radius: 4px;
  background-color: var(--nb-burgundy);
  border: 0;
  color: var(--nb-white);
}

.nb-cart .wc-proceed-to-checkout a.checkout-button:hover {
  background-color: var(--nb-terracotta);
  color: var(--nb-white);
}

/* Empty state — centred, matching the page heading. */
.nb-cart .cart-empty {
  text-align: center;
  font-family: var(--nb-font-head);
  font-size: 20px;
  font-weight: 300;
  margin: 40px 0 24px;
}

.nb-cart .return-to-shop {
  text-align: center;
  margin-bottom: 60px;
}

/* =========================================================================
   10. CHECKOUT
   No reference to copy: niswafashion.com is Shopify, so its checkout is
   Shopify's own hosted page — a locked template that cannot be reproduced in
   WooCommerce and is not the client's to edit either. Built instead in the
   cart's visual language: same heading, same field treatment, same button.
   ========================================================================= */

.nb-checkout #main-content h1.entry-title,
.nb-checkout .entry-title {
  text-align: center;
  font-size: var(--nb-h2-size);
  font-weight: 400;
  margin-bottom: 46px;
}

.nb-checkout .woocommerce-form-coupon-toggle,
.nb-checkout .woocommerce-form-login-toggle {
  max-width: 100%;
  margin-bottom: 24px;
}

/* These notices ship as white text on a dark bar. Repainting the background
   ivory without also setting the colour left white-on-ivory — the "Have a
   coupon?" toggle measured rgb(255,255,255) on rgb(250,243,234), i.e. fully
   invisible.

   The colour is flagged !important because Divi declares
   `.woocommerce-message, .woocommerce-error, .woocommerce-info { color: #fff
   !important }`. An !important declaration wins over a non-important one no
   matter how specific the loser is, so the first attempt at this fix — a
   plain `color` on a two-class selector — changed nothing. Confirmed by
   enumerating the rules that actually matched the element. */
.nb-cart .woocommerce-info,
.nb-cart .woocommerce-message,
.nb-checkout .woocommerce-info,
.nb-checkout .woocommerce-message {
  border-top: 0;
  border-left: 2px solid var(--nb-burgundy);
  background: var(--nb-ivory);
  color: var(--nb-espresso) !important;
  font-family: var(--nb-font-body);
  font-size: 14px;
  padding: 14px 18px;
  border-radius: 0;
}

.nb-cart .woocommerce-info a,
.nb-cart .woocommerce-message a,
.nb-checkout .woocommerce-info a,
.nb-checkout .woocommerce-message a {
  color: var(--nb-burgundy) !important;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.nb-cart .woocommerce-info a:hover,
.nb-cart .woocommerce-message a:hover,
.nb-checkout .woocommerce-info a:hover,
.nb-checkout .woocommerce-message a:hover {
  color: var(--nb-terracotta) !important;
}

/* Validation errors. Left out of the block above on purpose the first time,
   which was a mistake: Divi paints .woocommerce-error with the same
   #2EA3F2 info-blue and white text as the other two, so "Billing First name
   is a required field" arrived as a blue notice — legible, but reading as
   information rather than as something the shopper must fix, and off-brand.
   Measured by injecting a probe .woocommerce-error into the live checkout:
   rgb(255,255,255) on rgb(46,163,242).

   Given its own treatment here — same ivory panel as the other notices, but
   a red rule and red heading so an error is recognisable as one. */
.nb-cart .woocommerce-error,
.nb-checkout .woocommerce-error {
  border-top: 0;
  border-left: 2px solid #B3261E;
  background: #FCF2F1 !important;
  color: var(--nb-espresso) !important;
  font-family: var(--nb-font-body);
  font-size: 14px;
  line-height: 1.7;
  padding: 14px 18px 14px 20px;
  margin: 0 0 22px;
  border-radius: 0;
  list-style: none;
}

.nb-cart .woocommerce-error::before,
.nb-checkout .woocommerce-error::before { display: none; }

.nb-cart .woocommerce-error li,
.nb-checkout .woocommerce-error li {
  color: var(--nb-espresso) !important;
  margin: 0 0 4px;
  padding: 0;
  list-style: none;
}

.nb-cart .woocommerce-error li:last-child,
.nb-checkout .woocommerce-error li:last-child { margin-bottom: 0; }

.nb-cart .woocommerce-error strong,
.nb-checkout .woocommerce-error strong { color: #B3261E !important; }

.nb-cart .woocommerce-error a,
.nb-checkout .woocommerce-error a {
  color: #B3261E !important;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* A required field that failed validation needs to be findable without
   reading the notice — WooCommerce marks the row, nothing was styling it. */
.nb-checkout .woocommerce-invalid input.input-text,
.nb-checkout .woocommerce-invalid textarea,
.nb-checkout .woocommerce-invalid .select2-selection--single {
  border-color: #B3261E;
}

.nb-checkout .woocommerce-info::before,
.nb-checkout .woocommerce-message::before { display: none; }

/* Two columns: details left, order review right. */
/* grid-template-rows is required, not cosmetic. #customer_details spans both
   rows, and a spanning item's height is distributed across the tracks it
   covers — so row 1 sized itself to 180px off the 1099px details block and
   left a 148px hole between the "Your order" heading and its panel. Pinning
   row 1 to min-content makes it exactly as tall as the heading. */
.nb-checkout form.checkout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 400px;
  grid-template-rows: min-content 1fr;
  column-gap: 60px;
  align-items: start;
}

/* The details block must SPAN BOTH ROWS. The form has three children —
   details, the review heading, and the review table — so the heading takes
   column 2 row 1 and the table column 2 row 2. Without the span, row 1 is as
   tall as the details block (1099px measured), which pushed the review table
   down to y=1534: beside the details in column terms, but a full screen below
   it on the page. */
.nb-checkout form.checkout #customer_details {
  grid-column: 1;
  grid-row: 1 / span 2;
  width: 100%;
  float: none;
}

.nb-checkout form.checkout #customer_details .col-1,
.nb-checkout form.checkout #customer_details .col-2 {
  width: 100%;
  float: none;
  max-width: 100%;
}

.nb-checkout form.checkout h3,
.nb-checkout form.checkout #order_review_heading {
  font-family: var(--nb-font-head);
  font-size: 18px;
  font-weight: 400;
  letter-spacing: 0.5px;
  margin: 0 0 20px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--nb-line);
}

.nb-checkout form.checkout #order_review_heading {
  grid-column: 2;
  grid-row: 1;
}

.nb-checkout form.checkout #order_review {
  grid-column: 2;
  grid-row: 2;
  align-self: start;
}

.nb-checkout form.checkout #order_review {
  background: var(--nb-ivory);
  padding: 26px 28px;
}

/* --- form fields -------------------------------------------------------- */

.nb-checkout .woocommerce form .form-row {
  padding: 0;
  margin: 0 0 18px;
}

.nb-checkout .woocommerce form .form-row label {
  font-family: var(--nb-font-body);
  font-size: 12px;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--nb-espresso);
  margin-bottom: 7px;
  display: block;
}

.nb-checkout .woocommerce form .form-row input.input-text,
.nb-checkout .woocommerce form .form-row textarea {
  width: 100%;
  height: 48px;
  padding: 0 14px;
  border: 1px solid var(--nb-line);
  border-radius: 0;
  background: var(--nb-white);
  font-family: var(--nb-font-body);
  font-size: 14px;
  color: var(--nb-espresso);
  box-shadow: none;
}

.nb-checkout .woocommerce form .form-row textarea {
  height: 110px;
  padding: 12px 14px;
  line-height: 1.6;
}

.nb-checkout .woocommerce form .form-row input.input-text:focus,
.nb-checkout .woocommerce form .form-row textarea:focus {
  border-color: var(--nb-burgundy);
  outline: none;
}

.nb-checkout .select2-container--default .select2-selection--single {
  height: 48px;
  border: 1px solid var(--nb-line);
  border-radius: 0;
}

.nb-checkout .select2-container--default .select2-selection--single
  .select2-selection__rendered {
  line-height: 46px;
  padding-left: 14px;
  font-family: var(--nb-font-body);
  font-size: 14px;
  color: var(--nb-espresso);
}

.nb-checkout .select2-container--default .select2-selection--single
  .select2-selection__arrow { height: 46px; }

/* --- order review table ------------------------------------------------- */

.nb-checkout #order_review table.shop_table {
  border: 0;
  border-radius: 0;
  margin: 0;
}

.nb-checkout #order_review table.shop_table th,
.nb-checkout #order_review table.shop_table td {
  border: 0;
  padding: 10px 0;
  font-family: var(--nb-font-body);
  font-size: 14px;
  color: var(--nb-espresso);
  background: none;
}

.nb-checkout #order_review table.shop_table thead th {
  font-family: var(--nb-font-head);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 1.3px;
  text-transform: uppercase;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--nb-line);
}

.nb-checkout #order_review table.shop_table td.product-total,
.nb-checkout #order_review table.shop_table th.product-total,
.nb-checkout #order_review table.shop_table tfoot td {
  text-align: right;
}

.nb-checkout #order_review table.shop_table tfoot tr:first-child th,
.nb-checkout #order_review table.shop_table tfoot tr:first-child td {
  border-top: 1px solid var(--nb-line);
  padding-top: 16px;
}

.nb-checkout #order_review table.shop_table tfoot .order-total th,
.nb-checkout #order_review table.shop_table tfoot .order-total td {
  font-family: var(--nb-font-head);
  font-size: 17px;
  font-weight: 400;
}

.nb-checkout #order_review .product-name .variation {
  margin: 5px 0 0;
  font-size: 12px;
  opacity: 0.7;
}

.nb-checkout #order_review .product-name .variation dt,
.nb-checkout #order_review .product-name .variation dd {
  display: inline;
  margin: 0;
}

/* --- payment box -------------------------------------------------------- */

.nb-checkout #payment {
  background: none;
  border-radius: 0;
  margin-top: 22px;
}

.nb-checkout #payment ul.payment_methods {
  border-bottom: 1px solid var(--nb-line);
  padding: 0 0 16px;
  margin: 0 0 16px;
}

.nb-checkout #payment ul.payment_methods li {
  font-family: var(--nb-font-body);
  font-size: 14px;
  margin-bottom: 8px;
}

.nb-checkout #payment div.payment_box {
  background: var(--nb-white);
  font-size: 13px;
  line-height: 1.7;
  border-radius: 0;
  color: var(--nb-espresso);
}

.nb-checkout #payment div.payment_box::before { display: none; }

.nb-checkout #payment .woocommerce-terms-and-conditions-wrapper {
  font-size: 13px;
  line-height: 1.7;
  margin-bottom: 16px;
}

.nb-checkout #payment #place_order {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 50px;
  padding: 0;
  margin: 0;
  float: none;
  font-family: var(--nb-font-body);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 2.6px;
  text-transform: uppercase;
  border-radius: 4px;
  border: 0;
  background-color: var(--nb-burgundy);
  color: var(--nb-white);
}

.nb-checkout #payment #place_order:hover {
  background-color: var(--nb-terracotta);
}

/* =========================================================================
   11. CART / CHECKOUT — RESPONSIVE
   The cart's five-column row cannot survive a phone. Below 981px the row
   becomes a two-column card: thumbnail left, everything else stacked right,
   with the WooCommerce data-title labels doing the work the dropped table
   header used to do.
   ========================================================================= */

@media (max-width: 1100px) {
  .nb-cart .woocommerce {
    grid-template-columns: minmax(0, 1fr) 300px;
    column-gap: 32px;
  }

  .nb-cart .woocommerce table.shop_table thead tr,
  .nb-cart .woocommerce table.shop_table tr.cart_item {
    grid-template-columns: 64px minmax(0, 1fr) 78px 100px 86px 32px;
    column-gap: 12px;
  }

  .nb-cart .cart-collaterals .cart_totals { padding: 20px 18px; }

  .nb-checkout form.checkout {
    grid-template-columns: minmax(0, 1fr) 340px;
    column-gap: 36px;
  }
}

@media (max-width: 980px) {
  .nb-cart .woocommerce table.shop_table thead { display: none; }

  .nb-cart .woocommerce table.shop_table tr.cart_item {
    grid-template-columns: 84px minmax(0, 1fr);
    grid-template-areas:
      "thumb name"
      "thumb price"
      "thumb qty"
      "thumb total";
    column-gap: 16px;
    row-gap: 6px;
    align-items: start;
    min-height: 0;
    padding: 20px 0;
    border-bottom: 1px solid var(--nb-line);
    position: relative;
  }

  .nb-cart .woocommerce table.shop_table .product-thumbnail {
    grid-area: thumb;
    align-self: start;
  }

  .nb-cart .product-thumbnail img { width: 84px; height: 126px; }

  .nb-cart .woocommerce table.shop_table .product-name     { grid-area: name; padding-right: 34px; }
  .nb-cart .woocommerce table.shop_table .product-price    { grid-area: price; text-align: left; }
  .nb-cart .woocommerce table.shop_table .product-quantity { grid-area: qty; }
  .nb-cart .woocommerce table.shop_table .product-subtotal { grid-area: total; text-align: left; }

  /* Out of the flow entirely so it does not claim a grid row of its own. */
  .nb-cart .woocommerce table.shop_table .product-remove {
    position: absolute;
    top: 14px;
    right: 0;
  }

  /* Stacked, the price and the subtotal are two bare numbers with nothing to
     tell them apart. WooCommerce already writes the label into data-title. */
  .nb-cart .product-price::before,
  .nb-cart .product-subtotal::before {
    content: attr(data-title) ": ";
    font-size: 12px;
    letter-spacing: 0.6px;
    opacity: 0.65;
  }

  .nb-cart .woocommerce table.shop_table td.actions {
    flex-direction: column;
    align-items: stretch;
  }

  .nb-cart .woocommerce table.shop_table td.actions .coupon { width: 100%; }
  .nb-cart .woocommerce table.shop_table td.actions .input-text { flex: 1 1 auto; width: auto; }

  /* Side by side stops working once the table has collapsed to cards — the
     totals column would be squeezed against a stack. Back to one column. */
  .nb-cart .woocommerce {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 34px;
  }

  .nb-cart .woocommerce > form.woocommerce-cart-form,
  .nb-cart .woocommerce > .cart-collaterals { grid-column: 1; }

  .nb-cart .cart-collaterals,
  .nb-cart .cart-collaterals .cart_totals { width: 100%; }
  .nb-cart .wc-proceed-to-checkout a.checkout-button { width: 100%; }

  .nb-checkout form.checkout {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: none;
    row-gap: 34px;
  }

  /* grid-row must be released too, or the desktop row spans survive into the
     single-column layout and reorder the blocks. */
  .nb-checkout form.checkout #customer_details,
  .nb-checkout form.checkout #order_review_heading,
  .nb-checkout form.checkout #order_review {
    grid-column: 1;
    grid-row: auto;
  }
}

@media (max-width: 640px) {
  .nb-cart #main-content h1.entry-title,
  .nb-checkout #main-content h1.entry-title {
    font-size: 28px;
    margin-bottom: 30px;
  }

  .nb-cart .woocommerce table.shop_table tr.cart_item {
    grid-template-columns: 68px minmax(0, 1fr);
    column-gap: 12px;
  }

  .nb-cart .product-thumbnail img { width: 68px; height: 102px; }
  .nb-cart .product-name a { font-size: 15px; }
  .nb-cart .product-quantity .quantity { width: 108px; }

  .nb-checkout form.checkout #order_review { padding: 20px 18px; }
}


/* =========================================================================
   12. PRODUCT ARCHIVES — SHOP (T2) AND CATEGORY (T4)
   Measured on the reference's /collections/all at a 1521px viewport:
     content full-bleed 1421 at x=50
     h1 36px serif weight 400, CENTRED, at y=168
     toolbar row y=230, 40px tall, full width
     product count "448 products" 14px sans, rgba(33,35,38,.7), LEFT, y=285
     grid y=340, FOUR columns, column-gap 20px, row-gap 55px
     card 340 wide, image 340x509 (2:3), title centred 16px w300, price 14px

   The grid itself already matched — four columns, 20/55 gaps and 2:3 cards
   were built for the home page and the archives inherit them. What was
   missing was the header block: the title rendered at Divi's default 30px
   left-aligned, and WooCommerce's "Showing 1-9 of 44 results" sat on the same
   line as the sort dropdown rather than on its own row beneath it.
   ========================================================================= */

.woocommerce-products-header {
  margin: 0 0 30px;
  padding: 0;
  text-align: center;
}

.woocommerce-products-header__title.page-title,
.nb-full-width .woocommerce-products-header__title {
  font-family: var(--nb-font-head);
  font-size: var(--nb-h2-size);
  font-weight: 400;
  line-height: var(--nb-h2-lh);
  letter-spacing: var(--nb-h2-ls);
  text-align: center;
  margin: 0;
  padding: 0;
}

/* A category's own description, when the client writes one. Centred under the
   title and held to a readable measure rather than running the full 1421. */
.woocommerce-products-header .term-description {
  max-width: 680px;
  margin: 14px auto 0;
  font-family: var(--nb-font-body);
  font-size: 15px;
  line-height: 1.8;
  color: var(--nb-espresso);
  opacity: 0.75;
}

.woocommerce-products-header .term-description p:last-child { margin-bottom: 0; }

/* --- toolbar: sort row, then count row ---------------------------------- */

/* Both are floated by WooCommerce, which is what put them side by side. Once
   they are blocks in normal flow they stack, matching the reference. */
.nb-full-width .woocommerce-ordering,
.nb-full-width .woocommerce-result-count {
  float: none;
  display: block;
  width: 100%;
  margin: 0;
}

.nb-full-width .woocommerce-ordering {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--nb-line);
}

/* WooCommerce ships the ordering form with only a screen-reader label, so the
   visible "SORT BY" the reference shows has to be supplied here. */
.nb-full-width .woocommerce-ordering::before {
  content: "Sort by";
  font-family: var(--nb-font-body);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 1.3px;
  text-transform: uppercase;
  color: var(--nb-espresso);
  opacity: 0.8;
  white-space: nowrap;
}

.nb-full-width .woocommerce-ordering select.orderby {
  height: 34px;
  padding: 0 28px 0 8px;
  border: 0;
  border-radius: 0;
  background: none;
  font-family: var(--nb-font-body);
  font-size: 14px;
  color: var(--nb-espresso);
  cursor: pointer;
  box-shadow: none;
  -webkit-appearance: none;
  appearance: none;

  /* Native select arrows differ per platform and the border is gone, so the
     control needs its own chevron to still read as a dropdown. */
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23241512' stroke-width='1.3'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
}

.nb-full-width .woocommerce-result-count,
.nb-full-width p.nb-result-count {
  margin: 14px 0 22px;
  font-family: var(--nb-font-body);
  font-size: 14px;
  letter-spacing: 0.3px;
  color: rgba(36, 21, 18, 0.7);
  text-align: left;
}

/* --- pagination ---------------------------------------------------------
   Deliberate departure. The reference paginates with a single full-width
   "SHOW MORE" button that appends the next batch over AJAX. Reproducing that
   means a custom endpoint and front-end script to own and debug; numbered
   pages are WooCommerce's own mechanism, work without JavaScript, and are
   what the client can reason about. Styled to sit quietly under the grid.
   ------------------------------------------------------------------------ */

.nb-full-width .woocommerce-pagination {
  margin: 55px 0 0;
  text-align: center;
}

.nb-full-width .woocommerce-pagination ul.page-numbers {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 0;
  margin: 0;
  padding: 0;
}

.nb-full-width .woocommerce-pagination ul.page-numbers li {
  border: 0;
  margin: 0;
  overflow: visible;
}

.nb-full-width .woocommerce-pagination ul.page-numbers li .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  height: 40px;
  padding: 0 6px;
  border: 1px solid transparent;
  border-radius: 0;
  background: none;
  font-family: var(--nb-font-body);
  font-size: 14px;
  letter-spacing: 0.5px;
  color: var(--nb-espresso);
  transition: border-color 0.2s ease, color 0.2s ease;
}

.nb-full-width .woocommerce-pagination ul.page-numbers li a.page-numbers:hover {
  border-color: var(--nb-line);
  color: var(--nb-burgundy);
  background: none;
}

.nb-full-width .woocommerce-pagination ul.page-numbers li span.current {
  border-color: var(--nb-burgundy);
  color: var(--nb-burgundy);
  background: none;
}

/* --- no-results state ---------------------------------------------------- */

.nb-full-width .woocommerce-info.woocommerce-no-products-found,
.nb-full-width .woocommerce-no-products-found .woocommerce-info {
  border-top: 0;
  border-left: 2px solid var(--nb-burgundy);
  background: var(--nb-ivory);
  border-radius: 0;
  padding: 16px 20px;
  font-family: var(--nb-font-body);
  font-size: 15px;
}

.nb-full-width .woocommerce-no-products-found .woocommerce-info::before { display: none; }

@media (max-width: 980px) {
  .nb-full-width .woocommerce-ordering { min-height: 0; }
  .nb-full-width .woocommerce-result-count { margin: 12px 0 18px; }
}

@media (max-width: 640px) {
  .woocommerce-products-header { margin-bottom: 22px; }

  .woocommerce-products-header__title.page-title,
  .nb-full-width .woocommerce-products-header__title { font-size: 28px; }

  .nb-full-width .woocommerce-pagination { margin-top: 34px; }

  .nb-full-width .woocommerce-pagination ul.page-numbers li .page-numbers {
    min-width: 34px;
    height: 34px;
    font-size: 13px;
  }
}

/* =========================================================================
   BREADCRUMBS — single product page only.
   The action is removed in functions.php; this is the belt-and-braces half,
   covering any breadcrumb Divi's Theme Builder emits outside the WooCommerce
   hook, which PHP alone would not catch.
   ========================================================================= */
body:not(.single-product) .woocommerce-breadcrumb {
  display: none !important;
}

/* =========================================================================
   MOBILE CART — corrections against woocommerce-smallscreen.css
   -------------------------------------------------------------------------
   The card layout for cart rows is defined in the max-width:980px block
   further up. Three of its declarations were being beaten by WooCommerce's
   own small-screen stylesheet, which the theme never contested:

     .woocommerce table.cart .product-thumbnail { display: none }
       -- the theme assigns the thumbnail a grid-area but never a `display`,
          so there was nothing to override this and the photo was absent.

     .woocommerce table.shop_table_responsive tr td { text-align: right !important }
       -- !important, so the theme's `text-align: left` lost and every value
          sat hard against the right edge.

     table.shop_table_responsive tr td::before { content: attr(data-title) ": " }
       -- applied to EVERY cell, so the thumbnail cell rendered a bare ": "
          and the name cell a redundant "Product: ".

   The remove control is absolutely positioned top-right, so the name cell
   needs real padding to keep the two apart — measured overlapping by 44px.
   ========================================================================= */
@media (max-width: 980px) {
  .nb-cart table.cart .product-thumbnail,
  .nb-cart table.shop_table_responsive .product-thumbnail {
    display: block !important;
  }

  .nb-cart table.cart tr.cart_item td,
  .nb-cart table.shop_table_responsive tr.cart_item td {
    text-align: left !important;
  }

  .nb-cart table.shop_table_responsive tr td::before { float: none !important; }

  .nb-cart table.shop_table_responsive tr td.product-thumbnail::before,
  .nb-cart table.shop_table_responsive tr td.product-name::before,
  .nb-cart table.shop_table_responsive tr td.product-quantity::before,
  .nb-cart table.shop_table_responsive tr td.product-remove::before {
    content: none !important;
  }

  .nb-cart table.shop_table_responsive tr td.product-price::before,
  .nb-cart table.shop_table_responsive tr td.product-subtotal::before {
    content: attr(data-title) ": " !important;
    font-size: 12px;
    letter-spacing: 0.6px;
    opacity: 0.65;
  }

  .nb-cart table.shop_table_responsive tr td.product-name {
    padding-right: 56px !important;
  }
}
