/**
 * WooCommerce — single product
 * ==========================================================================
 * Enqueued by inc/woocommerce.php on product pages only.
 *
 * Implements UI-LAYOUTS.md §7 (Product Page). Layout is a two-column grid: gallery leads on
 * desktop, summary sits sticky beside it; on mobile the gallery is full-bleed
 * and the summary follows.
 *
 * @package Preloved
 * @since   1.0.0
 * ========================================================================== */

.product-page {
	padding-block: var(--pl-space-5) var(--pl-space-9);
}


/* ==========================================================================
   1. Hero layout
   ========================================================================== */

.product-single__hero {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--pl-space-6);
	align-items: start;
}

/* Containing block for the sale badge. Without it the badge resolves against
   the page and paints over the header — which is exactly what WooCommerce's
   own `.onsale` flash did here before it was replaced. */
.product-single__media {
	position: relative;
}

.product-single__sale {
	position: absolute;
	inset-block-start: var(--pl-space-3);
	inset-inline-start: var(--pl-space-3);
	z-index: 2;
}

@media (min-width: 1024px) {
	.product-single__hero {
		grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
		gap: var(--pl-space-9);
	}

	/*
	 * The summary tracks the gallery on the way down. Offset by the sticky
	 * header so the title never slides under it.
	 */
	.product-single__summary {
		position: sticky;
		inset-block-start: calc(var(--pl-header-height) + var(--pl-space-5));
	}
}


/* ==========================================================================
   2. Gallery
   ========================================================================== */

.gallery {
	display: flex;
	flex-direction: column;
	gap: var(--pl-space-3);
}

.gallery__stage {
	position: relative;
	overflow: hidden;
	background-color: var(--pl-bg-sunken);
	border: 1px solid var(--pl-line-soft);
	border-radius: var(--pl-radius-lg);
	aspect-ratio: 4 / 5;
}

/*
 * No-JS baseline: the slides are a scroll-snapping strip. `show()` in
 * product.js switches to the stacked presentation below by adding
 * `is-active`, but until then every image is reachable by scrolling.
 */
.gallery__slides {
	display: flex;
	block-size: 100%;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
}

.gallery__slides::-webkit-scrollbar { display: none; }

.gallery__slide {
	position: relative;
	flex: 0 0 100%;
	margin: 0;
	block-size: 100%;
	scroll-snap-align: center;
}

.gallery__image {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
}

/*
 * Once scripting is available the strip becomes a crossfade stack. The
 * `.js` class is set on <html> before first paint by inc/enqueue.php, so
 * there is no flash of the scroller.
 */
.js .gallery__slides {
	display: block;
	position: relative;
	overflow: hidden;
}

.js .gallery__slide {
	position: absolute;
	inset: 0;
	opacity: 0;
	visibility: hidden;
	transition:
		opacity var(--pl-slow) var(--pl-ease-standard),
		visibility var(--pl-slow);
}

.js .gallery__slide.is-active {
	position: relative;
	opacity: 1;
	visibility: visible;
}

.gallery__placeholder {
	display: flex;
	align-items: center;
	justify-content: center;
	block-size: 100%;
	color: var(--pl-text-disabled);
}


/* Hover zoom -------------------------------------------------------------- */

/*
 * The full-size image is painted as a background layer on top of the <img>
 * and revealed on hover, with its position following the pointer. Scaling the
 * <img> itself would resample the already-downscaled 720px file and look
 * soft; this samples the original.
 */
.gallery__slide::after {
	content: "";
	position: absolute;
	inset: 0;
	background-image: var(--pl-zoom-image);
	background-repeat: no-repeat;
	background-size: 190%;
	background-position: var(--pl-zoom-x, 50%) var(--pl-zoom-y, 50%);
	opacity: 0;
	transition: opacity var(--pl-base) var(--pl-ease-standard);
	pointer-events: none;
}

