/* =============================================================
   50 — PRODUCT CARD

   Owns: template-parts/components/product-card.php only.
   Loads after main.css, woocommerce.css and every earlier part, so
   every rule here carries its own breakpoints — main.css's media
   queries cannot reach past this file.

   WHERE IT SHOWS: the shop archive, product-tag and brand archives,
   search, the wishlist page, and the related shelf on a PDP. It is
   the most repeated object on the site: 12 of them are the whole of
   /shop/, so the card is the store's perceived quality.

   WHAT WAS HERE BEFORE
   A square photograph in a bordered box, a two-line 0.92rem/700
   title, a bold price one step LARGER than the name, and a
   full-width grey "Add to Cart" slab that unfolded on hover and
   pushed the card taller. Tidy, generic, and — because the raw
   catalogue photographs run from near-black studio stills to
   scarlet marketplace banners — a contact sheet rather than a
   catalogue.

   THE FIVE MOVES

   1 · ONE FAMILY WITH THE HOME SHELF.  36-carousel.css settled the
       language: a 4:5 plate on the night ground, no box, a 1px ring
       of caught light instead of a drawn border, a soft cast shadow
       under it, type hanging beneath. §2 and §3 build the shop card
       from those same parts so the grid and the carousel read as one
       system, then add what a shop card needs and a shelf card does
       not: badges, a wishlist, a way in, and a way to buy.

   2 · ONE KEY FOR 581 PHOTOGRAPHS — THREE LAYERS, ALL ALWAYS ON.
       The catalogue's supplier shots run from near-black studio
       stills to bleached white wrappers and scarlet marketplace
       banners, and a grid of them reads as a contact sheet unless
       something authors them. Three layers do it, and none of them
       is gated on hover or on a class:
         a · THE GRADE (§3) — `saturate(.74) contrast(1.06)
             brightness(.9)` on the photograph itself, so a white
             wrapper and a red seal arrive in one tonal band.
         b · THE CONSTANT (§3) — a flat 20% wash of --night, the
             page's own ground colour, over the whole plate top to
             bottom. Same amount on every card, so the differences
             between 581 photographs shrink by a fifth at a stroke.
         c · THE TONE LAYER (§3b) — an inner vignette closing to
             34% of --night at the corners, so each plate's edge
             dissolves into the field rather than cutting a lit
             rectangle out of it, plus a 46% bottom scrim that
             seats the plate and buries the banner strips that run
             along the foot of a third of the catalogue.
       §3b used to declare `background: none` — a tone-control
       layer that painted nothing. That was the whole reason the
       grid stopped reading as one authored surface.

   3 · THE NAME OUTRANKS THE PRICE.  The verified critic finding on
       the carousel was that product names were set in Inter while
       everything else used Fraunces, and that the price out-typed
       the name. Here the name is Fraunces 400 at 1.06-1.22rem in
       --ink, and the price is deliberately NOT a second display
       line: Inter 500 at 0.8rem, tracked 0.06em, in
       --color-text-light. The serif name is the card's one voice;
       the ledger beneath the hairline reads as data.

   4 · A HOVER WITH SOMETHING TO SAY.  Not a lift and a shadow. The
       plate crossfades to a second, genuinely different photograph
       from the product's own gallery (see the template header), the
       shot wakes up out of the grade, and a HUD bar rises along the
       plate's foot — the hero's own closing gesture, a micro-label
       at the left and a mark at the right. Everything rides
       cubic-bezier(0.2, 0.75, 0.2, 1); nothing pops.

   5 · FOUR EDGES, RESOLVED.  Chips at the plate's top left, the
       wishlist at its top right, the HUD along its foot. Under it
       the ledger closes on a hairline with the price at the left
       and one round action at the right, so no row of this card
       ever ends in a dead half.

   THE CHROME IS NEVER TINTED.  The stack is photograph 0, second
   frame 1, constant veil 2, tone layer + ring 3, HUD 4, chips and
   wishlist 5. The wishlist disc in particular carries its own
   opaque ground (72% of --night-2) ABOVE the scrim, because at 52%
   and below it it took its colour from whatever supplier photograph
   sat behind it — maroon over a scarlet seal, grey over a white
   wrapper. One disc, the same disc, on all 581 plates.

   THE RATING ROW IS EMPTY BY DESIGN. Nothing in this catalogue has
   a review; teashop_star_rating() returns nothing below 1 star and
   §4 collapses the element with `:empty`. It is never faked.

   SPECIFICITY NOTE (load bearing)
   25-controls.css styles this card at `.shop-page .product-card…`,
   i.e. 0,2,0. Every rule below is written to at least 0,2,0 —
   `.product-card.product-card` for the root, `.product-card .x` for
   children — so this file wins on source order rather than on
   `!important`. Dropping a doubled class or a descendant step will
   silently hand the rule back to 25-controls.
   ============================================================= */


