.product-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
  /* Insets the frame from the grid cell's edges. Percentage padding always
     resolves against the containing block's WIDTH — on every side, top and
     bottom included — so this produces a pixel-equal gap on all four sides
     instead of the old width:79.2%/margin:auto, which only inset the frame
     horizontally and left it flush with the grid row's top/bottom. */
  padding: 4%;
}

/* Owns the size, rounding and gradient border ring for the whole tile — the
   photo (top) and the name bar (bottom) are stacked inside it as one fused
   unit, sharing a single outline rather than being two separately-bordered
   pieces with a gap between them. */
.product-card__frame {
  position: relative;
  border-radius: var(--radius-md);
  overflow: hidden;
}

.product-card__image {
  position: relative;
  aspect-ratio: 1 / 1;
  background: transparent;
}

.product-card__image img {
  width: 100%;
  height: 100%;
  /* contain, not cover: the photos carry real transparency now, so any
     crop would clip the product itself rather than trimming a filled tile. */
  object-fit: contain;
  transition: transform 0.6s var(--ease-out);
}

.product-card:hover .product-card__image img {
  transform: scale(1.08);
}

.product-card__missing {
  border-radius: 0;
}

/* Gradient stroke around the (now transparent) tile. A plain `border` can't
   take a gradient, so the element is filled with the gradient and then masked
   down to just the padding ring: the two mask layers cancel out everywhere
   except the 1px band between border-box and content-box. */
.product-card__frame::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: var(--gradient-brand);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
}

/* Attached directly under the photo, outside it — not overlaid on top —
   sharing the frame's rounded bottom corners (via the frame's overflow:
   hidden) so the two pieces read as one card rather than a badge floating
   over the image. */
.product-card__title {
  display: block;
  position: relative;
  /* .product-card__image is a positioned ancestor (position: relative), so
     without this the zoomed img — which visually bleeds past its own box
     into the title's space on hover — paints above this static sibling
     despite coming first in DOM order. z-index puts the name back on top. */
  z-index: 1;
  padding: 8px 10px;
  background: var(--gradient-brand);
  color: #ffffff;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-align: center;
}
