/**
 * Harvest — Product card (C7). The single most reused component.
 *
 * Styles BOTH surfaces so it works on custom Harvest templates AND real Magento
 * catalog output with no core edits:
 *   - `.hrv-card`             → Harvest-authored cards (home rails, quick view)
 *   - `.product-item-info`    → Magento grid / related / cross-sell / search
 *
 * Comp reference: surface panel, 1px border, 12px radius, 14px pad, aspect-1/1
 * image, accent star rating, Space-Grotesk price, add-to-cart + wishlist row,
 * absolute badge top-left. Hover: lift + reveal secondary actions.
 */

/* ---------- Card shell ----------
   T17 ADDED `.widget-product-grid` TO THIS LIST, UNSCOPED.

   WHICH MARKUP WAS ACTUALLY MISSING THE SHELL, measured rather than assumed. Home renders
   TWO product grids, enumerated from `cms_page_view_id_harvest-home.xml`: ONE CatalogWidget
   `ProductsList` (line 122, "Fresh this week") and ONE `EcommPaaS` `Bestsellers` block
   (line 147). The live page agrees — 2 `.widget-product-grid`, 8 `.product-item`.
   CatalogWidget nests its `widget-product-grid` INSIDE `div.products-grid.grid`, so
   `.products-grid .product-item-info` above already covered it and it was never broken
   (measured: white surface, 1px border, 18px radius, 14px padding, info filling its 332px
   track).
   The ONLY markup that emits a BARE `<ol class="widget-product-grid">`, with no
   `.products-grid` ancestor, is this theme's own `bestsellers.phtml`. That is the one
   surface the list missed, and it appears on Home and on the empty cart.

   THIS RULE WAS BRIEFLY SCOPED TO `.checkout-cart-index`, AND THAT WAS THE BUG.
   Home's Bestsellers row was rendering `.product-item-info` at 152px inside a 332px track
   with no surface, border, radius or padding — four bare images with 54% dead space per
   card, on the flagship page. It had simply been invisible because that row was EMPTY
   until an order was seeded; seeding it for the cart is what exposed a defect that had
   always been there, and the cart-only scope then fixed the copy nobody was looking at
   while leaving the original. A defect in shared core/widget markup belongs to the
   component, not to whichever page happened to notice it.

   A SCREENSHOT FOUND THE ORIGINAL, NOT A MEASUREMENT. Every property the task set measured
   correctly, and the card typography (14.5/700 name, Bricolage 17px price) really was
   coming from this component — which is what made "the card component is being reused"
   feel true. It was half true: the component owned the type and the photo behaviour, and
   its shell never listed this surface. */
.hrv-card,
.products-grid .product-item-info,
.products-list .product-item-info,
.block.related .product-item-info,
.block.upsell .product-item-info,
.block.crosssell .product-item-info,
.widget-product-grid .product-item-info {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: var(--hrv-surface);
  border: 1px solid var(--hrv-border);
  border-radius: var(--hrv-radius);
  padding: 14px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
  height: 100%;
}
.hrv-card:hover,
.products-grid .product-item-info:hover,
.products-list .product-item-info:hover,
.widget-product-grid .product-item-info:hover {
  border-color: var(--hrv-border-strong);
  box-shadow: var(--hrv-shadow-card);
  transform: translateY(-2px);
}

/* THE CARD MUST FILL ITS GRID TRACK (T17).

   MEASURED: the grid track (<li>) was 283px while `.product-item-info` inside it computed
   width: 152px — Blank sizes this card to the image role, not to its column, so four cards
   sat as narrow slabs in wide tracks. Establishing that it was a WIDTH DECLARATION and not
   a shrink-to-fit layout mode took one experiment rather than a guess: forcing width:100%
   inline returned 283, so a declaration was winning and no !important was involved.
   (0,3,0) here beats Blank's (0,1,0)/(0,2,0).

   This is the repo's recorded "a grid reskin must reset inherited float/width" lesson —
   native markup restyled into a grid collapses unless the base sizing is reset. It stayed
   invisible in the first screenshot because the images were ALSO undersized, so the card
   looked deliberately small rather than broken.

   UNSCOPED for the same reason as the shell above: this is bestsellers.phtml's markup, and
   it renders on Home as well as the cart. A CatalogWidget grid is unaffected — its card
   already fills its track — so this only ever repairs the surface that is broken. */
.widget-product-grid .product-item-info {
  width: 100%;
}