/* -------------------------------------------------------------
   1 · THE CARD — no box, no fill, no lift
   ------------------------------------------------------------- */

.product-card {
  /* One curve for the component. Falls back to the hero's own bezier
     if 05-motion.css is ever not present. */
  --pcard-ease: var(--ease-brand, cubic-bezier(0.2, 0.75, 0.2, 1));

  /* The plate's inner margin: what the chips, the wishlist and the
     HUD all hang off, so the four corners agree at every width. */
  --pcard-inset: clamp(10px, 0.85vw, 14px);

  /* The disc used by the wishlist and by the ledger's action. Both
     read as the same object at the two ends of the card. */
  --pcard-disc: 34px;
}

.product-card.product-card {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  /* Load bearing. `.products-grid` is `repeat(4, 1fr)`, and `1fr` is
     `minmax(auto, 1fr)`: a grid item's automatic minimum size raises its
     track's floor. The kicker below is `white-space: nowrap`, so one long
     category — "TEA · GAOSHAN HANLU GONG MEI" — was widening its whole
     column by 26px and, through `aspect-ratio`, making that column's plates
     26px taller than its neighbours'. Zeroing the automatic minimum lets
     the four tracks stay equal; the kicker clips with an ellipsis instead. */
  min-width: 0;
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  overflow: visible;
  box-shadow: none;
  text-align: left;
  color: inherit;
  isolation: isolate;
  transition: none;
}

/* The old shell lifted 2-3px and grew a shadow. The plate below does
   the lifting now; the card itself must not move, or the whole grid
   twitches under the cursor. */
.product-card.product-card:hover,
.product-card.product-card:focus-within {
  transform: none;
  box-shadow: none;
  border-color: transparent;
}


/* -------------------------------------------------------------
   2 · THE PLATE
   4:5, because the catalogue is objects on tables and a portrait
   crop takes the marketplace banners off the top and bottom of
   the frame for free.

   No border. The frame is a 1px inset ring carried by ::after at
   the very top of the stack (§3), so it reads as light catching
   an edge rather than as a drawn box, and so it still draws over
   the HUD's opaque foot.
   ------------------------------------------------------------- */

.product-card .product-card-image {
  position: relative;
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  margin: 0;
  padding: 0;
  overflow: hidden;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--night-2);
  box-shadow:
    0 26px 50px -30px rgba(0, 0, 0, 0.92),
    0 9px 22px -15px rgba(0, 0, 0, 0.62);
  transition: box-shadow 0.55s var(--pcard-ease);
}

.product-card .pc-plate {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: block;
  overflow: hidden;
  border-radius: inherit;
  color: inherit;
  text-decoration: none;
}


/* -------------------------------------------------------------
   3 · THE GRADE — one key for 581 photographs
   ------------------------------------------------------------- */

.product-card .pc-shot {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  object-fit: cover;
  /* Just above centre: these are objects standing on a surface, and
     the surface is the half worth losing. */
  object-position: 50% 46%;
  /* THE KEY. The catalogue is 581 supplier photographs shot in 581
     rooms: near-black studio stills next to bleached marketplace
     banners in white, yellow and scarlet. Pulling saturation down a
     quarter, lifting contrast a hair and taking 10% off the top is
     what lands a white wrapper and a red seal in the same tonal band
     BEFORE the tone layers (§3b) shape them. */
  filter: saturate(0.74) contrast(1.06) brightness(0.9);
  transition:
    transform 1.15s var(--pcard-ease),
    opacity 0.7s var(--pcard-ease),
    filter 0.6s var(--pcard-ease);
}

