/* -------------------------------------------------------------------------
 * Product page layout.
 *
 * The theme is standalone: there is no parent container to neutralise, so the
 * former `.ast-*` / `#primary` override block is gone. The product template is
 * rendered inside `.lf-site-content--flush`, which already has no padding.
 *
 * Breadcrumbs: the bespoke template renders the only breadcrumb and
 * latin_flowers_remove_duplicate_breadcrumb() unhooks WooCommerce's default, so
 * the former `.lf-product-template .woocommerce-breadcrumb { display: none }`
 * blanket hide is gone.
 * ---------------------------------------------------------------------- */

.lf-product-page {
	/* One axis for the whole page: breadcrumbs, product, description, trust,
	 * reviews and related all share this width. */
	--lf-product-page-width: min(1600px, 86vw);
	--lf-product-column-gap: clamp(28px, 3.4vw, 60px);
	--lf-product-section-gap: clamp(40px, 5vw, 76px);
	/* Distance between stacked blocks; the single-column layout (<=1024px) tightens it. */
	--lf-product-row-gap: var(--lf-product-section-gap);
	/* Typography is WordPress/Elementor's call, not this template's: every
	 * heading/paragraph/label below relies on plain inheritance from here
	 * (no per-component font-family left in this file) instead of hardcoding
	 * Boska/Hanken Grotesk. */
	font-family: inherit;
	color: var(--lf-text);
}

.lf-product-page *,
.lf-product-page *::before,
.lf-product-page *::after {
	box-sizing: border-box;
}

.lf-product-page [hidden] {
	display: none !important;
}

.lf-product-page button,
.lf-product-page input,
.lf-product-page select,
.lf-product-page textarea {
	font: inherit;
}

.lf-product-layout {
	display: grid;
	/* Only the gallery/buy pair is two columns; everything else spans the full
	 * width via `grid-column: 1 / -1` and auto-flows into implicit rows, so a
	 * conditionally-absent block (no reviews) never leaves a phantom gap.
	 * Gallery carries the visual weight (~58%); the buy column keeps a 360px
	 * floor so it never feels cramped at 1024-1200px. */
	grid-template-columns: minmax(0, 1.4fr) minmax(360px, 1fr);
	column-gap: var(--lf-product-column-gap);
	row-gap: var(--lf-product-row-gap);
	width: var(--lf-product-page-width);
	margin: 0 auto;
	padding: 24px 0 88px;

	/* Single source of truth for "where the product visually begins".
	 * `.lf-product-layout__visuals` (the gallery's grid column) is a flexible
	 * track, wider than the gallery's own capped width on large screens -- the
	 * gallery centres itself inside it on purpose, for breathing room. That
	 * means the column's own left edge is NOT the photo's left edge. Both the
	 * gallery (below) and the breadcrumb read this same variable to centre
	 * themselves identically inside that column, so their rendered left edges
	 * always coincide, at any viewport -- no per-breakpoint pixel guess. */
	--lf-gallery-thumb-width: 80px;
	--lf-gallery-gap: 16px;
	--lf-gallery-image-width: 480px;
	--lf-gallery-total-width: calc(var(--lf-gallery-image-width) + var(--lf-gallery-thumb-width) + var(--lf-gallery-gap));
}

/* Products with a single image render no thumbnail column (see gallery.php):
 * the gallery's box is the image alone, so the shared width must match. */
.lf-product-layout--single-image {
	--lf-gallery-total-width: var(--lf-gallery-image-width);
}

/* min-width:0 on every child so long content can't blow out a track. Column
 * placement is assigned per block by its own class -- nothing here relies on
 * `> *` plus source order to win a specificity tie. */
.lf-product-layout > * {
	min-width: 0;
}

/* The only two-column row: gallery + testimonial carousel on the left, the buy
 * card on the right. */
.lf-product-layout__visuals {
	grid-column: 1 / 2;
	display: flex;
	flex-direction: column;
	gap: clamp(28px, 3vw, 44px);
}

.lf-product-layout__visuals > * {
	min-width: 0;
}

/* Every other block spans the full width and auto-flows into its own implicit
 * row. There is no grid-template-areas and no grid-template-rows, so a block
 * that is not rendered (a product with no reviews) reserves no row and leaves
 * no gap: `related` simply follows `benefits` with one section gap. */
.lf-product-layout__benefits,
.lf-product-layout__all-reviews,
.lf-product-layout__related {
	grid-column: 1 / -1;
}

/* The breadcrumb row is a single line of links, but it sits in the layout's
 * section rhythm (40-76px between blocks). Pull the content up so the gap below
 * it is a tight, constant distance at every width: the row-gap minus itself plus
 * the wanted spacing. */
.lf-product-layout__breadcrumbs {
	margin-bottom: calc(clamp(6px, 1vw, 14px) - var(--lf-product-row-gap));

	/* Confined to the gallery's own column (not spanning the buy card too) and
	 * centred inside it with the exact box the gallery itself uses
	 * (--lf-gallery-total-width, declared on .lf-product-layout above). The
	 * grid column is a flexible track, wider than the gallery on large
	 * screens; matching its centring math here -- instead of just spanning
	 * the track -- is what makes the two left edges coincide. `width: 100%`
	 * is deliberate, not redundant: a grid item with an `auto` margin on an
	 * axis is not stretched on that axis (the auto margin takes priority
	 * over the default stretch), so without it the box would shrink to fit
	 * its text instead of filling the column before `max-width` clamps it --
	 * `margin-inline: auto` would then have no free space left to centre it
	 * in and the breadcrumb would stay flush left. */
	grid-column: 1 / 2;
	width: 100%;
	max-width: var(--lf-gallery-total-width);
	margin-inline: auto;
}

/* .lf-product-page prefix (0,3,0): WooCommerce's `.woocommerce .woocommerce-breadcrumb`
 * (margin-bottom: 1em, its own font size and colour) is (0,2,0). */
.lf-product-page .lf-product-layout__breadcrumbs .woocommerce-breadcrumb {
	margin: 0;
	padding: 0;
	font-size: 14px;
	line-height: 1.5;
	color: var(--lf-green);
}

.lf-product-page .lf-product-layout__breadcrumbs .woocommerce-breadcrumb a {
	color: var(--lf-purple);
}

/* The buy card is a normal block in this first section -- NOT sticky, NOT
 * fixed. It is only as tall as its own content (align-self: start), so it
 * never stretches to match a taller left column. Following the scroll is the
 * job of the fixed bottom bars further down this file. */
.lf-product-layout__buy {
	grid-column: 2 / 3;
	align-self: start;
	display: flex;
	flex-direction: column;
}

.lf-product-header {
	padding-bottom: 20px;
	border-bottom: 1px solid var(--lf-border);
}

.lf-product-header .product-title {
	width: 100%;
	max-width: none;
	margin: 0 0 12px;
	font-size: clamp(30px, 2.6vw, 40px);
	font-weight: 500;
	line-height: 1.06;
	letter-spacing: -0.025em;
	color: var(--lf-green);
}

.lf-product-header__excerpt {
	font-size: 15px;
	line-height: 1.6;
	color: var(--lf-text-soft);
}

.lf-product-header__excerpt p {
	margin: 0 0 9px;
}

.lf-product-header__excerpt p:last-child {
	margin-bottom: 0;
}

.lf-product-rating {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 8px;
	margin-top: 14px;
	font-size: 14px;
}

.lf-product-rating__score {
	font-weight: 700;
	color: var(--lf-text);
}

/* wc_get_rating_html() renders a proportional .star-rating (role="img" +
 * aria-label), so the width reflects the real average -- no hardcoded glyphs. */
