/* ============================================================
   RHINORY v13 PAINT over the wordpress-for-wineries STOREFRONT
   ------------------------------------------------------------
   Brief: docs/briefs/2026-08-16-shop-embeddable-catalog.md (B1 — pin + paint).

   The plugin (gsati-dev/wordpress-for-wineries v0.97.0) owns STRUCTURE and
   BEHAVIOR of the `winery/*` storefront display blocks. This file owns PAINT
   only, via the two surfaces the plugin publishes:

     1. `--winery-*` custom properties  (contract.md § Storefront styling tokens)
     2. `.winery-*` class hooks         (contract.md § CSS class hooks (.winery-*))

   Boundary per ~/dev/wordpress-for-wineries/docs/operator-storefront-styling.md
   § Styling boundary — additive declarations only. No renderer fork, no class
   rename, no data-attribute rewrite, and nothing here touches the FROZEN
   `.winery-c7-*` / `data-winery-c7-*` / `winery-c7:*` surface the cards
   co-emit for member reveal, live pricing and cart writes.

   Design source (do not re-derive — these are ports):
     prototypes/13/11-shop-all.html + prototypes/13/shop-all.css   (catalog + card)
     prototypes/13/15-sale-price-treatment.html + sale-price.css   (sale treatment)
     prototypes/13/v13-shared.css                                  (type scale)
   and their already-WP-ported twin, assets/css/shop-all.css, which is the
   in-production paint for the equivalent `rhinory/*` blocks.

   REGISTER: light / paper. The dark Reserve-cool chrome (nav, campaign bar,
   footer) is untouched — every `--winery-*` token is only ever read by a
   `.winery-*` selector, so a `:root` override cannot leak into site chrome.

   WHY THE LOCAL `--rhw-*` NAMES: style.css already defines `--ink`, `--paper`
   and `--rule` at `:root` with DARK values. Re-using those names here would
   read as the dark register to anyone skimming, so the light palette is
   declared under its own `--rhw-` (Rhinory winery) prefix and scoped to the
   block roots.

   WHY THE TOKENS ARE DECLARED ON THE BLOCK ROOTS AND NOT ONLY `:root`:
   the plugin derives its aliases at ITS `:root` (e.g.
   `--winery-card-background: var(--winery-shop-color-surface)`), so a var()
   in an alias resolves against `:root`'s value of the primitive. Overriding a
   primitive further down the tree would therefore NOT reach an alias declared
   above it. Declaring the whole set on both `:root` and each block root keeps
   the paint correct regardless of stylesheet order or nesting depth.

   WHY A FEW SELECTORS DOUBLE THEIR CLASS (`.winery-product-card.winery-product-card`):
   those rules match a block ROOT, where the plugin's own rule carries identical
   (0,1,0) specificity, so the winner would otherwise be decided by stylesheet
   print order. Doubling the class decides it here instead. Every other rule in
   this file is already a root-scoped descendant (0,2,0) and needs no help.
   ============================================================ */

:root,
.winery-product-catalog,
.winery-product-card,
.winery-featured-row,
.winery-ad-tile,
.winery-gift-sets{
	/* ---- v13 light palette (prototypes/13/shop-all.css:.shop-all) ---- */
	--rhw-paper: #FBF7EE;
	--rhw-paper-2: #F7F1E5;
	--rhw-card: #F4EEE0;
	--rhw-card-2: #EAE1CE;
	--rhw-card-3: #E2D6BE;
	--rhw-ink: #2D2926;
	--rhw-ink-2: #4A443D;
	--rhw-muted: #8A8177;
	--rhw-burgundy: #520000;
	--rhw-burgundy-2: #3D0000;
	--rhw-burgundy-tint: rgba(82, 0, 0, 0.07);
	--rhw-acacia: #B97727;
	--rhw-acacia-soft: #E2C58F;
	--rhw-carbon: #241C16;
	--rhw-rule: rgba(45, 41, 38, 0.11);
	--rhw-rule-2: rgba(45, 41, 38, 0.20);
	--rhw-rule-burg: rgba(82, 0, 0, 0.24);

	--rhw-ff-display: "Cormorant Garamond", Georgia, serif;
	--rhw-ff-label: "Josefin Sans", system-ui, sans-serif;
	--rhw-ff-body: "Lora", Georgia, serif;

	/* v13 type scale (prototypes/13/v13-shared.css:370-377) */
	--rhw-type-h2: clamp(40px, 5.4vw, 76px);
	--rhw-type-h3: clamp(26px, 2.6vw, 34px);
	--rhw-type-lede: 18px;
	--rhw-type-body: 16px;
	--rhw-type-meta: 14px;
	--rhw-type-eyebrow: 11px;

	/* ---- shared color primitives ---- */
	--winery-shop-color-text: var(--rhw-ink);
	--winery-shop-color-muted: var(--rhw-muted);
	--winery-shop-color-surface: var(--rhw-paper);
	--winery-shop-color-surface-subtle: var(--rhw-paper);
	--winery-shop-color-surface-emphasis: var(--rhw-card-2);
	--winery-shop-color-border: var(--rhw-rule);
	--winery-shop-color-control-border: var(--rhw-rule-2);
	--winery-shop-color-accent: var(--rhw-burgundy);
	--winery-shop-color-accent-hover: var(--rhw-burgundy-2);
	--winery-shop-color-accent-contrast: var(--rhw-paper);
	--winery-shop-color-focus: var(--rhw-burgundy);
	--winery-shop-color-sale: var(--rhw-burgundy);
	--winery-shop-color-success: #1F4F37;
	--winery-shop-color-warning: var(--rhw-acacia);
	--winery-shop-color-disabled: var(--rhw-muted);
	--winery-shop-color-overlay: rgba(45, 41, 38, 0.52);

	/* ---- shared typography primitives ---- */
	--winery-shop-font-family-body: var(--rhw-ff-body);
	--winery-shop-font-family-heading: var(--rhw-ff-display);
	--winery-shop-font-size-xs: 10.5px;
	--winery-shop-font-size-sm: var(--rhw-type-meta);
	--winery-shop-font-size-base: var(--rhw-type-body);
	--winery-shop-font-size-lg: var(--rhw-type-lede);
	--winery-shop-font-size-xl: var(--rhw-type-h3);
	--winery-shop-font-size-2xl: var(--rhw-type-h2);
	--winery-shop-font-weight-normal: 400;
	--winery-shop-font-weight-medium: 500;
	--winery-shop-font-weight-semibold: 600;
	--winery-shop-line-height-tight: 1.04;
	--winery-shop-line-height-base: 1.55;
	--winery-shop-letter-spacing-eyebrow: 0.14em;
	--winery-shop-text-transform-eyebrow: uppercase;

	/* ---- shared spacing / shape / motion primitives ----
	   v13 is a hairline-and-square register: radii collapse to the 2px the
	   prototype uses on chips and buttons, and card elevation is a hover-only
	   shadow rather than a resting one. */
	--winery-shop-space-1: 4px;
	--winery-shop-space-2: 8px;
	--winery-shop-space-3: 12px;
	--winery-shop-space-4: 18px;
	--winery-shop-space-5: 24px;
	--winery-shop-space-6: 34px;
	--winery-shop-space-7: 64px;
	--winery-shop-radius-sm: 2px;
	--winery-shop-radius-md: 0px;
	--winery-shop-radius-lg: 0px;
	--winery-shop-radius-pill: 2px;
	--winery-shop-border-width: 1px;
	--winery-shop-shadow-card: none;
	--winery-shop-shadow-popover: 0 26px 64px -26px rgba(45, 41, 38, 0.6);
	--winery-shop-transition: 220ms ease;
	--winery-shop-focus-ring: 2px solid var(--rhw-burgundy);
	--winery-shop-control-min-height: 44px;
	--winery-shop-button-padding: 12px 18px;

	/* ---- shared layout tokens (v0.99.0) ----
	   winery/product-catalog, winery/featured-row and winery/gift-sets all
	   read --winery-shop-max-width / --winery-shop-inline-gutter directly
	   (the catalog's --winery-catalog-* pair now aliases these), so setting
	   them here is enough to line up all three sections on one page — no
	   per-block gutter override needed (contract.md § Storefront styling
	   tokens; closes B2/B4 contract gap #3/#5, see brief B5 changelog). */
	--winery-shop-max-width: 2100px;
	--winery-shop-inline-gutter: 44px;

	/* ---- catalog aliases ----
	   --winery-catalog-card-min-width IS overridden as of the 2026-08-19
	   fidelity pass (docs/2026-08-19-shop-b6-fidelity-gaps.md gap #7): B6
	   deliberately left it at the plugin's 12rem/192px default to hold 5-up
	   at 1440px, but that reads as too-narrow cards against the prototype's
	   own `.sa-grid` `minmax(300px,1fr)` floor (prototypes/13/shop-all.css:229).
	   Restoring ~300px (18.75rem) trades 5-up-at-1440 for wider cards that
	   step to fewer columns sooner as the column narrows, which is the
	   prototype's stated intent ("4-up at full width, steps to 3/2/1 as the
	   product column narrows, not the viewport") — 5 columns is still
	   reachable at the ~2100px max-width. `--winery-catalog-columns-max: 5`
	   stays unoverridden as the ceiling; the floor is what does the work now.
	   SUPERSEDED 2026-08-29 (v13.2): the floor is 21.25rem/340px, not 300px.
	   The reasoning above still holds — the floor is what does the work — but
	   300px turned out to be too tight for real Commerce7 names and was
	   cutting them. See the declaration's own comment below.

	   --winery-catalog-max-width / --winery-catalog-inline-gutter ARE
	   overridden directly here too (2026-08-19 fidelity rework, gap #7 cont.):
	   headless measurement showed `.winery-product-catalog__layout` still
	   computing --winery-catalog-max-width as the plugin's own 100rem
	   default and --winery-catalog-inline-gutter as its clamp(1rem,4vw,2rem)
	   default, NOT the 2100px/44px set above via the shared --winery-shop-*
	   tokens they're documented to alias (contract.md § Storefront styling
	   tokens). The alias is declared on the plugin's own block root at the
	   same (0,1,0) specificity as this ruleset's `.winery-product-catalog`
	   selector, so which declaration wins is a source-order tie the theme
	   must not depend on (see rhinory_v4_attach_winery_storefront_paint()
	   docblock) — same class of collision the doubled `.winery-product-card.
	   winery-product-card` selectors below resolve. Setting the catalog-
	   prefixed tokens directly, the same way --winery-catalog-sidebar-width
	   already does two lines down, settles it without relying on alias
	   resolution order. */
	--winery-catalog-max-width: 2100px;
	--winery-catalog-inline-gutter: 44px;
	/* 21.25rem / 340px, RAISED from the prototype's own 300px `.sa-grid`
	   floor (shop-all.css:229) — see the § 2b title-reserve note for the
	   reasoning. Short version: the design's 300px was drawn against curated
	   short names, and real Commerce7 names are longer. Measured at the 34px
	   desktop size, the longest live name ("Keras Cabernet Franc") needs a
	   333px column to hold one line, and "Roussanne-Marsanne" is a single
	   unbreakable 283px token. At 300px the grid packed 5-up at ~304px in the
	   1876-1920 band and BOTH Keras names ran to three lines and were cut with
	   an ellipsis — the one thing the card system forbids. 340px steps each
	   band down a column before it reaches that width. It is deliberately
	   under 362px so /shop/ keeps 3-up at 1440 and 5-up at the 2100px
	   max-width, both of which hold every live name on one line. */
	--winery-catalog-card-min-width: 21.25rem;
	/* The SAME 340px below the plugin's 48rem rail breakpoint, where the grid
	   switches to its own compact floor (product-catalog/style.css:587) and the
	   plugin's 15rem/240px default took over. Two live names were cut with an
	   ellipsis at 560px on that default. 340px is the binding number here for a
	   second reason as well: the card's own `@container (max-width: 332px)`
	   block reserves 74px of the title's measure for the stacked vintage/ABV
	   mark, so a card under 332px loses that width off the name before the name
	   is even measured — which is what made six titles wrap at 640px on a
	   283px card. Holding every card above 332px keeps that block off the
	   catalog entirely; it stays as the safety net it was written to be.
	   Effect: 640px and below go 1-up, which is what the prototype does
	   (`.sa-grid` is a single 567px column at 640 — shop-all.css:846). */
	--winery-catalog-card-min-width-compact: 21.25rem;
	--winery-catalog-background: var(--rhw-paper);
	--winery-catalog-block-padding: 0px;
	--winery-catalog-sidebar-width: 220px;
	--winery-catalog-grid-gap: 0px;
	--winery-catalog-toolbar-gap: 18px;
	--winery-catalog-facet-gap: 0px;

	/* ---- product-card aliases ---- */
	--winery-card-background: var(--rhw-paper);
	--winery-card-border-color: var(--rhw-rule);
	--winery-card-border-radius: 0px;
	--winery-card-shadow: none;
	--winery-card-shadow-hover: 0 10px 22px -14px rgba(45, 41, 38, 0.28);
	--winery-card-padding: 22px;
	--winery-card-content-gap: 0px;
	--winery-card-media-aspect-ratio: 3 / 3.4;
	--winery-card-image-fit: contain;
	--winery-card-badge-background: var(--rhw-card-3);
	--winery-card-badge-color: var(--rhw-burgundy);
	--winery-card-sale-color: var(--rhw-burgundy);
	--winery-card-cta-background: var(--rhw-burgundy);
	--winery-card-cta-background-hover: var(--rhw-burgundy-2);
	--winery-card-cta-color: var(--rhw-paper);
	/* stack order is the plugin's documented paint knob. v13.1 (CD card pass,
	   2026-08-29) moves the sale mark BELOW the price row's hairline, so the
	   sale label is ordered AFTER the price row rather than before it — the
	   whole relocation is this one token, no markup assumption. See § 2b. */
	--winery-card-member-preview-order: 1;
	--winery-card-price-row-order: 3;
	--winery-card-sale-label-order: 4;

	/* the struck retail's reserved width on the price row's second line, and
	   that line's own height. Both are read by § 2b's sale rules; see the
	   comment there for why the reserve exists and how it was sized.
	   ABSOLUTE, not `ch`: the element that consumes this reserve is the sale
	   label, and that label carries `font-size: 0` (§ 2b explains why), so a
	   font-relative unit resolves to ZERO there and the mark lands on top of
	   the struck figure. Measured instead: "$189" sets 38.7px in the struck
	   figure's own type (Cormorant Garamond 20px/500, tabular), + the
	   prototype's 8px gap = 47px. */
	--rhw-sale-was-reserve: 47px;
	--rhw-sale-line-h: 20px;

	/* ---- shared sale aliases (prototypes/13/sale-price.css) ---- */
	--winery-sale-label-color: var(--rhw-burgundy);
	--winery-sale-label-font-size: 10px;
	--winery-sale-was-strike-color: rgba(45, 41, 38, 0.52);
	--winery-sale-was-strike-thickness: 1px;
	--winery-sale-savings-color: var(--rhw-burgundy);
	--rhw-was-size: 20px;

	/* ---- featured-row / ad-tile / gift-set aliases ----
	   --winery-featured-row-background is intentionally NOT overridden: the
	   v0.100.0 default (var(--winery-shop-color-surface)) already resolves
	   to --rhw-paper through the primitive above, matching the v13 design;
	   a "transparent" override here would fight the class rule below that
	   already paints --rhw-paper explicitly (B6 cleanup). */
	--winery-featured-row-gap: 0px;
	--winery-featured-row-min-card-width: 300px;
	--winery-ad-tile-background: var(--rhw-card);
	--winery-ad-tile-color: var(--rhw-ink);
	--winery-ad-tile-border-color: var(--rhw-rule);
	--winery-ad-tile-border-radius: 0px;
	--winery-ad-tile-padding: clamp(30px, 3.4vw, 50px);
	--winery-ad-tile-min-height: 270px;
	--winery-ad-tile-media-width: 46%;
	--winery-gift-sets-background: var(--rhw-card);
	--winery-gift-sets-grid-gap: 0px;
}

/* ============================================================
   1 · CATALOG SECTION  (.winery-product-catalog)
   Ports .sa-hero / .sa-shopby / .sa-layout / .sa-rail / .sa-results-bar
   from prototypes/13/shop-all.css.
   ============================================================ */
.winery-product-catalog.winery-product-catalog{
	background: var(--rhw-paper);
	color: var(--rhw-ink);
	font-family: var(--rhw-ff-body);
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
	padding-block: 64px;
}
.winery-product-catalog.winery-product-catalog a:not([class]){ color: var(--rhw-burgundy); text-decoration: none; }
.winery-product-catalog.winery-product-catalog a:not([class]):hover{ color: var(--rhw-burgundy-2); }

/* ---- header ---- */
.winery-product-catalog .winery-product-catalog__header{ padding-bottom: 26px; }
.winery-product-catalog .winery-product-catalog__eyebrow{
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.18em; text-transform: uppercase; color: var(--rhw-burgundy);
	display: inline-flex; align-items: center; gap: 12px; margin: 0;
}
.winery-product-catalog .winery-product-catalog__eyebrow::before{
	content: ""; width: 24px; height: 1px; background: currentColor; flex: none;
}
.winery-product-catalog .winery-product-catalog__title{
	font-family: var(--rhw-ff-display); font-weight: 500; font-size: var(--rhw-type-h2);
	line-height: 0.98; letter-spacing: -0.01em; color: var(--rhw-ink); text-transform: none;
	margin: 18px 0 0 0; text-wrap: pretty; max-width: 16ch;
}
.winery-product-catalog .winery-product-catalog__description{
	font-family: var(--rhw-ff-body); font-size: var(--rhw-type-lede); line-height: 1.64;
	max-width: 60ch; color: var(--rhw-ink-2); margin: 20px 0 0 0;
}

/* ---- shop-by strip (.sa-shopby port) ---- */
.winery-product-catalog .winery-product-catalog__shop-by{
	padding-block: 26px; border-top: 1px solid var(--rhw-rule);
	display: flex; align-items: center; gap: 18px 22px; flex-wrap: wrap;
}
.winery-product-catalog .winery-product-catalog__shop-by-label{
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.2em; text-transform: uppercase; color: var(--rhw-muted);
}
.winery-product-catalog .winery-product-catalog__shop-by-list{
	display: flex; flex-wrap: wrap; gap: 7px; align-items: center; list-style: none; margin: 0; padding: 0;
}
/* the collection group and the region group are separated by container CSS,
   not a divider element (contract.md § Product catalog) */