/* The second frame waits underneath at a hair of extra scale, so the
   crossfade lands as one continuous move rather than two pictures
   swapping. */
.product-card .pc-shot-alt {
  z-index: 1;
  opacity: 0;
  transform: scale(1.05);
}

/* The veil — layer (b) of the grade. A constant night wash across the
   WHOLE plate, the same amount on all 581 cards, is the part that does
   the unifying; the head shade above it seats the chips. The foot that
   used to live here is now the tone layer's scrim (§3b), so the plate
   is lit by one bottom-weighted gradient rather than two stacked. */
.product-card .pc-veil {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: block;
  pointer-events: none;
  border-radius: inherit;
  background:
    /* head: enough shade to sit a glass chip on and to bury the
       scarlet "0克 / 核心产区" banner strips a third of this
       catalogue carries along its top edge; gone by a third. */
    linear-gradient(180deg,
      color-mix(in srgb, var(--night-2) 40%, transparent) 0%,
      color-mix(in srgb, var(--night-2) 16%, transparent) 18%,
      transparent 33%),
    /* THE CONSTANT: the same 20% of --night over every photograph, top to
       bottom, at rest and on hover. This is the layer that makes a scarlet
       marketplace banner and a near-black studio still belong to the same
       set — and it is --night (#0e1611), not --night-2 (#070c08), on
       purpose: the page's ground has a green cast, so washing every frame
       with it pulls 581 photographs toward one key instead of merely
       darkening them. The FOOT that used to live here has moved to the
       tone layer in §3b, so the two never stack into a curtain. */
    linear-gradient(180deg,
      color-mix(in srgb, var(--night) 20%, transparent) 0%,
      color-mix(in srgb, var(--night) 20%, transparent) 100%);
  transition: opacity 0.55s var(--pcard-ease);
}

/* -------------------------------------------------------------
   3b · THE TONE LAYER — the shape of the light
   main.css uses this pseudo-element as a 1px foot rule under the
   photograph. The plate is framed now, so it is free: it carries
   the ring AND the tone control, because those are one object —
   the edge of the picture and the way the picture is lit into it.

   It used to declare `background: none`, which meant the tile had
   a tone-control layer that painted nothing, and 581 heterogeneous
   supplier photographs punched bright white, yellow and scarlet
   rectangles through the dark field. The grid stopped reading as
   one authored surface. Two stops fix that, and they are ALWAYS
   ON — never gated on hover, never on a class:

     · a full-tile inner VIGNETTE, transparent through the middle
       so the object itself is untouched, then closing to 34% of
       --night at the sides and corners. Because the page ground
       IS --night, every plate's edge now dissolves into the field
       instead of cutting a lit rectangle out of it. THE RADII ARE
       LOAD BEARING: an ellipse larger than the tile (120% x 90%)
       puts the outermost corner at r≈0.59 of the gradient's own
       ray, so it delivers about a tenth of its nominal strength
       and the vertical edges — where this catalogue's marketplace
       banner strips live — get essentially nothing. 58% x 52%
       centred at 50% 38% puts the corners past r=1 and the side
       edges at r≈0.86, i.e. ~24% at the sides and the full 34% in
       the corners, while the middle third stays untouched.
     · a bottom-weighted SCRIM, 62% of --night-2 at the foot,
       falling away by the halfway line. It seats the plate, it
       gives the HUD (§4) something to rise out of, and it is what
       puts the marketplace banner strips that live along the
       bottom edge of a third of this catalogue back into the set.
       It is shaped rather than linear because those strips sit in
       the bottom fifth of the frame, not on the last pixel.

   NOTE ON THE MIX COLOURS. --ink in this theme is #f4f0e4, the
   *light* pole; mixing toward it would bleach the photographs
   rather than grade them. The dark poles carry the same weights.

   z-index 3 puts it over the plate's whole stack (photograph,
   second frame, constant veil) and UNDER the chrome — the HUD at
   4, the chips and the wishlist at 5 — so no scrim can ever tint
   a control. See the stacking note in §4. */