/* MEDIA SIZING FOR THE BARE WIDGET GRID (T17).

   `.product-item-photo` below already declares aspect-ratio 1/1, but the markup nests TWO
   more elements inside it — `.product-image-container` and `.product-image-wrapper` — and
   Magento generates a per-product rule sizing the container to the view.xml role (measured:
   the image rendered 152x203 inside a 283px card, letterboxed, with a white band above it).

   Specificity is deliberate, not incidental: Magento's generated
   `.product-image-container-N` is (0,1,0); these are (0,2,0), so no !important is needed.

   _home.css carries a NEARLY-equivalent block at (0,3,0), which therefore wins on Home. An
   earlier version of this comment called the two "identical declarations, so the rendering is
   the same either way". THAT IS FALSE, and a two-line grep disproves it: this rule clips the
   media with --hrv-radius-md while _home.css uses --hrv-radius-sm, and _base.css sets
   md = 14px against sm = 12px. The same component therefore clips at 14px on the cart and
   12px on Home / T2 / T3 — and the old advice to "delete Home's copy" would have moved Home
   from 12 to 14 silently, which is exactly the kind of change that should never arrive as a
   side effect.

   WHICH ONE IS CORRECT, decided against the artboards rather than by preference: every
   product-card media in the comps is drawn at 14px — 8 of 8 in Home.dc.html, and the same in
   T17's. So 14px (--hrv-radius-md) is right and is what this rule ships. _home.css, _t2.css
   and _t3.css render 12px against their own comps; correcting them is a three-page change to
   CLOSED pages needing its own verification pass, so it is RAISED here, not taken from inside
   a cart task. */
.widget-product-grid .product-image-container {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  height: auto;
}
.widget-product-grid .product-image-wrapper {
  padding: 0;
  height: auto;
  aspect-ratio: 1 / 1;
  display: block;
  overflow: hidden;
  border-radius: var(--hrv-radius-md);
}
.widget-product-grid .product-image-photo {
  position: static;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ---------- Image ---------- */
.hrv-card-media,
.product-item-photo {
  display: block;
  position: relative;
  border-radius: var(--hrv-radius-md);
  overflow: hidden;
  background: color-mix(in oklab, var(--hrv-text) 5%, var(--hrv-surface));
  aspect-ratio: 1 / 1;
}
.hrv-card-media img,
.product-item-photo .product-image-photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.35s ease, opacity 0.25s ease;
}
.hrv-card:hover .hrv-card-media img,
.product-item-info:hover .product-item-photo .product-image-photo {
  transform: scale(1.04);
}
/* Hover image swap (Harvest cards may ship a second .hrv-card-media-hover img). */
.hrv-card-media-hover {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.25s ease;
}
.hrv-card:hover .hrv-card-media-hover { opacity: 1; }

/* ---------- Badges ---------- */
.hrv-badge {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 1;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  border-radius: var(--hrv-radius-sm);
  padding: 5px 10px;
  background: var(--hrv-accent);
  color: var(--hrv-accent-text);
}
.hrv-badge--sale { background: var(--hrv-error); }
.hrv-badge--sold-out { background: var(--hrv-text-muted); }

/* ---------- Details ---------- */
.hrv-card-body,
.product-item-details {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

/* Rating — accent stars. Works with Harvest's .hrv-rating and Magento's
   .rating-result (which uses a % width overlay of ★ glyphs). */
.hrv-rating { color: var(--hrv-accent); font-size: 13px; letter-spacing: 2px; }
.product-reviews-summary .rating-summary .rating-result > span::before,
.product-reviews-summary .rating-summary .rating-result::before { color: var(--hrv-accent); }

.hrv-card-name,
.product-item-name,
.product-item-name > a.product-item-link {
  font-size: 14px;
  font-weight: 500;
  line-height: 1.35;
  color: var(--hrv-text);
  text-decoration: none;
}
.product-item-name > a.product-item-link:hover,
.hrv-card-name:hover { color: var(--hrv-accent); }

/* Price — Bricolage Grotesque display face, weight 600. */
.hrv-card-price,
.price-box .price {
  font-family: var(--hrv-font-display);
  font-weight: 600;
  font-size: 16px;
  color: var(--hrv-text);
}
.hrv-card-price--old,
.price-box .old-price .price,
.price-box .special-price ~ .old-price .price {
  font-family: var(--hrv-font-body);
  font-weight: 400;
  font-size: 12.5px;
  text-decoration: line-through;
  color: var(--hrv-text-subtle);
}
.price-box .special-price .price { color: var(--hrv-error); }

/* ---------- Actions row ---------- */
.hrv-card-actions,
.product-item-info .product-item-inner .actions-primary,
.product-item-info .product-item-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 4px;
}
.hrv-card-actions .hrv-btn { flex: 1; }
/* The native actions row must be allowed to WRAP. Its secondary slot holds up to
   three 40px icon buttons (wishlist, compare and the client-injected quick-view
   trigger) = 117px of `white-space: nowrap` content, which cannot sit beside the
   add-to-cart button on a ~214px-wide grid card. While this row was `nowrap`, the
   secondary slot could not shrink below min-content, so it pushed past the card
   edge and gave the whole PAGE a 25px horizontal scrollbar (measured on
   /audio.html at 1280px). Wrapping drops the icon row onto its own line instead. */