/* v13 draws this as a standalone 1px x 22px mark centred on the chip row
   (`.sa-shopby-div`, shop-all.css:124 — `margin:0 4px` inside the list's own 7px
   gap, so 11px of air each side). A `border-left` on the item can only be the
   item's FULL height (42px chips), which reads as a hard column divider rather
   than the short centred tick the design uses. Same geometry, drawn as a
   centred pseudo-element instead: 4px + 1px + 11px reproduces the prototype's
   7+4 / 4+7 spacing exactly.

   MATCHED ON THE GROUP BOUNDARY, not on `:first-of-type`. `:first-of-type`
   reads element TYPE only and ignores the rest of the compound, so
   `li[…="region"]:first-of-type` asks for "the first `li`, which also happens
   to be a region" — and the first `li` is always a collection chip, so it
   matched nothing and the divider never painted (measured: no such element in
   the rendered page). The adjacent-sibling form asks the real question: the
   region chip that follows a collection chip. It also degrades correctly — a
   list with no collections gets no divider, which is right. */
.winery-product-catalog .winery-product-catalog__shop-by-item[data-winery-catalog-shop-by-group="collection"] + .winery-product-catalog__shop-by-item[data-winery-catalog-shop-by-group="region"]{
	position: relative; margin-left: 4px; padding-left: 12px; border-left: 0;
}
.winery-product-catalog .winery-product-catalog__shop-by-item[data-winery-catalog-shop-by-group="collection"] + .winery-product-catalog__shop-by-item[data-winery-catalog-shop-by-group="region"]::before{
	content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
	width: 1px; height: 22px; background: var(--rhw-rule-2);
}
.winery-product-catalog .winery-product-catalog__shop-by-chip{
	display: inline-flex; align-items: center; white-space: nowrap; padding: 10px 15px; min-height: 42px;
	background: none; border: 1px solid var(--rhw-rule-2); border-radius: 2px; cursor: pointer;
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.13em; text-transform: uppercase; color: var(--rhw-ink);
	transition: border-color 0.2s, background 0.2s, color 0.2s;
}
.winery-product-catalog .winery-product-catalog__shop-by-chip:hover{ border-color: var(--rhw-burgundy); color: var(--rhw-burgundy); }
.winery-product-catalog .winery-product-catalog__shop-by-chip[aria-pressed="true"]{
	background: var(--rhw-burgundy); border-color: var(--rhw-burgundy); color: var(--rhw-paper);
}
/* term-description popover (D — v0.102.0 ships this as a real hover/focus
   popover, `aria-describedby`-linked, no native title=; item B's earlier plan
   to read title= into a JS tooltip is superseded). Reveal/position/pointer-
   events stay the plugin's own mechanics (blocks/product-catalog/style.css
   `.winery-product-catalog__shop-by-item:hover` / `:focus-within`) — this
   only paints, matching v13's `.sa-shopby-chip[data-tip]::after` tooltip.
   Unscoped by a `.winery-product-catalog` ancestor because the identical
   shared markup also renders inside the standalone `.winery-shop-by` hero
   wrapper (contract.md § Product catalog: "same shared descendants"). */
.winery-product-catalog__shop-by-description{
	/* plugin default opens DOWNWARD (top:calc(100% + space-1)), which the hero's
	   overflow:hidden clips at the bottom. v13's .sa-shopby-chip[data-tip]::after
	   opens ABOVE the chip instead (shop-all.css:115-122) — flip the anchor. */
	top: auto; bottom: calc(100% + 10px); left: 0; right: auto;
	width: max-content; max-width: 260px; padding: 12px 14px;
	background: var(--rhw-paper); border: 1px solid var(--rhw-rule-2); border-radius: 2px;
	box-shadow: 0 18px 40px -20px rgba(45, 41, 38, 0.5);
	font-family: var(--rhw-ff-body); font-size: var(--rhw-type-meta); font-weight: 400;
	line-height: 1.5; color: var(--rhw-ink-2);
	/* long region/collection term descriptions run the tower to ~425px tall;
	   cap the popover at 5 lines and keep the full copy in the rail info +
	   PDP where there's room for it. */
	display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical;
	overflow: hidden; max-height: 7.5em;
}

/* ---- standalone shop-by (winery/shop-by, v0.101.0) — hero-copy placement ----
   Same shared .winery-product-catalog__shop-by* descendants as the in-catalog
   strip above (contract.md § winery/shop-by "Shared strip markup"), wrapped in
   the plugin's structural-only `.winery-shop-by` root instead of
   `.winery-product-catalog`. Scoped to `.sa-hero-copy` (rhinory/shop-hero-reel's
   InnerBlocks slot) so this doesn't repaint a standalone strip dropped anywhere
   else on the site; a bare top rule/padding (matching the in-catalog port) would
   read wrong stacked directly under the hero sub-paragraph, so this port swaps
   the prototype's own `.sa-shopby` spacing (prototypes/13/shop-all.css:96-98)
   instead: a top margin, no top rule. */
/* The hero grid carries no vertical padding of its own (v13 — see
   shop-hero-reel.css), so the 26px of air the prototype puts UNDER the chips
   comes from `.sa-shopby`'s own padding-bottom. Without it the chip row butts
   the hero's bottom rule, which is visible the moment the column stacks. */
.sa-hero-copy .winery-shop-by .winery-product-catalog__shop-by{
	margin-top: 30px; padding-block: 0 26px; border-top: 0;
	display: flex; align-items: center; gap: 18px 22px; flex-wrap: wrap;
}
.sa-hero-copy .winery-shop-by .winery-product-catalog__shop-by-label{
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.2em; text-transform: uppercase; color: var(--rhw-muted);
}
.sa-hero-copy .winery-shop-by .winery-product-catalog__shop-by-list{
	display: flex; flex-wrap: wrap; gap: 7px; align-items: center; list-style: none; margin: 0; padding: 0;
}
/* group-boundary match, and the centred-tick geometry, both for the reasons
   given on the in-catalog copy of these two rules above. */
.sa-hero-copy .winery-shop-by .winery-product-catalog__shop-by-item[data-winery-catalog-shop-by-group="collection"] + .winery-product-catalog__shop-by-item[data-winery-catalog-shop-by-group="region"]{
	position: relative; margin-left: 4px; padding-left: 12px; border-left: 0;
}
.sa-hero-copy .winery-shop-by .winery-product-catalog__shop-by-item[data-winery-catalog-shop-by-group="collection"] + .winery-product-catalog__shop-by-item[data-winery-catalog-shop-by-group="region"]::before{
	content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
	width: 1px; height: 22px; background: var(--rhw-rule-2);
}
.sa-hero-copy .winery-shop-by .winery-product-catalog__shop-by-chip{
	display: inline-flex; align-items: center; white-space: nowrap; padding: 10px 15px; min-height: 42px;
	background: none; border: 1px solid var(--rhw-rule-2); border-radius: 2px; cursor: pointer;
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.13em; text-transform: uppercase; color: var(--rhw-ink);
	transition: border-color 0.2s, background 0.2s, color 0.2s;
}
.sa-hero-copy .winery-shop-by .winery-product-catalog__shop-by-chip:hover{ border-color: var(--rhw-burgundy); color: var(--rhw-burgundy); }
.sa-hero-copy .winery-shop-by .winery-product-catalog__shop-by-chip[aria-pressed="true"]{
	background: var(--rhw-burgundy); border-color: var(--rhw-burgundy); color: var(--rhw-paper);
}

/* ---- rail + results split (.sa-layout port) ---- */
.winery-product-catalog .winery-product-catalog__layout{ gap: 44px; padding-top: 44px; }

/* rail-collapse breakpoint widened to the prototype's 1024px (gap #7, 2026-08-19
   fidelity rework). The plugin's own off-canvas facets drawer — __layout to a
   single column, __filter-toggle shown, __facets pinned fixed + slid off-screen,
   __facet-scrim dimming behind it — only activates at its documented <=48rem/
   768px breakpoint (contract.md § Storefront styling tokens, __catalog-card-
   min-width-compact row). The prototype gates that same treatment to <=1024px
   (`.sa-layout`, `.sa-filter-toggle`, `.sa-rail-close`, `.sa-rail-scrim` all
   switch together at prototypes/13/shop-all.css:779-811), which is also what
   frees the grid to reach 3-up at 1024 instead of 2-up. This block mirrors the
   plugin's own <=48rem declarations (read off computed styles in-browser, not
   its source, per the do-not-grep-plugin-source rule) at the wider prototype
   breakpoint: a no-op duplicate for <=768px, and the only rule in effect for
   the 768-1024px gap the plugin's own query doesn't cover. The click-to-open/
   close JS targets classes/attributes, not viewport width, so widening which
   range shows the toggle doesn't touch behavior. */
@media (max-width: 1024px){
	.winery-product-catalog .winery-product-catalog__layout{
		grid-template-columns: 1fr; gap: 0;
	}
	.winery-product-catalog .winery-product-catalog__filter-toggle{ display: flex; }
	.winery-product-catalog .winery-product-catalog__facets-close{ display: flex; }
	.winery-product-catalog .winery-product-catalog__facets{
		position: fixed; top: 0; left: 0; bottom: 0;
		width: var(--winery-catalog-sidebar-width);
		z-index: 1001; background: var(--rhw-paper);
		box-shadow: 0 26px 64px -26px rgba(45, 41, 38, 0.6);
		padding: 24px; overflow-y: auto;
		transform: translateX(-100%); transition: transform 0.22s;
	}
	.winery-product-catalog .winery-product-catalog__facets--open{ transform: translateX(0); }
	.winery-product-catalog .winery-product-catalog__facet-scrim{ display: none; }
	.winery-product-catalog .winery-product-catalog__facet-scrim:not([hidden]){
		display: block; position: fixed; inset: 0; z-index: 1000;
		background: rgba(45, 41, 38, 0.52);
	}
}

.winery-product-catalog .winery-product-catalog__facets-header{
	display: flex; align-items: center; justify-content: space-between; gap: 14px;
	/* min-height is the alignment mechanism (matches .winery-featured-row__header's
	   own min-height below): both headers float to the same 56px floor regardless
	   of their differing content, so the two border-bottom rules land on the same
	   Y without hand-tuning padding per header (v13 .sa-rail-head/.sa-featured-head
	   both use this exact min-height:56px/padding-bottom:20px pair). */
	/* height (not min-height): the rail title + Clear-all control's intrinsic
	   line height pushed a min-height box to 59px, 3px past the featured-row
	   header's matching box — a fixed border-box height locks both to exactly
	   56px regardless of child intrinsic size. */
	height: 56px; padding-bottom: 14px; border-bottom: 1px solid var(--rhw-rule-2);
}
.winery-product-catalog .winery-product-catalog__facets-title{
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.2em; text-transform: uppercase; color: var(--rhw-ink);
}
.winery-product-catalog .winery-product-catalog__facets-clear,
.winery-product-catalog .winery-product-catalog__facets-close{
	background: none; border: 0; padding: 0; cursor: pointer;
	font-family: var(--rhw-ff-label); font-size: 10.5px; font-weight: 600;
	letter-spacing: 0.14em; text-transform: uppercase; color: var(--rhw-muted);
	transition: color 0.2s;
}
.winery-product-catalog .winery-product-catalog__facets-clear:hover,
.winery-product-catalog .winery-product-catalog__facets-close:hover{ color: var(--rhw-burgundy); }