.product-card .product-card-image::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  width: auto;
  height: auto;
  pointer-events: none;
  border-radius: inherit;
  background:
    radial-gradient(58% 52% at 50% 38%,
      transparent 34%,
      color-mix(in srgb, var(--night) 10%, transparent) 66%,
      color-mix(in srgb, var(--night) 34%, transparent) 100%),
    linear-gradient(to top,
      color-mix(in srgb, var(--night-2) 62%, transparent) 0%,
      color-mix(in srgb, var(--night-2) 40%, transparent) 13%,
      color-mix(in srgb, var(--night-2) 16%, transparent) 30%,
      transparent 48%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--paper) 12%, transparent);
  transition:
    opacity 0.55s var(--pcard-ease),
    box-shadow 0.5s var(--pcard-ease);
}


/* -------------------------------------------------------------
   4 · THE HUD — the hero's closing bar, on a plate
   A micro-label at the left, a mark at the right, over a ground
   of its own so it never depends on the veil beneath it.

   THE STACK, top to bottom, and it is load bearing:
     5  chips (left) and the wishlist (right)   — never tinted
     4  the HUD                                 — never tinted
     3  the tone layer + ring  (§3b)            — grades everything under it
     2  the constant veil      (§3)
     1  the second frame
     0  the photograph
   The HUD moved OUT of the <a class="pc-plate"> in the template to
   reach this layer (the plate is its own stacking context at 0), so
   it takes `pointer-events: none` and clicks fall through to the
   link beneath it. It is aria-hidden decoration either way.

   It is also inset 1px on three sides: at z-index 4 its opaque foot
   would otherwise paint over the bottom of the ring at 3 and cut a
   hole in the frame.
   ------------------------------------------------------------- */

