/* ------------------------------------------------------------
   The shelf: accessories under a product, related products, and "Worth
   adding" on the bag (Oct 24).
   ------------------------------------------------------------
   One component on all three, so moved here from pdp.css unchanged, and
   loaded on product pages (after pdp.css) and on the bag (after bag.css).
   The product page was compared pixel for pixel before and after the move.
   ------------------------------------------------------------ */

/* Accessories under a product: add to bag from the card, with one menu for
   an accessory sold in colours or sizes (deviceland_accessory_card_cart). */
body.deviceland-shop .cross-sells .dl-acc-cart {
  display: grid;
  gap: 8px;
  margin-top: 12px;
}

/* Colour dots: the same swatches as the category cards; the chosen colour's
   name beside them. */
body.deviceland-shop .cross-sells .dl-acc-dots {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  min-height: 20px;
}

body.deviceland-shop .cross-sells .dl-acc-dot {
  width: 16px;
  height: 16px;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--dot);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.14);
  cursor: pointer;
}

body.deviceland-shop .cross-sells .dl-acc-dot.is-on {
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.14), 0 0 0 2px var(--paper, #f6f0e6), 0 0 0 3px var(--on-paper, #16130f);
}

body.deviceland-shop .cross-sells .dl-acc-dot:focus-visible {
  outline: 2px solid var(--ember, #c4501f);
  outline-offset: 3px;
}

body.deviceland-shop .cross-sells .dl-acc-colour {
  margin-left: 2px;
  font-size: 12.5px;
  color: var(--muted-fg, #6b6259);
}

body.deviceland-shop .cross-sells .dl-acc-pick[hidden] {
  display: none;
}

/* "Fits your selection": only while the build shown is one the evidence
   says fits the product build chosen above. */
body.deviceland-shop .cross-sells .dl-acc-fit {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: var(--muted-fg, #6b6259);
}

body.deviceland-shop .cross-sells .dl-acc-fit::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #3f7d4e;
}

body.deviceland-shop .cross-sells .dl-acc-fit[hidden] {
  display: none;
}

body.deviceland-shop .cross-sells .dl-acc-pick {
  width: 100%;
  height: 38px;
  padding: 0 10px;
  border: 1px solid rgba(22, 19, 15, 0.18);
  border-radius: 8px;
  background: #fff;
  font-size: 13px;
  color: var(--fg, #16130f);
}

/* "+ Add": a quiet text control at the card's foot, right-aligned, in the
   card's own type (owner, Oct 15). A pill on every card, outlined or not,
   read as a second buy button beside the product's own Add to bag. The
   underline appears on hover; the hit area stays a comfortable 36px. */
body.deviceland-shop .cross-sells .dl-acc-add.button,
body.deviceland-shop .cross-sells .dl-acc-add.button:hover,
body.deviceland-shop .cross-sells .dl-acc-add.button:focus {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  align-self: flex-end;
  width: auto;
  min-width: 0;
  height: 36px;
  min-height: 0;
  margin: 0 0 0 auto;
  padding: 0 2px;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  color: var(--ink, #16130f);
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  text-decoration: none;
  line-height: 1;
}

body.deviceland-shop .cross-sells .dl-acc-add.button:hover,
body.deviceland-shop .cross-sells .dl-acc-add.button:focus-visible {
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-thickness: 1px;
}

body.deviceland-shop .cross-sells .dl-acc-plus {
  font-size: 16px;
  font-weight: 400;
  line-height: 1;
}

/* "Pairs well with ..." under the product (deviceland_pairs_well_with): the
   same serif heading the page's sections use, a quiet link to the rest, and
   one row of four cards. */
/* The product row's own column: Elessi's .focus-info is 1,400px wide and
   centred, padded 30px until the window can hold it whole. Full-bleed, the
   row started at the window's left edge with 435px cards at 1920 (owner,
   Oct 15). */
html body.deviceland-shop .dl-pairs {
  clear: both;
  box-sizing: border-box;
  max-width: 1400px;
  margin: 56px auto 24px;
  padding: 0 30px;
}

@media (min-width: 1460px) {
  html body.deviceland-shop .dl-pairs {
    padding: 0;
  }
}

/* One row: four cards in view, the rest scroll sideways (arrows above, swipe
   on touch). Snap so a card is never left half in view after a scroll. */
html body.deviceland-shop .dl-pairs .cross-sells ul.products {
  display: flex !important;
  flex-wrap: nowrap;
  gap: 20px;
  /* Room inside the scroll edge for the chosen-colour ring and the hover
     shadow, given back as negative margin (see the under-gallery row). */
  margin: -6px -6px 0 !important;
  padding: 6px 6px 10px;
  scroll-padding: 0 6px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

html body.deviceland-shop .dl-pairs .cross-sells ul.products::-webkit-scrollbar {
  display: none;
}

html body.deviceland-shop .dl-pairs .cross-sells ul.products::before,
html body.deviceland-shop .dl-pairs .cross-sells ul.products::after {
  content: none;
}

/* Until the script has decided where the row goes (two-column pages). */
html body.deviceland-shop .dl-pairs.is-pending {
  display: none;
}

/* Under the gallery (the script moves it there when the buy column leaves
   room): the gallery's own width, three across, a slightly smaller heading. */
html body.deviceland-shop .dl-pairs.is-aside {
  max-width: none;
  margin: 44px 0 0;
  padding: 0;
}

/* A caption to the photo above, not a section competing with the product
   title (owner, Oct 15). */
html body.deviceland-shop .dl-pairs .dl-pairs-title,
html body.deviceland-shop .dl-pairs.is-aside .dl-pairs-title {
  font-size: 20px;
  letter-spacing: -0.005em;
}

html body.deviceland-shop .dl-pairs-head {
  margin-bottom: 14px;
}

/* Related products is a section of the page, a peer of Description and
   Additional information, not a caption: their heading, size, ink and the
   hairline to the right edge from 1024px (owner, Oct 24). The cards stay
   the shelf's. */
html body.deviceland-shop .dl-pairs.dl-pairs-related .dl-pairs-head {
  margin-bottom: 22px;
}

html body.deviceland-shop .dl-pairs.dl-pairs-related .dl-pairs-title {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(1.55rem, 2.2vw, 2rem);
  line-height: 1.05;
  letter-spacing: -0.015em;
  color: var(--on-paper);
}

@media (min-width: 1024px) {
  html body.deviceland-shop .dl-pairs.dl-pairs-related .dl-pairs-title::after {
    content: "";
    flex: 1 1 auto;
    height: 0;
    min-width: 24px;
    margin: 0 0 0 18px;
    border-bottom: 1px solid var(--hair-light);
  }
}

/* 768-1023px: Elessi's own short stub beside those headings, so this one too. */
@media (min-width: 768px) and (max-width: 1023px) {
  html body.deviceland-shop .dl-pairs.dl-pairs-related .dl-pairs-title::after {
    content: "";
    display: block;
    flex: 0 1 auto;
    width: 40px;
    height: 3px;
    margin: 0 0 0 20px;
    border-bottom: 1px solid #ddd;
  }
}

/* Three across under the gallery, scrolling sideways (owner, Oct 15).
   A scrolling row clips whatever crosses its edge, which cut the ring
   round the first card's chosen colour and the tiles' hover shadow: the
   row gets 6px of room inside each edge and gives it back as a negative
   margin, so the tiles still line up with the photo above. */
html body.deviceland-shop .dl-pairs.is-aside .cross-sells ul.products {
  display: grid !important;
  grid-auto-flow: column;
  grid-template-rows: auto;
  grid-template-columns: none;
  grid-auto-columns: calc((100% - 32px) / 3);
  gap: 16px;
  margin: -6px -6px 0 !important;
  padding: 6px 6px 10px;
  scroll-padding: 0 6px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
}

html body.deviceland-shop .dl-pairs.is-aside .cross-sells ul.products > li {
  min-width: 0;
}

html body.deviceland-shop .dl-pairs.is-aside .dl-pairs-more-title {
  font-size: 20px;
}

/*
 * The shelf (owner, Oct 15): no card boxes. Each accessory is a white photo
 * tile, the same white surface and soft edge as the gallery's photo, so a
 * product always sits on white; its name, price, availability, colours,
 * size menu and "+ Add" sit on the page beneath, like a caption. The boxed
 * card put a box inside a box (stone card, white photo, text), the only
 * nesting on the page, which read as a shop widget and weighed more than
 * two cables should.
 */
html body.deviceland-shop .dl-pairs .cross-sells .product {
  margin: 0 !important;
  padding: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: transparent !important;
  box-shadow: none !important;
  text-align: left;
}

html body.deviceland-shop .dl-pairs .cross-sells .product-img-wrap {
  margin: 0 0 12px !important;
  background: transparent !important;
}

/* Every tile square, the photo fitted inside it: photos come in 1:1 and
   4:3, and the tiles came out different heights side by side. */
html body.deviceland-shop .dl-pairs .cross-sells .product-img {
  aspect-ratio: 1 / 1;
  display: block;
  overflow: hidden;
  border: 0 !important;
  border-radius: 4px;
  background: #fff !important;
  box-shadow: 0 0 0 1px rgba(20, 17, 14, 0.09), 0 2px 4px rgba(20, 17, 14, 0.04);
  transition: box-shadow 0.2s ease;
}

html body.deviceland-shop .dl-pairs .cross-sells .product-img .main-img,
html body.deviceland-shop .dl-pairs .cross-sells .product-img .back-img {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

html body.deviceland-shop .dl-pairs .cross-sells .product-img {
  position: relative;
}

html body.deviceland-shop .dl-pairs .cross-sells .product-img img {
  width: 100% !important;
  height: 100% !important;
  object-fit: contain;
}

html body.deviceland-shop .dl-pairs .cross-sells .product:hover .product-img {
  box-shadow: 0 0 0 1px rgba(20, 17, 14, 0.16), 0 6px 14px -6px rgba(20, 17, 14, 0.18);
}

html body.deviceland-shop .dl-pairs .cross-sells .product-info-wrap {
  margin: 0 !important;
  padding: 0 !important;
  text-align: left;
}

html body.deviceland-shop .dl-pairs .cross-sells .product-info-wrap .name {
  display: block;
  margin: 0 0 3px !important;
  padding: 0 !important;
  font-size: 13.5px;
  font-weight: 500;
  line-height: 19px;
}

html body.deviceland-shop .dl-pairs .cross-sells .product-info-wrap .price {
  display: block;
  margin: 0 !important;
  font-size: 13px;
  line-height: 18px;
}

html body.deviceland-shop .dl-pairs .cross-sells .dl-loop-ready {
  margin: 3px 0 0 !important;
  font-size: 12px;
  line-height: 16px;
}

html body.deviceland-shop .dl-pairs .cross-sells .dl-acc-pick {
  height: 32px;
  font-size: 12.5px;
}

/* No reserved colour row on the shelf: the tiles in a row are equal height
   and "+ Add" sits at each foot (margin-top auto), so the reserve only
   added empty height under every caption. */
html body.deviceland-shop .dl-pairs .cross-sells .dl-acc-cart {
  min-height: 0 !important;
  gap: 6px;
  padding-top: 6px;
}



/* Every card the same height, every Add to bag on one line: the colour
   row is reserved on cards without one. */
/* Five across on a wide screen, so each card is about the size of a
   gallery thumbnail strip's neighbour rather than half the product photo;
   four on a laptop, three on a tablet. */
html body.deviceland-shop .dl-pairs .cross-sells ul.products > li {
  display: flex;
  flex: 0 0 calc((100% - 80px) / 5);
  /* min-width 0: a card's photo (595px wide in the markup) otherwise
     widens its card past the share, so cards came out unequal. */
  min-width: 0;
  width: auto !important;
  max-width: none !important;
  margin: 0 !important;
  padding: 0 !important;
  float: none !important;
  scroll-snap-align: start;
}

@media (max-width: 1199px) {
  html body.deviceland-shop .dl-pairs .cross-sells ul.products > li {
    flex-basis: calc((100% - 60px) / 4);
  }
}

@media (max-width: 1023px) {
  html body.deviceland-shop .dl-pairs .cross-sells ul.products > li {
    flex-basis: calc((100% - 40px) / 3);
  }
}

@media (max-width: 759px) {
  html body.deviceland-shop .dl-pairs .cross-sells ul.products {
    gap: 12px;
  }

  /* Two and a half in view (owner, Oct 15): the half tile shows the shelf
     scrolls. */
  html body.deviceland-shop .dl-pairs .cross-sells ul.products > li {
    flex-basis: calc((100% - 24px) / 2.5);
  }

  /* The row runs to the screen's edges, so the next card peeks in from
     the edge instead of being clipped 24px short of it (which read as cut
     off); it still starts in line with the page text. */
  html body.deviceland-shop .dl-pairs .cross-sells ul.products {
    margin: -6px -24px 0 !important;
    padding: 6px 24px 10px;
    scroll-padding: 0 24px;
  }
}

/* The row's last tile: the whole range. A square the size of the photo
   tiles, in line with them, with nothing beneath (owner, Oct 15: at full
   card height it read as a different kind of object). Hairline on the
   page, serif name and a small arrow; no photo, no price. */
html body.deviceland-shop .dl-pairs .cross-sells ul.products > li.dl-pairs-more {
  display: flex;
  align-items: flex-start;
  align-self: start;
}

html body.deviceland-shop .dl-pairs-more a {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  width: 100%;
  aspect-ratio: 1 / 1;
  height: auto;
  box-sizing: border-box;
  border: 1px solid var(--hair-light-2, rgba(22, 19, 15, 0.14));
  border-radius: 4px;
  background: transparent;
  color: var(--ink);
  text-decoration: none;
  transition: border-color 0.15s ease;
}

html body.deviceland-shop .dl-pairs-more a:hover,
html body.deviceland-shop .dl-pairs-more a:focus-visible {
  border-color: var(--ink);
}

/*
 * Photo badges, toned down (owner, Oct 15). Elessi drew "Featured" in coral
 * and "Sale" in green, solid pills: the two loudest marks on the page, in
 * colours the palette does not use. Now small spaced capitals on a paper
 * pill with a hairline; Sale keeps the ember accent, the palette's signal
 * colour, since the price line beside it says what the saving is.
 */
html body.deviceland-shop .nasa-badges-wrap .badge,
html body.deviceland-shop .nasa-badges-wrap .badge.featured-label,
html body.deviceland-shop .nasa-badges-wrap .badge.sale-label {
  padding: 4px 9px !important;
  border: 1px solid rgba(20, 17, 14, 0.14) !important;
  border-radius: 999px !important;
  background: var(--paper, #f8f2e8) !important;
  box-shadow: none !important;
  color: var(--ink, #16130f) !important;
  font-size: 10px !important;
  font-weight: 500 !important;
  letter-spacing: 0.1em !important;
  line-height: 1.2 !important;
  text-transform: uppercase !important;
}

html body.deviceland-shop .nasa-badges-wrap .badge.sale-label {
  border-color: rgba(196, 80, 31, 0.35) !important;
  color: var(--ember, #c4501f) !important;
}

html body.deviceland-shop .nasa-badges-wrap .badge::before,
html body.deviceland-shop .nasa-badges-wrap .badge::after {
  display: none !important;
}

@media (max-width: 759px) {
  /* A 127-165px tile on a phone: the name wraps, centred, rather than
     running past the edge. */
  html body.deviceland-shop .dl-pairs-more a {
    gap: 10px;
    padding: 10px;
  }

  html body.deviceland-shop .dl-pairs .dl-pairs-more-title {
    font-size: 17px !important;
    line-height: 1.15;
    text-align: center;
  }

  html body.deviceland-shop .dl-pairs-more-arrow {
    width: 28px;
    height: 28px;
  }
}

html body.deviceland-shop .dl-pairs-more-title {
  font-family: var(--display);
  font-size: 22px;
  font-weight: 500;
  letter-spacing: -0.01em;
}

html body.deviceland-shop .dl-pairs-more-arrow {
  position: relative;
  width: 34px;
  height: 34px;
  border: 1px solid currentColor;
  border-radius: 50%;
}

html body.deviceland-shop .dl-pairs-more-arrow::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 8px;
  height: 8px;
  border-top: 1.5px solid currentColor;
  border-right: 1.5px solid currentColor;
  transform: translate(-70%, -50%) rotate(45deg);
}

/* The arrows sit ON the row (owner, Oct 24): at its left and right edges,
   level with the middle of the photo tiles, white with a soft shadow, so it
   reads at a glance that the row scrolls. In the heading's corner customers
   missed them. The script measures the tile middle and the row's edges
   (--dl-pairs-arrow-y, --dl-pairs-row-l/-r); they never leave the screen. */
html body.deviceland-shop .dl-pairs {
  position: relative;
}

html body.deviceland-shop .dl-pairs-tools {
  position: static;
}

html body.deviceland-shop .dl-pairs-nav {
  position: absolute;
  z-index: 4;
  top: var(--dl-pairs-arrow-y, 40%);
  width: 44px;
  height: 44px;
  margin: -22px 0 0;
  padding: 0;
  border: 1px solid rgba(22, 19, 15, 0.08);
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 2px 12px rgba(22, 19, 15, 0.16), 0 1px 3px rgba(22, 19, 15, 0.1);
  color: var(--ink);
  cursor: pointer;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

html body.deviceland-shop .dl-pairs-prev {
  left: max(4px, calc(var(--dl-pairs-row-l, 0px) - 16px));
}

html body.deviceland-shop .dl-pairs-next {
  right: max(4px, calc(var(--dl-pairs-row-r, 0px) - 16px));
}

html body.deviceland-shop .dl-pairs-nav[hidden] {
  display: none;
}

html body.deviceland-shop .dl-pairs-nav:hover,
html body.deviceland-shop .dl-pairs-nav:focus-visible {
  box-shadow: 0 4px 16px rgba(22, 19, 15, 0.22), 0 1px 3px rgba(22, 19, 15, 0.12);
  transform: scale(1.06);
}

html body.deviceland-shop .dl-pairs-nav::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 10px;
  height: 10px;
  border-top: 2px solid var(--ink);
  border-right: 2px solid var(--ink);
}

html body.deviceland-shop .dl-pairs-prev::before {
  transform: translate(-30%, -50%) rotate(-135deg);
}

html body.deviceland-shop .dl-pairs-next::before {
  transform: translate(-70%, -50%) rotate(45deg);
}

/* Arrows on phones too (owner, Oct 15): swipe works, but the arrows say
   there is more before anyone tries. */

html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product {
  display: flex;
  flex-direction: column;
  width: 100%;
  min-width: 0;
}

html body.deviceland-shop .dl-pairs .cross-sells ul.products > li img {
  max-width: 100%;
  height: auto;
}

/* Names in full, never "iPhone 17 Pro Clear Case with Mag..." (owner, Nov 11).
   Two lines (2 x 19px) are kept for every name so a one-line name's price still
   sits level with its neighbours'; a longer name takes the lines it needs. */
html body.deviceland-shop .dl-pairs .cross-sells .woocommerce-loop-product__title,
html body.deviceland-shop .dl-pairs .cross-sells .name {
  min-height: 38px;
}

html body.deviceland-shop .dl-pairs .cross-sells .dl-acc-cart {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 84px;
  margin-top: auto;
}

html body.deviceland-shop .dl-pairs-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin: 0 0 18px;
}

html body.deviceland-shop .dl-pairs-title {
  margin: 0;
  font-family: var(--display);
  font-size: 29px;
  font-weight: 500;
  letter-spacing: -0.015em;
  line-height: 1.15;
  color: var(--ink);
}

html body.deviceland-shop .dl-pairs-all {
  flex: none;
  font-size: 13.5px;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--hair-light-2, rgba(22, 19, 15, 0.22));
}

html body.deviceland-shop .dl-pairs-all:hover {
  border-bottom-color: var(--ink);
}

@media (max-width: 849px) {
  html body.deviceland-shop .dl-pairs {
    padding: 0;
  }
}

@media (max-width: 759px) {
  html body.deviceland-shop .dl-pairs {
    margin-top: 40px;
  }

  html body.deviceland-shop .dl-pairs-head {
    align-items: center;
  }

  html body.deviceland-shop .dl-pairs-title {
    flex: 1 1 auto;
    min-width: 0;
  }

  /* Phones: a touch smaller, inside the screen edge. */
  html body.deviceland-shop .dl-pairs-nav {
    width: 40px;
    height: 40px;
    margin-top: -20px;
  }
}

/* A build with no second photo: no hover swap, rather than another
   colour's photo. */
body.deviceland-shop .cross-sells .product.dl-acc-noback .back-img {
  display: none !important;
}

/* Waiting for a size: quiet, but still clickable, because a click opens
   the size menu rather than doing nothing. */
body.deviceland-shop .cross-sells .dl-acc-add.button.disabled,
body.deviceland-shop .cross-sells .dl-acc-add.button.disabled:hover {
  opacity: 0.45;
  background: transparent;
  color: var(--ink, #16130f);
  cursor: pointer;
  pointer-events: auto;
}

body.deviceland-shop .cross-sells .dl-acc-add.loading {
  opacity: 0.6;
  pointer-events: none;
}

/* WooCommerce adds "View cart" after an add; the bag drawer already opens. */
body.deviceland-shop .cross-sells .added_to_cart {
  display: none;
}

/* ------------------------------------------------------------
   Related products, cross-sells and accessories
   ------------------------------------------------------------

   These were square because only their typography had been restyled, and
   because dequeuing Elessi's loop-product stylesheet on this page removed the
   rounding the nasa-image-round body class expects. Not intentional.

   Rather than restore Elessi's card, these now carry the homepage's own
   product card verbatim: 16px padding, 1px hairline at ink 7%, --r-lg on the
   card, --r-md on an inset square photograph over the warm studio gradient,
   and the single -4px hover lift the design uses everywhere. Same component
   on the homepage floor grid and here, so a shopper cannot tell which page
   built it.
   ------------------------------------------------------------ */

/* Left-aligned, matching every other section heading on the site.

   Related Products was centred because Elessi ships it with .text-center;
   Accessories, Description, Additional Information and Reviews are all left.
   You asked which is more consistent, and it is not a combination: the design
   has one section-head pattern and it is left-aligned, optionally with a link
   pushed to the right edge (.sec-head on the homepage is a flex row with
   space-between). A centred heading appears nowhere in the system, so the
   centred one is the outlier rather than a second valid option. */
/* One treatment for all five peer sections below the summary.

   Two separate bugs produced the outlier you saw, and neither was a choice.

   Font: Elessi marks up these headings inconsistently. Description,
   Additional information, Accessories and Reviews are all

     <h3 class="nasa-title nasa-crazy-box ns-woo-tab-title nasa-bold">

   while Related Products is

     <h3 class="nasa-title-relate text-center">

   My previous rule targeted `.nasa-title h2` — an h2 INSIDE .nasa-title, which
   never exists, since .nasa-title IS the h3. So four headings kept Elessi's
   sans bold and only Related Products picked up the serif, which is what made
   it look like the deliberate exception. All five are named explicitly now.

   Alignment: `.text-center { text-align: center !important }` is a parent
   utility class, so a plain declaration could never win. Matched with
   !important rather than stripping the class in PHP, because the class is
   printed by the parent's related.php and overriding a whole template to
   delete one word costs more than it saves.

   Serif is correct here, not an accident: section headings on the homepage are
   Instrument Serif via .display, and these are section headings. font-weight
   is forced back to 400 because Instrument Serif is a single-weight face and
   .nasa-bold would otherwise ask the browser to synthesise a bold. */
/* Specificity note, because the last attempt lost silently.

   Elessi styles these with

     .nasa-vertical-notabs .nasa-content > .nasa-title   -> (0,3,1)

   and my selector was `html body.deviceland-shop .ns-woo-tab-title`, which is
   (0,2,2). Three classes beat two regardless of the element count, so Elessi
   kept its 25px and its #2d2a2a while Related Products — matched by a
   different, unopposed selector — took the clamp. That is the whole reason the
   sizes and colours disagreed. Leading with .nasa-content > .nasa-title makes
   it (0,3,2) and wins on the same axis. */
html body.deviceland-shop .nasa-content > .nasa-title,
html body.deviceland-shop .ns-woo-tab-title,
html body.deviceland-shop .nasa-title-relate,
html body.deviceland-shop .woocommerce-Reviews-title,
html body.deviceland-shop .related h3,
html body.deviceland-shop .up-sells h3,
html body.deviceland-shop .cross-sells h3 {
  padding-left: 0; padding-right: 0;
  display: flex;
  align-items: center;
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.55rem, 2.2vw, 2rem);
  line-height: 1.05;
  letter-spacing: -0.015em;
  color: var(--on-paper);
  text-align: left !important;
  margin: 0 0 22px;
}

/* The rule beside the heading.

   Accessories, Description and Additional information get one from Elessi as a
   ::after — a 40px stub with `border-bottom: 1px solid #ddd` on an inline-flex
   heading. Related Products uses a different class and never had it, which is
   the missing line you spotted.

   Rather than copy the 40px stub, the rule now runs to the end of the line on
   all of them. A stub is a decoration; a rule that fills the remaining measure
   states where the section's column ends, which is the same job the hairline
   under the breadcrumb does and closer to the homepage's .sec-head, where the
   heading sits on one side of a full-width row. Colour comes from the token
   rather than #ddd so it matches every other hairline on the page. */
@media (min-width: 1024px) {
  html body.deviceland-shop .nasa-content > .nasa-title::after,
  html body.deviceland-shop .ns-woo-tab-title::after,
  html body.deviceland-shop .nasa-title-relate::after,
  html body.deviceland-shop .woocommerce-Reviews-title::after {
    content: "";
    flex: 1 1 auto;
    height: 0;
    width: auto;
    min-width: 24px;
    margin: 0 0 0 18px;
    border-bottom: 1px solid var(--hair-light);
  }
}

/* overflow is VISIBLE, deliberately.

   Elessi hangs a circular add-to-cart button off the bottom-right corner of
   the photograph, half outside it. With overflow:hidden on the card that
   button was being sliced through the middle — the same clipping that shaved
   the gallery thumbnails, from the same cause. The radius lives on the photo
   panel instead, which is the only thing that needs clipping. */
html body.deviceland-shop .related-product .product-item,
html body.deviceland-shop .cross-sells .product-item,
html body.deviceland-shop .up-sells .product-item {
  display: flex;
  flex-direction: column;
  padding: 16px;
  overflow: visible;
  border: 1px solid rgba(20, 17, 14, 0.07);
  border-radius: var(--r-lg);
  background: var(--paper);
  transition: transform 0.5s var(--ease), border-color 0.5s var(--ease),
    box-shadow 0.5s var(--ease);
}

html body.deviceland-shop .related-product .product-item:hover,
html body.deviceland-shop .cross-sells .product-item:hover,
html body.deviceland-shop .up-sells .product-item:hover {
  transform: translateY(-4px);
  border-color: var(--hair-light-2);
  box-shadow: var(--sh-2);
}

/* Elessi paints a hover wash on the card via ::after; the border and lift
   above already carry that job. */
html body.deviceland-shop .related-product .product-item:after,
html body.deviceland-shop .cross-sells .product-item:after {
  display: none;
}

/* White, not the warm gradient.

   You are right, and it is the same call as the product gallery. The gradient
   exists for the homepage's category photographs, which carry their own cream
   ground. Apple's catalogue shots are cut out on pure white, so a warm plate
   draws a visible rectangle around every cable and every watch. The plate
   matches the photography; the cream stays on the card around it. */
/* One outline per card, not two.

   You are right to question it — I had put a hairline on this plate as well as
   on the card, which nests a box inside a box 16px apart and makes the inner
   rule do no work: white against cream already separates by value, so an
   outline around it is a second statement of something already said.

   The design's own card settles it. On the homepage, .prod carries the
   hairline and .prod-media inside it carries only a fill, no border. Same
   here: outer hairline, white plate, nothing else. Keeping the text on cream
   rather than making the whole card white is deliberate too — it lets the
   photograph read as an object sitting on the card instead of the card
   becoming a white rectangle floating on cream. */
html body.deviceland-shop .related-product .product-img-wrap,
html body.deviceland-shop .cross-sells .product-img-wrap,
html body.deviceland-shop .up-sells .product-img-wrap {
  position: relative;
  overflow: visible;
  border-radius: var(--r-md);
  background: #fff;
  box-shadow: none;
}

/* Clip the photograph itself rather than its container, so the add button can
   still overhang the corner.

   display:block is load-bearing and its absence is what shrank the accessory
   thumbnails to icons on mobile. The chain is

     .product-img-wrap > a.product-img > div.main-img > img

   and `a.product-img` is an anchor, so inline by default. Giving it a radius
   and overflow:hidden without a display made it shrink-wrap, and `width: 100%`
   on the image then resolved against a collapsed box. Both links in the chain
   are blocks at full width now. */
html body.deviceland-shop .related-product .product-img,
html body.deviceland-shop .cross-sells .product-img,
html body.deviceland-shop .up-sells .product-img,
html body.deviceland-shop .related-product .main-img,
html body.deviceland-shop .cross-sells .main-img,
html body.deviceland-shop .up-sells .main-img {
  display: block;
  width: 100%;
  border-radius: var(--r-md);
  overflow: hidden;
  background: #fff;
}

html body.deviceland-shop .related-product .product-img-wrap img,
html body.deviceland-shop .cross-sells .product-img-wrap img,
html body.deviceland-shop .up-sells .product-img-wrap img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: contain;
  mix-blend-mode: normal;
}

html body.deviceland-shop .related-product .product-item .info,
html body.deviceland-shop .cross-sells .product-item .info {
  padding: 14px 2px 0;
  text-align: left;
}

html body.deviceland-shop .product-item .info .name,
html body.deviceland-shop .woocommerce-loop-product__title {
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 500;
  line-height: 1.35;
  color: var(--on-paper);
}

html body.deviceland-shop .product-item .price {
  font-family: var(--sans);
  font-size: 13.5px;
  font-weight: 500;
  color: var(--muted-fg);
}

/* The slider nav sits on paper now, not on Elessi's white card. */
html body.deviceland-shop .related-product .nasa-slick-nav .slick-arrow,
html body.deviceland-shop .related-product .icon-next-prev {
  background: var(--bone);
  border: 1px solid var(--hair-light-2);
  color: var(--on-paper);
  border-radius: var(--r-pill);
}

/* ------------------------------------------------------------
   Variation preview on a card: swatches yes, word lists no
   ------------------------------------------------------------

   You spotted the inconsistency exactly. Both carousels render the same
   Elessi component, .nasa-product-content-variable-warp, but it draws colour
   attributes as swatches and everything else as text — so Accessories, whose
   variations are colours, looked right, while Related Products printed
   "Black Titanium / Natural Titanium / Alpine Loop / Ocean Band / Trail Loop /
   Standard 1-year / Extended 3-years" as a list of orange links straight over
   the watch.

   Swatches are a legitimate preview: they show a real choice in a glance and
   cost no reading. A seven-line word list over a photograph is neither a
   preview nor a product shot. So the colour swatches stay and are moved below
   the image where they belong; the text variants are suppressed.

   This is also the component that inlines every variation into the markup and
   makes the category archive 10.5MB — it is switched off there entirely in
   the archive work. */
html body.deviceland-shop .related-product .nasa-product-content-variable-warp,
html body.deviceland-shop .cross-sells .nasa-product-content-variable-warp {
  position: static;
  padding: 10px 2px 0;
  background: transparent;
  opacity: 1;
  visibility: visible;
  transform: none;
}

html body.deviceland-shop .nasa-product-content-variable-warp .nasa-attr-ux-label,
html body.deviceland-shop .nasa-product-content-variable-warp .nasa-attr-ux-image,
html body.deviceland-shop .nasa-product-content-variable-warp .nasa-product-content-nasa_label-wrap,
html body.deviceland-shop .nasa-product-content-variable-warp .nasa-toggle-content-attr-select,
html body.deviceland-shop .nasa-product-content-variable-warp .nasa-product-content-select-wrap {
  display: none !important;
}

html body.deviceland-shop .nasa-product-content-variable-warp .nasa-attr-ux-color {
  width: 15px;
  height: 15px;
  min-height: 0;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--hair-light-2);
  box-shadow: none;
}

html body.deviceland-shop .nasa-product-content-variable-warp .nasa-attr-ux-color.selected {
  box-shadow: 0 0 0 1px var(--ink);
}

html body.deviceland-shop .nasa-product-content-variable-warp .nasa-attr-text {
  display: none;
}

/* Related products (Oct 24): the colour dots only, no menu and no "+ Add";
   the product is configured on its own page. */
html body.deviceland-shop .dl-pairs .cross-sells .dl-shelf-colours {
  margin-top: 6px;
  padding-top: 6px;
}

/* Related products sit at the page's own level, outside the product column
   whose gutter the accessories row relies on below 850px (at 820px the row's
   6px ring room spilled past the screen; on phones the row began 24px off
   it). The page gutter here too, as Elessi's related wrapper had. */
@media (max-width: 849px) {
  html body.deviceland-shop .dl-pairs.dl-pairs-related {
    padding: 0 var(--gut, 24px);
  }
}

/* A row where no card has colours, a size menu or a fit note reserves no
   room for them (Oct 24): on the bag's cables "+ Add" floated about 80px
   below the availability line. A row with any of them keeps the room, so
   every "+ Add" in it stays on one line. */
html body.deviceland-shop .dl-pairs .cross-sells ul.products:not(:has(.dl-acc-dots, .dl-acc-pick:not([hidden]), .dl-acc-fit:not([hidden]))) .dl-acc-cart {
  min-height: 0;
}

/* "+ Add to bag" on the price line (owner, Oct 25).
   ------------------------------------------------------------
   It sat at the card's foot, pinned level with the tallest card's, so on a
   card with no colours or sizes (Magic Keyboard, Apple Pencil) it floated
   about 150px below its own price, far from the product. Now the card is a
   two-column grid: the price and the Add share a line, so the Adds still
   line up across the row (names are one line), and the colours, fit note
   and size menu follow below. No DOM moves: the info wrapper and the cart
   box are display: contents, so the card scripts still find everything
   where they put it. Words, not a box, make it clear: "Add to bag" with a
   permanent underline; a bordered control read as a second buy button
   (Oct 15). Only cards with an Add; browse cards are unchanged. */
html body.deviceland-shop .dl-pairs .cross-sells ul.products > li:has(.dl-acc-cart) {
  container-type: inline-size;
}

html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: 10px;
  align-content: start;
  align-items: center;
  width: 100%;
}

html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) > .product-info-wrap,
html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) > .dl-acc-cart {
  display: contents;
}

html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) > *,
html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) > .product-info-wrap > *,
html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) > .dl-acc-cart > * {
  grid-column: 1 / -1;
  min-width: 0;
  order: 9;
}