.winery-product-catalog .winery-product-catalog__facet{ border-bottom: 1px solid var(--rhw-rule); padding: 20px 0; }
.winery-product-catalog .winery-product-catalog__facet-toggle{
	width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 10px;
	background: none; border: 0; padding: 0; cursor: pointer; text-align: left;
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.16em; text-transform: uppercase; color: var(--rhw-ink);
}
.winery-product-catalog .winery-product-catalog__facet-options{
	display: flex; flex-direction: column; gap: 2px; margin-top: 14px;
}
.winery-product-catalog .winery-product-catalog__facet-option-row{ position: relative; display: flex; align-items: center; gap: 8px; }
.winery-product-catalog .winery-product-catalog__facet-option{
	flex: 1; display: flex; align-items: center; gap: 10px; padding: 7px 0; cursor: pointer;
	font-family: var(--rhw-ff-body); font-size: var(--rhw-type-meta); color: var(--rhw-ink-2);
	transition: color 0.2s;
}
.winery-product-catalog .winery-product-catalog__facet-option:hover{ color: var(--rhw-ink); }
.winery-product-catalog .winery-product-catalog__facet-check{
	appearance: none; width: 17px; height: 17px; flex: none; margin: 0; cursor: pointer;
	background: var(--rhw-paper); border: 1px solid var(--rhw-rule-2); border-radius: 2px;
	display: inline-grid; place-items: center; transition: background 0.2s, border-color 0.2s;
}
.winery-product-catalog .winery-product-catalog__facet-check:checked{ background: var(--rhw-burgundy); border-color: var(--rhw-burgundy); }
.winery-product-catalog .winery-product-catalog__facet-check:checked::after{
	content: ""; width: 5px; height: 9px; margin-top: -2px;
	border: solid var(--rhw-paper); border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.winery-product-catalog .winery-product-catalog__facet-check:focus-visible{ outline: 2px solid var(--rhw-burgundy); outline-offset: 2px; }
.winery-product-catalog .winery-product-catalog__facet-label{ flex: 1; }
.winery-product-catalog .winery-product-catalog__facet-count{
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.06em; color: var(--rhw-muted);
}
.winery-product-catalog .winery-product-catalog__facet-info{
	background: none; border: 1px solid var(--rhw-rule-2); border-radius: 50%;
	width: 19px; height: 19px; flex: none; cursor: pointer; line-height: 1;
	font-family: var(--rhw-ff-display); font-size: 12px; font-weight: 600; font-style: italic;
	color: var(--rhw-muted); transition: border-color 0.18s, color 0.18s, background 0.18s;
}
.winery-product-catalog .winery-product-catalog__facet-info:hover,
.winery-product-catalog .winery-product-catalog__facet-info:focus-visible{
	border-color: var(--rhw-burgundy); color: var(--rhw-burgundy); background: var(--rhw-burgundy-tint);
}
/* term-description popover (D — v0.102.0 hover/focus popover, `aria-
   describedby`-linked, no native title=). Reveal/position/pointer-events
   stay the plugin's own mechanics (blocks/product-catalog/style.css
   `.winery-product-catalog__facet-option-row:hover` / `:focus-within`) —
   this only paints, matching v13's `.sa-info-pop` tooltip. */
.winery-product-catalog .winery-product-catalog__facet-description{
	/* plugin default anchors right:0, which extends LEFTWARD off-screen for the
	   leftmost rail (it sits at the far left of the page). Anchor left:0 instead
	   so it opens inward, matching v13's .sa-info-pop (shop-all.css:719). */
	top: calc(100% + 8px); left: 0; right: auto; width: 236px;
	padding: 13px 15px;
	background: var(--rhw-paper); border: 1px solid var(--rhw-rule-burg);
	border-left: 2px solid var(--rhw-burgundy); border-radius: 0;
	box-shadow: 0 22px 54px -24px rgba(45, 41, 38, 0.55);
	font-family: var(--rhw-ff-body); font-size: var(--rhw-type-meta); line-height: 1.5; color: var(--rhw-ink-2);
}
.winery-product-catalog .winery-product-catalog__facet-select{
	width: 100%; margin-top: 12px; padding: 10px 12px; min-height: 44px;
	background: var(--rhw-paper); border: 1px solid var(--rhw-rule-2); border-radius: 2px;
	font-family: var(--rhw-ff-body); font-size: var(--rhw-type-meta); color: var(--rhw-ink);
}

/* chip + range facets (.sa-shopby-chip / .sa-range2 port) */
.winery-product-catalog .winery-product-catalog__facet-chips{ display: flex; flex-wrap: wrap; gap: 7px; margin-top: 14px; }
.winery-product-catalog .winery-product-catalog__facet-chip{
	display: inline-flex; align-items: center; padding: 9px 13px; min-height: 40px;
	background: none; border: 1px solid var(--rhw-rule-2); border-radius: 2px; cursor: pointer;
	font-family: var(--rhw-ff-label); font-size: 10.5px; font-weight: 600;
	letter-spacing: 0.13em; text-transform: uppercase; color: var(--rhw-ink);
	transition: border-color 0.2s, background 0.2s, color 0.2s;
}
.winery-product-catalog .winery-product-catalog__facet-chip:hover{ border-color: var(--rhw-burgundy); color: var(--rhw-burgundy); }
.winery-product-catalog .winery-product-catalog__facet-chip--active{
	background: var(--rhw-burgundy); border-color: var(--rhw-burgundy); color: var(--rhw-paper);
}
.winery-product-catalog .winery-product-catalog__facet-range-values{
	display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-top: 14px;
	font-family: var(--rhw-ff-display); font-size: 20px; font-weight: 600; color: var(--rhw-ink);
	font-variant-numeric: lining-nums;
}
.winery-product-catalog .winery-product-catalog__facet-range-track{ background: var(--rhw-rule-2); }
.winery-product-catalog .winery-product-catalog__facet-range-fill{ background: var(--rhw-burgundy); }
.winery-product-catalog .winery-product-catalog__facet-range-handle{
	background: var(--rhw-paper); border: 2px solid var(--rhw-burgundy);
	box-shadow: 0 1px 4px rgba(45, 41, 38, 0.28);
}
.winery-product-catalog .winery-product-catalog__facets-apply{
	width: 100%; margin-top: 18px; padding: 14px 20px; min-height: 44px;
	background: var(--rhw-burgundy); color: var(--rhw-paper); border: 0; border-radius: 2px; cursor: pointer;
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.16em; text-transform: uppercase;
}

/* ---- toolbar (.sa-results-bar port) ---- */
.winery-product-catalog .winery-product-catalog__toolbar{
	display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
	gap: var(--winery-catalog-toolbar-gap);
	padding-bottom: 16px; border-bottom: 1px solid var(--rhw-rule-2);
}
.winery-product-catalog .winery-product-catalog__result-count{
	font-family: var(--rhw-ff-body); font-size: var(--rhw-type-meta); color: var(--rhw-ink-2); margin: 0;
}
.winery-product-catalog .winery-product-catalog__result-count b{
	font-family: var(--rhw-ff-display); font-size: 22px; font-weight: 600; color: var(--rhw-ink); margin-right: 4px;
}
.winery-product-catalog .winery-product-catalog__per-page,
.winery-product-catalog .winery-product-catalog__sort{
	display: flex; align-items: center; gap: 10px;
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.14em; text-transform: uppercase; color: var(--rhw-muted);
}
.winery-product-catalog .winery-product-catalog__per-page select,
.winery-product-catalog .winery-product-catalog__sort select{
	padding: 9px 12px; min-height: 40px; background: var(--rhw-paper);
	border: 1px solid var(--rhw-rule-2); border-radius: 2px;
	font-family: var(--rhw-ff-body); font-size: var(--rhw-type-meta); color: var(--rhw-ink); cursor: pointer;
}
.winery-product-catalog .winery-product-catalog__filter-toggle{
	padding: 11px 16px; min-height: 44px; background: none;
	border: 1px solid var(--rhw-rule-2); border-radius: 2px; cursor: pointer;
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.14em; text-transform: uppercase; color: var(--rhw-ink);
}
.winery-product-catalog .winery-product-catalog__filter-toggle:hover{ border-color: var(--rhw-burgundy); color: var(--rhw-burgundy); }

/* ---- active filter pills (.sa-active .pill port) ---- */
.winery-product-catalog .winery-product-catalog__active-filters{ display: flex; flex-wrap: wrap; gap: 9px; padding: 18px 0 2px 0; }
.winery-product-catalog .winery-product-catalog__active-filter{
	display: inline-flex; align-items: center; gap: 9px; padding: 8px 12px;
	background: var(--rhw-burgundy-tint); border: 1px solid var(--rhw-rule-burg); border-radius: 2px; cursor: pointer;
	font-family: var(--rhw-ff-label); font-size: 10.5px; font-weight: 600;
	letter-spacing: 0.12em; text-transform: uppercase; color: var(--rhw-burgundy);
}
.winery-product-catalog .winery-product-catalog__active-filter:hover{ background: var(--rhw-card-2); }

/* ---- cellar grid (.sa-grid port) ----
   gap:0 with a top+left hairline on the container and a right+bottom hairline
   on each card draws the continuous ledger rule the prototype uses. */
.winery-product-catalog .winery-product-catalog__grid{
	margin-top: 24px; background: var(--rhw-paper);
	border-top: 1px solid var(--rhw-rule); border-left: 1px solid var(--rhw-rule);
}

/* ---- pagination (.sa-page port) ---- */
.winery-product-catalog .winery-product-catalog__pagination{
	display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding-top: 34px;
}
.winery-product-catalog .winery-product-catalog__page-link{
	min-width: 42px; min-height: 42px; padding: 10px 13px;
	background: none; border: 1px solid var(--rhw-rule-2); border-radius: 2px; cursor: pointer;
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.1em; color: var(--rhw-ink); transition: border-color 0.2s, background 0.2s, color 0.2s;
}
.winery-product-catalog .winery-product-catalog__page-link:hover{ border-color: var(--rhw-burgundy); color: var(--rhw-burgundy); }
.winery-product-catalog .winery-product-catalog__page-link--current{
	background: var(--rhw-burgundy); border-color: var(--rhw-burgundy); color: var(--rhw-paper);
}
.winery-product-catalog .winery-product-catalog__load-more{
	margin: 34px auto 0; display: block; padding: 14px 26px; min-height: 44px;
	background: var(--rhw-burgundy); color: var(--rhw-paper); border: 0; border-radius: 2px; cursor: pointer;
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.16em; text-transform: uppercase;
}
.winery-product-catalog .winery-product-catalog__load-more:hover{ background: var(--rhw-burgundy-2); }

/* ---- empty state (.sa-empty port) ---- */
.winery-product-catalog .winery-product-catalog__empty{ padding: 64px 0; text-align: center; }
.winery-product-catalog .winery-product-catalog__empty-title{
	font-family: var(--rhw-ff-display); font-weight: 500; font-size: var(--rhw-type-h3); color: var(--rhw-ink); text-transform: none; margin: 0;
}
.winery-product-catalog .winery-product-catalog__empty-message{
	font-family: var(--rhw-ff-body); font-size: var(--rhw-type-body); line-height: 1.6; color: var(--rhw-ink-2); margin: 12px 0 0 0;
}
.winery-product-catalog .winery-product-catalog__empty-clear{
	margin-top: 20px; padding: 12px 22px; min-height: 44px;
	background: var(--rhw-burgundy); color: var(--rhw-paper); border: 0; border-radius: 2px; cursor: pointer;
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.16em; text-transform: uppercase;
}

/* ============================================================
   2 · PRODUCT CARD  (.winery-product-card)
   Ports .sa-badge / .sa-body / .sa-buy PAINT from prototypes/13/shop-all.css
   (and their WP twin in assets/css/shop-all.css) onto the plugin's OWN card
   structure.

   PAINT-ONLY as of B5 (docs/briefs/2026-08-16-shop-embeddable-catalog.md).
   v0.98.0 fixed contract gap #1: blocks/product-card/style.css is now
   enqueued by the shared render_product_card() choke point on every render
   (it was previously silent because `winery/product-card` is never a saved
   block). This file therefore no longer needs to (and must not) restate the
   card's box model, media centering, badge positioning, or control layout —
   the plugin's own neutral default already provides all of that. What
   remains below is either (a) a genuine v13 visual decision the token layer
   can't express (asymmetric hairline border, inset/zoomed bottle image,
   stacked badges, dashed-underline member-preview, sale eyebrow, ledger
   grid look), or (b) a targeted cancellation of a DEFAULT declaration that
   would otherwise fight one of those decisions (documented inline at each
   site — these are real collisions the strip surfaced, not leftover
   layout).
   ============================================================ */
.winery-product-card.winery-product-card{
	border-right: 1px solid var(--rhw-rule); border-bottom: 1px solid var(--rhw-rule);
	transition: background 0.22s, transform 0.28s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.winery-product-card.winery-product-card::after{
	content: ""; position: absolute; inset: 0; border: 1px solid transparent;
	pointer-events: none; transition: border-color 0.22s;
}
.winery-product-card.winery-product-card:hover{ background: var(--rhw-paper-2); }
.winery-product-card.winery-product-card:hover::after,
.winery-product-card.winery-product-card:focus-within::after{ border-color: var(--rhw-burgundy); }
.winery-product-card.winery-product-card:hover,
.winery-product-card.winery-product-card:focus-within{ transform: translateY(-2px); }

/* ---- media (.sa-shot port) ----
   The default __media/__media-link already centers a full-bleed image via
   grid + place-items:center; the v13 "inset bottle" (image smaller than its
   box, drop-shadow, hard hover-zoom) is a sizing/paint change on __image
   alone, so no centering-mechanism override is needed here. */
.winery-product-card .winery-product-card__media{
	background: transparent; border-bottom: 1px solid var(--rhw-rule);
	position: relative;
}
.winery-product-card .winery-product-card__image,
.winery-product-card .winery-product-card__secondary-image{
	/* max-height:88% used to over-constrain taller/narrower bottles (Keras Cab
	   Franc/Sauv): percentage heights don't resolve against an aspect-ratio-
	   derived cell height (not a definite containing-block height in these
	   engines), so max-height resolved to none and the img took its
	   max-width:76%-derived intrinsic height, overflowing the fixed 3/3.4
	   media cell and getting clipped by its overflow:hidden
	   (docs/2026-08-19-shop-prod-walk-fixes.md item A; rework 2026-08-19).
	   position:absolute + inset:0 + width/height:100% forces the img ELEMENT
	   itself to the cell's box (which aspect-ratio does size), then
	   object-fit:contain letterboxes the source inside it — no overflow for
	   any source aspect. */
	position: absolute; inset: 0; width: 100%; height: 100%;
	object-fit: contain; object-position: center;
	filter: saturate(0.96) contrast(1.03) drop-shadow(0 14px 26px rgba(45, 41, 38, 0.16));
	transform-origin: 50% var(--rhw-label-y, 86%);
	transition: transform 1.1s cubic-bezier(0.2, 0.7, 0.2, 1);
}
/* the intentional hard zoom into the bottle label (assets/css/shop-all.css) */
.winery-product-card:hover .winery-product-card__image{ transform: scale(1.55); }
/* a card with a real secondary image cross-fades instead of zooming. */
.winery-product-card--has-secondary-image .winery-product-card__secondary-image{
	transition: opacity 1.2s ease;
}
/* the lifestyle flip shot (unlike the bottle) should fill the media box
   edge-to-edge rather than letterbox — bottle shot above stays `contain`.
   ROUND 2 (2026-08-25): `cover` alone still left a 16px inset frame because
   the shared position:absolute;inset:0 rule above resolves against this
   img's nearest positioned ancestor, .winery-product-card__media-link
   (position:relative, 0 padding of its own) — NOT .winery-product-card__media,
   which is where the plugin's 16px inset (--winery-card-media-inset, 1rem)
   actually lives, one level further out. Pulling inset negative by exactly
   that padding breaks the image out of __media-link's box and lands it flush
   on __media's edges; __media's own overflow:hidden clips it there.
   Two dead ends first: (1) `inset:-16px` alone, keeping the shared rule's
   width/height:100% — over-constrained, so the engine solves top+left and
   silently drops right/bottom, only the top-left corner moves. (2) adding
   width/height:auto on top of that — for an absolutely-positioned replaced
   element (an <img>) with all of top/right/bottom/left AND width/height
   auto, engines fall back to the image's own intrinsic ratio instead of
   solving the box from the insets, so it stretched to the wrong aspect.
   Explicitly sizing width/height in calc() off the 100%-of-link baseline
   and positioning only top+left (leaving right/bottom auto, so nothing is
   over-constrained) sidesteps both. A third dead end even after that: the
   base stylesheet's global `img{ max-width:100% }` (style.css) still
   resolves against this img's own containing block (the un-inset link box)
   and clamps the calc()'d width straight back down to it — `max-width:none`
   is needed alongside the explicit width or the cap wins regardless of
   selector specificity, since max-width and width are separate properties.
   Primary bottle image is untouched (still inset:0/100%/100%, still
   `contain`). */
.winery-product-card .winery-product-card__secondary-image{
	object-fit: cover; object-position: center;
	top: calc(var(--winery-card-media-inset, 1rem) * -1);
	left: calc(var(--winery-card-media-inset, 1rem) * -1);
	right: auto; bottom: auto;
	width: calc(100% + (var(--winery-card-media-inset, 1rem) * 2));
	height: calc(100% + (var(--winery-card-media-inset, 1rem) * 2));
	max-width: none;
}
/* cancels the base hover zoom so a secondary-image card fades instead of zooming;
   the opacity swap itself is already the plugin's own default behavior. */
.winery-product-card--has-secondary-image:hover .winery-product-card__image,
.winery-product-card--has-secondary-image:focus-within .winery-product-card__image{
	transform: none; transition: opacity 1.2s ease;
}
.winery-product-card .winery-product-card__image-placeholder{
	padding: 20px;
	font-family: var(--rhw-ff-label); font-size: 10.5px; font-weight: 600;
	letter-spacing: 0.14em; text-transform: uppercase; color: var(--rhw-muted); line-height: 1.7;
	background: repeating-linear-gradient(-45deg, rgba(45, 41, 38, 0.045) 0 10px, transparent 10px 20px), var(--rhw-card);
}

/* ---- Sumatran Sparkles overlay (.sa-sparkle port) ----
   (prototypes/13/11-shop-all.html:238-241, shop-all.css:281-286) — gold
   twinkle stars over the bottle on hover, ONE product only (a nod to the
   name). Injected theme-side by assets/js/shop-catalog-polish.js, matched
   by product title text (not price/collection — those aren't reliably
   Sumatran-specific), gated behind `.has-sparkle` on the card root so no
   other card's media cell picks up the animation rule. */
.winery-product-card .rhinory-sparkle{ position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.winery-product-card .rhinory-sparkle i{
	position: absolute; left: var(--x); top: var(--y); width: var(--s); height: var(--s);
	margin: calc(var(--s) / -2) 0 0 calc(var(--s) / -2); opacity: 0;
	background: radial-gradient(circle at 50% 50%, #FFF7E4 0%, #F1C878 45%, #B97727 100%);
	clip-path: polygon(50% 0, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0 50%, 40% 40%);
	filter: drop-shadow(0 0 6px rgba(241, 200, 120, .9)) drop-shadow(0 0 12px rgba(185, 119, 39, .5));
}
.winery-product-card.has-sparkle:hover .rhinory-sparkle i{
	animation: rhinory-v4-twinkle 1.5s ease-in-out var(--d) infinite;
}
@keyframes rhinory-v4-twinkle{
	0%{ opacity: 0; transform: scale(.3) rotate(0deg); }
	40%, 60%{ opacity: 1; transform: scale(1) rotate(90deg); }
	100%{ opacity: 0; transform: scale(.3) rotate(160deg); }
}
@media (prefers-reduced-motion: reduce){
	.winery-product-card.has-sparkle:hover .rhinory-sparkle i{ animation: none; opacity: .9; }
}

/* ---- badges (.sa-badge port) ----
   v13 stacks badges in a column; the default wraps them in a row. The
   plugin's own absolute top/left positioning is left alone. */
.winery-product-card .winery-product-card__badges{
	flex-direction: column; align-items: flex-start; gap: 6px;
}
/* v13's `.sa-badge` (shop-all.css:296-301) is a label-register chit: Josefin
   9.5/700 at .14em, uppercase, 5x10 padding. The plugin's neutral default is
   body-register (Lora 10.5/500, sentence case, 4x8), so only the chit COLOURS
   were being themed and the type was still reading as the host default. The
   featured chit above is drawn to these same metrics, so the two registers have
   to agree or a card carrying both would show two different badge shapes. */
.winery-product-card .winery-product-card__badge{
	padding: 5px 10px;
	font-family: var(--rhw-ff-label); font-size: 9.5px; font-weight: 700;
	letter-spacing: 0.14em; text-transform: uppercase; line-height: 1.55;
	gap: 6px;
}
.winery-product-card .winery-product-card__badge--featured{ background: var(--rhw-burgundy); color: var(--rhw-paper); }
.winery-product-card .winery-product-card__badge--bestseller{ background: var(--rhw-card-3); color: var(--rhw-burgundy); }
.winery-product-card .winery-product-card__badge--library{ background: var(--rhw-paper); color: var(--rhw-burgundy); border: 1px solid var(--rhw-rule-burg); }
.winery-product-card .winery-product-card__badge--member{ background: var(--rhw-carbon); color: var(--rhw-acacia-soft); }
.winery-product-card .winery-product-card__badge--sale{ background: var(--rhw-burgundy); color: var(--rhw-paper); }
.winery-product-card .winery-product-card__badge--region{ background: var(--rhw-paper); color: var(--rhw-ink-2); border: 1px solid var(--rhw-rule-2); }
/* The availability chip is deliberately NOT restyled here. The card co-emits
   the frozen `.winery-c7-availability-badge` root, and the theme already owns
   that surface in assets/css/c7-overrides.css
   `[data-winery-c7-availability] .winery-c7-availability-badge` (ink-glass
   chip, top-left, gold for low-stock/allocation). Restyling it here would
   fight a considered treatment and, because both rules set an inline-start,
   stretch the chip across the whole media box. Only make room for it. */
.winery-product-card .winery-product-card__media:has(.winery-product-card__availability) .winery-product-card__badges{
	top: 52px;
}

/* ---- body (.sa-body port) ---- */
.winery-product-card .winery-product-card__body{
	position: relative;
	padding: var(--winery-card-padding) var(--winery-card-padding) 24px var(--winery-card-padding);
}
.winery-product-card .winery-product-card__eyebrow{
	font-family: var(--rhw-ff-label); font-size: 10.5px; font-weight: 600;
	letter-spacing: 0.14em; text-transform: uppercase; color: var(--rhw-burgundy);
	align-items: center; gap: 7px;
	/* The eyebrow is the row's baseline reference: the ABV + vintage cluster is
	   positioned off THIS text's baseline, not the other way round. Its 1em top
	   margin and `normal` (font-metric) line-height are both inputs to the
	   cluster's `top` in the `@container (width > 332px)` block below — change
	   either and re-measure the three baselines together. */
	margin: 1em 0;
	padding-right: 64px;
}
/* repaints the default's own eyebrow-separator dot rather than adding a second
   one — the default already draws "·" via this exact selector/pseudo-element;
   duplicating it on a different selector (::after / :not(:last-child)) would
   double the dot. */
.winery-product-card .winery-product-card__eyebrow-item + .winery-product-card__eyebrow-item::before{
	content: "\00b7"; color: var(--rhw-rule-2); margin-right: 7px;
}
.winery-product-card .winery-product-card__vintage{
	position: absolute; top: 35px; right: 22px; z-index: 3; line-height: 1; background: none;
	font-family: var(--rhw-ff-label); font-size: 12px; font-weight: 600;
	letter-spacing: 0.12em; text-transform: uppercase; color: var(--rhw-ink-2);
	text-align: right;
}
/* ---- ABV spec (Google Alcohol advertising policy, eff. 2026-09-30) ----
   Ported from prototypes/13/shop-all.css:333-364. Bound to _wc7_abv, rendered by the
   plugin's own native `showAbv` opt-in as of wordpress-for-wineries v0.116.0 (enabled
   on the Shop's `winery/product-catalog` + `winery/featured-row` instances in
   page-shop.html) — contract.md § `winery/product-card` `showAbv` attribute +
   `.winery-product-card__abv` frozen DOM row. Unlike the retired stopgap
   (docs/briefs/2026-08-28-abv-native-retire.md), `.winery-product-card__abv` is a
   plain sibling of `.winery-product-card__vintage`, not nested inside it — the
   plugin emits its own positive-only "<value>% ABV" text and omits the element
   entirely when empty/null/zero, so no `:empty` guard is needed here. Positioned to
   sit INLINE, to the LEFT of the vintage mark, matching placement A
   (prototypes/13/shop-all.css:333-364) and the original nested layout: right-anchored
   past the widest observed vintage text ("NV" ~38px) plus the separator's own width,
   so the group reads as one line regardless of which vintage form (NV / 'YY) is
   present. The base `top` / `right` below are the narrow-column + no-container-query
   fallback geometry; the wide/inline cluster's own geometry lives in the
   `@container (width > 332px)` block further down, which is what actually paints on the
   catalog grid. */
.winery-product-card .winery-product-card__abv{
	position: absolute; top: 41px; right: 76px; z-index: 3; line-height: 1; text-align: right;
	white-space: nowrap;
	font-family: var(--rhw-ff-label); font-size: 10px; font-weight: 600; letter-spacing: 0.1em;
	color: var(--rhw-muted);
	font-variant-numeric: tabular-nums lining-nums; font-feature-settings: "lnum" 1, "tnum" 1;
}
.winery-product-card .winery-product-card__abv::after{
	content: "\00b7"; margin-left: 6px; opacity: 0.55;
}
/* The mark is absolute, so the eyebrow reserves room for it rather than running under it.
   Only cards that actually carry an ABV pay the reserve. */
.winery-product-card__body:has(.winery-product-card__abv) .winery-product-card__eyebrow{ padding-right: 96px; }
.winery-product-card{ container-type: inline-size; }

/* ---- wide/inline layout: ABV + vintage as one baseline-shared cluster ----
   The two marks are separate absolutely-positioned siblings in the plugin's frozen DOM
   (no wrapper to hand a flex/`align-items: baseline` to, and the theme does not restructure
   plugin markup), so a shared baseline has to be built out of their box geometry instead:

   baseline_y = box top + line-height/2 + font-size * (ascent - descent) / 2

   Give both marks the SAME `top`, no padding, and line-heights as ABSOLUTE lengths that
   differ by exactly `(12px - 10px) * (ascent - descent)` — 20px on the vintage, 21px on
   the ABV — and every term cancels: the baselines coincide, by construction rather than by
   a hand-tuned nudge. Josefin Sans's own metrics supply the one constant, read off the
   used face rather than guessed (`canvas` `measureText().fontBoundingBoxAscent/Descent`
   at `600 100px "Josefin Sans"` -> ascent 0.75em, descent 0.25em, so `ascent - descent`
   = 0.5 and the two line-heights differ by 2px * 0.5 = 1px). Retune either font-size and
   the same one-line arithmetic gives the new pair.

   Verified live, both marks probed with a zero-size `display:inline-block` appended to the
   mark (its bottom margin edge sits ON that line's baseline): delta 0.00px across all six
   vintage forms in the catalog, at both devicePixelRatio 1 and 2. The unequal-line-height
   form beats the simpler equal-line-height one, which measured -1.00px at dpr 1.

   Two things had to be normalised away to get there. The vintage carries the plugin's own
   chip padding (`4px 8px`) and, being an absolutely-positioned `inline-flex`, blockifies to
   a `flex` box — the theme already drops its background, so the padding is dead space that
   only offsets its text; `padding: 0` plus `display: block` removes both the 4px vertical
   offset and the flex box that makes the mark's own baseline unreadable. The offsets then
   re-add what that padding used to contribute (`right` + 8px, `line-height` = 12px text +
   the 8px of vertical padding) so the vintage's glyphs stay on exactly the pixel they
   painted on before this rule existed — verified by probe, not by eye.

   Vertical datum: the cluster reads as one row with the eyebrow to its left, so the eyebrow's
   text baseline — not the vintage's box — is what both marks are positioned against. The
   eyebrow's baseline sits at `card padding + 1em margin + normal-line-height half-leading +
   ascent` below the body's padding box; the cluster's at `top + line-height/2 + font-size *
   (ascent - descent) / 2`. Solving the two for a shared baseline gives an 8px offset, and
   because BOTH sides carry the same `--winery-card-padding` term it cancels — one constant
   holds at the 22px and the 16px padding alike. Measured: the earlier `13px` (which had been
   derived against the vintage box alone, never against the eyebrow) left the whole cluster
   4.7px low on prod / 5.00px on DDEV. At 8px all three baselines land on 0.00px in headed
   Chrome, and the neighbouring candidates come back at exactly their arithmetic difference
   (7.75px -> -0.25, 8.25px -> +0.25) — the check that the value is solved, not eyeballed.
   The closed-form answer is 8.2625px; the 0.26px gap to it, and the +0.50px the same 8px
   measures under headless Chromium (identical font metrics — line-height 16.275px, ascent
   0.75em, descent 0.25em — so it is rasterizer baseline snapping, not a metric mismatch),
   are why this is tuned to the browser people actually read the page in. Every environment
   measured lands inside +/-0.5px.

   Both offsets are derived from `--winery-card-padding` rather than hard-coded, because the
   card's own `@media (max-width: 640px)` block drops that token 22px -> 16px and re-pins the
   vintage to match (`top: 29px; right: 16px`). A hard-coded pair here would be silently
   overridden there, and that window is real: phones proper fall through to the stacked
   branch (a 390px viewport leaves a 301px card), but the band between them does not — a
   500px viewport gives a single 411px column, wide branch, 16px card padding. The doubled
   `.winery-product-card.winery-product-card` class is what wins against that later media
   block, the same specificity trick the stacked branch below uses.

   Note for anyone re-measuring: `Range.getBoundingClientRect()` over a text node returns
   its LINE box, not its baseline, so matching two ranges' `bottom` values aligns line
   boxes and leaves the baselines apart whenever the font-sizes differ. That is how the
   earlier `top: 41px` value was arrived at. Probe the baseline itself.

   Horizontal: the gap to the vintage used to be a fixed `right`, so it drifted with the
   vintage string's own width — measured from the ABV box's right edge to the vintage text,
   24.3px on `NV` vs 26.2px on `'24` vs 28.7px on `'21`, all of them loose. CSS anchor
   positioning pins the ABV's right edge — the middot's trailing edge — a flat 6.00px off
   the vintage's left edge for every vintage form. The `@supports` fallback
   keeps the fixed offset, tuned to the widest observed vintage ("NV"), for engines without
   anchor positioning. */
@container (width > 332px){
	.winery-product-card.winery-product-card .winery-product-card__vintage{
		display: block; padding: 0; line-height: 20px;
		top: calc(var(--winery-card-padding) + 8px);
		right: calc(var(--winery-card-padding) + 8px);
		anchor-name: --rhw-vintage-mark;
	}
	.winery-product-card.winery-product-card .winery-product-card__abv{
		line-height: 21px;
		top: calc(var(--winery-card-padding) + 8px);
		right: calc(var(--winery-card-padding) + 36px);
	}
	@supports (anchor-name: --rhw-probe){
		.winery-product-card.winery-product-card .winery-product-card__abv{
			position-anchor: --rhw-vintage-mark;
			/* the fallback length is the widest vintage's own left edge — it only comes into
			   play on a card that carries an ABV but no vintage to anchor to. */
			right: calc(anchor(left, calc(var(--winery-card-padding) + 30px)) + 6px);
		}
	}
}

/* Column-aware, like the grid itself. The catalog packs a 300px minimum column, and below
   ~332px the longest eyebrow plus the 96px reserve stops clearing — there the mark stacks
   (vintage over ABV, right-aligned), the middot hides, and the reserve moves from the
   eyebrow to the title, so the eyebrow never wraps at any width the grid reaches. */
@container (max-width: 332px){
	/* A compact breakpoint re-pins .winery-product-card__vintage's `right` from 22px to 16px
	   on small viewports. Attributed to the plugin when this block was written; walking the
	   live CSSOM for the rules that match the mark shows it is this file's own
	   `@media (max-width: 640px)` block, further down. Pinning both marks to the same fixed
	   22px here keeps their stacked right edges flush regardless of that. */
	.winery-product-card.winery-product-card .winery-product-card__vintage{ top: 35px; right: 22px; }
	.winery-product-card .winery-product-card__abv{
		top: 60px; right: 22px; left: auto;
	}
	.winery-product-card .winery-product-card__abv::after{ content: none; }
	.winery-product-card__body:has(.winery-product-card__abv) .winery-product-card__eyebrow{ padding-right: 0; }
	.winery-product-card__body:has(.winery-product-card__abv) .winery-product-card__title{ padding-right: 74px; }
}
.winery-product-card .winery-product-card__title{
	font-family: var(--rhw-ff-display); font-weight: 600; font-size: var(--rhw-type-h3);
	line-height: 1.04; letter-spacing: -0.004em; color: var(--rhw-ink); text-transform: none; margin: 5px 0 0 0;
	/* raw Commerce7 product names are long; the prototype's curated short names
	   never wrapped, so the 2-line clamp is a theme-side addition that keeps the
	   grid's per-row height rhythm. */
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; min-height: 2.1em;
}
.winery-product-card .winery-product-card__title-link:hover,
.winery-product-card .winery-product-card__title-link:focus-visible{ text-decoration: underline; }
.winery-product-card .winery-product-card__teaser{
	font-family: var(--rhw-ff-label); font-size: 11px; font-weight: 600;
	letter-spacing: 0.1em; text-transform: uppercase; color: var(--rhw-ink-2);
	margin: 11px 0 0 0; line-height: 1.5;
}
/* same double-dot avoidance as the eyebrow separator above. */
.winery-product-card .winery-product-card__teaser-term + .winery-product-card__teaser-term::before{
	content: "\00b7"; color: var(--rhw-burgundy); margin-right: 3px;
}
.winery-product-card .winery-product-card__varietal{
	font-family: var(--rhw-ff-label); font-size: 10.5px; font-weight: 600;
	letter-spacing: 0.12em; text-transform: uppercase; color: var(--rhw-muted); margin: 12px 0 0 0;
}
.winery-product-card .winery-product-card__excerpt{
	font-family: var(--rhw-ff-body); font-size: var(--rhw-type-body); line-height: 1.5;
	color: var(--rhw-ink-2); margin: 10px 0 0 0;
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* ---- member preview (.sa-memberest / .sa-crashsub port) ----
   v0.102.0 ships this as a real hover/focus popover (button + absolutely-
   positioned popover, `.is-open`/`.is-closed` pin state, `aria-expanded`
   synced across hover/focus/pin) — the plugin owns reveal/dismiss mechanics
   entirely (blocks/product-card/style.css `.winery-product-card__member-
   preview:hover:not(.is-closed)` / `.is-open`), this section only paints. */
.winery-product-card .winery-product-card__member-preview{
	/* cancels the default's boxed top+bottom rule (a considered v13 choice:
	   a dashed-underline summary reads lighter than a bordered panel) and
	   keeps the auto-margin foot-pin the default doesn't apply here.
	   v13.1: the 16px padding-top is gone. This element is the TOP of the
	   bottom-pinned selling block, so its own padding was extra air between
	   the middle region and the qualifier line; the reserved middle regions
	   in § 2b now make that gap deterministic without it. */
	margin-top: auto; margin-bottom: 0; padding-top: 0; border-top: 0; border-bottom: 0;
}
.winery-product-card .winery-product-card__member-preview-toggle{
	/* inline-flex + min-height:0 trade the default's full-width 44px control
	   for a compact inline mark — the dashed underline IS the affordance. */
	display: inline-flex; min-height: 0; gap: 6px;
	padding: 0 0 3px 0; border-bottom: 1px dashed var(--rhw-rule-2);
	font-family: var(--rhw-ff-body); font-size: 13px; font-weight: 500; letter-spacing: 0.01em;
	color: var(--rhw-ink-2); font-variant-numeric: tabular-nums;
	transition: color 0.2s, border-color 0.2s;
}
.winery-product-card .winery-product-card__member-preview-toggle strong{
	font-family: var(--rhw-ff-display); font-size: 19px; font-weight: 600; letter-spacing: -0.01em;
	color: var(--rhw-burgundy); line-height: 1; font-variant-numeric: lining-nums;
}
.winery-product-card .winery-product-card__member-preview-toggle span{
	font-family: var(--rhw-ff-body); font-size: 12px; font-style: italic;
	text-transform: none; letter-spacing: 0; color: var(--rhw-muted);
}
/* aria-expanded is the plugin's own synced state across hover/focus/pin
   (contract.md § Product card, __member-preview-toggle row) — one selector
   covers every reveal path instead of re-deriving hover/open separately. */
.winery-product-card .winery-product-card__member-preview-toggle:hover,
.winery-product-card .winery-product-card__member-preview-toggle[aria-expanded="true"]{
	color: var(--rhw-burgundy); border-color: var(--rhw-rule-burg);
}
.winery-product-card .winery-product-card__member-preview-popover{
	/* the plugin's own default draws a full 1px border in --winery-card-border-color
	   (blocks/product-card/style.css); adding only a left border on top of that
	   left the thin default border on the other 3 sides, reading as a broken
	   corner frame behind the burgundy bar. Reset the border fully, then apply
	   the v13 single treatment (shop-all.css:406-415 .sa-crashsub-pop).

	   The plugin's default box-shadow (--winery-shop-shadow-popover, a
	   16px/40px/0 drop with no negative spread) was the ACTUAL offset-frame
	   culprit: on a popover that opens upward, that shadow paints a large
	   hazy rectangle bleeding down past the box edge toward the toggle,
	   reading as a second offset frame behind the v13 box. Swap it for
	   v13's tighter shadow (26px/64px/-26px spread hugs the box) and zero
	   the plugin's 8px border-radius default, which v13 never sets. */
	margin-top: 12px; padding-block-start: 18px; padding-inline: 18px 20px;
	background: var(--rhw-paper);
	border: 1px solid var(--rhw-rule-burg);
	border-left: 2px solid var(--rhw-burgundy);
	border-radius: 0;
	box-shadow: 0 26px 64px -26px rgba(45, 41, 38, 0.6);
	width: min(300px, 84vw);
	/* LOAD-BEARING: contract.md:1250 — this token is the ONLY source for the
	   popover's block-end padding AND the join anchor's hover-bridge hit
	   region (blocks/product-card/style.css:356/407-408). A theme that
	   changes the popover's block-end padding MUST set this token and let
	   both consumers read it; a hardcoded padding-bottom here (the prior
	   `padding: 18px 20px 18px 18px` shorthand) desyncs the two and opens a
	   ~6px dead zone between the popover edge and the join CTA's real hit
	   area, since the anchor was still bridging off the unset 12px default. */
	--winery-card-member-popover-padding-block-end: 18px;
}
.winery-product-card .winery-product-card__member-preview-popover::after{
	/* v13 rotated-square arrow (shop-all.css:409-412 .sa-crashsub-pop::after) */
	content: ""; position: absolute; left: 20px; top: 100%; width: 12px; height: 12px;
	margin-top: -6px; background: var(--rhw-paper);
	border-right: 1px solid var(--rhw-rule-burg); border-bottom: 1px solid var(--rhw-rule-burg);
	transform: rotate(45deg);
}
.winery-product-card .winery-product-card__member-preview-join{
	/* v13 .sa-crashsub-pop .cs-link (shop-all.css:397-404) — burgundy text
	   link + the trailing arrow the plugin already appends to the label.
	   Deliberately uses text-decoration, not border-bottom/padding-bottom:
	   the anchor's own padding-block-end/margin-block-end are the LOAD-
	   BEARING hover-bridge hit region above (contract.md:1003) — a literal
	   border-bottom would sit at the token-extended box edge instead of
	   under the text, and a literal padding-bottom would fight the token
	   math and reopen the dead zone this pass exists to close. */
	display: inline-block; margin-block-start: 13px;
	font-family: var(--rhw-ff-label); font-size: 10.5px; font-weight: 600;
	letter-spacing: 0.14em; text-transform: uppercase; color: var(--rhw-burgundy);
	text-decoration-line: underline; text-decoration-color: var(--rhw-rule-burg);
	text-underline-offset: 3px; transition: text-decoration-color 0.2s, color 0.2s;
}
.winery-product-card .winery-product-card__member-preview-join:hover,
.winery-product-card .winery-product-card__member-preview-join:focus-visible{
	text-decoration-color: var(--rhw-burgundy);
}
.winery-product-card .winery-product-card__member-preview-title{
	font-family: var(--rhw-ff-display); font-size: 19px; line-height: 1.14; text-transform: none;
}
.winery-product-card .winery-product-card__member-preview-tiers{ margin: 9px 0 11px; gap: 7px; }
.winery-product-card .winery-product-card__member-preview-tier{
	align-items: baseline; gap: 18px;
	font-family: var(--rhw-ff-body); font-size: 13px; line-height: 1.2; color: var(--rhw-ink);
}
.winery-product-card .winery-product-card__member-preview-tier strong{
	font-family: var(--rhw-ff-label); font-size: 11px; font-weight: 600;
	letter-spacing: 0.1em; text-transform: uppercase; color: var(--rhw-burgundy);
}
.winery-product-card .winery-product-card__member-preview-savings,
.winery-product-card .winery-product-card__member-preview-note{
	font-family: var(--rhw-ff-body); line-height: 1.5; color: var(--rhw-ink-2); margin: 8px 0 0 0;
}
.winery-product-card .winery-product-card__member-preview-note{ font-style: italic; color: var(--rhw-muted); }

/* ---- Crash "Subscribe & Save" — v13 hover/focus popover
   (prototypes/13/11-shop-all.html:447-455, shop-all.css:389-437
   .sa-crashsub--pop) — injected theme-side by assets/js/shop-catalog-
   polish.js for Crash-collection cards, which never carry a
   `.winery-product-card__member-preview` (Crash routes to the Crash Club,
   not the Conservation Circle preview). The wrapper occupies the IDENTICAL
   body slot + foot-pin the member-preview uses (margin-top:auto,
   padding-top:16px, no border) and the toggle is stretched full-width
   (v13's `.sa-crashsub-mark` is only as wide as its label; the plugin's
   own `__member-preview-toggle` is a `<button>` the plugin stretches to
   100% of the body column) so both marks draw the SAME full-width dashed
   hairline — a Crash card's mark row and a non-Crash "Members from" row
   are interchangeable in the same slot (Erik parity ask, 2026-08-20).
   Reveal is CSS-native (:hover / :focus-within) for pointer/keyboard,
   mirroring the plugin's own member-preview popover mechanics
   (contract.md:839); `.is-open` + `aria-expanded` (theme JS) pin the
   reveal for touch/click. This is a theme-owned component — it does NOT
   reuse the plugin's frozen `.winery-product-card__member-preview*`
   classnames (that surface is consumed-only), it duplicates the same
   box-skin values (border, shadow, arrow, type) already shipped for that
   popover so the two read as one system. */
/* v13.1: Crash "Subscribe & Save" is a content affordance, not part of the
   selling block (prototypes/13/shop-all.css:1006-1008) — it stays in the middle
   region on a fixed margin and the spacer below it absorbs the difference. It
   used to carry the foot-pin's auto margin, which is now the price row's. */
.winery-product-card .rhinory-crash-subscribe{
	position: relative;
	margin-top: 14px; padding-top: 0;
}
.winery-product-card .rhinory-crash-subscribe-toggle{
	display: flex; align-items: center; gap: 6px; width: 100%;
	background: none; border: 0; margin: 0; padding: 0 0 3px 0; cursor: pointer;
	border-bottom: 1px dashed var(--rhw-rule-2);
	font-family: var(--rhw-ff-label); font-size: 10.5px; font-weight: 600;
	letter-spacing: 0.13em; text-transform: uppercase; color: var(--rhw-muted); text-align: left;
	transition: color 0.2s, border-color 0.2s;
}
.winery-product-card .rhinory-crash-subscribe-icon{
	width: 12px; height: 12px; flex: none;
	stroke: currentColor; fill: none; stroke-width: 1.6;
	stroke-linecap: round; stroke-linejoin: round;
}
.winery-product-card .rhinory-crash-subscribe-toggle:hover,
.winery-product-card .rhinory-crash-subscribe-toggle:focus-visible,
.winery-product-card .rhinory-crash-subscribe-toggle[aria-expanded="true"]{
	color: var(--rhw-burgundy); border-color: var(--rhw-rule-burg);
}
/* popover — opens UPWARD so it never covers the buy row (matches the
   member-preview popover's own upward reveal, contract.md:997). */
.winery-product-card .rhinory-crash-subscribe-popover{
	position: absolute; left: 0; bottom: calc(100% + 12px); z-index: 9;
	width: min(300px, 84vw);
	background: var(--rhw-paper);
	border: 1px solid var(--rhw-rule-burg);
	border-left: 2px solid var(--rhw-burgundy);
	border-radius: 0;
	box-shadow: 0 26px 64px -26px rgba(45, 41, 38, 0.6);
	padding: 18px 20px 18px 18px;
	opacity: 0; visibility: hidden; pointer-events: none; transform: translateY(6px);
	transition: opacity 0.2s, transform 0.2s, visibility 0.2s;
}
.winery-product-card .rhinory-crash-subscribe-popover::after{
	content: ""; position: absolute; left: 20px; top: 100%; width: 12px; height: 12px;
	margin-top: -6px; background: var(--rhw-paper);
	border-right: 1px solid var(--rhw-rule-burg); border-bottom: 1px solid var(--rhw-rule-burg);
	transform: rotate(45deg);
}
.winery-product-card .rhinory-crash-subscribe:hover .rhinory-crash-subscribe-popover,
.winery-product-card .rhinory-crash-subscribe:focus-within .rhinory-crash-subscribe-popover,
.winery-product-card .rhinory-crash-subscribe.is-open .rhinory-crash-subscribe-popover{
	opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(0);
}
.winery-product-card .rhinory-crash-subscribe-heading{
	font-family: var(--rhw-ff-display); font-weight: 600; font-size: 19px; line-height: 1.14;
	color: var(--rhw-ink); margin: 0;
}
.winery-product-card .rhinory-crash-subscribe-note{
	font-family: var(--rhw-ff-body); font-size: var(--rhw-type-meta); line-height: 1.5;
	color: var(--rhw-ink-2); margin: 8px 0 0 0;
}
.winery-product-card .rhinory-crash-subscribe-link{
	display: inline-flex; align-items: center; gap: 7px; margin: 13px 0 0 0;
	font-family: var(--rhw-ff-label); font-size: 10.5px; font-weight: 600;
	letter-spacing: 0.14em; text-transform: uppercase; color: var(--rhw-burgundy);
	text-decoration-line: underline; text-decoration-color: var(--rhw-rule-burg);
	text-underline-offset: 3px; transition: text-decoration-color 0.2s, color 0.2s;
}
.winery-product-card .rhinory-crash-subscribe-link:hover,
.winery-product-card .rhinory-crash-subscribe-link:focus-visible{
	text-decoration-color: var(--rhw-burgundy);
}
@media (prefers-reduced-motion: reduce){
	.winery-product-card .rhinory-crash-subscribe-popover{ transition: none; }
}

/* ---- sale treatment ----
   v13.1 moved this entirely: the mark no longer rides its own line ABOVE the
   price row, it is told inside the price row's second line in struck-retail
   grammar. Everything about it now lives in § 2b with the rest of the selling
   block, because its position, its type and the price row's reserved height are
   one decision and reading them apart is what produced the old drift. */

/* ---- price + buy row (.sa-buy / .sa-price / .sa-add port) ---- */
/* The plugin emits price, `was` label, `was` figure and the action group as
   four SIBLINGS — there is no price sub-wrapper to make a flex box of. So the
   figures cluster on the shared baseline at the start of the row and the CTA
   takes the auto margin, which reproduces the prototype's `.sa-buy` (row, CTA
   right) plus `.sa-price` (baseline group, left) without inventing markup. */
/* geometry (the pin, the hairline, the reserved height) is § 2b's; this block
   keeps only the type and colour of what sits in the row. */
.winery-product-card .winery-product-card__price,
.winery-product-card .winery-product-card__price-now{
	gap: 6px;
	font-family: var(--rhw-ff-display); font-weight: 600; font-size: 34px; line-height: 0.9;
	letter-spacing: -0.01em; color: var(--rhw-ink);
	font-variant-numeric: lining-nums; font-feature-settings: "lnum" 1, "tnum" 1;
}
/* the plugin reveals the member figure through the frozen customer-state
   runtime; never force a [hidden] price marker visible. */
.winery-product-card .winery-product-card__price[hidden]{ display: none; }
.winery-product-card .winery-product-card__price--member{ color: #1F4F37; }
.winery-product-card .winery-product-card__price-was-label{
	margin-left: 4px;
	font-family: var(--rhw-ff-label); font-size: 9.5px; font-weight: 600;
	letter-spacing: 0.16em; text-transform: uppercase; font-style: normal;
	color: var(--winery-sale-was-strike-color);
}
/* the strike is a centered pseudo-element rule, NOT text-decoration, which
   misrenders on Cormorant Garamond italic. "was" sits outside it so the rule
   only ever crosses the figure. */
.winery-product-card .winery-product-card__price-was{
	font-family: var(--rhw-ff-display); font-size: var(--rhw-was-size); font-weight: 500;
	font-style: italic; line-height: 1; color: var(--winery-sale-was-strike-color);
	text-decoration: none; font-variant-numeric: lining-nums;
}
.winery-product-card .winery-product-card__price-was::after{
	content: ""; position: absolute; left: -2px; right: -2px; top: 50%;
	height: var(--winery-sale-was-strike-thickness); background: currentColor;
	transform: translateY(-0.5px); pointer-events: none;
}
/* the default forces __actions onto its own full-width row (flex:1 1 100%),
   which would break the v13 "price left, CTA right, same row" layout;
   cancel it so margin-left:auto can push the CTA to the row's end instead. */
.winery-product-card .winery-product-card__actions{ flex: 0 0 auto; align-items: center; gap: 10px; margin-left: auto; align-self: flex-end; }
.winery-product-card .winery-product-card__cta{
	gap: 8px; border: 1px solid var(--winery-card-cta-background);
	font-family: var(--rhw-ff-label); font-size: 10.5px;
	letter-spacing: 0.14em; text-transform: uppercase;
	transition: background 0.22s, transform 0.22s, color 0.22s, border-color 0.22s;
}
.winery-product-card .winery-product-card__cta:hover{ background: var(--winery-card-cta-background-hover); border-color: var(--winery-card-cta-background-hover); transform: translateY(-1px); }
/* join / claim read as "not buyable this way": carbon fill, not burgundy */
.winery-product-card .winery-product-card__cta--join,
.winery-product-card .winery-product-card__cta--claim{
	background: var(--rhw-carbon); border-color: var(--rhw-carbon); color: var(--rhw-acacia-soft);
}
.winery-product-card .winery-product-card__cta--join:hover,
.winery-product-card .winery-product-card__cta--claim:hover{ background: #100C09; border-color: #100C09; }
.winery-product-card .winery-product-card__cta--disabled{
	background: none; border-color: var(--rhw-rule-2); color: var(--rhw-muted); cursor: default;
}
.winery-product-card .winery-product-card__cta--disabled:hover{ background: none; border-color: var(--rhw-rule-2); transform: none; }

/* ---- state modifiers (no default equivalent for these three) ---- */
.winery-product-card--sold-out .winery-product-card__media,
.winery-product-card--coming-soon .winery-product-card__media{ opacity: 0.62; }
.winery-product-card--member-only .winery-product-card__media{ background: transparent; }

/* ---- bundle slot (delegated gift-set cards) ---- */
.winery-product-card .winery-product-card__bundle-contents{ margin: 12px 0 0 0; }
.winery-product-card .winery-product-card__bundle-count{
	font-family: var(--rhw-ff-label); font-size: 10.5px;
	letter-spacing: 0.14em; text-transform: uppercase; color: var(--rhw-burgundy);
}
.winery-product-card .winery-product-card__bundle-items{ margin: 9px 0 0 0; gap: 5px; }
.winery-product-card .winery-product-card__bundle-item{
	font-family: var(--rhw-ff-body); font-size: var(--rhw-type-meta); line-height: 1.45; color: var(--rhw-ink-2);
	display: flex; align-items: baseline; gap: 10px;
}
.winery-product-card .winery-product-card__bundle-item::before{
	content: ""; width: 4px; height: 4px; background: var(--rhw-burgundy); flex: none; transform: translateY(-2px);
}
/* The row is a flex line built for ONE thing: the child wine's name. Since
   v0.105.0 the resolver also enriches each row with a thumbnail, a primary-
   collection eyebrow, a vintage, a varietal and a card teaser (contract.md
   § DOM contract — .winery-product-card__bundle-item-image / -eyebrow /
   -vintage / -varietal / -teaser). Every one of those is a flex SIBLING of
   the name text node, so left unstyled they lay out as extra baseline-
   aligned columns and the tidy bullet list becomes a four-column dump of
   fragments — which is exactly what /shop/ started painting when the pin
   moved to ^0.109.0.
   The catalog tile is not the place for that breakdown: it answers "what is
   in this box" in one line per bottle, and the v13 prototype's own gift card
   (13/11-shop-all.html:748 `.gc-bottles`) is a plain name-only list. The
   bundle PDP is where the enriched component card belongs, and it renders
   its own markup. So the enrichment is hidden HERE rather than forked or
   suppressed upstream — the plugin still emits every node, the frozen
   surface is untouched, and this is paint on published `.winery-*` hooks.
   Contract: ~/dev/wordpress-for-wineries/docs/contract.md § DOM contract —
   .winery-product-card__bundle-item-image / -eyebrow / -vintage / -varietal
   / -teaser */
.winery-product-card .winery-product-card__bundle-item-image,
.winery-product-card .winery-product-card__bundle-item-eyebrow,
.winery-product-card .winery-product-card__bundle-item-vintage,
.winery-product-card .winery-product-card__bundle-item-varietal,
.winery-product-card .winery-product-card__bundle-item-teaser{ display: none; }
/* the separate-retail comparison is the same struck figure as the sale "was" */
.winery-product-card .winery-product-card__bundle-value{
	position: relative; display: inline-block; margin: 10px 0 0 0;
	font-family: var(--rhw-ff-display); font-size: 16px; font-style: italic; font-weight: 500;
	color: var(--winery-sale-was-strike-color); font-variant-numeric: lining-nums;
}
.winery-product-card .winery-product-card__bundle-value::after{
	content: ""; position: absolute; left: -2px; right: -2px; top: 50%;
	height: var(--winery-sale-was-strike-thickness); background: currentColor;
	transform: translateY(-0.5px); pointer-events: none;
}

/* ============================================================
   2b · CARD SYSTEM — v13.1
   Port of prototypes/13/shop-all.css:885-1018 (CD card-consistency pass,
   ingested 2026-08-29 as the design of record).

   THE PROBLEM the design solves: card copy length varies — a 1-line vs a
   2-line product name, a varietal that wraps, tasting notes that wrap — so
   the selling block landed at a different height on every card and a row read
   ragged instead of as a grid.

   THE DECISION: three regions per card body, and the variable one is bounded.

   1  HEAD    eyebrow + vintage/ABV + title. The title RESERVES its worst case
              (2 lines) and clamps there.
   2  MIDDLE  tasting notes, varietal, excerpt. Each reserves 2 lines and
              clamps at 2. Reserving, not just clamping, is the point: the
              content column is then the same height on every card, so the
              grid aligns ACROSS rows too, not only within one.
   3  FOOT    the selling block. Bottom-pinned, and the hairline rides the
              PRICE ROW itself rather than the top of the group. The price row
              reserves a constant height, so the rule, the price and the CTA
              land at the same distance above the card's bottom border on
              every card and in every state — anon, member, sale, Crash,
              locked — whatever the qualifier above them is doing.

   Exactly ONE auto margin is allowed in the body flow. Every other member of
   the selling block carries a fixed margin; that is what keeps the group
   welded together instead of splitting the free space between two anchors.
   The plugin's `.winery-product-card__body` is already a flex column and its
   `__price-row` is a distinct direct child with a published `order` knob, so
   all of this is paint on the frozen surface — no markup is restructured.
   Contract: ~/dev/wordpress-for-wineries/docs/contract.md § DOM contract —
   .winery-product-card__body / __price-row / __sale-label
   ============================================================ */

/* ---- 1 + 2 · head and middle: reserved, clamped regions ----
   Each min-height is `lines x line-height`, read off the same rule that sets
   the line-height a few declarations up. Change one and change the other. */

/* THE TITLE RESERVE IS PER-SURFACE (v13.2 CD pass, shop-all.css:920-946 +
   :1009-1017). v13.1 reserved the worst case — 2 lines — on BOTH card types.
   On the wine cards that read wrong: catalog names are almost all one line
   (Mourvèdre, Renoster, Five Species, Picpoul Blanc), so the second line was
   empty on nearly every card and left an airy hole between the name and the
   notes. Wine drops to a 1-line reserve; the gift cards genuinely run to two
   lines in their measure and keep the 2-line reserve (§ 5, further down).

   BOTH card types are `.winery-product-card`, so the SURFACE does the
   scoping. `.winery-product-catalog` is the wine scope, and it covers the
   featured row as well as the grid: the plugin nests `winery/featured-row`
   inside the catalog's `__featured-slot`, which is exactly the prototype's
   own arrangement — `.shop-all .sa-card-title` catches the `.sa-fcard` cards
   along with `.sa-grid`'s. The 2-line default below stays as the base for
   anything the two scopes do not name.

   OPERATOR CONVENTION: a wine's DISPLAY title should be kept to one line via
   the plugin's `web_title` field — that is where a long Commerce7 product
   name gets shortened for the catalog. The wrap below is the exception,
   never a cut. */
.winery-product-card .winery-product-card__title{
	min-height: calc(2 * 1.04em);
}
/* WINE — one line reserved, and a long name WRAPS rather than truncating.
   `1.04em + 6px` is one line-height plus descender room: at line-height 1.04
   a Cormorant 'g' or 'y' sits below the line box and the clamp's
   `overflow: hidden` would shave it, so the same 6px is both reserved and
   padded. line-clamp stays at 2 (set on the base rule above) as the WRAP
   SAFETY NET — a name too long for its column takes a second line and the
   card's foot stays level, because region 3 is bottom-pinned. An ellipsis
   was rejected upstream: the name IS the product on a catalog card, and
   there is nowhere else on the card to recover a cut one. */
.winery-product-catalog .winery-product-card__title{
	min-height: calc(1.04em + 6px); padding-bottom: 6px; margin-top: 6px;
}
/* head-to-middle seam, rebalanced for the shorter head: the gap that used to
   be an empty reserved line is now an authored 16px — 10px here plus the 6px
   of descender room above — so a 1-line name sits against the notes
   deliberately, not by leftover (shop-all.css:943-946). */
.winery-product-catalog .winery-product-card__title + .winery-product-card__teaser{
	margin-top: 10px;
}
/* /gift/ IS HELD AT TWO LINES, and it takes an explicit exception to do it.
   That page renders its sets through the SAME `winery/product-catalog` block
   as the shop, so the wine rule above reaches it by block reuse rather than
   by design intent — and there the 1-line reserve is wrong for the same
   reason it is right on the shop: every name on that page is "<vintage>
   <wine> Gift Set", so two lines is the NORM, not the exception. Measured on
   /gift/ at 1440, the 1-line reserve leaves "2022 Keras Collection Cabernet
   Franc Gift Set" on two lines beside two 1-line names, and the "1 bottle ·
   gift box included" spec line then lands at three different heights across
   one row — the alignment the 2-line reserve was blessed for holding in the
   v13.1 pass. UPGRADED FROM EXCEPTION TO DESIGN 2026-08-29: the gift
   design-of-record now states the same rule (`2026-08-29-gift-v13-card-reconcile`,
   09-gifts.html `.gcat h3`), so this is no longer a live-page behaviour the
   design was silent about — see the re-cut values in the rule below. */
.rhinory-page--gifts .winery-product-catalog .winery-product-card__title{
	/* RECONCILED WITH THE DESIGN-OF-RECORD 2026-08-29 (09-gifts.html `.gcat h3`).
	   The reserve above was inherited: `2 x 1.04em` came from the old 2-line
	   default and its 1.04, while gifts.css sets this card's line-height to
	   1.08, so it reserved slightly UNDER two real lines and the clamp shaved
	   the descender off the second (measured: 51.83px painted against a 53px
	   scrollHeight on the Keras set). The prototype now states the same rule
	   the live page was holding by accident, so the two are stated once here
	   rather than stacked: THE TWO-LINE RESERVE IS THE DESIGN ON THIS SURFACE,
	   not an exception patched onto the wine rule. Every name on /gift/ is
	   "<vintage> <wine> Gift Set", so the second line is the norm here.

	   `2 x 1.08em` is two real lines at this card's own line-height, + 5px of
	   descender room, reserved and padded the same way the wine rule does its
	   6px. CLAMP 3, not 2: reserve two, cap at three, NEVER cut. The name IS
	   the product on a catalog tile and there is nowhere else on the card to
	   recover a truncated one, so a pathological name takes a third line and
	   region 3 absorbs it — that row runs a line taller with its price rows
	   still level, because the selling block is bottom-pinned. */
	min-height: calc(2 * 1.08em + 5px); padding-bottom: 5px;
	-webkit-line-clamp: 3;
}
.rhinory-page--gifts .winery-product-catalog .winery-product-card__title + .winery-product-card__teaser{
	/* INERT TODAY — the gift cards render no `__teaser`, so neither this nor
	   the wine seam rule above currently matches on /gift/. It is here because
	   the two TIE on specificity, and gifts.css's load order relative to this
	   file is explicitly not something the theme depends on (see that file's
	   header): the day a gift product syncs tasting notes, the seam should be
	   decided by this rule rather than by enqueue order. 9px is gifts.css's own
	   authored value. Everything else about that card — margins, size,
	   line-height — is left to gifts.css rather than re-declared here. */
	margin-top: 9px;
}
.winery-product-card .winery-product-card__teaser{
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
	min-height: calc(2 * 1.5em);
}
.winery-product-card .winery-product-card__varietal{
	line-height: 1.45;
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
	min-height: calc(2 * 1.45em);
}
.winery-product-card .winery-product-card__excerpt{
	min-height: calc(2 * 1.5em);
}

/* ---- 3 · the pinned selling block ----
   The price row is the anchor: it carries the hairline, the reserved height
   and the bottom inset, so it sits just above the card border at a constant
   height on every card. */
.winery-product-card .winery-product-card__body{ padding-bottom: 20px; }
.winery-product-card .winery-product-card__price-row{
	margin-top: auto; padding-top: 16px; border-top: 1px solid var(--rhw-rule);
	align-items: flex-end; gap: 0 14px; min-height: 74px; flex-wrap: wrap;
	/* the reserve is taller than the content, and the selling block hangs from
	   the BOTTOM of it — bottom-aligning the line stack is what makes a 1-line
	   row and a 2-line sale row put their price and CTA at the same height. */
	align-content: flex-end;
}
/* the qualifier line travels WITH the row on a fixed margin, so the auto
   margin above the group stays the only spacer in the body. */
.winery-product-card .winery-product-card__member-preview ~ .winery-product-card__price-row{
	margin-top: 12px;
}
.winery-product-card .winery-product-card__actions{ flex: none; }

/* ---- 3b · SALE: the mark sits BELOW the hairline, inside the price row ----
   It used to ride its own line above the rule, which pushed the "Members from
   $X" line up on sale cards only — so the one thing that had to be constant
   moved. Sale is now told entirely inside the price row, in the same
   struck-retail grammar the member-view cards use: the sale figure on line
   one, "$65 · 30% off" on line two, and nothing above the rule changes.

   TWO THINGS THE PLUGIN'S MARKUP DECIDES, and how they are handled:

   (a) The line break, and why it is a GRID and not a wrapped flex row.
       `__price--public`, `__price-was-label`, `__price-was` and `__actions`
       are four flat siblings — there is no price sub-wrapper to make line two
       out of. Wrapping the flex row makes line two, but it makes it BELOW the
       CTA, so the row grows by that line and the card grows with it — measured
       at 84px against the reserve's 74px, which breaks the one invariant this
       whole section exists to hold. v13 stacks the two figures BESIDE the
       button (`.sa-price` is a column inside `.sa-buy`), so the second line
       costs the row nothing. Two explicit grid tracks reproduce that from flat
       siblings: the figures stack in track 1, the CTA spans both rows in
       track 2, and the row's height is the taller of the two — 53.6px of
       figures against a 44px button, inside the 74px reserve.
       `__price-was-label` is taken out of flow entirely rather than made into
       the break: v13 drops the word on sale cards (the strike already says
       "was", and it is the grammar the member-view cards use one row down).
       Clipped rather than `display:none` on purpose — the word stays in the
       accessibility tree, where the strike-through cannot be read.

       KNOWN ONE-LINE DELTA AGAINST THE /gift/ DESIGN-OF-RECORD, DECIDED — NOT
       DRIFT. `prototypes/13/09-gifts.html`'s gift tile keeps the word visible
       and reads "WAS $̶2̶3̶0̶ · 24% OFF"; this rule hides it on /gift/ too,
       because the brief asked for ONE sale grammar across both gift surfaces
       and /shop/'s reasoning transfers intact — the strike already says "was",
       and dropping the word is what holds line two's min-content under the CTA
       budget at a 300px column, which the /gift/ shelf now also has as its
       stated floor. Decided 2026-08-29 in
       docs/briefs/2026-08-29-gift-v13-card-reconcile.md § the three decisions;
       it rides back into the prototype on Claude Design's next touch of that
       file rather than costing a round trip for one line.

   (b) The "N% off" mark. It lives in `__sale-label`, a sibling of the price
       row, not inside it — and two boxes in different flex parents cannot
       share a line. The plugin's own `--winery-card-sale-label-order` knob
       moves the label below the row (no markup assumption), and it is then
       pulled onto line two by exactly one reserved line height. Its LEFT
       offset is a reserve rather than the struck figure's measured width,
       because CSS cannot read a sibling's used width — `--rhw-sale-was-reserve`
       is sized to the widest struck figure this catalog can show, with the
       figures set tabular so digit count is the only variable. It is an
       ABSOLUTE length, not a `ch` measure: this element zeroes its own
       font-size, and a font-relative reserve computes to nothing here. A
       shorter
       figure therefore leaves a little more air before the mark than the
       prototype does — measured 18px against the prototype's 8px for a
       two-digit "$65" at 1440, and 21px at 390, where the struck figure drops
       to 18px type against a reserve still sized at the desktop measure. The
       reserve is deliberately NOT re-tuned per breakpoint: a second magic
       number would not close the gap (the gap is digit count, not type size)
       and the whole sub-block goes away with the plugin fix below.
       That residual is the one thing here that is not exact,
       and it closes properly on the plugin side: the neutral ask is for the
       savings mark to be emitted INSIDE `__price-row` (or for the price
       figures to share a `__price-group` wrapper), at which point this whole
       sub-block collapses to ordinary flex. Flagged, not worked around with
       theme-side markup surgery. */
.winery-product-card--sale .winery-product-card__price-row{
	display: grid; grid-template-columns: 1fr auto; grid-template-rows: auto auto;
	column-gap: 14px;
	/* the rows hang from the BOTTOM of the 74px reserve, exactly as the flex
	   row they replace did — this is what lets the mark below be pulled up by
	   one line height and land on the struck figure. */
	align-content: end;
}
.winery-product-card--sale .winery-product-card__price-was-label{
	position: absolute; width: 1px; height: 1px; margin: 0; padding: 0;
	overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
/* both price slots share the first cell — only one of the public/member pair
   is ever visible, so they never collide. */
.winery-product-card--sale .winery-product-card__price{ grid-area: 1 / 1; justify-self: start; }
.winery-product-card--sale .winery-product-card__actions{
	grid-column: 2; grid-row: 1 / span 2; align-self: end;
}
/* NOTE: `justify-self: start`, and no min-width. The struck rule is a
   pseudo-element spanning this element's own box, so letting the box stretch
   to the `1fr` track — or padding it out to the reserve — would drag the
   strike across the empty space with it. The reserve lives entirely on the
   mark's margin-left below; the figure stays exactly as wide as its text. */
.winery-product-card--sale .winery-product-card__price-was{
	grid-area: 2 / 1; justify-self: start; margin-top: 3px;
	line-height: var(--rhw-sale-line-h);
	font-variant-numeric: tabular-nums lining-nums; font-feature-settings: "lnum" 1, "tnum" 1;
}
.winery-product-card--sale .winery-product-card__sale-label{
	display: flex; align-items: baseline; gap: 0;
	height: var(--rhw-sale-line-h); line-height: var(--rhw-sale-line-h);
	margin: calc(-1 * var(--rhw-sale-line-h)) 0 0 var(--rhw-sale-was-reserve);
	/* "On sale" and the "·" between it and the figure are bare text nodes in
	   the plugin's markup — no element to hide. Zeroing the label's font-size
	   collapses both while leaving the words in the accessibility tree, and
	   the savings span restates its own size and separator. */
	font-size: 0;
}
.winery-product-card--sale .winery-product-card__sale-label::before{ content: none; }
.winery-product-card--sale .winery-product-card__sale-savings{
	font-family: var(--rhw-ff-label); font-size: 9px; font-weight: 700;
	letter-spacing: 0.11em; text-transform: uppercase; color: var(--rhw-burgundy);
	white-space: nowrap; opacity: 1;
	display: inline-flex; align-items: baseline; gap: 8px;
}
.winery-product-card--sale .winery-product-card__sale-savings::before{
	content: "\00b7"; color: var(--rhw-rule-2); font-weight: 400;
}
/* the percentage is omitted when it rounds to zero; with nothing left to show,
   the label goes back to reading as words rather than as an empty line. The
   reserve is NOT reset with it — the words sit after the struck figure on the
   same line, where the mark would have been. Zeroing the offset here would put
   them on top of it. */
.winery-product-card--sale .winery-product-card__sale-label:not(:has(.winery-product-card__sale-savings)){
	font-size: var(--winery-sale-label-font-size);
}

/* ============================================================
   3 · FEATURED ROW  (.winery-featured-row)
   ============================================================ */
.winery-featured-row.winery-featured-row{
	background: var(--rhw-paper); color: var(--rhw-ink); font-family: var(--rhw-ff-body);
	padding-block: 64px 0;
}
/* E (docs/2026-08-19-shop-prod-walk-fixes.md) — the row's own top section
   padding above only makes sense for a standalone top-level section; nested
   inside the catalog's featured-slot (the row's only usage in this theme)
   it pushed the "Featured this season" header ~64px below the facets rail's
   flush "Filter / Clear all" header even though both columns top-align at
   the `__layout` level. The catalog's own
   `.winery-product-catalog{padding-block:64px}` already supplies the outer
   top gutter, so the nested row needs none of its own. */
.winery-product-catalog__featured-slot .winery-featured-row.winery-featured-row{
	padding-top: 0;
}
/* plugin default is display:grid (vertical stack), which is why the note landed
   below/left of the eyebrow instead of beside it. v13's .sa-featured-head
   (shop-all.css:679) is a flex row, eyebrow left + note pushed right by
   space-between; min-height:56px is the same alignment floor the rail's
   facets-header uses so the two border-bottom rules land on the same Y. */
.winery-featured-row .winery-featured-row__header{
	display: flex; align-items: flex-end; justify-content: space-between; flex-wrap: wrap; gap: 16px;
	/* MIN-height, not height (v13 shop-all.css:712): 56px is the alignment floor
	   that lands this rule on the same Y as the facets rail's own header at
	   desktop, but at phone width the eyebrow and the note wrap onto separate
	   lines and a fixed 56 would crop the second one. */
	min-height: 56px; padding-bottom: 20px;
	/* v13's `.sa-featured-head` (shop-all.css:712) closes on a --rule-2 hairline.
	   Without this the row inherits the plugin's neutral --winery-shop-color-border
	   (#cbd5e1, a slate blue) — an invented colour on a warm-paper band, and the
	   one place on this section where the neutral default was still showing. */
	border-bottom: 1px solid var(--rhw-rule-2);
}
/* v13 runs the head rule to the same edges as the grid beneath it
   (shop-all.css:712 + :720 are siblings in one column). The grid already breaks
   out of the featured slot's 24px inline padding to line its tracks up with the
   catalog's; the header and toggle have to take the same breakout or the rule
   stops 24px short of the tracks it is supposed to cap. One local property so
   the three stay defined together — change it once, all three follow. */
.winery-featured-row.winery-featured-row{
	--rhw-featured-breakout: 24px;
}
.winery-featured-row .winery-featured-row__header{
	margin-inline: calc(-1 * var(--rhw-featured-breakout));
	width: calc(100% + (2 * var(--rhw-featured-breakout)));
}
/* The toggle only needs its LEADING edge moved onto the same line as the header
   and grid. Widening it too would stretch a ~190px control across the full row
   and centre its label — it is a text-link affordance, not a bar. */
.winery-featured-row .winery-featured-row__toggle{
	margin-inline-start: calc(-1 * var(--rhw-featured-breakout));
	justify-self: start; width: auto;
}
/* the only copy authored into this row's description slot on this page is the
   short "Hand-picked · pour these first" NOTE — skin it as v13's .sa-featured-note
   (shop-all.css:686), not a body-copy paragraph. */
.winery-featured-row .winery-featured-row__description{
	font-family: var(--rhw-ff-label); font-size: 10.5px; font-weight: 600;
	letter-spacing: 0.14em; text-transform: uppercase; color: var(--rhw-muted);
	max-width: none; margin: 0;
}
.winery-featured-row .winery-featured-row__eyebrow{
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.18em; text-transform: uppercase; color: var(--rhw-burgundy);
	display: inline-flex; align-items: center; gap: 12px; margin: 0;
}
/* v13 explicitly SUPPRESSES the 24px leading rule on this one eyebrow
   (shop-all.css:715, `.sa-featured-t .eyebrow::before{display:none}`) — the
   featured head is a compact toolbar row inside the catalog column, not a
   section opener like the gift band's, and the rule read as a second hairline
   stacked above the head's own. Kept as a suppressed declaration rather than
   deleted so the divergence from the shared eyebrow stays legible here. */
.winery-featured-row .winery-featured-row__eyebrow::before{ content: none; }
.winery-featured-row .winery-featured-row__title{
	font-family: var(--rhw-ff-display); font-weight: 500; font-size: var(--rhw-type-h3);
	line-height: 1.04; letter-spacing: -0.008em; color: var(--rhw-ink); text-transform: none; margin: 14px 0 0 0;
}

/* ---- header-as-disclosure (.sa-featured-t port, shop-all.css:714-717) ----
   Plugin v0.120.0, `collapseControl: "header"`: the row's `<h2>` hosts a real
   `<button class="winery-featured-row__disclosure">` wrapping the headline text
   (contract.md § DOM contract — .winery-featured-row__disclosure). v13 does not
   render that headline as a heading at all — it is the compact eyebrow-register
   label of a toolbar row, sitting beside a −/+ indicator.

   Scoped with `:has()` rather than applied to every `__title`, because the SAME
   class holds a genuine headline when a row selects the standalone-button
   affordance instead; only the disclosure form gets flattened out of the
   heading register. */
.winery-featured-row .winery-featured-row__title:has(.winery-featured-row__disclosure){
	display: inline-flex; align-items: center;
	margin: 0; font: inherit; letter-spacing: normal; color: inherit;
}
.winery-featured-row .winery-featured-row__disclosure{
	display: inline-flex; align-items: center; gap: 14px;
	background: none; border: 0; padding: 0; margin: 0;
	text-align: start;
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.18em; text-transform: uppercase; line-height: 1.55;
	color: var(--rhw-burgundy);
}
/* v13's `<span class="tog">`: a body-register glyph in muted ink that the
   prototype's script swaps between − and +. Here it is generated content keyed
   off the button's own `aria-expanded`, which the plugin's runtime already
   maintains — no theme JS, and the visual can never disagree with the state
   screen readers are given. */
.winery-featured-row .winery-featured-row__disclosure::after{
	/* `/ ""` is the alternative-text half of `content`: it keeps the glyph out of
	   the button's accessible name, which stays the headline alone. The state it
	   depicts is already carried by `aria-expanded`, so announcing it again would
	   be duplication — the prototype, whose glyph is a real span, reads out
	   "Featured this season−". */
	content: "\2212" / "";
	font-family: var(--rhw-ff-body); font-size: 18px; line-height: 1;
	letter-spacing: normal; color: var(--rhw-muted);
	transition: color 0.2s;
}
.winery-featured-row .winery-featured-row__disclosure[aria-expanded="false"]::after{ content: "+" / ""; }
.winery-featured-row .winery-featured-row__disclosure:hover::after,
.winery-featured-row .winery-featured-row__disclosure:focus-visible::after{ color: var(--rhw-burgundy); }
.winery-featured-row .winery-featured-row__disclosure:focus-visible{
	outline: 2px solid var(--rhw-burgundy); outline-offset: 4px;
}
/* WHOLE-ROW HIT AREA — the plugin ships the semantics and leaves the target to
   the theme (contract.md § .winery-featured-row__disclosure: "The plugin ships
   semantics, not a hit area"). A transparent overlay stretched from inside the
   button covers the header box, so the note beside the label is clickable too.
   Deliberately a pseudo-element on the BUTTON rather than a wrapper or a JS
   forward: the accessible name stays the headline alone, the heading stays a
   heading, and Enter/Space keep working natively.
   Do not add `overflow: hidden`, a `z-index` or a transform to the note or the
   header — any of those would take the overlay out of the paint order that puts
   it above the statically-positioned description, and the row would go dead
   outside the label. */
.winery-featured-row .winery-featured-row__header{ position: relative; }
/* QUALIFIED ON `button` ON PURPOSE. In the Site Editor canvas the plugin emits
   this same class on a `<span>` instead — a RichText cannot live inside a button
   and stay editable (contract.md § .winery-storefront-editorial-copy). An
   overlay there would sit over the sibling description RichText and swallow the
   clicks an operator needs to edit the note, so the hit area is front-end only.
   Everything above is class-based and does paint in-canvas, which is the half
   that matters there. */
button.winery-featured-row__disclosure{ cursor: pointer; }
button.winery-featured-row__disclosure::before{
	content: ""; position: absolute; inset: 0; cursor: pointer;
}
.winery-featured-row .winery-featured-row__toggle{
	background: none; border: 0; padding: 0 0 2px 0; cursor: pointer; margin-top: 14px;
	border-bottom: 1px dashed var(--rhw-rule-2);
	font-family: var(--rhw-ff-label); font-size: 10px; font-weight: 600;
	letter-spacing: 0.13em; text-transform: uppercase; color: var(--rhw-muted);
	transition: color 0.2s, border-color 0.2s;
}
.winery-featured-row .winery-featured-row__toggle:hover{ color: var(--rhw-burgundy); border-color: var(--rhw-rule-burg); }
/* THEME OVERRIDE (docs/briefs/2026-08-25-shop-featured-row-and-flip-image-fit.md,
   ROUND 6) — round 5's flex row reached the full featured count but clipped
   the trailing card MID-CARD (a half card hanging off the right edge) and its
   column count didn't match the catalog's (e.g. catalog 4-up read as ~4.5 in
   the featured row) -- flex:1 1 0 shares width by card COUNT, not by the
   catalog's track formula, so the two rows only agreed by coincidence.
   Fix: give this grid the catalog's OWN grid-template-columns formula
   (blocks/product-catalog/style.css .winery-product-catalog__grid in the
   wordpress-for-wineries plugin) verbatim, reading the same
   --winery-catalog-card-min-width / --winery-catalog-columns-max /
   --winery-catalog-grid-gap custom properties the catalog grid reads. Same
   inputs + same formula = same computed track count AND same track width at
   every viewport, by construction (not a copied breakpoint table that can
   drift). auto-FILL (not auto-fit) collapses only EMPTY tracks, so a lone
   featured card stays exactly one catalog-track wide and left-aligns with
   empty tracks to its right -- no width cap or justify-content needed to
   avoid ballooning (satisfies the r3/r4 goals as a byproduct). The old
   grid-auto-rows:0 + overflow:hidden single-row clip (round 2) returns
   unchanged: a card that auto-places into row 2 because it doesn't fit in
   row 1 renders at 0 height and is clipped whole -- never a partial card,
   since grid tracks are whole units (unlike the flex approach's fractional
   width-sharing).
   FALLBACK TOGGLE (decouple from the catalog, revert to a fixed featured
   card floor): swap var(--winery-catalog-card-min-width) for
   var(--winery-featured-row-min-card-width, 300px) in the minmax() floor
   below -- one substitution, rest of the formula unchanged. */
.winery-featured-row .winery-featured-row__grid{
	border-top: 1px solid var(--rhw-rule); border-left: 1px solid var(--rhw-rule); background: var(--rhw-paper);
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(min(100%, max(var(--winery-catalog-card-min-width), (100% - ((var(--winery-catalog-columns-max) - 1) * var(--winery-catalog-grid-gap))) / var(--winery-catalog-columns-max))), 1fr));
	grid-template-rows: auto;
	grid-auto-rows: 0;
	align-items: stretch;
	gap: var(--winery-catalog-grid-gap, 0px);
	margin-inline: calc(-1 * var(--rhw-featured-breakout));
	width: calc(100% + (2 * var(--rhw-featured-breakout)));
	overflow: hidden;
}
.winery-featured-row .winery-featured-row__grid[hidden]{ display: none; }

/* ---- featured CARD treatment (.sa-fcard port, shop-all.css:721-726) ----
   The featured band reads as its own shelf, not as five catalog tiles that
   happen to sit higher up: a warmer card fill than the catalog's paper, and a
   3px burgundy cap rule across the top of each card. */
.winery-featured-row .winery-product-card--featured{
	background: var(--rhw-paper-2);
}
.winery-featured-row .winery-product-card--featured::before{
	content: ""; position: absolute; left: 0; right: 0; top: 0; height: 3px;
	background: var(--rhw-burgundy); z-index: 2; pointer-events: none;
}

/* ---- star "Featured" chit (.sa-badge.b-featured port, shop-all.css:303) ----
   WHY THIS HANGS OFF THE ROOT MODIFIER AND NOT A BADGE NODE: the card emits a
   badge only when the product carries a matching collection TERM, so
   `.winery-product-card__badge--featured` is data — on this page exactly one of
   the five featured products happens to be tagged, which would put a star on
   one card and nothing on the other four. `.winery-product-card--featured` is
   the PLACEMENT marker the featured-row renderer sets on every card it emits
   (contract.md:869 + :1026), so it is the hook that actually means "this card is
   in the featured row". No plugin change: the chit is generated here.
   The star is a background-image rather than a mask because it is always
   paper-on-burgundy — one fixed pair, no token to inherit. */
.winery-featured-row .winery-product-card--featured .winery-product-card__media::after{
	content: "Featured";
	position: absolute; inset-inline-start: 12px; top: 12px; z-index: 3;
	display: inline-flex; align-items: center;
	padding: 5px 10px 5px 27px;
	background-color: var(--rhw-burgundy);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22' fill='none' stroke='%23FBF7EE' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M11 3l2.3 5.2 5.7.5-4.3 3.7 1.3 5.6L11 20.6l-5 3 1.3-5.6L3 14.4l5.7-.5z'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: 10px center;
	background-size: 11px 11px;
	border-radius: 2px;
	color: var(--rhw-paper);
	font-family: var(--rhw-ff-label); font-size: 9.5px; font-weight: 700;
	letter-spacing: 0.14em; text-transform: uppercase; line-height: 1.55;
	white-space: nowrap;
}
/* The chit owns the top-left corner, so a data badge stack in the same card
   drops below it rather than under it. */
.winery-featured-row .winery-product-card--featured .winery-product-card__badges{
	top: 47px;
}
.winery-featured-row .winery-product-card--featured .winery-product-card__media:has(.winery-product-card__availability) .winery-product-card__badges{
	top: 87px;
}
/* A product tagged with a collection term literally named "Featured" would
   otherwise render the word twice inside the featured row — once as the chit
   above, once as its own data badge. Redundant HERE only (every card in this
   row is featured by placement); the catalog grid keeps the data badge. */
.winery-featured-row .winery-product-card__badge--featured{ display: none; }

/* ============================================================
   4 · AD TILE  (.winery-ad-tile)
   Two presets, two ported treatments: `membership` is the .sa-promo panel
   (card fill, media + copy), `free-shipping` is the .sa-slot strip (burgundy
   tint, single row). `custom` inherits the membership panel.
   ============================================================ */
.winery-ad-tile.winery-ad-tile{
	color: var(--rhw-ink); font-family: var(--rhw-ff-body);
	background: var(--winery-ad-tile-background); border-color: var(--winery-ad-tile-border-color);
}
.winery-ad-tile.winery-ad-tile[hidden]{ display: none; }
.winery-ad-tile .winery-ad-tile__media{ background: var(--rhw-card-2); }
.winery-ad-tile .winery-ad-tile__content{
	display: flex; flex-direction: column; justify-content: center;
	padding: var(--winery-ad-tile-padding); container-type: inline-size;
}
.winery-ad-tile .winery-ad-tile__eyebrow{
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.18em; text-transform: uppercase; color: var(--rhw-burgundy);
	display: inline-flex; align-items: center; gap: 11px; margin: 0;
}
.winery-ad-tile .winery-ad-tile__eyebrow::before{ content: ""; width: 6px; height: 6px; background: currentColor; flex: none; }
.winery-ad-tile .winery-ad-tile__title{
	font-family: var(--rhw-ff-display); font-weight: 500; font-size: min(var(--rhw-type-h2), 9cqw);
	line-height: 1.04; letter-spacing: -0.008em; color: var(--rhw-ink); text-transform: none;
	margin: 14px 0 0 0; text-wrap: pretty; max-width: 22ch;
}
.winery-ad-tile .winery-ad-tile__body{
	font-family: var(--rhw-ff-body); font-size: var(--rhw-type-body); line-height: 1.55;
	color: var(--rhw-ink-2); margin: 14px 0 0 0; max-width: 70ch;
}
.winery-ad-tile .winery-ad-tile__points{ list-style: none; margin: 20px 0 0 0; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.winery-ad-tile .winery-ad-tile__point{
	font-family: var(--rhw-ff-body); font-size: var(--rhw-type-body); line-height: 1.45;
	color: var(--rhw-ink-2); display: flex; align-items: baseline; gap: 11px;
}
.winery-ad-tile .winery-ad-tile__point::before{ content: ""; width: 5px; height: 5px; background: var(--rhw-burgundy); flex: none; transform: translateY(-2px); }
.winery-ad-tile .winery-ad-tile__actions{ margin-top: 26px; display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.winery-ad-tile .winery-ad-tile__cta{
	display: inline-flex; align-items: center; gap: 10px; padding: 14px 24px; min-height: 44px;
	background: var(--rhw-burgundy); color: var(--rhw-paper); border: 1px solid var(--rhw-burgundy); border-radius: 2px;
	font-family: var(--rhw-ff-label); font-size: 10.5px; font-weight: 600;
	letter-spacing: 0.14em; text-transform: uppercase; transition: background 0.22s, transform 0.22s;
}
.winery-ad-tile .winery-ad-tile__cta:hover{ background: var(--rhw-burgundy-2); color: var(--rhw-paper); transform: translateY(-1px); }
.winery-ad-tile .winery-ad-tile__secondary-link{
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.16em; text-transform: uppercase; color: var(--rhw-burgundy);
	border-bottom: 1px solid var(--rhw-rule-burg); padding-bottom: 2px;
}
.winery-ad-tile .winery-ad-tile__disclaimer{
	margin-top: 18px; font-family: var(--rhw-ff-label); font-size: 10px; font-weight: 600;
	letter-spacing: 0.1em; text-transform: uppercase; color: var(--rhw-muted);
	max-width: 40ch; line-height: 1.65;
}
/* free-shipping preset — the .sa-slot strip: one burgundy-tinted row, no media
   track, copy and link on the same line. */
.winery-ad-tile--free-shipping.winery-ad-tile--free-shipping{
	grid-template-columns: 1fr; min-height: 0;
	background: var(--rhw-burgundy-tint); border-color: var(--rhw-rule-burg);
}
.winery-ad-tile--free-shipping .winery-ad-tile__content{
	flex-direction: row; align-items: center; flex-wrap: wrap; gap: 10px 26px; padding: 26px 34px;
}
.winery-ad-tile--free-shipping .winery-ad-tile__title{
	font-family: var(--rhw-ff-label); font-size: 11.5px; font-weight: 600;
	letter-spacing: 0.18em; text-transform: uppercase; color: var(--rhw-burgundy);
	margin: 0; max-width: none;
}
.winery-ad-tile--free-shipping .winery-ad-tile__body{ margin: 0; flex: 1 1 340px; }
.winery-ad-tile--free-shipping .winery-ad-tile__actions{ margin: 0; }
.winery-ad-tile--free-shipping .winery-ad-tile__disclaimer{ margin: 0; flex: 1 1 100%; }
/* the plugin forces this notice while the shipping example is unresolved
   (data-winery-stand-in="true"); v13 states it, it does not hide it. */
.winery-ad-tile--stand-in .winery-ad-tile__disclaimer{ color: var(--rhw-acacia); }

/* ============================================================
   5 · GIFT SETS  (.winery-gift-sets)
   ============================================================ */
.winery-gift-sets.winery-gift-sets{
	background: var(--winery-gift-sets-background); color: var(--rhw-ink);
	font-family: var(--rhw-ff-body); padding-block: 96px; border-top: 1px solid var(--rhw-rule-2);
}
.winery-gift-sets .winery-gift-sets__header{
	padding-bottom: 26px;
	/* the plugin closes the header on --winery-shop-color-border, whose neutral
	   default (#cbd5e1, slate blue) was still painting here. v13's
	   `.gift-pack-head` carries no rule at all — the band's own top rule and the
	   card borders below do that work. */
	border-bottom: 0;
}
/* the eyebrow attribute is unset in the template (v13.1 removed the decorative
   eyebrows), but the paint stays: `eyebrow` is an operator-editable block
   attribute and paint that only holds while the default copy is absent breaks
   the moment someone fills it in. It owns the gap to the headline. */
.winery-gift-sets .winery-gift-sets__eyebrow{
	font-family: var(--rhw-ff-label); font-size: var(--rhw-type-eyebrow); font-weight: 600;
	letter-spacing: 0.18em; text-transform: uppercase; color: var(--rhw-burgundy);
	display: inline-flex; align-items: center; gap: 12px; margin: 0 0 14px;
}
.winery-gift-sets .winery-gift-sets__eyebrow::before{ content: ""; width: 24px; height: 1px; background: currentColor; flex: none; }
.winery-gift-sets .winery-gift-sets__title{
	font-family: var(--rhw-ff-display); font-weight: 500; font-size: var(--rhw-type-h2);
	line-height: 1.04; letter-spacing: -0.01em; color: var(--rhw-ink); text-transform: none; margin: 0;
}
/* v13.1's `.gift-pack-sub` (shop-all.css:1015) — the line that took over from
   the eyebrow as the band's supporting beat, so it reads as body copy under
   the headline rather than as the lede-width paragraph it replaced. */
.winery-gift-sets .winery-gift-sets__description{
	font-family: var(--rhw-ff-body); font-size: var(--rhw-type-lede); line-height: 1.7;
	color: var(--rhw-ink-2); margin: 18px 0 0 0; max-width: 44ch; text-wrap: pretty;
}
/* v13's `.gift-pack-head` / `.gift-grid` (shop-all.css:576, :584) both cap at
   1240 and centre inside the band's own 40px wrap, so the gift band reads
   narrower than the full-bleed catalog above it — that inset IS the treatment,
   it is what makes the two-up horizontal cards read as a considered shelf
   rather than as a fifth catalog row. The plugin lays both children out on the
   shared shop gutter/max-width tokens, which run them to the catalog's width. */
.winery-gift-sets .winery-gift-sets__header,
.winery-gift-sets .winery-gift-sets__grid{
	max-width: 1240px; margin-inline: auto;
}
/* ---- the grid: TWO wide tracks, not a card wall (shop-all.css:584) ----
   The catalog's grid is a hairline lattice (shared borders, zero gap). This one
   is the opposite shape: separated cards, each carrying its own full border, so
   the lattice borders + paper fill come off the container. */
.winery-gift-sets .winery-gift-sets__grid{
	display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px;
	border: 0; background: none;
}
/* plugin default is already flex row/space-between (blocks/gift-sets/style.css);
   the theme had overridden it to flex-direction:column + centered, which is what
   read as a centered heading. Restated as an explicit row so it can't drift back. */
/* v13.1 `.gc-seeall` (shop-all.css:1000-1005): the signpost is ONE display line
   against its CTA, so it opts out of the 2-line title reserve the product gift
   cards carry, and copy + CTA centre on a shared baseline row. */
.winery-gift-sets .winery-gift-sets__browse-all{
	display: flex; flex-direction: row; align-items: center; justify-content: space-between; gap: 40px;
	padding: 30px 40px;
	background: var(--rhw-card);
	border-right: 1px solid var(--rhw-rule); border-bottom: 1px solid var(--rhw-rule);
}
.winery-gift-sets .winery-gift-sets__browse-all-eyebrow{
	font-family: var(--rhw-ff-label); font-size: 10.5px; font-weight: 600;
	letter-spacing: 0.16em; text-transform: uppercase; color: var(--rhw-burgundy); margin: 0;
}
.winery-gift-sets .winery-gift-sets__browse-all-copy{ gap: 0; }
.winery-gift-sets .winery-gift-sets__browse-all-title{
	font-family: var(--rhw-ff-display); font-weight: 600; font-size: var(--rhw-type-h3);
	line-height: 1.06; color: var(--rhw-ink); text-transform: none; margin: 0;
	max-width: 34ch; text-wrap: pretty;
}
.winery-gift-sets .winery-gift-sets__browse-all-eyebrow{ margin-bottom: 8px; }
.winery-gift-sets .winery-gift-sets__browse-all-cta{ align-self: center; }
/* the plugin's own default paints this as a FILLED burgundy button (background +
   border in --winery-shop-color-accent, both burgundy) — the theme set the TEXT to
   burgundy on top of that without cancelling the fill, so the label went invisible
   (burgundy-on-burgundy), reading as an empty button. Cancel the button paint, then
   apply v13's text-link treatment (shop-all.css:591 .gc-cta). The label itself
   ("Browse all gift sets") is plugin-authored copy — unchanged; the arrow is an
   additive ::after so no plugin markup/label is touched. */
.winery-gift-sets .winery-gift-sets__browse-all-cta{
	flex: none; display: inline-flex; align-items: center; gap: 8px;
	min-height: 0; padding: 0 0 2px 0; margin: 0;
	background: none; border: 0; border-bottom: 1px solid var(--rhw-rule-burg); border-radius: 0; box-shadow: none;
	font-family: var(--rhw-ff-label); font-size: 10.5px; font-weight: 600;
	letter-spacing: 0.14em; text-transform: uppercase; color: var(--rhw-burgundy);
	transition: color 0.2s, border-color 0.2s;
}
.winery-gift-sets .winery-gift-sets__browse-all-cta::after{ content: "\2192"; display: inline-block; transition: transform 0.2s; }
.winery-gift-sets .winery-gift-sets__browse-all-cta:hover{ background: none; color: var(--rhw-burgundy-2); border-color: var(--rhw-burgundy); }
.winery-gift-sets .winery-gift-sets__browse-all-cta:hover::after{ transform: translateX(3px); }
.winery-gift-sets .winery-gift-sets__browse-all-cta,
.winery-featured-row .winery-featured-row__title,
.winery-gift-sets .winery-gift-sets__title{ text-decoration: none; }

/* ------------------------------------------------------------
   5b · GIFT CARD  (.gift-card / .gc-* port, shop-all.css:586-618)
   The gift set is the one card on this page that is NOT a bottle shot with a
   caption under it. v13 turns it on its side: cover photo filling the left
   column, contents + price reading down the right. The plugin delegates gift
   sets to the same `winery/product-card` renderer as the catalog, so the whole
   change is a re-layout of that one card inside the gift-set root — every
   selector below is scoped to `.winery-gift-sets`, and the catalog's own
   vertical bottle card is untouched.
   ------------------------------------------------------------ */
.winery-gift-sets .winery-product-card.winery-product-card{
	/* The media band's height is a named value because the bottle-count chip is
	   positioned against it from a different subtree (see below) — the two have
	   to move together, and at the stacked breakpoint they both change. */
	--rhw-gift-media-height: 340px;
	display: grid; grid-template-columns: 0.82fr 1fr; align-items: stretch;
	position: relative; overflow: hidden;
	background: var(--rhw-paper);
	border: 1px solid var(--rhw-rule-2);
	transition: transform 0.25s ease, border-color 0.25s ease;
}
.winery-gift-sets .winery-product-card.winery-product-card:hover,
.winery-gift-sets .winery-product-card.winery-product-card:focus-within{
	transform: translateY(-4px); border-color: var(--rhw-burgundy); box-shadow: none;
}

/* ---- media column (.gc-img) ----
   The catalog card insets its bottle shot inside a padded box (a bottle wants
   air around it). A gift set's media is a lifestyle photograph, so here it
   bleeds to the column edges and covers. */
.winery-gift-sets .winery-product-card .winery-product-card__media{
	display: block; position: relative; overflow: hidden;
	padding: 0; min-height: var(--rhw-gift-media-height);
	/* the catalog card pins its media to a 3/3.4 bottle-portrait ratio, which
	   here drove the column WIDTH off the card height (measured 366px into a
	   273px track) and pushed the photo under the copy. A gift-set photo is
	   sized by its grid track and its own min-height, not by a bottle ratio. */
	aspect-ratio: auto;
	background-color: var(--rhw-card-2);
	border-right: 1px solid var(--rhw-rule-2); border-bottom: 0;
}
.winery-gift-sets .winery-product-card .winery-product-card__media-link{
	display: block; position: absolute; inset: 0;
}
.winery-gift-sets .winery-product-card .winery-product-card__image,
.winery-gift-sets .winery-product-card .winery-product-card__secondary-image{
	position: absolute; inset: 0;
	width: 100%; height: 100%; max-height: none; object-fit: cover; object-position: center;
	transition: transform 0.8s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.winery-gift-sets .winery-product-card:hover .winery-product-card__image{ transform: scale(1.045); }

/* ---- set chip (.gc-badge, shop-all.css:596) ----
   v13 puts a dark carbon chip in this corner of a gift card, not the burgundy
   chit the catalog uses — the gift band's cards are photographs rather than
   bottle shots on paper, and carbon is what holds against them. The chip's TEXT
   is whatever collection term the product carries; only the register is themed. */
.winery-gift-sets .winery-product-card .winery-product-card__badges{ top: 14px; inset-inline-start: 14px; }
.winery-gift-sets .winery-product-card .winery-product-card__badge{
	padding: 6px 12px; letter-spacing: 0.18em;
	background: var(--rhw-carbon); color: #F1E4CE; border: 0;
}

/* ---- bottle-count chip (.gc-count) ----
   The count is already rendered, as a line of copy at the top of the contents
   block. v13 reads it as a chip on the photograph instead — same node, same
   text, positioned against the card box (whose first column IS the media). */
/* The chip is a descendant of the COPY column, so it can only reach the photo
   if the card is its containing block. The body's own `position: relative`
   (needed by the catalog card's vintage cluster, which a gift set never emits)
   is dropped here, and the member-preview keeps its popover anchored by taking
   the relative position itself — otherwise the popover would jump to the card. */
.winery-gift-sets .winery-product-card .winery-product-card__body{ position: static; }
.winery-gift-sets .winery-product-card .winery-product-card__member-preview{ position: relative; }
.winery-gift-sets .winery-product-card .winery-product-card__bundle-count{
	position: absolute; inset-inline-start: 14px; bottom: 14px; z-index: 2;
	margin: 0; padding: 6px 12px;
	background: var(--rhw-burgundy); color: var(--rhw-paper);
	font-family: var(--rhw-ff-label); font-size: 10px; font-weight: 700;
	letter-spacing: 0.16em; text-transform: uppercase; line-height: 1.55;
}

/* ---- copy column (.gc-body) ---- */
.winery-gift-sets .winery-product-card .winery-product-card__body{
	padding: 30px 32px 26px; display: flex; flex-direction: column; gap: 12px;
}
.winery-gift-sets .winery-product-card .winery-product-card__eyebrow{
	margin: 0; padding-inline-end: 0;
	font-size: 11px; letter-spacing: 0.2em;
}
.winery-gift-sets .winery-product-card .winery-product-card__title{
	margin: 0; font-weight: 500; line-height: 1.08; letter-spacing: normal;
}
.winery-gift-sets .winery-product-card .winery-product-card__excerpt{ margin: 0; }
.winery-gift-sets .winery-product-card .winery-product-card__bundle-contents{ margin: 0; }
/* .gc-bottles: name-only rows, body register, a burgundy mid-dot per line
   (shop-all.css:610-614). The enrichment nodes stay hidden by the § 2 rule. */
.winery-gift-sets .winery-product-card .winery-product-card__bundle-items{
	margin: 4px 0 0 0; gap: 6px;
	font-family: var(--rhw-ff-body); font-size: var(--rhw-type-body);
	line-height: 1.45; color: var(--rhw-ink-2);
}
.winery-gift-sets .winery-product-card .winery-product-card__bundle-item{
	font-size: var(--rhw-type-body); line-height: 1.45; gap: 8px;
}
.winery-gift-sets .winery-product-card .winery-product-card__bundle-item::before{
	content: "\00B7"; width: auto; height: auto; background: none; transform: none;
	color: var(--rhw-burgundy);
}
/* ---- foot (.gc-foot) — pinned to the bottom of the copy column ---- */
.winery-gift-sets .winery-product-card .winery-product-card__price-row{
	margin-top: auto; padding-top: 16px; border-top: 1px solid var(--rhw-rule-2);
	align-items: flex-end; align-content: flex-end; justify-content: space-between;
	min-height: 72px;
}

/* ---- the v13.1 card system, in its gift-card form (shop-all.css:1008-1023) ----
   Same three regions as § 2b, with two differences the shape forces: this
   card's title sets its own line-height, and its variable middle is the
   CONTENTS LIST rather than a run of prose. The list is fixed at its worst
   case — 4 lines plus the 3 x 6px gaps between them — and clipped there, so a
   3-bottle set and a 4-bottle set are one shape.

   THE 2-LINE TITLE RESERVE HERE IS DELIBERATE, not leftover (v13.2). Wine
   dropped to one line in § 2b; gift did not. "2022 Keras Collection Cabernet
   Franc Gift Set", "2023 Texas Mourvèdre Gift Set" and "Drawn to Protect
   Allocation" all take two lines in this card's measure, so the second line
   is the NORM here rather than the exception, and reserving it is what keeps
   the contents list and the pinned foot level across the gift grid
   (shop-all.css:1009-1017). */
/* WHY THIS CARD DEPARTS FROM `--rhw-type-h3` (v13.2 CD pass 2026-08-29, ported
   from shop-all.css's gift-title block). `.winery-gift-sets__grid` caps at
   1240px, 2-up with a 24px gap, so at 1328px and up the card is a constant
   608px, split 273px media / 333px copy, and the copy column's 32px side
   padding leaves the heading a measure of 269px. `--rhw-type-h3` is
   `clamp(26px, 2.6vw, 34px)`, so from about 1307px up it is pinned at 34px:
   roughly 7.9 characters a line. The catalog card's `__title` uses the SAME
   token in about 390px. Same size, two-thirds the room — which is why "2022
   Keras Collection Cabernet Franc Gift Set" wanted four lines (measured
   `scrollHeight` 149px against a 73.44px reserve) and got cut at the 2-line
   clamp.

   ONE PREMISE OF THE DESIGN NOTE IS NOT TRUE OF THE LIVE BAND, and it is
   recorded here rather than repeated. The prototype's block reads "the card is
   608px at every viewport at or above 1100px", i.e. that it does not grow with
   the window. Measured on the live band 2026-08-29, it does: the grid is
   `min(1240px, viewport - 88px)`, so the card is 608px only at 1328px and
   above, and below that it tracks the viewport — 594px at 1300, 544px at 1200,
   524px at 1160 — until the plugin's 64rem step drops it to one column. The
   prototype's own gift grid behaves identically; the note reads as it does
   because the prototype's four card names are short display names, and none of
   them can exercise the wrap that a 44-character Commerce7 name does.

   CONSEQUENCE, MEASURED AND LEFT OPEN DELIBERATELY: 28px + clamp 3 fixes the
   whole desktop range down to a 225.6px measure (viewport 1170), which is where
   the Keras name still sets in three lines. Below that it wants a fourth and is
   clipped again — a residual cut band from about 1164px down to the 1-up step
   at 1024px. That is strictly narrower than what shipped before this pass (cut
   from 1440px down), but it is not zero, and closing it is a LAYOUT decision on
   a band the design-of-record does not draw: drop to one column early (the
   mechanism the /gift/ shelf uses, but here it would have to move the
   card-upright step with it), re-cut the `0.82fr 1fr` split (closes the top of
   the band only, not the bottom), or accept a fourth line on this card. That
   belongs to the pass that chose 28px, not to this consume — flagged in the
   brief's handoff rather than decided here.

   The token is not wrong; it was sized against a wider measure. So this card
   states its own size, 28px, one deliberate step down — and the CLAMP GOES TO
   3 with it. 28px alone is where all four of today's names fit two lines, and
   taking only that would be designing against one dataset: a future name longer
   than today's longest now WRAPS to a third line instead of being truncated.
   Because region 3 is bottom-pinned and the contents list below is fixed at its
   4-line worst case, the cost is that one row runs a line taller with its price
   rows still level. Reserve 2, cap 3, never cut — the same rule the /gift/
   shelf carries.

   Rejected, and recorded so the next pass does not re-derive them: 26px (the
   token's own floor) buys about one character a line over 28px and leaves the
   same cliff for a visibly smaller product name; re-cutting the media/copy
   split from `0.82fr 1fr` to `0.72fr 1fr` buys 21px of measure, not enough to
   change a line count at any size in the sweep, and it spends the photograph,
   which is this band's selling device at 2-up.

   EXPIRY CONDITION: the 28px exists because the card is a fixed 608px. If a
   later pass makes this card fluid or 3-up, this goes back to the shared token.
   `padding-bottom` is descender room the clamp's `overflow: hidden` would
   otherwise shave off a Cormorant g or y.

   The see-all tile keeps `--rhw-type-h3` deliberately (`__browse-all-title`,
   further up): it is one display line in a full-width card with plenty of
   measure, and it is not a `__title` so this rule never reaches it. */
.winery-gift-sets .winery-product-card .winery-product-card__title{
	font-size: 28px;
	-webkit-line-clamp: 3;
	min-height: calc(2 * 1.08em + 4px); padding-bottom: 4px;
}
.winery-gift-sets .winery-product-card .winery-product-card__bundle-items{
	min-height: calc(4 * 1.45em + 18px); max-height: calc(4 * 1.45em + 18px); overflow: hidden;
}
/* (the copy column's own `padding: 30px 32px 26px` above carries the 26px
   bottom inset this system asks for — not restated here.) */
.winery-gift-sets .winery-product-card .winery-product-card__price{
	font-family: var(--rhw-ff-display); font-style: italic; font-weight: 500;
	font-size: 32px; line-height: 1; letter-spacing: normal; color: var(--rhw-ink);
}

/* ---- see-all tile: spans both tracks (shop-all.css:637) ---- */
.winery-gift-sets .winery-gift-sets__browse-all{
	grid-column: 1 / -1; min-height: 0;
	border: 1px solid var(--rhw-rule-2);
}

/* ============================================================
   6 · RESPONSIVE + MOTION
   ============================================================ */
@media (max-width: 1024px){
	.winery-ad-tile.winery-ad-tile{ grid-template-columns: 1fr; }
	.winery-ad-tile .winery-ad-tile__media{ min-height: 200px; }
	/* round 1 reverted to a wrapping stack below 1024px here; round 2's §3
	   grid tracks the catalog's own column count at every width (the catalog
	   itself steps 5/4/3/2/1-up via its min-width floor, no separate
	   breakpoint table), so no override is needed at this or the 640px
	   breakpoint — removing both keeps the single-row clip behavior intact
	   down to mobile instead of fighting it with a stack. */
}
/* ---- page gutter, stepped to v13 ----
   v13 steps `.sa-shop-wrap` 44 -> 36 -> 20 (shop-all.css:38, :814, :854). The
   catalog derives its own `--winery-catalog-inline-gutter` from
   `--winery-shop-inline-gutter` at `:root`, where the theme's block-scoped
   override below never reaches it — measured 2026-08-29, the catalog held 44px
   all the way down to 390 while the prototype was at 20px, so every card and
   both ad slots sat 24px narrower than the design. Setting the catalog token
   directly on the block root is what actually lands (verified in-browser);
   doubling the class keeps it above the plugin's own root declaration.
   Desktop is unchanged: 44px is already the value at >1024. */
@media (max-width: 1024px){
	.winery-product-catalog.winery-product-catalog{ --winery-catalog-inline-gutter: 36px; }
	/* v13 stacks the gift grid to one column here (shop-all.css:585) and turns
	   each card back upright, media over copy. */
	.winery-gift-sets .winery-gift-sets__grid{ grid-template-columns: 1fr; }
	/* the see-all tile stacks with it (shop-all.css:1007-1010): copy over CTA,
	   both starting at the leading edge rather than centred on a shared row. */
	.winery-gift-sets .winery-gift-sets__browse-all{
		flex-direction: column; align-items: flex-start; gap: 20px; padding: 26px 28px;
	}
	.winery-gift-sets .winery-gift-sets__browse-all-cta{ align-self: flex-start; }
}
@media (max-width: 960px){
	:root,
	.winery-product-catalog,
	.winery-product-card,
	.winery-featured-row,
	.winery-ad-tile,
	.winery-gift-sets{
		--winery-shop-inline-gutter: 20px;
	}
	.winery-product-catalog.winery-product-catalog{ padding-block: 40px; }
	.winery-gift-sets.winery-gift-sets{ padding-block: 56px; }
	.winery-featured-row.winery-featured-row{ padding-block: 40px 0; }
}
@media (max-width: 640px){
	:root,
	.winery-product-catalog,
	.winery-product-card,
	.winery-featured-row,
	.winery-ad-tile,
	.winery-gift-sets{
		--winery-card-padding: 16px;
	}
	.winery-product-card .winery-product-card__price{ font-size: 27px; }
	/* v13 turns the gift card upright below 640 (shop-all.css:849-850): the
	   media stops being a left column and becomes a shorter band on top, its
	   right-hand rule moving to the bottom edge. */
	.winery-gift-sets .winery-product-card.winery-product-card{
		grid-template-columns: 1fr; --rhw-gift-media-height: 220px;
	}
	.winery-gift-sets .winery-product-card .winery-product-card__media{
		border-right: 0; border-bottom: 1px solid var(--rhw-rule-2);
	}
	/* Stacked, the card's bottom edge is the bottom of the COPY, so a chip pinned
	   there lands on the price row instead of on the photo. Re-anchor it to the
	   media band's lower edge: `top` puts its top at that edge, then it lifts by
	   its own height plus the 14px inset — v13 keeps the count on the photograph
	   at phone width too (11-shop-all.html, .gc-count inside .gc-img). */
	.winery-gift-sets .winery-product-card .winery-product-card__bundle-count{
		bottom: auto; top: var(--rhw-gift-media-height);
		transform: translateY(calc(-100% - 14px));
	}
	/* Superseded for both cluster branches above (each pins the vintage at a higher
	   specificity); retained as the no-container-query fallback path only. */
	.winery-product-card .winery-product-card__vintage{ top: 29px; right: 16px; }
	.winery-ad-tile--free-shipping .winery-ad-tile__content{ padding: 20px; }
}
@media (max-width: 520px){
	.winery-product-catalog.winery-product-catalog{ --winery-catalog-inline-gutter: 20px; }
}
@media (max-width: 400px){
	:root,
	.winery-product-card{ --rhw-was-size: 18px; }
}
@media (prefers-reduced-motion: reduce){
	.winery-product-card.winery-product-card:hover,
	.winery-product-card.winery-product-card:focus-within{ transform: none; box-shadow: none; }
	.winery-product-card:hover .winery-product-card__image{ transform: none; }
	.winery-product-card--has-secondary-image:hover .winery-product-card__secondary-image{ transition: none; }
	.winery-ad-tile .winery-ad-tile__cta:hover{ transform: none; }
}

/* ============================================================
   9 · NATIVE-CONTROL RESET
   Surfaced by B2 (docs/briefs/2026-08-16-shop-embeddable-catalog.md) when the
   five blocks were composed onto one page. Class-hook CSS on a frozen
   `.winery-*` root; does not touch plugin markup.

   The B2/B4 "shared page gutter" fix that used to live here (manually
   pinning `winery/featured-row` / `winery/gift-sets` padding to the
   catalog's private `--winery-catalog-inline-gutter`) is REMOVED as of B5:
   v0.99.0 promoted `--winery-shop-inline-gutter` / `--winery-shop-max-width`
   to shared primitives that all three blocks' own stylesheets read
   directly (contract.md § Storefront styling tokens), so overriding those
   two tokens once in the § 1 token block above is now sufficient — closes
   contract gap #3/#5 from the theme side.
   ============================================================ */

/* ---- price range handles ----
   The plugin overlays two bare `<input type="range">` on the drawn track and
   leaves them natively styled (`blocks/product-catalog/style.css` sets only
   position + `pointer-events`). B1's paint set a background + border on the
   INPUT, which paints a box instead of a knob and leaves the native blue thumb
   showing. Strip the input chrome and paint the thumb instead, per
   prototypes/13/shop-all.css:.sa-range2-handle. */
/* The two inputs are absolutely positioned against `.__facet-range` with
   `bottom: 0`, so they land BELOW the statically-flowed track. Pin the track's
   own box here and give the handles a matching offset (18px bottom padding +
   18px track margin + half the 4px track - half the 18px handle = 29px) so the
   knobs sit centred on the rule instead of under it. */
.winery-product-catalog .winery-product-catalog__facet-range{ padding-block-end: 18px; }
.winery-product-catalog .winery-product-catalog__facet-range-track{ margin-block: 18px; height: 4px; }
.winery-product-catalog .winery-product-catalog__facet-range-handle{
	-webkit-appearance: none; appearance: none;
	background: none; border: 0; box-shadow: none; padding: 0; height: 18px; bottom: 29px;
}
.winery-product-catalog .winery-product-catalog__facet-range-handle:focus{ outline: none; }
.winery-product-catalog .winery-product-catalog__facet-range-handle:focus-visible{
	outline: 2px solid var(--rhw-burgundy); outline-offset: 3px;
}
.winery-product-catalog .winery-product-catalog__facet-range-handle::-webkit-slider-runnable-track{
	background: none; border: 0; height: 18px;
}
.winery-product-catalog .winery-product-catalog__facet-range-handle::-moz-range-track{
	background: none; border: 0; height: 18px;
}
.winery-product-catalog .winery-product-catalog__facet-range-handle::-webkit-slider-thumb{
	-webkit-appearance: none; appearance: none;
	width: 18px; height: 18px; border-radius: 50%; cursor: grab;
	background: var(--rhw-paper); border: 2px solid var(--rhw-burgundy);
	box-shadow: 0 1px 4px rgba(45, 41, 38, 0.28);
}
.winery-product-catalog .winery-product-catalog__facet-range-handle::-moz-range-thumb{
	width: 18px; height: 18px; border-radius: 50%; cursor: grab;
	background: var(--rhw-paper); border: 2px solid var(--rhw-burgundy);
	box-shadow: 0 1px 4px rgba(45, 41, 38, 0.28);
}