.lf-stars,
.lf-product-page .star-rating {
	color: var(--lf-purple);
}

.lf-product-rating .star-rating {
	margin: 0;
	font-size: 15px;
}

.lf-product-gallery {
	/* --lf-gallery-thumb-width / --lf-gallery-gap / --lf-gallery-image-width /
	 * --lf-gallery-total-width are declared on .lf-product-layout: the
	 * breadcrumb needs the same values to stay aligned, and a value declared
	 * only here would not be visible to that sibling. Width of the photo
	 * itself: the gallery (thumbnails + photo) is capped to it plus the
	 * thumbnail column and centred in its column, so a big screen gets air
	 * around the product instead of a huge picture. The cap is a plain length
	 * on the section, never derived from the photo: FlexSlider measures its
	 * viewport once at init and freezes that number on every slide, so the
	 * viewport must have a width that is already known when the gallery starts. */
	/* Only ever engages for very tall photos; the picture then stays whole. */
	--lf-gallery-max-height: min(80svh, 720px);
	max-width: var(--lf-gallery-total-width);
	margin-inline: auto;
}

@media (max-width: 1024px) {
	.lf-product-layout {
		--lf-gallery-image-width: 560px;
	}
}

/* Thumbnails move under the photo and the gallery (and breadcrumb) use the
 * whole width. */
@media (max-width: 767px) {
	.lf-product-layout,
	.lf-product-layout--single-image {
		--lf-gallery-total-width: none;
	}
}

.lf-product-gallery .woocommerce-product-gallery {
	display: flex;
	position: relative;
	opacity: 1 !important;
	float: none !important;
	/* Always the width of its (capped) section. It must never depend on its own
	 * content: FlexSlider measures the viewport once, at init, and writes that
	 * number in pixels on every slide -- a shrink-wrapped frame collapses that
	 * measurement. */
	width: 100% !important;
	gap: var(--lf-gallery-gap);
	margin: 0 !important;
}

/* Reuse WooCommerce's own lightbox/zoom trigger (injected by wc-single-product.js
 * when the wc-product-gallery-lightbox theme support is active) instead of
 * building a second magnifier. Just give it a real, styled, circular button. */
.lf-product-gallery .woocommerce-product-gallery__trigger {
	position: absolute;
	z-index: 3;
	top: 14px;
	left: 14px;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	border-radius: 999px;
	/* background-color, not the `background` shorthand: WooCommerce may put its
	 * own icon on this element as a background-image, which a shorthand here
	 * would silently clobber. No custom glyph is added either, for the same
	 * reason -- this only supplies the circular backdrop and position. */
	background-color: rgba(255, 255, 255, 0.92);
	background-position: center;
	background-repeat: no-repeat;
	box-shadow: 0 2px 10px rgba(23, 23, 44, 0.16);
	color: var(--lf-green);
	opacity: 0;
	transform: translateY(4px);
	transition: opacity 160ms ease, transform 160ms ease;
}

/* WooCommerce adds the trigger to the gallery root, not to the image frame, and
 * the thumbnails column sits to the left of the frame (same width + gap as the
 * flex layout above). Offset by exactly that column so the magnifier lands inside
 * the main image instead of over the thumbnails. Below 768px the thumbnails move
 * under the image and the corner is the image's own corner again (see there). */
.lf-product-gallery--multi .woocommerce-product-gallery__trigger {
	left: calc(var(--lf-gallery-thumb-width) + var(--lf-gallery-gap) + 14px);
}

.lf-product-gallery .flex-viewport {
	flex: 1;
	order: 2;
	position: relative;
	min-width: 0;
	overflow: hidden;
	border-radius: 22px;
}

.lf-product-gallery .woocommerce-product-gallery__wrapper,
.lf-product-gallery .woocommerce-product-gallery__image,
.lf-product-gallery .woocommerce-product-gallery__image a {
	display: block;
}

/* Single image: FlexSlider never initialises (WooCommerce skips it below two
 * images), so .flex-viewport is never created and .woocommerce-product-gallery__wrapper
 * is the direct flex child instead. Give it the same flex:1 the viewport would
 * have had, or the lone image is left sized by its own content and the rest of
 * the row sits empty next to it. */
.lf-product-gallery--single .woocommerce-product-gallery__wrapper {
	flex: 1;
	min-width: 0;
	overflow: hidden;
	border-radius: 22px;
}

.lf-product-gallery .woocommerce-product-gallery__image img {
	display: block;
	width: 100%;
	object-fit: contain;
	border-radius: 22px;
}

.lf-product-gallery .flex-control-thumbs {
	display: flex !important;
	visibility: visible !important;
	flex: 0 0 var(--lf-gallery-thumb-width);
	flex-direction: column;
	order: 1;
	gap: 10px;
	margin: 0 !important;
	padding: 0;
	overflow-y: auto;
	list-style: none;
}

.lf-product-gallery .flex-control-thumbs:empty {
	display: none !important;
}

.lf-product-gallery .flex-control-thumbs li {
	float: none !important;
	width: 100% !important;
}

.lf-product-gallery .flex-control-thumbs img {
	width: var(--lf-gallery-thumb-width);
	height: 88px;
	object-fit: cover;
	border: 2px solid transparent;
	border-radius: 11px;
	opacity: 0.62;
	cursor: pointer;
}

.lf-product-gallery .flex-control-thumbs img.flex-active {
	border-color: var(--lf-purple);
	opacity: 1;
}

/* Prev/next controls -- real buttons, reusing the single existing FlexSlider
 * instance (see relocateGalleryNav() in single-product.js). Rendered only when
 * there is more than one image. */
.lf-product-gallery__nav {
	position: absolute;
	inset: 0;
	z-index: 2;
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 0 12px;
	pointer-events: none;
}

.lf-product-gallery__arrow {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	flex: none;
	border: 0;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.92);
	box-shadow: 0 2px 10px rgba(23, 23, 44, 0.16);
	color: var(--lf-green);
	cursor: pointer;
	opacity: 0;
	transition: opacity 160ms ease, background-color 160ms ease;
	pointer-events: auto;
}

.lf-product-gallery__arrow:hover,
.lf-product-gallery__arrow:focus-visible {
	background: var(--lf-white);
}

.lf-product-gallery__arrow:focus-visible {
	outline: 3px solid var(--lf-purple);
	outline-offset: 2px;
}

/* Desktop: controls stay subtle until the shopper actually engages the image. */
@media (hover: hover) and (pointer: fine) {
	.lf-product-gallery .woocommerce-product-gallery:hover .woocommerce-product-gallery__trigger,
	.lf-product-gallery .woocommerce-product-gallery:focus-within .woocommerce-product-gallery__trigger {
		opacity: 1;
		transform: none;
	}

	.lf-product-gallery .woocommerce-product-gallery:hover .lf-product-gallery__arrow,
	.lf-product-gallery .woocommerce-product-gallery:focus-within .lf-product-gallery__arrow {
		opacity: 1;
	}
}

/* Touch/no-hover: controls stay usable but visually quieter, never invisible. */
@media (hover: none), (pointer: coarse) {
	.lf-product-gallery .woocommerce-product-gallery__trigger,
	.lf-product-gallery__arrow {
		opacity: 0.85;
		transform: none;
	}
}