html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) > .product-img-wrap { order: 1; }
html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .name { order: 2; }

html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .price {
  order: 3;
  grid-column: 1;
  white-space: nowrap;
}

html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .dl-acc-add.button,
html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .dl-acc-add.button:hover,
html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .dl-acc-add.button:focus {
  order: 4;
  grid-column: 2;
  justify-self: end;
  position: relative;
  height: auto;
  margin: 0;
  padding: 0;
  line-height: 18px;
  font-size: 13.5px;
  white-space: nowrap;
  text-decoration: none;
}

/* The words carry the underline, not the "+" beside them. */
html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .dl-acc-label {
  text-decoration: underline;
  text-decoration-color: var(--hair-light-2, rgba(22, 19, 15, 0.35));
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

/* The words are 18px tall; the tap area is not. */
html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .dl-acc-add.button::after {
  content: "";
  position: absolute;
  top: -12px; right: -8px; bottom: -12px; left: -8px;
}

html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .dl-acc-add.button:hover .dl-acc-label,
html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .dl-acc-add.button:focus-visible .dl-acc-label {
  text-decoration-color: currentColor;
}

html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .dl-loop-ready { order: 5; }
html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .dl-acc-fit { order: 6; margin-top: 8px; }
html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .dl-acc-dots { order: 7; margin-top: 8px; }
html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .dl-acc-pick { order: 8; margin-top: 8px; }

/* A card too narrow for the price and the Add side by side: the Add takes
   its own line straight under the price, still level across the row. At
   175px (1440px, beside the gallery) "From $129.00" wrapped and dropped its
   card's Add 18px below the others (reviewer, Oct 25); below 200px every
   card stacks, so a row never mixes the two layouts by price length. */
@container (max-width: 199px) {
  html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .dl-acc-add.button,
  html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .dl-acc-add.button:hover,
  html body.deviceland-shop .dl-pairs .cross-sells ul.products > li > .product:has(> .dl-acc-cart) .dl-acc-add.button:focus {
    grid-column: 1 / -1;
    justify-self: start;
    margin-top: 6px;
  }
}

/* The card's own type everywhere: the availability line and the size menu
   were in Elessi's Jost, and the menu's 42px line height drew its text
   about 6px low in a 32px box. */
html body.deviceland-shop .dl-pairs .cross-sells .dl-loop-ready,
html body.deviceland-shop .dl-pairs .cross-sells .dl-acc-pick {
  font-family: var(--sans);
}

html body.deviceland-shop .dl-pairs .cross-sells .dl-acc-pick {
  line-height: normal;
}