.product-item-info .product-item-actions {
  flex-wrap: wrap;
}
.product-item-info .product-item-inner .actions-primary {
  min-width: 0; /* let the add-to-cart column shrink rather than overflow */
}
/* Secondary card actions (wishlist/compare/quickview) hidden until hover on
   desktop; always visible on touch (no hover) via the media query below. */
.hrv-card-actions-secondary {
  display: flex;
  gap: 6px;
}
.product-item-info .actions-secondary {
  opacity: 0;
  transition: opacity 0.15s ease;
}
.product-item-info:hover .actions-secondary { opacity: 1; }

/* Make Magento's add-to-cart fill the row like the comp. */
.product-item-info .actions-primary .action.tocart { width: 100%; }

/* ---------- Quick View trigger (T13) ----------
   Injected client-side by web/js/quick-view.js into each card's secondary-actions
   slot (see _product-card.css note above reserving room for it beside wishlist /
   compare). A 40px icon-only button; its text label is visually hidden (icon-only
   in the comp, name still exposed to AT + on hover title). It inherits the
   `.actions-secondary` hover-reveal on desktop / always-visible on touch. */
.hrv-quick-view-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--hrv-border);
  border-radius: var(--hrv-radius-md);
  background: var(--hrv-surface);
  color: var(--hrv-text);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease;
}
.hrv-quick-view-trigger:hover,
.hrv-quick-view-trigger:focus-visible {
  border-color: var(--hrv-accent);
  color: var(--hrv-accent);
  background: var(--hrv-accent-tint);
}
.hrv-quick-view-trigger:focus-visible {
  outline: 2px solid var(--hrv-focus-ring);
  outline-offset: 2px;
}
.hrv-quick-view-trigger__icon { display: block; }
/* Icon-only button: keep the translated label in the DOM for assistive tech,
   but visually hidden (matches the .hrv-visually-hidden pattern used elsewhere). */
.hrv-quick-view-trigger__label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------- Grid helper (Harvest-authored rails/grids) ----------
   T17 ADDED THE CART SELECTOR TO THIS RULE RATHER THAN WRITING ITS OWN.

   The empty cart's "Popular right now" row reuses Magento_Theme::home/bestsellers.phtml,
   which emits `.product-items.widget-product-grid` — a class whose every rule in _home.css
   is scoped `.cms-index-index.hrv-page-home`, so on the cart that markup would arrive with
   no grid at all. The fix could have been a fresh 4-column rule in _cart.css; it is a
   selector on THIS rule instead, so the column counts and both breakpoints keep exactly one
   definition and cannot drift apart later. What the comp asks of that section —
   repeat(4,1fr), gap 16px — is already what this helper declares. */
.hrv-product-grid,
.checkout-cart-index .widget-product-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
}

/* ---------- Responsive ---------- */
@media (max-width: 1023px) {
  .hrv-product-grid { grid-template-columns: repeat(3, 1fr); }

  /* THE WIDGET GRID GOES 4 -> 2 HERE, NOT 4 -> 3 -> 2.
     MEASURED at 768 with the 3-column step: 229.328px x3 with rows [3, 1] — one card alone
     beside two-thirds of an empty row. `products_count` is hard-set to 4, so that orphan is
     not an edge case, it is every tablet load.
     Home already takes this exact markup straight to 2 at this exact breakpoint
     (_home.css, S7-Home c4), so this matches the theme's existing answer rather than
     inventing a third one. `.hrv-product-grid` keeps its 3-column step above: it is the
     generic rail helper with other consumers, and its item counts are not fixed at 4. */
  .checkout-cart-index .widget-product-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 767px) {
  .hrv-product-grid,
  .checkout-cart-index .widget-product-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
  /* No hover on touch — keep secondary actions visible. */
  .product-item-info .actions-secondary { opacity: 1; }

  /* N-10 — TAP TARGETS. Measured on the live build at 375, not taken from the note:
       .action.tocart      120 x 43   <- ONE PIXEL under
       .action.towishlist   35 x 35   <- well under
     44px is the threshold `_home.css:434` already enforces on the hero CTAs, so this is the
     theme disagreeing with itself rather than a new standard being invented here.

     THE 43px IS THE INTERESTING ONE. A button one pixel short reads as correct in every
     screenshot and in any review that eyeballs it; only measuring the box finds it. It comes
     from `padding: 12px 22px` on the 767 button rule meeting a 1.2 line-height — nobody chose
     43. `min-height` fixes it without touching the padding rhythm the comp specifies.

     `.action.tocompare` measures 0x0 here (hidden), so it has no tap target to fix — a
     zero-size control is not a small control, and padding it would CREATE a target where the
     design deliberately has none.

     NOT changed: `.product-item-link`, the product name, at 113 x 36. It is an inline text
     link, which WCAG 2.5.8 explicitly excepts from the target-size minimum. Padding it to 44
     would put a large invisible hit area over neighbouring text. Recording the decision
     because "everything under 44" is the obvious sweep and it would be wrong. */
  .product-item-info .actions-primary .action.tocart {
    min-height: 44px;
  }

  .product-item-info .actions-secondary .action.towishlist,
  .product-item-info .actions-secondary .action.tocompare:not([style*="display: none"]) {
    min-width: 44px;
    min-height: 44px;
  }
}

