
  #product-grid.products.collection.row,
  .products.collection.row,
  ul#product-grid {
    row-gap: 15px !important;
    display: flex !important;
    flex-wrap: wrap !important;
  }
  #product-grid.products .column,
  #product-grid.products li {
    margin-bottom: 15px !important;
  }
  .product-card.has-shadow--true {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6) !important;
    transition: box-shadow 0.3s ease;
  }
  @media (min-width: 768px) {
    .product-card-title.custom-mobile-font {
      display: block !important;
      height: 72px !important;
      overflow: hidden;
    }
    /*
     * DESKTOP ONLY — the 20 px of dead space P'Ek measured under the per-unit price
     * (2026-09-13, staging /collections/*): every card ended ~40 px below its last line of
     * text where the block's own side padding is 20 px.
     *
     * WHERE IT CAME FROM. `product-grid.css` pairs two values for this grid
     * (`.product-card-spacing-medium .products.row .product-card`, inside its own
     * `@media (min-width: 768px)`): `margin-bottom: 20px` and `min-height: calc(100% - 20px)`
     * — i.e. the theme expects the card to be its row's height MINUS its own bottom margin.
     * The port's markup instead writes an inline `height: 100%`, which wins over that
     * min-height, so the card grows to the FULL row height and still adds its 20 px margin
     * below. Those 20 px of over-height land in `.product-card-info` (inline `flex: 1 0 auto`),
     * and because the desktop card no longer ends in a `margin-top: auto` spacer (that is the
     * mobile mechanism below) the free space collects at the BOTTOM, under the price.
     * Measured before: last price line -> card bottom = 40 px at 1440, 20 px at 390.
     *
     * The fix restates the theme's own intent for the one viewport that lost it. `!important`
     * because the competing `height` is an inline style, and 20px is a literal because the
     * shop layout hardcodes `product-card-spacing-medium` (`app/(shop)/layout.tsx`), so that
     * is the margin this grid always has above 768 px. Row rhythm is untouched: the card keeps
     * its 20 px margin, the `<li>` keeps its own 15 px, and the grid keeps `row-gap: 15px`.
     * Mobile (<= 767 px) never reaches this rule and keeps the pre-2026-09-13 card exactly.
     */
    .products .product-card { height: calc(100% - 20px) !important; }
  }
  /*
   * DESKTOP defaults for P'Ek's 2026-09-13 spacing pass (commit 6ebb3a444): the label spacer
   * and the subtitle/stock/price wrapper get a literal margin instead of the old var()-driven
   * spacer + `margin-top: auto` "stick to bottom" trick. P'Ek then asked (same day) to keep
   * this on desktop but revert mobile to how it looked before — "ไม่งั้นมันไม่สวย" — so these
   * are written as the DEFAULT (i.e. desktop) and the @media (max-width: 767px) block at the
   * bottom of this stylesheet restores the pre-6ebb3a444 mobile mechanism by winning the
   * cascade (same specificity, later in source order beats these). The inline styles that
   * used to carry these values were removed from the markup below — an inline style can't be
   * media-scoped, so the values had to move here.
   */
  .custom-product-labels { margin: 0 !important; }
  .product-card-bottom-block { margin-top: 0 !important; }
  .product-card-subtitle.custom-mobile-subtitle { margin: 0 0 0 0 !important; display: block; }
  .product-inventory-notice { font-size: 14px !important; margin-bottom: 4px !important; }
  .product-inventory-notice--wrapper .product-inventory-status {
    font-size: 16px !important;
    font-weight: 800 !important;
    display: inline-block !important;
    line-height: 1 !important;
  }
  .product-inventory-notice--wrapper .product-inventory-status--in { color: #1f9d55 !important; }
  .product-inventory-notice--wrapper .product-inventory-status--out { color: #555555 !important; }
  .product-card--badges .badge.pre-order { background: var(--intimo-preorder); color: #fff; }
  /*
   * A struck price keeps ONE line with the price that is paid (P'Ek 2026-09-23, "ไม่งั้นมันไม่สวย").
   * Desktop prints every part at the card's normal size. On a phone the paid price stays normal
   * and only เริ่มต้น and the struck price shrink, with the card, into what is left of the line —
   * sized for the widest pair the shop prints. The size sits on <del> itself, never on its child:
   * the line-through is drawn from the element that declares it, and a smaller child left the
   * line floating above the digits.
   */
  .product-card-bottom-block { container-type: inline-size; }
  .product-card .price .from { font-size: 0.75em; }
  .product-card .price.price--was ins + del { margin-left: 0.35em; }
  /*
   * NOT in the merchant's own CSS — the port's replacement for an inline attribute React
   * refuses to emit. snippets/product-card.liquid:132 writes
   * style="margin-bottom: 0 !important;" on the title anchor, which is what beats
   * app.css:3784 (.product-card-title { margin-bottom: 6px !important; }). React DOM throws
   * on a string style prop ("expects a mapping ... not a string", reproduced 2026-09-06),
   * so the same win is taken with specificity instead: (0,2,0) with !important beats
   * (0,1,0) with !important. Without it every grid row grew 6 px — Task 7 measured
   * +17/+18/+34 across three collection pages.
   */
  .product-card .product-card-title { margin-bottom: 0 !important; }
  /*
   * MOBILE ONLY — placed last on purpose so it wins the cascade (same selector specificity as
   * the desktop-default rules above; the rule that comes later in source order wins a tie).
   * Revives the exact pre-6ebb3a444 mobile card: values measured from
   * `git show 6ebb3a444^:.../ProductCard.tsx` and `.../app.css` (baseline), recorded in
   * projects/intimo-life/features/product-card-spacing/card-spacing-notes.md. P'Ek's
   * 2026-09-13 spacing pass now applies to desktop only.
   */
  @media (max-width: 767px) {
    #product-grid.products.collection.row { row-gap: 15px !important; }
    #product-grid.products .column, #product-grid.products li { margin-bottom: 15px !important; }
    .product-card-title.custom-mobile-font {
      font-size: 14px !important;
      line-height: 1.35 !important;
      display: block !important;
      height: 60px !important;
      overflow: hidden;
      white-space: normal;
    }
    .custom-product-labels {
      --product-labels-margin-top: 0px;
      margin: var(--product-labels-margin-top, -4px) 0 8px 0 !important;
    }
    .product-card-bottom-block { margin-top: auto !important; }
    .product-card-subtitle.custom-mobile-subtitle {
      margin: 0 0 4px 0 !important;
      font-size: 13px !important;
      line-height: 1.3 !important;
      opacity: 0.8;
    }
    .product-inventory-notice { font-size: 14px !important; }
    .product-inventory-notice--wrapper .product-inventory-status { font-size: 12px !important; }
    /* the struck-price line — see its comment above: the paid price keeps 15px, these two fit the rest */
    .product-card .price.price--was .from,
    .product-card .price.price--was del { font-size: clamp(8px, calc((100cqi - 75px) * 0.16), 0.75em); }
  }