.gallery.is-zooming .gallery__slide.is-active::after {
	opacity: 1;
}

/* Zoom is a pointer affordance; without a pointer it is dead weight. */
@media (hover: none), (pointer: coarse) {
	.gallery__slide::after { content: none; }
}

@media (prefers-reduced-motion: reduce) {
	.gallery__slide::after { transition: none; }
}


/* Stage controls ---------------------------------------------------------- */

.gallery__expand,
.gallery__nav {
	position: absolute;
	z-index: 2;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 44px;
	block-size: 44px;
	border: 1px solid rgb(255 255 255 / 45%);
	border-radius: var(--pl-radius-pill);
	color: var(--pl-ink);
	/*
	 * Glassmorphism earns its place here and nowhere else on the page: the
	 * control sits directly on the photograph, and a solid chip would hide
	 * part of the product. The white tint keeps contrast on dark images.
	 */
	background-color: rgb(255 255 255 / 62%);
	/* Prefixed for Safari < 18 — see components/modals.css. */
	-webkit-backdrop-filter: blur(10px) saturate(140%);
	backdrop-filter: blur(10px) saturate(140%);
	-webkit-backdrop-filter: blur(10px) saturate(140%);
	box-shadow: var(--pl-shadow-sm);
	transition:
		background-color var(--pl-fast) var(--pl-ease-standard),
		opacity var(--pl-base) var(--pl-ease-standard),
		transform var(--pl-fast) var(--pl-ease-out);
}

/* No backdrop-filter support: fall back to an opaque chip, never a smear. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
	.gallery__expand,
	.gallery__nav {
		background-color: rgb(255 255 255 / 92%);
	}
}

.gallery__expand:hover,
.gallery__nav:hover {
	background-color: rgb(255 255 255 / 88%);
	transform: scale(1.04);
}

.gallery__expand:active,
.gallery__nav:active { transform: scale(0.97); }

.gallery__expand {
	inset-block-start: var(--pl-space-3);
	inset-inline-end: var(--pl-space-3);
}

.gallery__nav {
	inset-block-start: 50%;
	margin-block-start: -22px;
}

.gallery__nav--prev { inset-inline-start: var(--pl-space-3); }
.gallery__nav--next { inset-inline-end: var(--pl-space-3); }

[dir="rtl"] .gallery__nav svg { transform: scaleX(-1); }

/*
 * On a precise pointer the arrows stay out of the way until the gallery is
 * hovered. On touch there is no hover, so they must always be visible —
 * hence the opacity is only reduced inside the hover query.
 */
@media (hover: hover) and (pointer: fine) {
	.gallery__nav { opacity: 0; }

	.gallery__stage:hover .gallery__nav,
	.gallery__nav:focus-visible { opacity: 1; }
}

.gallery__counter {
	position: absolute;
	inset-block-end: var(--pl-space-3);
	inset-inline-start: var(--pl-space-3);
	z-index: 2;
	margin: 0;
	padding: var(--pl-space-1) var(--pl-space-3);
	background-color: rgb(20 18 15 / 62%);
	backdrop-filter: blur(8px);
	-webkit-backdrop-filter: blur(8px);
	border-radius: var(--pl-radius-pill);
	color: var(--pl-text-inverse);
	font-size: var(--pl-micro);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.04em;
}

.gallery__sold {
	position: absolute;
	inset: 0;
	z-index: 2;
	display: flex;
	align-items: center;
	justify-content: center;
	pointer-events: none;
}

.gallery--empty .gallery__stage { border-style: dashed; }


/* Thumbnail rail ---------------------------------------------------------- */

.gallery__thumbs {
	display: flex;
	gap: var(--pl-space-2);
	overflow-x: auto;
	overscroll-behavior-inline: contain;
	scrollbar-width: none;
	padding-block-end: var(--pl-space-1);
}

.gallery__thumbs::-webkit-scrollbar { display: none; }

