/* ============================================================
   Single Product — default template
   ============================================================
   Formerly the opt-in "Card Picker" customTemplate; promoted on
   2026-07-23 to be THE default single-product experience (see
   docs/DECISION-LOG.md) — every product gets this unless it's
   explicitly assigned the one remaining opt-in alternative, Pill Panel
   (templates/single-product-pill-panel.html /
   assets/css/single-product-pill-panel.css). Scoped under
   .product-buy-box (the buy-box column in templates/single-product.html;
   no "--card-picker" modifier anymore since there's nothing left to
   distinguish it from) so this file only ever affects the default
   template's own markup — Pill Panel pages never load this stylesheet at
   all (see inc/single-product-template-variants.php's enqueue logic:
   this file loads on every is_product() page EXCEPT when Pill Panel is
   explicitly selected).

   WHAT THIS REPLACES. The native variation attribute <select>
   (table.variations, WooCommerce core markup, confirmed live on General
   Admission/ID 791 and Factory Tours/ID 785 — both variable products with
   a single "Age Group" attribute) is replaced, for sighted mouse/touch
   users, with a vertical stack of real <input type="radio"> "cards" (one
   per variation option, each showing its own resolved price) built by the
   inline script at the bottom of templates/single-product.html.

   PROGRESSIVE ENHANCEMENT — READ BEFORE EDITING SELECTORS BELOW. Every
   rule that hides the original range price / native select table is
   gated behind a `.cp-enhanced` class the script adds ONLY after it has
   successfully built a complete, working card set (see that script's
   comments for the full list of early-return bail conditions: no
   variations_form, no table.variations, more than one attribute select,
   missing/unparseable data-product_variations, fewer than 2 real
   options). Without JS, or on a product shape the script declines to
   enhance, `.cp-enhanced` is never added and the buy box quietly falls
   back to exactly the plain default experience (range price + native
   select both visible) — never a half-built or broken layout. Do not
   hide `.product-buy-box__price` or `table.variations` unconditionally
   here; that would break that fallback.

   TOKENS ONLY. No new colors/type — every value below is one of this
   theme's existing tokens.css custom properties, so light/dark/
   high-contrast all "just work" with zero theme-specific overrides here.
   ============================================================ */

/* ---- 1. Hide the native per-variation price + native select once cards
   are live ----
   Required reading order (Title → Price → Description → picker) needs
   the ONE price element to stay at the TOP, ahead of the picker/
   description — so `.product-buy-box__price` (top) stays visible always;
   the template's inline script swaps ITS OWN content for the resolved
   variation's price_html instead of hiding it (same mechanism as the
   Pill Panel template). What gets hidden instead is WooCommerce's native
   per-variation price (`.woocommerce-variation-price`, inside
   `single_variation_wrap`, further down the form, AFTER the card stack)
   — leaving it visible too would put a second, redundant resolved price
   below the picker. Gated on `.cp-enhanced` (only added once the script's
   own price-swap listeners are actually wired) so a bailout leaves the
   default range-price + native per-variation-price experience fully
   intact instead of a half-built page with no price feedback at all. */

.product-buy-box.cp-enhanced .woocommerce-variation-price {
	display: none;
}

/* Visually/AT-hidden, NOT display:none and NOT removed from the DOM —
   wc-add-to-cart-variation.js (core WooCommerce, untouched) still reads
   this table's <select> as its source of truth; the cards script only
   ever sets its .value and dispatches a native 'change' event, exactly
   mirroring a real user picking an option from it. Standard
   visually-hidden technique (not display:none/visibility:hidden) so the
   select stays part of the accessibility tree's layout calculations
   without the native "Age Group" dropdown appearing twice on screen. */