.product-card .pc-hud {
  position: absolute;
  z-index: 4;
  inset: auto 1px 1px 1px;
  pointer-events: none;
  border-radius: 0 0 calc(var(--radius-md) - 1px) calc(var(--radius-md) - 1px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 26px var(--pcard-inset) calc(var(--pcard-inset) + 1px);
  background: linear-gradient(0deg,
    color-mix(in srgb, var(--night-2) 92%, transparent) 0%,
    color-mix(in srgb, var(--night-2) 74%, transparent) 46%,
    transparent 100%);
  font-family: var(--font-primary);
  font-size: 0.7rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  opacity: 0;
  transform: translateY(10px);
  transition:
    opacity 0.42s var(--pcard-ease),
    transform 0.42s var(--pcard-ease);
}

.product-card .pc-hud-label {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.product-card .pc-hud-arrow {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--color-accent);
}

.product-card .pc-hud-arrow svg {
  display: block;
  width: 15px;
  height: 15px;
  transition: transform 0.42s var(--pcard-ease);
}


/* -------------------------------------------------------------
   5 · CHIPS AND THE WISHLIST
   25-controls.css already made every .badge a glass pill. These
   only place them and add the one chip that is not a badge —
   the variation count, which is HUD, not marketing, so it is
   set in the muted key with no colour of its own.
   ------------------------------------------------------------- */

.product-card .product-card-badges {
  position: absolute;
  z-index: 5;
  top: var(--pcard-inset);
  left: var(--pcard-inset);
  right: calc(var(--pcard-inset) + var(--pcard-disc) + 8px);
  display: flex;
  /* Both are load bearing. main.css stacks this box `column`, and a column
     flex container stretches its items across the cross axis — which turned
     every pill into a full-width bar with the label hard left. Row plus
     flex-start keeps a pill the width of its own word. */
  flex-direction: row;
  align-items: flex-start;
  justify-content: flex-start;
  flex-wrap: wrap;
  gap: 5px;
  pointer-events: none;
}

.product-card .product-card-badges .badge {
  flex: 0 0 auto;
  max-width: 100%;
  padding: 4px 9px 3px;
  font-size: 0.7rem;
  letter-spacing: 0.11em;
}

.product-card .product-card-badges .badge-opts {
  color: color-mix(in srgb, var(--paper) 66%, transparent);
  border-color: color-mix(in srgb, var(--paper) 20%, transparent);
  background: color-mix(in srgb, var(--night-2) 58%, transparent);
  font-weight: 500;
}

.product-card .product-card-actions {
  position: absolute;
  z-index: 5;
  top: var(--pcard-inset);
  right: var(--pcard-inset);
  left: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
  /* Present, not performed. The old card hid these until hover, which
     on a touch screen meant a wishlist nobody could find. */
  opacity: 1;
  transform: none;
}

.product-card .product-action-btn {
  width: var(--pcard-disc);
  height: var(--pcard-disc);
  padding: 0;
  border-radius: var(--radius-pill);
  border: 1px solid color-mix(in srgb, var(--paper) 24%, transparent);
  /* CONSTANT, not translucent chrome. At 52% the disc took its colour
     from whatever supplier photograph happened to be behind it — maroon
     over a scarlet seal, grey over a white wrapper. 72% of --night-2
     (rgba(7, 12, 8, .72)) plus z-index 5, above the tone layer, means
     one disc, the same disc, on all 581 plates. */
  background: color-mix(in srgb, var(--night-2) 72%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(0.6);
  backdrop-filter: blur(14px) saturate(0.6);
  box-shadow: 0 4px 14px -8px rgba(0, 0, 0, 0.9);
  color: color-mix(in srgb, var(--paper) 82%, transparent);
  cursor: pointer;
  transition:
    color 0.3s var(--pcard-ease),
    border-color 0.3s var(--pcard-ease),
    background-color 0.3s var(--pcard-ease),
    transform 0.3s var(--pcard-ease);
}

.product-card .product-action-btn svg {
  width: 15px;
  height: 15px;
  transition: fill 0.3s var(--pcard-ease);
}

.product-card .product-action-btn:hover {
  transform: none;
  border-color: var(--paper);
  background: var(--paper);
  color: var(--night);
}

/* Saved. The heart fills — the one state on this card that is allowed
   to carry the brand green. */
.product-card .js-wishlist-toggle.is-active {
  border-color: color-mix(in srgb, var(--color-accent) 52%, transparent);
  background: color-mix(in srgb, var(--color-primary) 34%, var(--night-2));
  color: var(--color-accent);
}

.product-card .js-wishlist-toggle.is-active svg {
  fill: currentColor;
}

.product-card .js-wishlist-toggle.is-active:hover {
  border-color: var(--color-accent);
  background: var(--color-accent);
  color: var(--night);
}

.product-card .js-wishlist-toggle[disabled] {
  opacity: 0.55;
  cursor: progress;
}


/* -------------------------------------------------------------
   6 · THE LEDGER — kicker, name, hairline, price and one action
   ------------------------------------------------------------- */

.product-card .product-card-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: clamp(7px, 0.7vw, 10px);
  margin: 0;
  padding: clamp(15px, 1.5vw, 21px) 0 0;
  text-align: left;
}

/* The kicker: category, then the varietal the template lifted out of
   the title's square brackets. Same setting as the hero's
   "01 · THE LEAF BEGINS". */
.product-card .product-card-category {
  display: flex;
  align-items: baseline;
  gap: 0;
  margin: 0;
  min-height: 1.25em;
  font-family: var(--font-primary);
  font-size: 0.7rem;
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  text-align: left;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  transition: color 0.35s var(--pcard-ease);
}

.product-card .product-card-category .pc-cat {
  flex: none;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

.product-card .product-card-category .pc-origin {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  color: color-mix(in srgb, var(--color-text-light) 92%, transparent);
  transition: color 0.35s var(--pcard-ease);
}

.product-card .product-card-category .pc-cat + .pc-origin::before {
  content: "\00b7";
  margin: 0 0.5em;
  color: var(--color-text-muted);
}

/* The line the card is for. Fraunces, because a product name in the
   body sans is the single most-cited inconsistency in review.

   The name and the price used to TIE: 0.99rem of Fraunces against
   0.94rem of Fraunces, two display voices at the same volume four
   lines apart, so neither led. The name now takes a clear step up
   and keeps the strongest ink on the page; the price steps down
   into the sans and becomes data. One voice, one figure. */
.product-card .product-card-title {
  margin: 0;
  font-family: var(--font-heading);
  font-size: clamp(1.06rem, 1.15vw, 1.22rem);
  font-weight: 400;
  line-height: 1.24;
  letter-spacing: -0.021em;
  color: var(--color-dark);
  text-align: left;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  /* em, never rem: the font-size clamps at the breakpoints below and a
     rem floor would leak a clipped third line under the clamp. */
  min-height: calc(2 * 1.24em);
}

.product-card .product-card-title a {
  color: inherit;
  text-decoration: none;
  transition: color 0.35s var(--pcard-ease);
}

.product-card .product-card-rating {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 6px;
  margin: 0;
}

/* Nothing in this catalogue has a review, so this is what actually
   renders. It collapses; it is never replaced by five hollow stars. */
.product-card .product-card-rating:empty {
  display: none;
}

.product-card .product-card-rating .pc-rating-count {
  font-family: var(--font-primary);
  /* 0.7rem is the legibility floor for micro-type on this site. */
  font-size: 0.72rem;
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
}

.product-card .product-card-rating .pc-rating-count::before {
  content: "(";
}

.product-card .product-card-rating .pc-rating-count::after {
  content: ")";
}

.product-card .pc-ledger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin: auto 0 0;
  padding-top: clamp(11px, 1.15vw, 15px);
  border-top: 1px solid var(--color-border);
  transition: border-color 0.35s var(--pcard-ease);
}

.product-card .product-card-price {
  display: flex;
  align-items: baseline;
  justify-content: flex-start;
  gap: var(--space-2);
  flex-wrap: nowrap;
  min-width: 0;
  margin: 0;
  padding: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* THE LEDGER READS AS DATA. Not a second display line: Inter, small,
   tracked open like every other piece of HUD on this site, in
   --color-text-light (#98a698). The serif name above is then the
   card's one clear voice, and the figure is a fact about the object
   rather than a competing headline. */
.product-card .product-card-price .price-current {
  font-family: var(--font-primary);
  font-size: 0.8rem;
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
  color: var(--color-text-light);
  transition: color 0.35s var(--pcard-ease);
}

.product-card .product-card-price .price-current del,
.product-card .product-card-price .price-current ins {
  text-decoration: none;
  background: none;
  color: inherit;
}

.product-card .product-card-price .price-original {
  flex: none;
  font-family: var(--font-primary);
  font-size: 0.74rem;
  font-weight: 400;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
  text-decoration: line-through;
}

/* A reduction is the one figure allowed to speak louder than its row. */
.product-card .product-card-price.is-reduced .price-current {
  color: var(--color-accent);
}

/* --- the action disc --- */

.product-card .pc-act {
  flex: none;
  display: flex;
  align-items: center;
}

.product-card .add-to-cart-btn {
  width: var(--pcard-disc);
  height: var(--pcard-disc);
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  padding: 0;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--color-text-light);
  cursor: pointer;
  text-decoration: none;
  overflow: hidden;
  /* main.js rewrites this button's innerHTML through "Adding…",
     "Added" and "Add to Cart". Zeroing the font size means those words
     can never break the disc — the swapped icon carries the state. */
  font-size: 0;
  line-height: 0;
  letter-spacing: 0;
  text-transform: none;
  transition:
    color 0.3s var(--pcard-ease),
    border-color 0.3s var(--pcard-ease),
    background-color 0.3s var(--pcard-ease);
}

.product-card .add-to-cart-btn svg {
  display: block;
  width: 15px;
  height: 15px;
  flex: none;
}

.product-card .add-to-cart-btn:hover,
.product-card .add-to-cart-btn:focus-visible {
  border-color: var(--paper);
  background: var(--paper);
  color: var(--night);
}

.product-card .add-to-cart-btn[disabled] {
  border-color: var(--color-border);
  background: transparent;
  color: var(--color-text-muted);
  cursor: not-allowed;
}

.product-card .add-to-cart-btn[disabled]:hover {
  border-color: var(--color-border);
  background: transparent;
  color: var(--color-text-muted);
}


/* -------------------------------------------------------------
   7 · THE HOVER — one gesture, five parts, all on one curve
   Gated on a real pointer: on touch there is no hover state to
   enter and no way to leave one, and a card stuck mid-transform
   after a tap is worse than no motion at all.
   ------------------------------------------------------------- */

@media (hover: hover) and (pointer: fine) {

  .product-card:hover .product-card-image,
  .product-card:focus-within .product-card-image {
    box-shadow:
      0 34px 62px -28px rgba(0, 0, 0, 0.98),
      0 12px 28px -15px rgba(0, 0, 0, 0.72);
  }

  /* The tone eases BACK — to 0.78, never to nothing: the hovered plate
     must still belong to the eleven around it. The ring is in the same
     box-shadow, so it is raised to 30% to compensate: 0.78 x 30% = 23%
     of caught light against 12% at rest, i.e. the frame brightens while
     the scrim lets go. One element, two opposite moves, one curve. */
  .product-card:hover .product-card-image::after,
  .product-card:focus-within .product-card-image::after {
    opacity: 0.78;
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--paper) 30%, transparent);
  }

  /* The shot wakes up out of the grade — a step toward the raw
     photograph, never all the way back to it. */
  .product-card:hover .pc-shot,
  .product-card:focus-within .pc-shot {
    filter: saturate(0.9) contrast(1.03) brightness(1);
  }

  /* No second frame in the gallery: the single shot simply pushes in. */
  .product-card:hover .pc-plate:not(.has-alt) .pc-shot-main,
  .product-card:focus-within .pc-plate:not(.has-alt) .pc-shot-main {
    transform: scale(1.055);
  }

  /* A second frame: one continuous move from one photograph to the next. */
  .product-card:hover .pc-plate.has-alt .pc-shot-main,
  .product-card:focus-within .pc-plate.has-alt .pc-shot-main {
    opacity: 0;
    transform: scale(1.06);
  }

  .product-card:hover .pc-plate.has-alt .pc-shot-alt,
  .product-card:focus-within .pc-plate.has-alt .pc-shot-alt {
    opacity: 1;
    transform: scale(1);
  }

  .product-card:hover .pc-veil,
  .product-card:focus-within .pc-veil {
    opacity: 0.86;
  }

  .product-card:hover .pc-hud,
  .product-card:focus-within .pc-hud {
    opacity: 1;
    transform: translateY(0);
  }

  .product-card:hover .pc-hud-arrow svg,
  .product-card:focus-within .pc-hud-arrow svg {
    transform: translateX(4px);
  }

  .product-card:hover .product-action-btn,
  .product-card:focus-within .product-action-btn {
    border-color: color-mix(in srgb, var(--paper) 40%, transparent);
    background: color-mix(in srgb, var(--night-2) 78%, transparent);
    color: var(--ink);
  }

  .product-card:hover .js-wishlist-toggle.is-active,
  .product-card:focus-within .js-wishlist-toggle.is-active {
    border-color: color-mix(in srgb, var(--color-accent) 70%, transparent);
    color: var(--color-accent);
  }

  /* The type follows the picture. */
  .product-card:hover .product-card-title a,
  .product-card:focus-within .product-card-title a {
    color: var(--color-accent);
  }

  .product-card:hover .product-card-category,
  .product-card:focus-within .product-card-category {
    color: var(--color-text-light);
  }

  .product-card:hover .pc-ledger,
  .product-card:focus-within .pc-ledger {
    border-top-color: color-mix(in srgb, var(--color-accent) 46%, var(--color-border));
  }

  .product-card:hover .product-card-price .price-current,
  .product-card:focus-within .product-card-price .price-current {
    color: var(--color-text);
  }
}