.gallery__thumb {
	position: relative;
	flex: 0 0 auto;
	inline-size: 72px;
	block-size: 72px;
	padding: 0;
	background: none;
	border: 1px solid var(--pl-line-soft);
	border-radius: var(--pl-radius);
	overflow: hidden;
	opacity: 0.65;
	transition:
		opacity var(--pl-fast) var(--pl-ease-standard),
		border-color var(--pl-fast) var(--pl-ease-standard),
		transform var(--pl-fast) var(--pl-ease-out);
}

.gallery__thumb:hover {
	opacity: 1;
	transform: translateY(-2px);
}

.gallery__thumb.is-active {
	opacity: 1;
	border-color: var(--pl-primary);
	box-shadow: 0 0 0 1px var(--pl-primary);
}

.gallery__thumb-image {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
}

@media (min-width: 768px) {
	.gallery__thumb {
		inline-size: 84px;
		block-size: 84px;
	}
}


/* ==========================================================================
   3. Lightbox
   ========================================================================== */

.lightbox {
	position: fixed;
	inset: 0;
	z-index: var(--pl-z-overlay);
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--pl-gutter);
	opacity: 0;
	transition: opacity var(--pl-base) var(--pl-ease-standard);
}

.lightbox.is-open { opacity: 1; }

.lightbox__backdrop {
	position: absolute;
	inset: 0;
	background-color: rgb(20 18 15 / 88%);
	backdrop-filter: blur(4px);
	-webkit-backdrop-filter: blur(4px);
}

.lightbox__inner {
	position: relative;
	z-index: 1;
	max-inline-size: min(100%, 1100px);
	max-block-size: 100%;
	transform: scale(0.97);
	transition: transform var(--pl-base) var(--pl-ease-out);
}

.lightbox.is-open .lightbox__inner { transform: scale(1); }

.lightbox__figure {
	margin: 0;
	display: flex;
	align-items: center;
	justify-content: center;
}

.lightbox__image {
	max-inline-size: 100%;
	/* `vh` first — see the note in woocommerce/filters.css. Without it the
	   lightbox image had no height cap at all on iOS 15.0–15.3. */
	max-block-size: calc(100vh - var(--pl-space-9));
	max-block-size: calc(100dvh - var(--pl-space-9));
	object-fit: contain;
	border-radius: var(--pl-radius);
}

/*
 * Anchored to the viewport, not to `.lightbox__inner`. Sitting it above the
 * inner block pushed it off the top of the screen on phones, where the
 * lightbox padding is smaller than the offset.
 */
.lightbox__close {
	position: fixed;
	inset-block-start: var(--pl-space-3);
	inset-inline-end: var(--pl-space-3);
	z-index: 2;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 44px;
	block-size: 44px;
	background: none;
	border: 0;
	border-radius: var(--pl-radius-pill);
	color: var(--pl-text-inverse);
	transition: background-color var(--pl-fast) var(--pl-ease-standard);
}

.lightbox__close:hover { background-color: rgb(255 255 255 / 16%); }


/* ==========================================================================
   4. Summary
   ========================================================================== */

.product__title {
	margin-block-end: var(--pl-space-3);
	font-size: var(--pl-h1);
}

.product__price {
	margin-block-end: var(--pl-space-4);
	font-family: var(--pl-font-display);
	font-size: var(--pl-price-lg);
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	color: var(--pl-text);
	line-height: var(--pl-leading-tight);
}

/* See the note on `.card__price del` — a sale's original price is content. */
.product__price del {
	margin-inline-end: var(--pl-space-3);
	color: var(--pl-text-muted);
	font-size: var(--pl-price);
	font-weight: 400;
}

.product__price ins {
	color: var(--pl-sale);
	text-decoration: none;
}

.product__stock {
	display: inline-flex;
	align-items: center;
	gap: var(--pl-space-2);
	margin-block-end: var(--pl-space-5);
	padding: var(--pl-space-2) var(--pl-space-4);
	border-radius: var(--pl-radius-pill);
	font-size: var(--pl-ui-sm);
	font-weight: 600;
}