/*
 * WooCommerce's own PhotoSwipe lightbox (wc-product-gallery-lightbox theme
 * support, enabled in inc/theme-setup.php) is not markup this theme builds:
 * wc-single-product.js appends its `.pswp` root straight to <body> when a
 * gallery image is activated, with PhotoSwipe v4's own default stylesheet
 * giving it `position: fixed; inset: 0; z-index: 1500`. That default already
 * covers the full viewport from a real `top: 0` -- the header was never
 * pushing it down. The bug was purely stacking order: `.lf-header` is
 * `position: sticky` with `z-index: var(--lf-z-header)` (9990, header.css),
 * which is its own stacking context sitting well above PhotoSwipe's 1500, so
 * the sticky header painted over the lightbox's top bar and close button
 * despite the lightbox being later in the DOM.
 *
 * The fix only touches the `.pswp` root's own z-index -- nothing inside it
 * (PhotoSwipe's internal stacking of its bg/scroll-wrap/ui/buttons is
 * untouched) and nothing about its layout. `--lf-z-lightbox` (header.css) is
 * deliberately defined above both `--lf-z-header` and `--lf-z-overlay`
 * (search/cart), so the whole fixed-layer system this theme uses now has one
 * coherent order: content < header < search/cart overlays < lightbox. The
 * fixed buy bars (900/999 below) were already under PhotoSwipe's own 1500,
 * so they needed no change to stay beneath it.
 *
 * RUNTIME PENDIENTE: 1500 is PhotoSwipe v4's own documented default and
 * WooCommerce does not override it, but this has not been confirmed by
 * reading `.pswp`'s computed z-index on real staging. It does not need to be
 * exact for this fix to hold -- --lf-z-lightbox only needs to stay above this
 * theme's own highest fixed layer, which it does regardless of PhotoSwipe's
 * precise number.
 */
.pswp {
	z-index: var(--lf-z-lightbox);
}

/* Main photo: natural proportions.
 *
 * Width comes from the viewport, height from the photo itself (`height: auto`),
 * so nothing is cropped, stretched or letterboxed and no background shows around
 * it. The viewport's height is whatever the current photo needs (FlexSlider's
 * smoothHeight copies the slide's height to it), so the arrows -- which live
 * inside the viewport -- are centred on the real photo. The max-height only
 * engages for exceptionally tall photos; object-fit: contain keeps those whole.
 *
 * The img selector is (0,4,1) on purpose: WooCommerce's
 * `.woocommerce div.product div.images img` (0,3,3) also sets width/height. */
.lf-product-page .lf-product-gallery .woocommerce-product-gallery .woocommerce-product-gallery__image img {
	width: 100%;
	height: auto;
	max-height: var(--lf-gallery-max-height);
	object-fit: contain;
}

/* Before FlexSlider initialises the slides are stacked in the bare wrapper: show
 * only the first frame so the gallery never flashes as a tall column. Once
 * initialised the wrapper lives inside .flex-viewport and this stops matching. */
.lf-product-page .lf-product-gallery--multi .woocommerce-product-gallery > .woocommerce-product-gallery__wrapper {
	flex: 1;
	min-width: 0;
	max-height: var(--lf-gallery-max-height);
	overflow: hidden;
}

/* Row layout (thumbnails beside the image): never taller than the image frame. */
@media (min-width: 768px) {
	.lf-product-gallery .flex-control-thumbs {
		max-height: var(--lf-gallery-max-height);
	}
}

.lf-product-page .lf-product-options {
	display: block;
	min-width: 0;
	margin: 0;
	padding: 22px 0 0;
	border: 0;
}

.lf-product-page .lf-form-title,
.lf-product-page h2.lf-form-title {
	display: block;
	width: 100%;
	max-width: none;
	margin: 0 0 12px;
	padding: 0;
	font-size: 20px;
	font-weight: 500;
	line-height: 1.2;
	letter-spacing: -0.02em;
	color: var(--lf-green);
	text-transform: none;
}

.lf-variation-cards {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 12px;
}

.lf-variation-cards--single {
	grid-template-columns: 1fr;
}

.lf-variation-card {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	align-items: center;
	gap: 6px;
	min-width: 0;
	min-height: 88px;
	padding: 12px;
	border: 1px solid var(--lf-border);
	border-radius: 14px;
	background: var(--lf-white);
	color: var(--lf-text);
	text-align: left;
	cursor: pointer;
	transition: border-color 160ms ease, box-shadow 160ms ease, background-color 160ms ease;
}

.woocommerce div.product .lf-variation-card:hover,
.woocommerce div.product .lf-variation-card:focus,
.woocommerce div.product .lf-variation-card:focus-visible,
.woocommerce div.product .lf-variation-card:active {
	border-color: var(--lf-purple);
	background: var(--lf-purple-soft) !important;
	color: var(--lf-text) !important;
	box-shadow: none;
	outline: 0;
}

.woocommerce div.product .lf-variation-card.is-selected,
.woocommerce div.product .lf-variation-card.is-selected:hover,
.woocommerce div.product .lf-variation-card.is-selected:focus,
.woocommerce div.product .lf-variation-card.is-selected:active {
	border-color: var(--lf-purple);
	background: var(--lf-purple-soft) !important;
	color: var(--lf-text) !important;
	box-shadow: 0 0 0 1px var(--lf-purple);
}

.lf-variation-card:disabled {
	opacity: 0.48;
	cursor: not-allowed;
}

.lf-variation-card__copy,
.lf-variation-card__heading {
	display: grid;
	min-width: 0;
	gap: 4px;
}

.lf-variation-card__copy strong {
	overflow-wrap: anywhere;
	font-size: 15px;
	line-height: 1.22;
}

.lf-variation-card__copy > span:last-child {
	font-weight: 700;
	color: var(--lf-green);
}

.lf-variation-card__pill {
	justify-self: start;
	padding: 3px 7px;
	border-radius: 999px;
	background: var(--lf-purple);
	color: var(--lf-white);
	font-size: 10px;
	font-weight: 700;
	line-height: 1.2;
}

/* The native WooCommerce cart form (simple.php / variable.php) is the real
 * purchase form now. Only the chrome the custom cards replace is hidden -- never
 * the form, never its submit button (the visible CTA). The quantity field is
 * hidden but keeps its WooCommerce-computed value (sold-individually / min). */
.lf-native-variations .variations,
.lf-native-variations .reset_variations,
.lf-native-variations .woocommerce-variation-price,
.lf-product-page form.cart .quantity {
	display: none !important;
}

.lf-native-variations .woocommerce-variation-add-to-cart {
	display: block;
}

/* A real choice the cards cannot represent (a single variation whose "Any"
 * attribute spans several product terms): keep the native <select> visible. */
.lf-native-variations--visible .variations {
	display: table !important;
	width: 100%;
	margin-bottom: 12px;
}

.lf-native-variations--visible .variations th,
.lf-native-variations--visible .variations td {
	padding: 6px 0;
	text-align: left;
	vertical-align: middle;
}

.lf-native-variations--visible .variations select {
	width: 100%;
	min-height: 44px;
	padding: 8px 12px;
	border: 1px solid var(--lf-border);
	border-radius: 10px;
	background: var(--lf-white);
}

.lf-product-page form.cart .single_add_to_cart_button {
	position: relative;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	min-height: 52px;
	margin-top: 20px;
	padding: 13px 24px;
	border: 1px solid var(--lf-green);
	border-radius: 999px;
	background: var(--lf-green);
	color: var(--lf-white);
	font-size: 17px;
	font-weight: 700;
	line-height: 1.2;
	text-align: center;
	cursor: pointer;
}

/* Hover / focus feedback only on a button that can actually be used: not
 * disabled, not "select an option" (WooCommerce only adds classes, not the
 * disabled attribute, to that state), not an unavailable variation, not while
 * the native POST is in flight. */
.lf-product-page form.cart:not(.is-submitting) .single_add_to_cart_button:not(:disabled, .disabled, .loading, .wc-variation-selection-needed, .wc-variation-is-unavailable, [aria-disabled="true"]):is(:hover, :focus-visible) {
	border-color: var(--lf-green-dark);
	background: var(--lf-green-dark);
}

