/**
 * Product card.
 *
 * Markup comes from vd_render_product_card() in the vd-cadenhead plugin, so it
 * is identical whether WooCommerce renders it or a Bricks query loop does.
 * Everything here is built on the design system's own tokens, so palette and
 * spacing changes made in Bricks still flow through.
 *
 * Follows the V8 design (Authentic Collection).
 */

/* Rules run across the top and bottom only, with no sides. They are drawn as
   pseudo-elements rather than borders so hover can push them outwards without
   changing the card's box, which would reflow the whole grid row. */
.product-card {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--at-space--2xs);
	padding: var(--at-space--2xs) 0;
	background: transparent;
	height: 100%;
}

/* Deliberately identical to .media-card on the homepage: same 2px rules, same
   --at-space--s push, same easing and duration, and the same single-pseudo
   "animate inset" technique. Matching the mechanism, not just the numbers,
   is what stops the two drifting apart again.
   Hover is gated to pointer devices for the same reason it is there: a tap
   should not leave a card stuck in its hovered state. */
.product-card::before {
	content: '';
	position: absolute;
	inset: 0;
	z-index: 1;
	border-block: 2px solid var(--secondary);
	pointer-events: none;
	transition: inset 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

@media (hover: hover) and (min-width: 992px) {
	.product-card:hover::before,
	.product-card:focus-within::before {
		inset: calc(-1 * var(--at-space--s)) 0;
	}
}

@media (prefers-reduced-motion: reduce) {
	.product-card::before { transition: none !important; }
}

/* --- media ------------------------------------------------------------- */

.product-card__media {
	position: relative;
	display: block;
	overflow: hidden;
	/* V8 shows a pure white panel, not the cream paper tone. Square, with the
	   whole bottle contained rather than cropped. */
	background: #fff;
	aspect-ratio: 1 / 1;
}

/* Two framings (Andy, 2026-10-16). A bottling is a cut-out bottle on white:
   contained, never cropped, with about 10% of white round it so the neck and
   base have air. Everything else (tours, the Club, merchandise) is a
   photograph that should fill the square, so it is covered. */
.product-card__media img,
.product-card__image {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.product-card--bottling .product-card__media img,
.product-card--bottling .product-card__image {
	object-fit: contain;
	padding: 10%;
	box-sizing: border-box;
}

/* Pointer devices only, as with the rules: the image sits fractionally held
   back and comes up to full strength with a slight push in on hover. On touch
   there is no hover to resolve it, so it stays at full strength throughout. */
@media (hover: hover) and (min-width: 992px) {
	.product-card__media img,
	.product-card__image {
		opacity: 0.9;
		transform: scale(1);
		transform-origin: center center;
		transition: opacity 0.4s ease, transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
		will-change: transform;
	}

	.product-card:hover .product-card__media img,
	.product-card:hover .product-card__image,
	.product-card:focus-within .product-card__media img,
	.product-card:focus-within .product-card__image {
		opacity: 1;
		transform: scale(1.04);
	}
}

@media (prefers-reduced-motion: reduce) {
	.product-card__media img,
	.product-card__image {
		transition: none !important;
		transform: none !important;
	}
}

/* Corner band, top right: Sale, or a grey Sold Out. Sized and placed with
   Andy on 2026-10-16 (made bigger and pulled into the corner, then taken back
   down by 40%). The holder is a point at the panel's top right corner and the
   band is centred on the diagonal --vd-ribbon-in from it; it is long enough to
   run off both edges, and the panel's overflow: hidden trims it. */
.product-card__ribbon {
	--vd-ribbon-in: 3.2rem; /* along each edge: about 4.5rem from the corner. */
	position: absolute;
	top: 0;
	right: 0;
	width: 0;
	height: 0;
	pointer-events: none;
	z-index: 2;
}

.product-card__ribbon span {
	position: absolute;
	display: block;
	left: calc(-1 * var(--vd-ribbon-in));
	top: var(--vd-ribbon-in);
	width: 40rem;
	transform: translate(-50%, -50%) rotate(45deg);
	background: var(--secondary);
	color: var(--primary-d-3, #1d2b22);
	text-align: center;
	font-weight: 600;
	font-size: 1.1rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	line-height: 1;
	padding: 0.5em 0;
	white-space: nowrap;
	box-sizing: border-box;
}

.product-card__ribbon--sold-out span {
	background: #8c8c8c;
	color: #fff;
}

/* --- title ------------------------------------------------------------- */

/* "yo" and "%" in a bottling title, set small on the baseline. Not scoped to
   the card: the product page heading uses the same markup. */
sub.vd-title-unit {
	font-size: 0.55em;
	vertical-align: baseline;
	line-height: 0;
	margin-left: 0.04em;
}

/* Two lines are reserved whether or not the title needs them, so a one line
   name and a two line name produce the same box and the spec tables beneath
   them start at the same height. Most bottling names land in that range;
   anything longer is caught by the bottom group rule further down. */
.product-card__title {
	--title-lines: 2;
	font-size: var(--at-heading--s);
	line-height: 1.2;
	min-height: calc(var(--title-lines) * 1.2em);
	margin: var(--at-space--2xs) 0 0;
	text-align: center;
}

.product-card__title a {
	color: inherit;
	text-decoration: none;
}

/* The title turns gold, and the range darkens, whenever any part of the card is
   hovered, not only the title text (2026-10-16). */
.product-card__title a {
	transition: color 0.3s ease;
}

.product-card:hover .product-card__title a,
.product-card:focus-within .product-card__title a {
	color: var(--secondary);
}

/* The range, in small gold capitals under a bottling's title. */
.product-card__range {
	margin: calc(-1 * var(--at-space--3xs)) 0 0;
	text-align: center;
	color: var(--secondary);
	font-size: var(--at-text--xs);
	letter-spacing: 0.1em;
	text-transform: uppercase;
	line-height: 1.3;
	transition: color 0.3s ease;
}

.product-card:hover .product-card__range,
.product-card:focus-within .product-card__range {
	color: color-mix(in srgb, var(--secondary) 60%, #000);
}

/* --- spec table -------------------------------------------------------- */

/* Every row carries a gold rule beneath it, as the design has it, not just the
   block as a whole. The columns therefore have no gap: the cells sit flush so
   each row's border-bottom reads as one continuous line across the card, and
   the spacing is done with padding instead. */
.product-card__spec {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr) auto minmax(0, 1fr);
	column-gap: 0;
	row-gap: 0;
	margin: var(--at-space--2xs) 0 0;
	border-top: 1px solid var(--secondary);
	font-size: var(--at-text--xs);
	line-height: 1.3;
}

.product-card__spec dt,
.product-card__spec dd {
	margin: 0;
	padding: 0.45em 0;
	border-bottom: 1px solid var(--secondary);
}

.product-card__spec-label {
	color: var(--primary-l-5);
}

/* Padding is set against dt so it matches the specificity of the shared
   dt/dd rule above. As .product-card__spec-label it loses to that rule's
   padding shorthand, which left the longest label in each column butted
   against its value. */
.product-card__spec dt {
	padding-right: 0.6em;
}

/* The second label in each row needs clear air from the first value. */
.product-card__spec dt:nth-of-type(even) {
	padding-left: var(--at-space--s);
}

/* Colon lives in CSS so the PHP labels stay clean for other uses. */
.product-card__spec-label::after {
	content: ':';
}

.product-card__spec-value {
	font-weight: 600;
	color: var(--at-white);
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* A value still waiting on its attribute. Deliberately visible, so a review
   grab shows what is outstanding rather than looking finished. */
.product-card__spec-value.is-pending {
	font-weight: 400;
	font-style: italic;
	opacity: 0.55;
}

/* --- price ------------------------------------------------------------- */

.product-card__price {
	font-family: georgia, serif;
	font-size: var(--at-heading--m);
	line-height: 1.1;
	margin-top: var(--at-space--2xs);
	text-align: center;
}

.product-card__price del {
	opacity: 0.5;
	font-size: 0.72em;
	margin-right: 0.3em;
	text-decoration: line-through;
}

.product-card__price ins {
	text-decoration: none;
}

/* --- actions ----------------------------------------------------------- */

.product-card__actions {
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	align-items: stretch; /* the two buttons always share a top and a height */
	gap: var(--at-space--2xs);
	padding-top: var(--at-space--2xs);
}

/* --- bottom group ------------------------------------------------------ */

/* Spec, price and actions line up across a row whatever the title above them
   does, and whether or not a card has a spec table at all. Whichever of the
   three comes first takes up the slack; the ones after it keep their normal
   spacing. Pinning only the actions, as this did before, left the spec table
   and the price riding up and down with the title. */
.product-card__spec,
.product-card__price,
.product-card__actions {
	margin-top: auto;
}

.product-card__spec ~ .product-card__price {
	margin-top: var(--at-space--2xs);
}

.product-card__spec ~ .product-card__actions,
.product-card__price ~ .product-card__actions {
	margin-top: 0;
}

.product-card__button {
	flex: 1 1 auto;
	/* Laid out the same whatever the browser or WooCommerce's button styles
	   add to the Add to Cart link (Andy saw it sit lower in Safari). */
	display: flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	margin: 0 !important;
	vertical-align: top;
	text-align: center;
	text-decoration: none;
	font-size: var(--at-text--xs);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	padding: 0.72em 1em;
	line-height: 1;
	border: 1px solid var(--secondary);
	transition: background-color 0.15s ease, color 0.15s ease;
}

.product-card__button--info {
	background: transparent;
	color: var(--light);
}

.product-card__button--info:hover {
	background: var(--secondary);
	color: var(--primary-d-3, #1d2b22);
}

.product-card__button--cart {
	background: var(--secondary);
	color: var(--primary-d-3, #1d2b22);
}

.product-card__button--cart:hover {
	filter: brightness(1.08);
}

.product-card__button.added,
.product-card__button.loading {
	opacity: 0.7;
}

/* --- out of stock ------------------------------------------------------ */

/* Greyed back as a whole (Andy, 2026-10-16): grey photograph with no zoom,
   muted text and rules, and "Out of Stock" as plain text in place of Add to
   Cart. More Info stays a working button. */
.product-card.is-out-of-stock {
	--vd-card-muted: color-mix(in srgb, var(--light) 45%, transparent);
	--vd-card-muted-rule: color-mix(in srgb, var(--light) 25%, transparent);
}

/* No border push on hover either: nothing about a sold-out card animates. */
.product-card.is-out-of-stock::before,
.product-card.is-out-of-stock:hover::before,
.product-card.is-out-of-stock:focus-within::before {
	border-color: var(--vd-card-muted-rule);
	inset: 0;
}

.product-card.is-out-of-stock .product-card__media img,
.product-card.is-out-of-stock .product-card__image {
	filter: grayscale(1);
	opacity: 0.55;
	transform: none !important;
	transition: none;
}

.product-card.is-out-of-stock .product-card__title,
.product-card.is-out-of-stock .product-card__range,
.product-card.is-out-of-stock .product-card__price,
.product-card.is-out-of-stock .product-card__spec-value,
.product-card.is-out-of-stock .product-card__spec-label {
	color: var(--vd-card-muted);
}

.product-card.is-out-of-stock .product-card__spec,
.product-card.is-out-of-stock .product-card__spec dt,
.product-card.is-out-of-stock .product-card__spec dd {
	border-color: var(--vd-card-muted-rule);
}

.product-card__stock {
	flex: 1 1 auto;
	text-align: center;
	font-size: var(--at-text--xs);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	padding: 0.72em 1em;
	line-height: 1;
	color: var(--vd-card-muted, var(--light));
	border: 1px solid transparent;
	cursor: default;
}

/* --- small screens ----------------------------------------------------- */

@media (max-width: 478px) {
	.product-card__spec {
		grid-template-columns: auto 1fr;
	}
	/* One label per row now, so none is indented as a second column. */
	.product-card__spec dt:nth-of-type(even) {
		padding-left: 0;
	}
	.product-card__actions {
		flex-direction: column;
		align-items: stretch;
	}
}

/* ==========================================================================
   Product grid
   --------------------------------------------------------------------------
   Any grid of product cards. Column count is a custom property so one class
   serves the 4-up homepage row and the 3-up range archive without a variant:

       <div class="product-grid" style="--product-grid-cols: 4">

   Cards stretch to equal height, so rows line up even when titles wrap to two
   lines or a spec row is missing.
   ========================================================================== */

.product-grid {
	display: grid;
	grid-template-columns: repeat(var(--product-grid-cols, 3), minmax(0, 1fr));
	gap: var(--at-space--m);
	align-items: stretch;
	width: 100%;
	/* Room for a hovered card's rules to travel into, taken back with a
	   negative margin so the grid occupies the same space as before. The
	   homepage track does the same for its own scroller. */
	padding-block: var(--at-space--s);
	margin-block: calc(-1 * var(--at-space--s));
}

/* A Bricks query loop cannot sit on a custom element, so the loop lives on a
   native block and the card element is its child. That puts two wrappers
   between the grid and the card, so both are made to pass height through,
   otherwise cards in a row do not match height. */
.product-grid > *,
.product-grid > * > * {
	min-width: 0;
	display: flex;
	flex-direction: column;
}

.product-grid > * > *,
.product-grid .product-card {
	flex: 1 1 auto;
}

@media (max-width: 991px) {
	.product-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 599px) {
	.product-grid {
		grid-template-columns: 1fr;
	}
}

/* Shown when a range has nothing in it yet. */
.product-grid__empty {
	grid-column: 1 / -1;
	padding: var(--at-space--l) 0;
	color: color-mix(in srgb, var(--light) 70%, transparent);
}

/* --- appear -------------------------------------------------------------- */

/* Cards fade up in turn as they arrive: each starts when the one before is half
   way in (Andy, 2026-10-16). vd-product-grid.js adds .vd-card-in and the delay,
   batch by batch, so without the script every card simply shows. */
@keyframes vd-card-in {
	from {
		opacity: 0;
		transform: translateY(1.2rem);
	}
	to {
		opacity: 1;
		transform: none;
	}
}

.product-card.vd-card-in {
	animation: vd-card-in var(--vd-card-in-duration, 0.5s) ease-out both;
}

@media (prefers-reduced-motion: reduce) {
	.product-card.vd-card-in {
		animation: none;
	}
}

/* ==========================================================================
   Shop grid (.vd-shop-grid): the Shop page and the attribute archives
   --------------------------------------------------------------------------
   Moved here from the Shop grid element's custom CSS (16 Oct 2026) so the
   archive template shares it. 4 columns, 3 on tablets, 2 on phones.
   ========================================================================== */

.vd-shop-grid {
	--product-grid-cols: 4;
	--vd-loader: url("../img/vd-loader.svg");
	position: relative;
}

@media (max-width: 991px) {
	.vd-shop-grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

@media (max-width: 599px) {
	.vd-shop-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/* Filter change: Bricks drops its loader into the grid, shown as a green wash
   over the results with our loading animation (vd-loader.svg, a cask with the
   sun and moon passing over it) centred and kept in view. Bricks' own ring is hidden.
   It spans every column explicitly and is centred with auto margins: as a
   flex item in an auto-placed grid child, Safari drew it in the first cell. */
.vd-shop-grid > .brx-loading-animation {
	position: absolute;
	inset: 0;
	grid-column: 1 / -1;
	width: auto;
	height: auto;
	z-index: 5;
	display: block;
	padding-top: var(--at-space--3xl);
	background: color-mix(in srgb, var(--primary-d-2) 75%, transparent);
	transform: none !important;
}

.vd-shop-grid > .brx-loading-animation > * {
	display: none !important;
}

.vd-shop-grid > .brx-loading-animation::before {
	content: "";
	display: block;
	margin: 0 auto;
	position: sticky;
	top: 40vh;
	width: 8rem;
	height: 8rem;
	background: var(--vd-loader) center / contain no-repeat;
}

/* Infinite scroll: no overlay (vd-shop-loading.js marks those requests), just
   the same animation under the last row while more products load. */
.vd-loading-more .vd-shop-grid > .brx-loading-animation {
	display: none !important;
}

.vd-loading-more .vd-shop-grid::after {
	content: "";
	grid-column: 1 / -1;
	height: 8rem;
	background: var(--vd-loader) center / 6rem auto no-repeat;
}