/* ==========================================================================
   COMP PARITY FOR THE CARD THE WHOLE THEME REPEATS  (wheat-Home / wheat-T2)
   ==========================================================================

   FOUND DURING wheat-T2's S8, AND IT REOPENED wheat-Home, WHICH I HAD CLOSED
   AN HOUR EARLIER. Home's artboard and T2's artboard ship the IDENTICAL card,
   so the gap was on the closed page all along.

   My S8 measured sections, headings, overflow at three viewports, dead
   controls, and translatable strings. All green. All true. None of them
   looking at the card. *** A GREEN BOARD IS NOT COVERAGE — the card had no
   instrument, so it had no verdict, and I read the silence as a pass. ***

   The comp's card: image 1/1 r14 - name 14.5/700 - a 12px per-unit line -
   bottom row [ price 17/700 Bricolage | 36x36 round accent "+" ].

   THE IMAGE RADIUS WAS NEVER WRONG, AND I FILED IT ANYWAY. My first probe read
   border-radius off the <img> element, got 0px, and I listed it as a defect.
   The radius lives on .product-item-photo with overflow:hidden, and
   --hrv-radius-md is already 14px - exactly the comp. *** A MEASUREMENT OF THE
   WRONG ELEMENT IS A FINDING ABOUT THE PROBE, NOT ABOUT THE PAGE. ***

   NOT FIXED, DECLARED: the "New" badge and the per-unit price line. Both need
   product data this catalogue does not carry (news_from_date is unset on every
   product; there is no per-unit attribute at all). Rendering them would mean
   inventing product facts on a storefront, which is worse than a fidelity gap
   - the same reasoning the T2 layout already records for the staples list.
   .hrv-badge is styled above and waits for a block that emits it.
   ========================================================================== */

/* Name - comp 14.5/700. The theme shipped 14/500 and its own rule WON, so this
   is a plain value change and not a cascade fight. */
.hrv-card-name,
.product-item-name,
.product-item-name > a.product-item-link {
  font-size: 14.5px;
  font-weight: 700;
}

/* Price - THE THEME'S DECLARED 16px/600 NEVER APPLIED TO A SINGLE CARD.
   Luma's styles-m.css carries `.product-item .price-box .price` at (0,3,0);
   the theme's `.price-box .price` above is (0,2,0) and loses, so every card
   has been rendering Luma's 1.4rem/700 while the theme's file says 16px/600.
   Enumerated with a cascade probe that ranks every matching rule, not guessed
   - a declaration check cannot see which rule won. Same family as N-16 and the
   Blank-beats-theme finding on the account pages.
   Answered at (0,4,0) so the fix does not depend on source order, which gets
   no vote until specificity ties. */
.product-item .product-item-info .price-box .price {
  font-family: var(--hrv-font-display);
  font-size: 17px;
  font-weight: 700;
  color: var(--hrv-text);
}

/* Bottom row - the comp puts price and add control on ONE line, price left and
   the round button right. Core stacks them: .price-box, then .product-item-inner
   wrapping .product-item-actions wrapping .actions-primary / .actions-secondary.

   `display: contents` on the two wrappers lets the real controls join the
   details grid, so the row can be composed WITHOUT a template override. The
   secondary slot (wishlist / compare) is deliberately NOT pulled onto the price
   row: it holds up to three 40px icon buttons and would blow out the auto
   column. It spans its own row underneath, where the existing wrap rule left it. */