/* The focus outline stays on every state: keyboard users must still see where
 * the focus is, even on a button that is currently unavailable. */
.lf-product-page form.cart .single_add_to_cart_button:focus-visible {
	outline: 3px solid var(--lf-purple);
	outline-offset: 3px;
}

/* Gradient border that slides horizontally on hover / keyboard focus.
 *
 * A 2px ring drawn by a pseudo-element: the mask keeps only the padding area
 * (content-box XOR border-box), so the button's own box, size, radius and text
 * are untouched -- nothing here affects layout. The gradient repeats its three
 * theme colours twice over a 200%-wide background, so moving the background
 * by exactly one element width loops seamlessly. Hidden (opacity 0) at rest,
 * and only ever shown on a usable button (same guard as above). */
.lf-product-page form.cart .single_add_to_cart_button::before {
	content: "";
	position: absolute;
	inset: -1px;
	padding: 2px;
	border-radius: inherit;
	background: linear-gradient(
		90deg,
		var(--lf-green),
		var(--lf-purple),
		var(--lf-yellow),
		var(--lf-green),
		var(--lf-purple),
		var(--lf-yellow),
		var(--lf-green)
	);
	background-size: 200% 100%;
	-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
	-webkit-mask-composite: xor;
	mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
	mask-composite: exclude;
	opacity: 0;
	pointer-events: none;
	transition: opacity 220ms ease;
}

.lf-product-page form.cart:not(.is-submitting) .single_add_to_cart_button:not(:disabled, .disabled, .loading, .wc-variation-selection-needed, .wc-variation-is-unavailable, [aria-disabled="true"]):focus-visible::before {
	opacity: 1;
}

@media (hover: hover) {
	.lf-product-page form.cart:not(.is-submitting) .single_add_to_cart_button:not(:disabled, .disabled, .loading, .wc-variation-selection-needed, .wc-variation-is-unavailable, [aria-disabled="true"]):hover::before {
		opacity: 1;
	}
}

@media (prefers-reduced-motion: no-preference) {
	.lf-product-page form.cart:not(.is-submitting) .single_add_to_cart_button:not(:disabled, .disabled, .loading, .wc-variation-selection-needed, .wc-variation-is-unavailable, [aria-disabled="true"]):focus-visible::before,
	.lf-product-page form.cart:not(.is-submitting) .single_add_to_cart_button:not(:disabled, .disabled, .loading, .wc-variation-selection-needed, .wc-variation-is-unavailable, [aria-disabled="true"]):hover::before {
		animation: lf-cta-border-flow 3s linear infinite;
	}
}

@keyframes lf-cta-border-flow {
	from {
		background-position: 0% 0;
	}

	to {
		background-position: 100% 0;
	}
}

.lf-product-page form.cart .single_add_to_cart_button:disabled,
.lf-product-page form.cart .single_add_to_cart_button.disabled,
.lf-product-page form.cart .single_add_to_cart_button.wc-variation-selection-needed {
	opacity: 0.55;
	cursor: not-allowed;
}

/* Discreet feedback while the native POST is in flight (single-product.js sets
 * .is-submitting + aria-busy on the first submit and clears it on pageshow). */
.lf-product-page form.cart.is-submitting .single_add_to_cart_button {
	opacity: 0.7;
	cursor: progress;
}

.lf-product-price {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: 6px 10px;
	margin: 0 0 12px;
	font-size: 30px;
	font-weight: 500;
	color: var(--lf-green);
}

/* Variable price ranges are wrapped by WooCommerce in an inner .price. */
.lf-product-price .price {
	display: inline-flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: 6px 10px;
}

/* Sale price first and prominent; the struck regular price second and quieter.
 * This only reorders WooCommerce's own <ins>/<del> markup -- no price is
 * recomputed here. A plain (non-sale) price has neither element and is
 * unaffected; a range has only text nodes and stays in source order. */
.lf-product-price ins {
	order: 0;
	text-decoration: none;
	font-weight: 500;
	color: var(--lf-green);
}

.lf-product-price del {
	order: 1;
	color: var(--lf-text-soft);
	font-weight: 400;
	font-size: 0.68em;
}

.lf-product-price del .woocommerce-Price-amount {
	text-decoration: line-through;
}

/* Klarna / payment-method messaging slot: empty until Fase 4, and while empty it
 * must not reserve vertical space. Fase 4's official markup makes it visible on
 * its own -- no layout rework needed then. */
.lf-payment-messaging {
	margin: 4px 0 16px;
}

.lf-payment-messaging:empty {
	display: none;
}

/* The custom checkout delivery form (fieldsets, invoice fields, address
 * autocomplete, phone input) was retired entirely: WooCommerce's own checkout
 * owns all of that now. The .lf-field* / .lf-field-grid / .lf-checkbox* /
 * .lf-invoice-fields* / .lf-address-suggestions* / .iti* rules that used to
 * live here were already dead after Fase 2 and stay removed. */

.lf-all-reviews__filters button:focus-visible,
.lf-review-pagination button:focus-visible,
.lf-all-reviews__sort select:focus-visible,
.lf-all-reviews__grid:focus-visible,
.lf-related-card__cta:focus-visible {
	outline: 3px solid var(--lf-purple);
	outline-offset: 2px;
}

.lf-button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 52px;
	padding: 13px 24px;
	border: 1px solid var(--lf-green);
	border-radius: 999px;
	background: var(--lf-green);
	color: var(--lf-white);
	font-weight: 700;
	cursor: pointer;
}

.lf-button:hover,
.lf-button:focus-visible {
	border-color: var(--lf-green-dark);
	background: var(--lf-green-dark);
	outline: 3px solid rgba(0, 78, 50, 0.16);
	outline-offset: 2px;
}

.lf-button:disabled {
	border-color: var(--lf-border);
	background: var(--lf-border);
	color: var(--lf-text-soft);
	cursor: not-allowed;
}

.lf-button--primary {
	width: 100%;
	margin-top: 27px;
	font-size: 17px;
}

.lf-section-heading {
	display: flex;
	align-items: end;
	justify-content: space-between;
	gap: 20px;
	margin-bottom: 14px;
}

.lf-section-heading .section-title,
.lf-related > .section-title {
	margin: 0;
	font-size: clamp(28px, 2.3vw, 38px);
	font-weight: 500;
	line-height: 1.1;
	letter-spacing: -0.025em;
	color: var(--lf-green);
}

.lf-reviews__track {
	display: flex;
	gap: 16px;
	padding: 6px 4px 10px;
	overflow-x: auto;
	overflow-y: hidden;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
	overscroll-behavior-x: contain;
	-webkit-overflow-scrolling: touch;
}

.lf-reviews__track::-webkit-scrollbar {
	display: none;
}

.lf-reviews__track:focus-visible {
	border-radius: 22px;
	outline: 3px solid var(--lf-purple);
	outline-offset: 4px;
}

.lf-reviews__track.is-dragging {
	cursor: grabbing;
	scroll-snap-type: none;
}

.lf-reviews__track.is-dragging .lf-review-card {
	user-select: none;
}

.lf-review-card {
	display: flex;
	flex: 0 0 min(100%, 360px);
	flex-direction: column;
	min-width: 0;
	min-height: 200px;
	padding: clamp(20px, 2vw, 28px);
	border: 1px solid rgba(23, 23, 44, 0.09);
	border-radius: 18px;
	background: #f5eff9;
	scroll-snap-align: center;
}

.lf-reviews__track .lf-review-card:nth-child(1) {
	transform: rotate(-1.4deg);
	background: #f5eff9;
}