/* -------------------------------------------------------------
   8 · FOCUS
   The plate's link is out of the tab order (the title link
   duplicates it), so the visible focus target is the title —
   and focusing it must light the plate as hover does, or a
   keyboard user gets a ring around a word and nothing else.
   ------------------------------------------------------------- */

.product-card .product-card-title a:focus-visible {
  outline: none;
  color: var(--color-accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.product-card .pc-act .add-to-cart-btn:focus-visible,
.product-card .product-action-btn:focus-visible {
  outline: none;
  box-shadow:
    0 0 0 2px var(--color-bg),
    0 0 0 4px rgba(var(--color-primary-rgb), 0.95);
}


/* -------------------------------------------------------------
   9 · TOUCH
   No hover means the second frame can never be seen and the HUD
   can never be dismissed. Drop both, and let the plate carry the
   one photograph it was graded for.
   ------------------------------------------------------------- */

@media (hover: none), (pointer: coarse) {
  .product-card .pc-shot-alt { display: none; }
  .product-card .pc-hud { display: none; }

  /* The old sheet hid the wishlist entirely below 480px. It is the
     only reason the heart exists; it stays. */
  .product-card .product-card-actions { display: flex; }
}


/* -------------------------------------------------------------
   10 · WIDTHS
   Part files load after every media query in main.css, so these
   are the last word on the card at every size.
   ------------------------------------------------------------- */

/* Three up. The plate is wider than it is at four, so the type can
   take a step up with it. */
@media (max-width: 1080px) {
  .product-card .product-card-title {
    font-size: clamp(1.04rem, 1.7vw, 1.18rem);
  }
}

/* Tablet. Uppercase micro-labels need a floor: below ~11px, wide
   letter-spacing stops helping and starts hurting. */
@media (max-width: 768px) {
  .product-card {
    --pcard-inset: 10px;
    --pcard-disc: 32px;
  }

  .product-card .product-card-category { font-size: 0.72rem; }

  .product-card .product-card-body {
    padding-top: 14px;
    gap: 7px;
  }

  .product-card .product-card-title {
    font-size: 1.02rem;
    min-height: calc(2 * 1.24em);
  }

  .product-card .product-card-price .price-current { font-size: 0.78rem; }
}

/* Two up on a phone. The plate keeps its 4:5 and its ring; the ledger
   loses nothing but a few pixels of measure, because the price and
   the action are the two things a shopper came for. */
@media (max-width: 560px) {
  .product-card {
    --pcard-inset: 9px;
    --pcard-disc: 30px;
  }

  .product-card .product-card-image {
    border-radius: var(--radius);
    box-shadow:
      0 16px 30px -22px rgba(0, 0, 0, 0.9),
      0 6px 14px -10px rgba(0, 0, 0, 0.55);
  }

  .product-card .product-card-badges {
    right: calc(var(--pcard-inset) + var(--pcard-disc) + 6px);
    gap: 4px;
  }

  .product-card .product-card-badges .badge {
    padding: 3px 7px 2px;
    font-size: 0.7rem;
    letter-spacing: 0.08em;
  }

  .product-card .product-card-body {
    padding-top: 12px;
    gap: 6px;
  }

  .product-card .product-card-category {
    font-size: 0.7rem;
    letter-spacing: 0.1em;
  }

  .product-card .product-card-title {
    font-size: 0.97rem;
    line-height: 1.28;
    min-height: calc(2 * 1.28em);
  }

  .product-card .pc-ledger {
    gap: var(--space-2);
    padding-top: 10px;
  }

  .product-card .product-card-price .price-current {
    font-size: 0.76rem;
    letter-spacing: 0.045em;
  }
  .product-card .product-card-price .price-original { font-size: 0.71rem; }

  .product-card .add-to-cart-btn svg,
  .product-card .product-action-btn svg { width: 14px; height: 14px; }
}

/* Below ~380px two columns leave ~150px of measure. A price range —
   "$122.00 – $663.00" — is the longest thing on the card, so it gets
   the room and the disc gives up two more pixels. */
@media (max-width: 400px) {
  .product-card { --pcard-disc: 28px; }
  .product-card .product-card-price .price-current {
    font-size: 0.74rem;
    letter-spacing: 0.03em;
  }
  .product-card .product-card-title { font-size: 0.93rem; }
}


/* -------------------------------------------------------------
   11 · REDUCED MOTION
   The card still changes state — colour, ring, HUD — it simply
   stops moving. Nothing here may hide content.
   ------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .product-card .pc-shot,
  .product-card .pc-veil,
  .product-card .pc-hud,
  .product-card .pc-hud-arrow svg,
  .product-card .product-card-image,
  .product-card .product-card-image::after,
  .product-card .product-card-title a,
  .product-card .product-card-category,
  .product-card .pc-ledger,
  .product-card .product-action-btn,
  .product-card .add-to-cart-btn {
    transition: none;
  }

  .product-card .pc-shot-alt { transform: none; }
  .product-card .pc-hud { transform: none; }

  .product-card:hover .pc-plate:not(.has-alt) .pc-shot-main,
  .product-card:hover .pc-plate.has-alt .pc-shot-main,
  .product-card:hover .pc-plate.has-alt .pc-shot-alt,
  .product-card:hover .pc-hud-arrow svg {
    transform: none;
  }
}