.product-buy-box.cp-enhanced table.variations {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* "Clear" doesn't apply to a card picker — the script always keeps
   exactly one card selected (defaults to the cheapest on load), so
   there's never an "unset" state to clear back to. */
.product-buy-box.cp-enhanced .reset_variations {
	display: none;
}

/* ---- 2. The card group (fieldset > legend + one label.cp-card per
   variation), inserted by the script immediately before table.variations
   so it lands in the same spot in reading/visual order the native select
   used to occupy — right above the resolved single_variation_wrap price,
   which itself is unaffected/unstyled here beyond what
   woocommerce-shop.css §3a already gives it (bold price treatment,
   tightened spacing to the control above it). Combined with this
   template moving the whole add-to-cart-form block up (see the .html
   file), that resolved price now sits directly beneath the title/rating
   instead of after the excerpt. ---- */

.cp-cards {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
	margin: 0;
	padding: 0;
	border: 0;
}

.cp-cards__legend {
	padding: 0 0 0.6rem;
	font-size: 0.8rem;
	font-weight: 700;
	color: var(--muted);
	text-transform: uppercase;
	letter-spacing: 0.06em;
}

.cp-card {
	display: flex;
	align-items: center;
	gap: 0.9rem;
	padding: 0.9rem 1.1rem;
	border: 1px solid var(--line);
	border-radius: var(--r-md);
	background: var(--surface);
	cursor: pointer;
	transition: border-color var(--motion-med) var(--ease),
		box-shadow var(--motion-med) var(--ease);
}

.cp-card:hover {
	border-color: var(--muted);
}

/* Selected state — two mechanisms, deliberately redundant: `:has()` for
   browsers that support it (confirmed already relied on elsewhere in
   this theme — woocommerce-shop.css §"woocommerce_events", fooevents-
   attendee-details.css, woocommerce-myaccount.css — so this project's
   supported-browser bar already assumes it), PLUS a `.is-selected` class
   the script toggles on every change event as a belt-and-suspenders
   fallback that doesn't depend on `:has()` at all. */
.cp-card:has(.cp-card__radio:checked),
.cp-card.is-selected {
	border-color: var(--accent);
	box-shadow: inset 0 0 0 1.5px var(--accent);
}

.cp-card:has(.cp-card__radio:focus-visible) {
	outline: 3px solid var(--focus);
	outline-offset: 2px;
}

.cp-card--disabled {
	cursor: not-allowed;
	opacity: 0.5;
}

.cp-card--disabled .cp-card__radio {
	cursor: not-allowed;
}

.cp-card__radio {
	flex: 0 0 auto;
	width: 1.2rem;
	height: 1.2rem;
	margin: 0;
	accent-color: var(--accent);
	cursor: pointer;
}

.cp-card__body {
	display: flex;
	flex: 1 1 auto;
	align-items: baseline;
	justify-content: space-between;
	gap: 0.75rem;
	min-width: 0;
}

.cp-card__name {
	font-size: var(--step-0);
	font-weight: 600;
	color: var(--ink);
}

.cp-card__price,
.cp-card__price .price,
.cp-card__price .woocommerce-Price-amount {
	flex: 0 0 auto;
	font-size: 1.15rem;
	font-weight: 800;
	color: var(--ink);
	white-space: nowrap;
}

/* ---- 3. Breathing room below the card stack ----
   `single_variation_wrap` no longer shows a visible price of its own
   (hidden above, §1) — it still holds availability/description text (if
   any) plus the FooEvents Bookings date/slot fields and the quantity/Add
   to Cart row, so it still needs separation from the card stack above
   it. ---- */
.product-buy-box .single_variation_wrap {
	margin-top: var(--wp--preset--spacing--40) !important;
}

/* ---- 4. Buy-box card wrapper ----
   Wraps the whole title→price→description→picker→quantity→Add to Cart
   column in the SAME bordered/tinted card treatment already established
   by the Pill Panel template's `.dot-pill-buy-panel`
   (single-product-pill-panel.css) — reused verbatim (identical
   property values, same tokens), not a new recipe. Pure visual
   container; doesn't change this template's content or order. */
.cp-buy-panel {
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--r-lg);
	padding: clamp(1.5rem, 3vw, 2.25rem);
}

/* ---- 5. Quantity — its own separated row, away from Add to Cart ----
   WooCommerce Blocks' own `wp-block-add-to-cart-form` stylesheet puts the
   WHOLE button container (`.woocommerce-variation-add-to-cart`/
   `.variations_button` for variable products, `form.cart` directly for
   simple ones) into `display: grid; grid-auto-flow: column;
   grid-template-columns: min-content auto auto` with the button
   explicitly `grid-column: 2/3` — confirmed live this sits quantity and
   the button on the SAME grid row, side by side, regardless of any
   `display`/`width` change on the children themselves (a grid ITEM's own
   `display` only governs its own children's layout, not how its PARENT's
   grid template places it). Overriding the parent container back to
   plain block flow is required first, at (0,2,0) same-or-lower
   specificity than that WC rule — `!important` needed for the same
   defensive-against-enqueue-order reasoning already used throughout this
   theme's WooCommerce overrides (woocommerce-shop.css's own documented
   convention for exactly this kind of fight). Client feedback: quantity
   needs to be moved away from Add to Cart, not flush/stacked directly
   against it, and Add to Cart needs to read as the obvious primary action
   via more width. `.quantity` becomes its own full block row with real
   spacing below it; the button becomes a full-width block on the line
   after. */
.product-buy-box .woocommerce-variation-add-to-cart,
.product-buy-box form.cart {
	display: block !important;
}

.product-buy-box .quantity {
	display: block !important;
	width: 100% !important;
	margin: 0 0 1rem !important;
}

.product-buy-box .single_add_to_cart_button {
	display: flex !important;
	width: 100% !important;
}

/* ---- 6. Sticky product gallery (left column) ----
   Client feedback: once the right-hand buy-box column scrolls taller
   than the gallery image, the image scrolls out of view early, leaving
   dead space beside a long description/picker/booking-fields column.
   Fix: make the gallery's own rendered wrapper sticky, following this
   project's established sticky-column pattern (5.5rem top offset,
   clears the sticky header — same value used throughout this codebase:
   checkout's #order_review, fooevents-attendee-details.css's sticky
   sidebar).

   The STICKY element is `.wp-block-woocommerce-product-image-gallery`
   (WooCommerce's own rendered wrapper INSIDE `.product-gallery-frame`),
   not `.product-gallery-frame` itself — `.product-gallery-frame` is the
   flex column, left at wp:columns' default stretch cross-size so it
   naturally grows to match the (usually taller) buy-box column's real
   height, giving the inner gallery wrapper real slack to travel/stick
   within before release. Making the column itself the sticky element
   instead would leave it with no travel room, since a stretched flex
   item has no natural height budget to travel inside. Same underlying
   mechanism this codebase already used for the (since-reverted) sticky
   buy-box panel: outer flex column = stretched container, inner block =
   the actual `position: sticky` element.

   The row itself gets no artificial min-height floor — it sizes
   naturally to its tallest column's real content, standard
   sticky-sidebar behavior. The sticky image simply stops being "stuck"
   once the row (dictated by the taller buy-box column) ends. */
@media (min-width: 1024px) {
	.product-gallery-frame .wp-block-woocommerce-product-image-gallery {
		position: sticky;
		top: 5.5rem;
		max-height: calc(100vh - 7rem);
		overflow: hidden;
	}
}