.product-item-info .product-item-details {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  column-gap: 10px;
  row-gap: 6px;
}
.product-item-info .product-item-inner,
.product-item-info .product-item-details .product-item-actions {
  display: contents;
}
.product-item-info .product-item-details > .product-item-name,
.product-item-info .product-item-details .actions-secondary {
  grid-column: 1 / -1;
}
.product-item-info .product-item-details > .price-box {
  grid-column: 1;
  grid-row: 2;
  margin: 0;
}
.product-item-info .product-item-details .actions-primary {
  grid-column: 2;
  grid-row: 2;
}

/* The add control itself. THE LABEL STAYS IN THE ACCESSIBILITY TREE - clipped,
   not removed, not font-size:0 - because an icon-only button with no accessible
   name is a worse defect than the one being fixed. */
.product-item-info .actions-primary .action.tocart {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  min-width: 0;
  padding: 0;
  border: none;
  border-radius: var(--hrv-radius-circle);
  background: var(--hrv-accent);
  color: var(--hrv-accent-text);
}
.product-item-info .actions-primary .action.tocart > span {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}
.product-item-info .actions-primary .action.tocart::after {
  content: '+';
  font-size: 19px;
  font-weight: 600;
  line-height: 1;
}
.product-item-info .actions-primary .action.tocart:hover {
  background: var(--hrv-accent-hover);
}

/* N-10 IS NOT BEING REVERSED. That fix raised the add button to 44 and was
   measured AT 375 - a touch viewport. The comp's 36 is a DESKTOP figure, and
   36x36 still clears WCAG 2.2 AA (2.5.8 asks 24x24). So: comp size on desktop,
   44 on touch. The existing max-width:767 block below already sets
   min-height:44px; width must be pinned there too, or the button would render
   36 wide and 44 tall. Stated here because silently shrinking a closed
   accessibility fix to chase a comp is exactly the kind of change that should
   never happen without a sentence explaining it. */
@media (max-width: 767px) {
  .product-item-info .actions-primary .action.tocart {
    width: 44px;
    height: 44px;
  }
}

/* A FIX THAT REPAIRED ONE PROPERTY BROKE A SECOND, AND THE RASTER IS WHAT SHOWED IT.
   Every number above was right - name 14.5/700, price 17/700, button 36x36 two pixels off
   the price row, comp-matching at 1440, 768 and 375 - and the card still looked wrong:
   roughly 50px of empty space below the price row.

   MEASURED RATHER THAN GUESSED: .actions-secondary is opacity:0 and position:static, so it
   is INVISIBLE AND IN FLOW - 35px of reserved height it never shows, plus the card's 14px
   padding. That condition predates this change; what changed is that the add button used to
   sit on that row and now sits beside the price, so reserved space became VISIBLE dead space.
   Pre-existing cause, defect introduced here, mine to fix.

   Pinned to the card's top-right, over the image, which is where a hover-revealed wishlist
   normally lives and is closer to the comp than an empty strip: the artboard's card has no
   secondary actions at all and ends immediately after the price row. On touch the block
   above deliberately sets opacity:1, and those controls are real reachable targets that
   SHOULD hold their own row rather than sit unrevealable on top of the image.

   THE QUERY IS `hover: hover` AND `min-width: 768px`, AND THE SECOND HALF IS THERE BECAUSE
   OF A MEASUREMENT PROBLEM, NOT A DESIGN ONE. `hover: hover` alone is the semantically
   correct test - but HEADLESS CHROME REPORTS `hover: hover` AT EVERY WIDTH, so the rig
   measured the overlay at 375 while a real phone would have got the in-flow version. The
   evidence and the shipped behaviour would have disagreed and no probe available here could
   have caught it. Adding the width test makes the two agree, matches the 767 breakpoint the
   rest of this file already uses, and is strictly better than `hover: hover` alone for the
   case BOTH miss: a TOUCH TABLET at 1024 has no hover, so under the old query it would have
   received an overlay it can never reveal. Now it keeps the in-flow row.
   *** A RULE I CANNOT MEASURE IS A RULE I CANNOT VERIFY, AND AN UNVERIFIABLE RULE IN A
   COMPONENT SHARED BY 434 PAGES IS WORSE THAN A BLUNTER ONE THAT I CAN. *** */
@media (hover: hover) and (min-width: 768px) {
  .product-item-info .product-item-details .actions-secondary {
    position: absolute;
    top: 26px;
    right: 26px;
    z-index: 2;
    display: flex;
    flex-direction: column;
    gap: 6px;
  }
}