.lf-reviews__track .lf-review-card:nth-child(2) {
	transform: rotate(1.2deg);
	background: #eef6f0;
}

.lf-reviews__track .lf-review-card:nth-child(3) {
	transform: rotate(-0.5deg);
	background: #fff8d9;
}

.lf-reviews__track .lf-review-card:nth-child(4) {
	transform: rotate(1deg);
	background: #f7f0ea;
}

.lf-reviews__track .lf-review-card:nth-child(5) {
	transform: rotate(-1.1deg);
	background: #eef3f9;
}

.lf-all-reviews__grid .lf-review-card:nth-child(4n + 1) { background: #f5eff9; }
.lf-all-reviews__grid .lf-review-card:nth-child(4n + 2) { background: #eef6f0; }
.lf-all-reviews__grid .lf-review-card:nth-child(4n + 3) { background: #fff8d9; }
.lf-all-reviews__grid .lf-review-card:nth-child(4n + 4) { background: #f7f0ea; }

.lf-review-card__stars {
	margin-bottom: 12px;
	color: #e0a92b;
	font-size: 17px;
	letter-spacing: 3px;
}

.lf-review-card__quote {
	margin: 0;
	font-size: clamp(17px, 1.15vw, 20px);
	font-style: normal;
	line-height: 1.4;
	letter-spacing: -0.015em;
	color: var(--lf-text);
}

.lf-review-card__quote p {
	margin: 0;
	font: inherit;
	color: inherit;
	overflow-wrap: anywhere;
}

.lf-review-card__quote p:first-child::before { content: '“'; }
.lf-review-card__quote p:last-child::after { content: '”'; }

.lf-review-card__quote p + p {
	margin-top: 0.6em;
}

.lf-review-card__meta {
	margin: auto 0 0;
	padding-top: 16px;
	font-size: 13px;
	line-height: 1.4;
	color: #5f5f6b;
}

.lf-review-card__meta strong {
	color: var(--lf-text);
}

.lf-all-reviews > .section-title,
.lf-all-reviews__heading .section-title {
	margin: 0;
	font-size: clamp(28px, 2.5vw, 38px);
	font-weight: 500;
	color: var(--lf-green);
}

.lf-all-reviews__heading {
	display: flex;
	align-items: end;
	justify-content: space-between;
	gap: 20px;
	margin-bottom: 16px;
}

.lf-all-reviews__sort {
	display: grid;
	gap: 5px;
	font-size: 13px;
	font-weight: 700;
}

.lf-all-reviews__sort select {
	min-height: 44px;
	padding: 8px 38px 8px 12px;
	border: 1px solid var(--lf-border);
	border-radius: 10px;
	background: var(--lf-white);
}

.lf-all-reviews__filters {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin-bottom: 14px;
}

.lf-all-reviews__filters button,
.lf-review-pagination button {
	min-height: 40px;
	padding: 8px 14px;
	border: 1px solid var(--lf-border);
	border-radius: 999px;
	background: var(--lf-white);
	color: var(--lf-text);
	cursor: pointer;
}

.lf-all-reviews__filters button[aria-pressed="true"],
.lf-review-pagination button[aria-current="page"] {
	border-color: var(--lf-purple);
	background: var(--lf-purple);
	color: var(--lf-white);
}

.lf-all-reviews__status {
	min-height: 20px;
	margin: 0 0 10px;
	font-size: 13px;
	color: var(--lf-text-soft);
}

.lf-all-reviews__grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 16px;
	padding: 4px;
}

.lf-all-reviews__grid:focus {
	border-radius: 20px;
	outline: 3px solid var(--lf-purple);
	outline-offset: 4px;
}

.lf-all-reviews__grid .lf-review-card {
	width: auto;
	min-width: 0;
}

.lf-all-reviews__grid .lf-review-card:nth-child(4n + 1) { transform: rotate(-1.1deg); }
.lf-all-reviews__grid .lf-review-card:nth-child(4n + 2) { transform: rotate(0.9deg); }
.lf-all-reviews__grid .lf-review-card:nth-child(4n + 3) { transform: rotate(-0.5deg); }
.lf-all-reviews__grid .lf-review-card:nth-child(4n + 4) { transform: rotate(1.2deg); }

.lf-product-page .lf-all-reviews__filter-title {
	margin: 0 0 8px;
	font-size: 13px;
	font-weight: 700;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: #5f5f6b;
}

.lf-all-reviews__empty {
	padding: 28px;
	border: 1px solid var(--lf-border);
	border-radius: 14px;
	background: var(--lf-green-soft);
	color: var(--lf-text-soft);
	text-align: center;
}

.lf-review-pagination {
	display: flex;
	align-items: center;
	justify-content: center;
	flex-wrap: wrap;
	gap: 7px;
	margin-top: 18px;
}

.lf-review-pagination button:disabled {
	opacity: 0.45;
	cursor: not-allowed;
}

.lf-carousel-controls {
	display: flex;
	flex: 0 0 auto;
	gap: 8px;
}

.lf-carousel-controls button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border: 1px solid var(--lf-border);
	border-radius: 50%;
	background: var(--lf-white);
	color: var(--lf-purple);
	font-size: 17px;
	line-height: 1;
	cursor: pointer;
	transition: border-color 160ms ease, background-color 160ms ease;
}

.lf-carousel-controls button:hover:not(:disabled) {
	border-color: var(--lf-purple);
	background: var(--lf-purple-soft);
}

.lf-carousel-controls button:focus-visible {
	border-color: var(--lf-purple);
	outline: 3px solid rgba(76, 41, 145, 0.35);
	outline-offset: 2px;
}

.lf-carousel-controls button:disabled {
	opacity: 0.4;
	cursor: not-allowed;
}

.lf-trust {
	display: flex;
	gap: 0;
	border: 1px solid var(--lf-border);
	border-radius: 14px;
	overflow: hidden;
	background: var(--lf-white);
	margin: 32px 0;
	font-family: inherit;
}

.lf-trust__item {
	flex: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	padding: 28px 20px;
	gap: 14px;
	border-right: 1px solid var(--lf-border);
	transition: background 0.2s, transform 240ms ease;
}

.lf-trust__item:last-child {
	border-right: none;
}

.lf-trust__item:hover {
	background: var(--lf-green-soft);
}

.lf-trust__icon {
	width: 52px;
	height: 52px;
	flex-shrink: 0;
	transition: transform 240ms ease;
}

.lf-trust__icon svg {
	display: block;
	width: 100%;
	height: 100%;
}

.lf-trust__text {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.lf-trust__text strong {
	font-size: 14px;
	font-weight: 700;
	color: var(--lf-text);
	line-height: 1.3;
}

.lf-trust__text span {
	font-size: 13px;
	color: var(--lf-text-soft);
	line-height: 1.6;
}

/* Reveal-on-scroll (setupTrustReveal() in single-product.js toggles these two
 * classes on the [data-lf-trust] section; the animation itself is unrelated
 * to the trust content/visual replaced above). */
@keyframes lfTrustReveal {
	from {
		opacity: 0;
		transform: translateY(12px);
	}
	to {
		opacity: 1;
		transform: translateY(0);
	}
}

.lf-trust.is-reveal-pending .lf-trust__item {
	opacity: 0;
}

.lf-trust.is-revealed .lf-trust__item {
	opacity: 1;
	animation: lfTrustReveal 460ms ease both 1;
}

.lf-trust.is-revealed .lf-trust__item:nth-child(1) { animation-delay: 0ms; }
.lf-trust.is-revealed .lf-trust__item:nth-child(2) { animation-delay: 90ms; }
.lf-trust.is-revealed .lf-trust__item:nth-child(3) { animation-delay: 180ms; }
.lf-trust.is-revealed .lf-trust__item:nth-child(4) { animation-delay: 270ms; }

@media (hover: hover) {
	.lf-trust__item:hover .lf-trust__icon {
		transform: translateY(-2px) rotate(-4deg);
	}
}

@media (max-width: 768px) {
	.lf-trust {
		flex-direction: column;
		border-radius: 12px;
	}

	.lf-trust__item {
		flex-direction: row;
		text-align: left;
		border-right: none;
		border-bottom: 1px solid var(--lf-border);
		padding: 18px 16px;
		gap: 14px;
		align-items: flex-start;
	}

	.lf-trust__item:last-child {
		border-bottom: none;
	}

	.lf-trust__icon {
		width: 40px;
		height: 40px;
		flex-shrink: 0;
		margin-top: 2px;
	}
}

.lf-related > .section-title {
	margin-bottom: 22px;
}

/* Homogeneous grid: four equal cards on desktop, two-up below 1100px. Each photo
 * sits in a portrait mat (4:5, the shape of most bouquets) and is fitted inside
 * it with object-fit: contain -- vertical bouquets fill the frame, squares and
 * landscapes get a little more of the soft-green mat, nothing is ever cropped.
 * No gradient or overlay touches the photograph: name, price and CTA live on the
 * white body of the card. */
.lf-related__grid {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: clamp(14px, 1.6vw, 24px);
}

.lf-related-card {
	position: relative;
	display: flex;
	min-width: 0;
	overflow: hidden;
	flex-direction: column;
	border: 1px solid var(--lf-border);
	border-radius: 16px;
	background: var(--lf-white);
	isolation: isolate;
}

.lf-related-card__media {
	position: relative;
	z-index: 0;
	aspect-ratio: 4 / 5;
	overflow: hidden;
	background: var(--lf-green-soft);
}

/* .lf-related-card prefix (0,2,1): WooCommerce's `.woocommerce img { height: auto }`
 * is (0,1,1) and would otherwise win. */
.lf-related-card .lf-related-card__media img {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: contain;
	transition: transform 320ms ease;
}

.lf-related-card__pill {
	position: absolute;
	z-index: 2;
	top: 12px;
	left: 12px;
	padding: 5px 10px;
	border-radius: 999px;
	background: var(--lf-white);
	color: var(--lf-purple);
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 0.01em;
	box-shadow: 0 1px 6px rgba(23, 23, 44, 0.12);
}

.lf-related-card__content {
	position: relative;
	z-index: 1;
	display: flex;
	flex: 1;
	flex-direction: column;
	gap: 6px;
	min-width: 0;
	padding: 14px 16px 16px;
}

.woocommerce div.product .lf-related-card__title {
	display: -webkit-box;
	min-width: 0;
	/* Two lines reserved: every price and CTA lines up across the row. */
	min-height: 2.4em;
	margin: 0;
	font-size: 18px;
	font-weight: 500;
	line-height: 1.2;
	letter-spacing: -0.025em;
	color: var(--lf-text);
	overflow-wrap: anywhere;
	overflow: hidden;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
}

.woocommerce div.product .lf-related-card__price {
	display: block;
	margin: 0 0 8px;
	font-size: 16px;
	font-weight: 700;
	line-height: 1.25;
	color: var(--lf-green);
}

.woocommerce div.product .lf-related-card__price del,
.woocommerce div.product .lf-related-card__price .woocommerce-Price-amount {
	color: inherit;
}

.woocommerce div.product .lf-related-card__cta {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 42px;
	/* Pinned to the bottom of the card so every CTA lines up across the row. */
	margin-top: auto;
	padding: 9px 18px;
	border: 1px solid var(--lf-green);
	border-radius: 999px;
	background: var(--lf-green);
	color: var(--lf-white);
	font-size: 14px;
	font-weight: 700;
	line-height: 1.2;
	text-decoration: none;
	transition: transform 200ms ease, background-color 200ms ease, border-color 200ms ease;
}

@media (hover: hover) {
	.lf-related-card:hover .lf-related-card__media img {
		transform: scale(1.03);
	}

	.woocommerce div.product .lf-related-card__cta:hover,
	.woocommerce div.product .lf-related-card__cta:focus-visible {
		background: var(--lf-green-dark);
		border-color: var(--lf-green-dark);
		color: var(--lf-white);
		transform: translateY(-2px);
	}
}

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

/* Native <details> disclosure, open by default. Keyboard + AT behaviour is the
 * browser's; we only swap the marker for a drawn +/- indicator. */
.lf-about {
	padding: clamp(24px, 2.4vw, 34px);
	border-radius: 20px;
	background: var(--lf-purple-soft);
}

.lf-about__summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	cursor: pointer;
	list-style: none;
}

/* Remove the native disclosure triangle in every engine. */
.lf-about__summary::-webkit-details-marker {
	display: none;
}

.lf-about__summary::marker {
	content: "";
}

.lf-about__summary:focus-visible {
	outline: 3px solid var(--lf-purple);
	outline-offset: 4px;
	border-radius: 6px;
}

.lf-about__title {
	margin: 0;
	font-size: clamp(24px, 2vw, 32px);
	font-weight: 500;
	line-height: 1.1;
	letter-spacing: -0.025em;
	color: var(--lf-green);
}

/* Drawn "+" that becomes "−" when the section is open. No icon font. */
.lf-about__icon {
	position: relative;
	flex: none;
	width: 22px;
	height: 22px;
	color: var(--lf-green);
}

.lf-about__icon::before,
.lf-about__icon::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	background: currentColor;
	transform: translate(-50%, -50%);
	transition: opacity 160ms ease;
}

.lf-about__icon::before {
	width: 16px;
	height: 2px;
}

.lf-about__icon::after {
	width: 2px;
	height: 16px;
}

.lf-about[open] .lf-about__icon::after {
	opacity: 0;
}

.lf-about__content {
	margin-top: 18px;
	font-size: 16px;
	line-height: 1.72;
}

.lf-about__content h2,
.lf-about__content h3,
.lf-about__content h4 {
	margin: 1.25em 0 0.5em;
	font-weight: 500;
	line-height: 1.2;
}

.lf-about__content h2 { font-size: 30px; }
.lf-about__content h3 { font-size: 25px; }
.lf-about__content h4 { font-size: 21px; }
.lf-about__content p { margin: 0 0 1em; font-size: 16px; }

/* Inside the buy card the description reads as its own section under the CTA:
 * a hairline divider instead of a tinted box, and a smaller title so it does
 * not compete with the H1. */
.lf-product-layout__about {
	margin-top: 22px;
}

.lf-product-layout__about .lf-about {
	padding: 20px 0 0;
	border-top: 1px solid var(--lf-border);
	border-radius: 0;
	background: transparent;
}

.lf-product-layout__about .lf-about__title {
	font-size: clamp(18px, 1.4vw, 22px);
}

/* Fixed bottom purchase bars. Mutually exclusive by breakpoint (desktop
 * >1024px / mobile <=1024px, see the media queries below) -- never both at
 * once. Extra bottom room so a visible bar never covers the footer. */
body.single-product {
	padding-bottom: 96px;
}

.lf-mobile-buy-bar,
.lf-desktop-buy-bar {
	display: none;
}

/* Desktop: fixed at the bottom, hidden while the canonical CTA
 * (form.cart .single_add_to_cart_button) is on screen. The same
 * IntersectionObserver that drives the mobile bar toggles
 * body.lf-primary-cta-visible for this one too (see single-product.js). It is
 * a proxy only -- no <form> here. `display: none` (not a transform) so the
 * hidden bar's button is never keyboard-focusable while invisible -- the same
 * pattern the mobile bar already uses. */
@media (min-width: 1025px) {
	.lf-desktop-buy-bar {
		display: flex;
		position: fixed;
		z-index: 900;
		left: 0;
		right: 0;
		bottom: 0;
		border-top: 1px solid var(--lf-border);
		background: rgba(255, 255, 255, 0.97);
		box-shadow: 0 -8px 30px rgba(23, 23, 44, 0.1);
		backdrop-filter: blur(12px);
	}

	body.lf-primary-cta-visible .lf-desktop-buy-bar {
		display: none;
	}

	.lf-desktop-buy-bar__inner {
		display: flex;
		align-items: center;
		gap: 20px;
		width: var(--lf-product-page-width);
		max-width: 100%;
		margin: 0 auto;
		padding: 10px var(--lf-gutter, 24px);
	}

	.lf-desktop-buy-bar__product {
		display: flex;
		align-items: center;
		gap: 12px;
		min-width: 0;
		flex: 1 1 auto;
	}

	.lf-buy-bar__img {
		width: 46px;
		height: 46px;
		flex: none;
		object-fit: cover;
		border-radius: 10px;
	}

	.lf-desktop-buy-bar__text {
		display: flex;
		flex-direction: column;
		min-width: 0;
	}

	.lf-desktop-buy-bar__title {
		font-size: 16px;
		font-weight: 500;
		color: var(--lf-green);
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
	}

	.lf-desktop-buy-bar__meta {
		font-size: 12px;
		color: var(--lf-text-soft);
	}

	.lf-desktop-buy-bar__price {
		flex: none;
		font-size: 20px;
		font-weight: 500;
		color: var(--lf-green);
	}

	.lf-desktop-buy-bar__price del {
		margin-right: 8px;
		font-size: 0.72em;
		color: var(--lf-text-soft);
	}

	.lf-desktop-buy-bar__price ins {
		text-decoration: none;
	}

	.lf-desktop-buy-bar .lf-button--sticky {
		flex: none;
		min-width: 220px;
		min-height: 48px;
	}

	.lf-desktop-buy-bar .lf-button--sticky.is-disabled,
	.lf-desktop-buy-bar .lf-button--sticky:disabled {
		border-color: var(--lf-border);
		background: var(--lf-border);
		color: var(--lf-text-soft);
		cursor: not-allowed;
	}
}

@media (max-width: 1200px) {
	.lf-product-page {
		--lf-product-column-gap: clamp(22px, 3vw, 40px);
	}
}

/* Below 1024px the two columns collapse to one stack. The layout switches to
 * flex so DOM order == visual order == tab order. The desktop fixed bar stays
 * off (see its own >1024px query above); the mobile fixed bar takes over. */
@media (max-width: 1024px) {
	.lf-product-page {
		--lf-product-row-gap: clamp(28px, 4.5vw, 48px);
	}

	.lf-product-layout {
		display: flex;
		flex-direction: column;
		grid-template-columns: none;
		gap: var(--lf-product-row-gap);
	}

	.lf-product-layout__visuals,
	.lf-product-layout__buy {
		min-width: 0;
	}

	.lf-product-layout__buy {
		align-self: stretch;
	}

	.lf-mobile-buy-bar {
		display: flex;
		position: fixed;
		z-index: 999;
		left: 0;
		right: 0;
		bottom: 0;
		align-items: center;
		justify-content: space-between;
		gap: 14px;
		padding: 11px max(16px, env(safe-area-inset-right)) calc(11px + env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
		border-top: 1px solid var(--lf-border);
		background: rgba(255, 255, 255, 0.97);
		box-shadow: 0 -8px 30px rgba(23, 23, 44, 0.1);
		backdrop-filter: blur(12px);
	}

	body.lf-primary-cta-visible .lf-mobile-buy-bar {
		display: none;
	}

	.lf-mobile-buy-bar__price {
		display: grid;
		font-size: 12px;
		color: var(--lf-text-soft);
	}

	.lf-mobile-buy-bar__price strong {
		font-size: 19px;
		line-height: 1.15;
		color: var(--lf-green);
	}

	.lf-mobile-buy-bar__price del {
		display: none;
	}

	.lf-mobile-buy-bar .lf-button--sticky {
		min-height: 46px;
		padding: 10px 20px;
	}

	/* Mirrors the canonical CTA: when WooCommerce disables its button (no
	 * variation chosen, out of stock) or the form is submitting, the mobile CTA
	 * must not look purchasable. single-product.js keeps them in step. */
	.lf-button--sticky.is-disabled,
	.lf-button--sticky:disabled {
		border-color: var(--lf-border);
		background: var(--lf-border);
		color: var(--lf-text-soft);
		cursor: not-allowed;
	}
}

@media (max-width: 900px) {
	/* .lf-product-page prefix (specificity 0,2,0): must not lose the column
	 * count to a later, lower-effort override anywhere else in the cascade. */
	.lf-product-page .lf-all-reviews__grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

}

@media (max-width: 767px) {
	body.single-product {
		overflow-x: hidden;
	}

	.lf-product-page {
		--lf-product-page-width: min(680px, calc(100% - 2rem));
	}

	.lf-product-layout {
		padding: 8px 0 44px;
		gap: 22px;
	}

	/* Visual order == DOM order == tab order: the single-column stack (set on
	 * .lf-product-layout at <=1024px) follows the markup exactly. */
	.lf-product-layout__visuals {
		display: flex;
		flex-direction: column;
		gap: 22px;
		min-width: 0;
	}

	.lf-product-layout__buy {
		gap: 0;
	}

	.lf-product-header {
		padding-bottom: 18px;
	}

	.lf-product-header .product-title {
		max-width: none;
		font-size: clamp(30px, 9vw, 38px);
		line-height: 1;
	}

	.lf-product-gallery .woocommerce-product-gallery {
		flex-direction: column;
		gap: 11px;
	}

	/* Thumbnails now sit under the image: the trigger is back on the image's own
	 * top-left corner. */
	.lf-product-gallery--multi .woocommerce-product-gallery__trigger {
		left: 14px;
	}

	/* Column layout: the viewport's height must come from the slide (FlexSlider
	 * writes it inline through smoothHeight). `flex: 1` would turn into a
	 * vertical flex-basis and ignore that height, leaving empty space under
	 * landscape photos and the arrows off-centre. */
	.lf-product-gallery .flex-viewport,
	.lf-product-page .lf-product-gallery--multi .woocommerce-product-gallery > .woocommerce-product-gallery__wrapper {
		flex: none;
	}

	.lf-product-gallery .flex-viewport {
		order: 1;
	}

	.lf-product-gallery .flex-control-thumbs {
		justify-content: center;
		flex: 0 0 auto;
		flex-direction: row;
		order: 2;
		overflow-x: auto;
	}

	.lf-product-gallery .flex-control-thumbs li {
		flex: 0 0 70px;
		width: 70px !important;
	}

	.lf-product-gallery .flex-control-thumbs img {
		width: 70px;
		height: 76px;
	}

	.lf-product-gallery .woocommerce-product-gallery__image img,
	.lf-product-gallery .flex-viewport,
	.lf-product-gallery--single .woocommerce-product-gallery__wrapper {
		border-radius: 15px;
	}

	.lf-section-heading .section-title,
	.lf-related > .section-title,
	.lf-about > .section-title {
		font-size: 32px;
	}

	/*
	 * Two cards visible at once (375/390/430px), not one: width alone is not
	 * the fix -- the carousel's JS (setupReviewCarousel() in
	 * single-product.js) measures the *rendered* first card's width via
	 * getBoundingClientRect() to compute its scroll step, so it already
	 * advances by exactly one card at this width without any JS change.
	 * `scroll-snap-align: start` (overriding the desktop `center` below)
	 * matters here specifically for the last position: with `center`, the
	 * final card would snap centred with dangling empty space after it since
	 * the viewport only fits two; `start` guarantees the native
	 * scrollWidth - clientWidth maximum lands the last two cards flush
	 * against the right edge -- the actual browser-enforced scroll ceiling
	 * syncControls() already reads to disable the "next" arrow correctly.
	 */
	.lf-reviews__track {
		gap: 10px;
	}

	.lf-reviews__track .lf-review-card {
		flex: 0 0 calc((100% - 10px) / 2);
		min-height: 0;
		padding: 14px 12px;
		scroll-snap-align: start;
	}

	/* A lone review has no second card to share the row with -- give it the
	 * full width instead of a half-width card next to empty space. Higher
	 * specificity than the rule above on purpose, so it wins at every width
	 * this file later narrows the 2-up layout for (430px, 340px) without
	 * needing to repeat the override there. */
	.lf-reviews__track .lf-review-card:only-child {
		flex: 0 0 100%;
	}

	.lf-reviews__track .lf-review-card__stars {
		margin-bottom: 8px;
		font-size: 14px;
		letter-spacing: 2px;
	}

	.lf-reviews__track .lf-review-card__quote {
		font-size: 15px;
		line-height: 1.4;
	}

	.lf-reviews__track .lf-review-card__meta {
		padding-top: 10px;
		font-size: 11px;
	}

	.lf-all-reviews__heading {
		align-items: stretch;
		flex-direction: column;
	}

	/* .lf-product-page prefix: same defensive specificity bump as the 900px
	 * rule above -- 375/390/430px must land on 2 columns regardless of what
	 * else targets .lf-all-reviews__grid plainly. */
	.lf-product-page .lf-all-reviews__grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 10px;
	}

	.lf-all-reviews__grid .lf-review-card {
		min-height: 0;
		padding: 14px 12px;
		border-radius: 14px;
	}

	.lf-all-reviews__grid .lf-review-card__stars {
		margin-bottom: 8px;
		font-size: 14px;
		letter-spacing: 2px;
	}

	.lf-all-reviews__grid .lf-review-card__quote {
		font-size: 14px;
		line-height: 1.4;
	}

	.lf-all-reviews__grid .lf-review-card__meta {
		padding-top: 10px;
		font-size: 11px;
	}

	.lf-variation-cards {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.lf-variation-card {
		grid-template-columns: minmax(0, 1fr);
		gap: 5px;
		padding: 10px;
	}

	.lf-variation-card.is-most-expensive:nth-child(odd) {
		grid-column: 1 / -1;
	}

	.lf-product-options {
		padding: 18px 0 0;
	}

	.lf-related__grid {
		gap: 10px;
	}

	.lf-related-card__content {
		padding: 12px;
		gap: 4px;
	}

	.woocommerce div.product .lf-related-card__title {
		font-size: 15px;
	}

	.woocommerce div.product .lf-related-card__price {
		font-size: 14px;
	}

	.woocommerce div.product .lf-related-card__cta {
		min-height: 40px;
		padding: 8px 14px;
		font-size: 13px;
	}

	.lf-about {
		padding: 22px 20px;
	}
}

@media (max-width: 430px) {
	.lf-product-page {
		--lf-product-page-width: calc(100% - 1.25rem);
	}

	.lf-variation-card {
		grid-template-columns: minmax(0, 1fr);
		font-size: 13px;
	}

	.lf-related__grid {
		gap: 8px;
	}

	.lf-related-card__content {
		padding: 10px;
	}

	.woocommerce div.product .lf-related-card__cta {
		min-height: 38px;
		padding: 8px 11px;
	}

	.lf-reviews__track .lf-review-card {
		padding: 13px 11px;
	}
}

@media (max-width: 350px) {
	/* Two columns of opinion cards stop being usable below ~340px; one column
	 * with no horizontal scroll instead. 375px and up keep the 2-column grid
	 * set above. Same .lf-product-page specificity (0,2,0) as that rule, so
	 * this one wins here purely by being the narrower, later-matching query. */
	.lf-product-page .lf-all-reviews__grid {
		grid-template-columns: 1fr;
	}

	.lf-variation-cards {
		grid-template-columns: 1fr;
	}

	.lf-variation-card.is-most-expensive:nth-child(odd) {
		grid-column: auto;
	}
}

/*
 * Down to 320px the short "Lo que dicen nuestros clientes" carousel keeps its
 * 2-up layout (unlike the long opinions grid above, which already falls back
 * to one column at this width) -- there was no genuine legibility problem
 * that required giving it up, only tighter spacing.
 */
@media (max-width: 340px) {
	.lf-reviews__track {
		gap: 6px;
	}

	.lf-reviews__track .lf-review-card {
		flex: 0 0 calc((100% - 6px) / 2);
		padding: 11px 9px;
	}

	.lf-reviews__track .lf-review-card__stars {
		margin-bottom: 6px;
		font-size: 12px;
		letter-spacing: 1px;
	}

	.lf-reviews__track .lf-review-card__quote {
		font-size: 13.5px;
		line-height: 1.35;
	}

	.lf-reviews__track .lf-review-card__meta {
		padding-top: 8px;
		font-size: 10.5px;
	}
}

@media (prefers-reduced-motion: reduce) {
	.lf-product-page *,
	.lf-product-page *::before,
	.lf-product-page *::after {
		scroll-behavior: auto !important;
		transition-duration: 0.01ms !important;
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
	}

	.lf-trust.is-reveal-pending .lf-trust__item,
	.lf-trust .lf-trust__item {
		opacity: 1;
		animation: none !important;
	}

	.lf-trust__item:hover .lf-trust__icon,
	.lf-related-card:hover .lf-related-card__image,
	.lf-related-card:hover .lf-related-card__media img,
	.woocommerce div.product .lf-related-card__cta:hover,
	.woocommerce div.product .lf-related-card__cta:focus-visible {
		transform: none;
	}
}

/* -------------------------------------------------------------------------
 * Disabled-look controls
 * ---------------------------------------------------------------------- */

.lf-button[aria-disabled="true"],
.lf-button.is-disabled {
	opacity: 0.55;
	cursor: not-allowed;
}

.lf-button[aria-disabled="true"]:hover,
.lf-button.is-disabled:hover {
	transform: none;
}

/* -------------------------------------------------------------------------
 * Highlighted variation ("Recomendado" -- an editorial pick, not a sales claim)
 *
 * Deliberately a DIFFERENT visual language from the selected state:
 * - highlighted  = green ring + green pill  (a property of the option itself)
 * - selected     = purple fill              (a property of the current choice)
 * A card can be highlighted while another card is selected, and both states
 * must stay readable at the same time.
 * ---------------------------------------------------------------------- */

.woocommerce div.product .lf-variation-card--featured,
.lf-variation-card--featured {
	border-color: var(--lf-green);
	box-shadow: 0 0 0 1px var(--lf-green);
}

/* Selection still reads as selection on top of the highlight. */
.woocommerce div.product .lf-variation-card--featured.is-selected,
.woocommerce div.product .lf-variation-card--featured.is-selected:hover,
.woocommerce div.product .lf-variation-card--featured.is-selected:focus,
.woocommerce div.product .lf-variation-card--featured.is-selected:active {
	border-color: var(--lf-purple);
	box-shadow: 0 0 0 1px var(--lf-purple), 0 0 0 4px rgba(0, 78, 50, 0.18);
}

.lf-variation-card--featured .lf-variation-card__pill {
	background: var(--lf-green);
}