.product__stock--in {
	background-color: var(--pl-peach-50);
	color: var(--pl-success);
}

.product__stock--out {
	background-color: var(--pl-clay-100);
	color: var(--pl-clay-600);
}

.product__excerpt {
	margin-block-end: var(--pl-space-6);
	color: var(--pl-text-secondary);
	font-size: var(--pl-body-lg);
	line-height: var(--pl-leading-body);
}


/* Variations -------------------------------------------------------------- */

.product__variations {
	display: grid;
	gap: var(--pl-space-5);
	margin-block-end: var(--pl-space-6);
	padding-block: var(--pl-space-5);
	border-block: 1px solid var(--pl-line-soft);
}

.product__variation-label {
	margin-block-end: var(--pl-space-3);
	font-family: var(--pl-font-body);
	font-size: var(--pl-micro);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: var(--pl-tracking-wide);
	color: var(--pl-text-muted);
}

.product__variation-options {
	display: flex;
	flex-wrap: wrap;
	gap: var(--pl-space-2);
	margin: 0;
	padding: 0;
	list-style: none;
}

/* Read-only until the add-to-cart form arrives in Phase 6. */
.chip--static { cursor: default; }

.chip--unavailable {
	color: var(--pl-text-disabled);
	border-color: var(--pl-line);
	background-color: var(--pl-bg-sunken);
	text-decoration: line-through;
}


/* Specs and meta ---------------------------------------------------------- */

.product__specs { margin-block-end: var(--pl-space-6); }

.product__specs-title,
.product__section-title {
	margin-block-end: var(--pl-space-4);
	font-family: var(--pl-font-body);
	font-size: var(--pl-ui-sm);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: var(--pl-tracking-wide);
	color: var(--pl-text-muted);
}

.spec-list {
	margin: 0;
	display: grid;
	gap: 0;
}

.spec-list__row {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
	gap: var(--pl-space-4);
	padding-block: var(--pl-space-3);
	border-block-end: 1px solid var(--pl-line-soft);
	font-size: var(--pl-body-sm);
}

.spec-list__row:last-child { border-block-end: 0; }

.spec-list__label {
	margin: 0;
	color: var(--pl-text-muted);
}

.spec-list__value {
	margin: 0;
	color: var(--pl-text);
	font-weight: 500;
}

.product__meta {
	display: grid;
	gap: var(--pl-space-2);
	margin: 0;
	padding-block-start: var(--pl-space-5);
	border-block-start: 1px solid var(--pl-line-soft);
	font-size: var(--pl-caption);
	color: var(--pl-text-muted);
}

.product__meta-row {
	display: flex;
	flex-wrap: wrap;
	gap: var(--pl-space-2);
}

.product__meta-row dt {
	margin: 0;
	font-weight: 600;
	color: var(--pl-text-secondary);
}

.product__meta-row dt::after { content: ":"; }

.product__meta-row dd { margin: 0; }

.product__meta-row a { color: inherit; text-decoration: underline; }
.product__meta-row a:hover { color: var(--pl-primary); }

.product__sku {
	font-family: var(--pl-font-mono);
	font-size: var(--pl-micro);
	letter-spacing: 0.04em;
	text-transform: uppercase;
}


/* ==========================================================================
   5. Description and related products
   ========================================================================== */

.product__description {
	margin-block-start: var(--pl-space-9);
	padding-block-start: var(--pl-space-8);
	border-block-start: 1px solid var(--pl-line-soft);
}

.related.products {
	margin-block-start: var(--pl-space-10);
	padding-inline: var(--pl-gutter);
	max-inline-size: var(--pl-container);
	margin-inline: auto;
}

.related.products > h2 {
	margin-block-end: var(--pl-space-6);
	font-size: var(--pl-h2);
}
