/**
 * Factory Direct PDP styles.
 *
 * Factory Fresh tokens: logo lime #80BC00 and logo grey #52575A are the brand;
 * everything else is a contrast-safe cut of those or a warm neutral already
 * shipping in cw-home-rebuild. Dark olive on lime (never white) because white
 * on #80BC00 fails contrast at roughly 2:1.
 *
 * This stylesheet also RESTYLES plugin-rendered markup rather than replacing it
 * (WooCommerce's variations form and quantity input, woo-variation-swatches'
 * pills, the TI wishlist button, the related-products grid). Those selectors are
 * marked "borrowed" below - if a plugin changes its markup, that is where to
 * look first.
 *
 * NOTE for WP Rocket: .is-selected, .is-visible, .is-best, .is-oos and
 * .is-prompting are toggled by JS and never appear in the served HTML. Remove
 * Unused CSS is currently enabled but failing on this site; if it ever starts
 * succeeding, add these to the safelist or the states will be stripped.
 *
 * @package cw-pdp
 */

.cwpdp {
	--cwpdp-lime: var(--cw-lime, #80bc00);
	--cwpdp-lime-deep: var(--cw-lime-deep, #5f8c00);
	--cwpdp-lime-dark: var(--cw-lime-dark, #4c7000);
	--cwpdp-lime-wash: var(--cw-lime-wash, #f3f9e4);
	--cwpdp-lime-row: var(--cw-lime-row, #f9fcf0);
	--cwpdp-olive: var(--cw-olive, #16210a);
	--cwpdp-ink: var(--cw-ink, #263238);
	--cwpdp-ink-2: var(--cw-ink-2, #52575a);
	--cwpdp-grey: var(--cw-grey, #6b6b6b);
	--cwpdp-faint: var(--cw-faint, #9a9a94);
	--cwpdp-ground: var(--cw-ground, #f7f7f5);
	--cwpdp-card: #fff;
	--cwpdp-line: var(--cw-line, #e7e5df);
	--cwpdp-line-2: var(--cw-line-2, #d6d3ca);
	--cwpdp-blue: var(--cw-rewards, #185aa6);
	--cwpdp-blue-deep: var(--cw-rewards-deep, #12467f);
	--cwpdp-blue-wash: var(--cw-rewards-tint, #e9f1fa);
	--cwpdp-blue-line: var(--cw-rewards-line, #cdddf0);
	/* Softer blue for the rewards eyebrow - full --cwpdp-blue at 800 weight
	   competes with the sentence underneath it rather than labelling it. */
	--cwpdp-blue-soft: var(--cw-rewards-soft, #5b87bb);
	--cwpdp-bad: var(--cw-brick, #a3372c);

	/*
	 * PROMO. Same aliases as shop-simple-grid.css, deliberately identical: the
	 * shop card and this page show the same badge, and one value behind both is
	 * the whole point of the token pattern.
	 *
	 * --cw-campaign-amber is the token whose documented job is promo banners.
	 * --cw-promo-deep is the gap it does not fill - the campaign amber is a FILL
	 * and measures 2.42:1 as type on white, where #a8530a measures 5.38:1.
	 * Aliased, not hardcoded, so promoting it into cw-tokens.css later touches
	 * neither of the two files that use it.
	 */
	--cwpdp-promo: var(--cw-campaign-amber, #fc881d);
	--cwpdp-promo-ink: var(--cw-amber-ink, #3d2000);
	--cwpdp-promo-deep: var(--cw-promo-deep, #a8530a);
	--cwpdp-promo-wash: var(--cw-amber-tint, #fdf4e6);
	--cwpdp-promo-line: var(--cw-amber-line, #ecdcc0);

	background: var(--cwpdp-ground);
	color: var(--cwpdp-ink);
	font-size: 15px;
	line-height: 1.55;
	padding-bottom: 130px;
}

.cwpdp *,
.cwpdp *::before,
.cwpdp *::after {
	box-sizing: border-box;
}

.cwpdp-product {
	max-width: 1080px;
	margin: 0 auto;
	padding: 0 20px 40px;
}

.cwpdp h1,
.cwpdp h2 {
	color: var(--cwpdp-ink);
}

/* --- breadcrumb --- */
.cwpdp-crumb {
	font-size: 11.5px;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	color: var(--cwpdp-grey);
	padding: 18px 0 0;
}

.cwpdp-crumb a {
	color: inherit;
	text-decoration: none;
}

.cwpdp-crumb a:hover {
	color: var(--cwpdp-ink);
}

/* --- hero --- */
.cwpdp-hero {
	display: flex;
	gap: 36px;
	align-items: center;
	flex-wrap: wrap;
	padding: 24px 0 4px;
}

.cwpdp-gallery {
	/* position: relative anchors .cwpdp-strip; it changes nothing else here. */
	position: relative;
	flex: 0 1 330px;
	min-width: 240px;
	background: var(--cwpdp-card);
	border: 1px solid var(--cwpdp-line);
	border-radius: 14px;
	padding: 14px;
}

/*
 * THE PROMO STRIP over the hero photo - the same badge the shop card carries,
 * so arriving from a card that announced a promo does not land on a silent page.
 *
 * Inset by the gallery's own 14px padding rather than bled to the edges: this
 * box is a bordered rounded card, and a full-bleed bar would need its corners
 * clipped by an overflow:hidden that would also clip flexslider's controls.
 */
.cwpdp-strip {
	position: absolute;
	right: 14px;
	bottom: 14px;
	left: 14px;
	z-index: 2;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	padding: 6px 11px;
	border-radius: 0 0 10px 10px;
	background: var(--cwpdp-promo);
	color: var(--cwpdp-promo-ink);
	font-size: 11px;
	font-weight: 800;
	letter-spacing: 0.05em;
	text-transform: uppercase;
	line-height: 1.35;
}

.cwpdp-strip .cw-promo-text {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.cwpdp-strip .cw-promo-figure {
	flex: none;
	background: var(--cwpdp-promo-ink);
	color: #fff;
	border-radius: 3px;
	padding: 1px 6px;
	letter-spacing: 0.02em;
}

/*
 * Same rewards-only treatment as the shop card - see shop-simple-grid.css'
 * .cwsg-promo.cw-promo--rewards / .cw-promo-mark for the full rationale
 * (cw_promo_strip() in inc/promo.php emits identical markup on both surfaces).
 */
.cwpdp-strip.cw-promo--rewards {
	background: var(--cwpdp-blue-wash);
	color: var(--cwpdp-blue);
	box-shadow: inset 0 0 0 1px var(--cwpdp-blue-line);
}

.cwpdp-strip .cw-promo-mark {
	flex: none;
	display: block;
	height: 22px;
	width: auto;
}

.cwpdp-gallery img {
	max-width: 100%;
	height: auto;
	border-radius: 10px;
}

/*
 * borrowed: WooCommerce gallery container.
 *
 * It arrives as a shrink-to-fit flex container that measured 150px, so the whole
 * gallery collapsed to thumbnail width inside a 330px box. Forced to fill its
 * parent, and back to block flow since nothing here needs flex. !important is
 * required: the 150px comes from the gallery's own scripts, not a stylesheet
 * rule we could outrank.
 */
.cwpdp-gallery .woocommerce-product-gallery {
	display: block !important;
	width: 100% !important;
	max-width: 100%;
	margin: 0;
	overflow: hidden;
}

.cwpdp-gallery .flex-control-thumbs {
	display: flex;
	gap: 8px;
	list-style: none;
	margin: 10px 0 0;
	padding: 0;
}

.cwpdp-gallery .flex-control-thumbs li {
	margin: 0;
	width: 60px;
}

.cwpdp-intro {
	flex: 1 1 420px;
	min-width: 290px;
}

.cwpdp-kicker {
	font-size: 12px;
	font-weight: 800;
	text-transform: uppercase;
	letter-spacing: 0.09em;
	color: var(--cwpdp-lime-dark);
	margin: 0 0 8px;
}

.cwpdp-title {
	font-size: clamp(28px, 4.4vw, 42px);
	font-weight: 800;
	letter-spacing: -0.022em;
	line-height: 1.08;
	margin: 0;
}

.cwpdp-from {
	font-size: clamp(21px, 3.2vw, 30px);
	font-weight: 800;
	letter-spacing: -0.02em;
	color: var(--cwpdp-lime-deep);
	margin: 6px 0 0;
	line-height: 1.15;
}

.cwpdp-from .cwpdp-from-lead {
	font-weight: 700;
}

.cwpdp-from .woocommerce-Price-amount {
	font-weight: 800;
}

.cwpdp-from-unit {
	font-size: 0.5em;
	font-weight: 700;
	color: var(--cwpdp-grey);
	letter-spacing: 0;
}

.cwpdp-sub {
	color: var(--cwpdp-ink-2);
	font-size: 14.5px;
	max-width: 54ch;
}

.cwpdp-sub p {
	margin: 12px 0 0;
}

.cwpdp-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	list-style: none;
	margin: 16px 0 0;
	padding: 0;
}

.cwpdp-chips li {
	font-size: 11px;
	font-weight: 700;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	border: 1px solid var(--cwpdp-line);
	background: var(--cwpdp-card);
	color: var(--cwpdp-ink-2);
	border-radius: 8px;
	padding: 5px 13px;
	margin: 0;
}

/* ==================================================================
   CHOOSE BLOCK: ladder on the left, buy panel on the right.
   One decision, one row of the page.
   ================================================================== */
.cwpdp-choose {
	display: flex;
	gap: 16px;
	align-items: flex-start;
	flex-wrap: wrap;
	margin-top: 24px;
}

/*
 * THE HERO BUY PANEL (2026-08-21 desktop-layout revision, "option 1").
 * The 'plain' and 'simple' states have no ladder, so their buy controls sit
 * INSIDE the hero's intro column, directly under the title - a separate
 * "Buy now" card below a full-width hero read as an orphan on desktop
 * (live-reported on Bow Saw Blade 600MM). This variant strips the card
 * chrome: the hero IS the card here, and a border-in-border box under the
 * title read as a widget rather than a page. Width is capped so the
 * add-to-basket row does not stretch across the intro column's full ~650px.
 *
 * The compound selector (0,2,0) is deliberate: the mobile media query's
 * plain `.cwpdp-buy` rules (padding, width) must never re-apply card
 * styling to this variant regardless of source order.
 */
.cwpdp-buy.cwpdp-buy--hero {
	flex: none;
	width: 100%;
	max-width: 480px;
	min-width: 0;
	background: transparent;
	border: none;
	border-radius: 0;
	padding: 0;
	margin-top: 18px;
}

/*
 * With the buy panel inside it, the intro column is usually taller than the
 * gallery; the hero's default align-items: center would float the photo at
 * mid-height beside it, which reads as a layout accident. Top-align these
 * two states; the ladder state keeps the centred hero it was designed with.
 */
.cwpdp--simple .cwpdp-hero,
.cwpdp--plain .cwpdp-hero {
	align-items: flex-start;
}

/* --- the ladder --- */
.cwpdp-ladder {
	flex: 1 1 440px;
	min-width: 300px;
	background: var(--cwpdp-card);
	border: 1px solid var(--cwpdp-line);
	border-radius: 14px;
	overflow: hidden;
	transition: box-shadow 0.2s ease;
}

.cwpdp-ladder.is-prompting,
.cwpdp-buy.is-prompting {
	box-shadow: 0 0 0 3px rgba(128, 188, 0, 0.55);
}

/*
 * ONE row layout at every width. Size and price share the first line; the
 * per-unit figure gets the second line to itself so it is never squeezed by a
 * neighbouring column. There is no wide-screen table variant to keep in sync,
 * and no horizontal scrolling at any size.
 */
.cwpdp-ladder table {
	width: 100%;
	border-collapse: collapse;
	font-size: 14px;
	margin: 0;
}

/*
 * The header row is removed with display:none - see the comment in the
 * template on why this replaced the usual clip/screen-reader-text technique.
 */
.cwpdp-ladder-thead {
	display: none;
}

.cwpdp-ladder tbody,
.cwpdp-ladder tbody td {
	display: block;
}

.cwpdp-ladder tbody tr.cwpdp-row {
	display: grid;
	grid-template-columns: 30px 1fr auto;
	align-items: center;
	row-gap: 2px;
	padding: 13px 18px;
	border-bottom: 1px solid var(--cwpdp-line);
}

/*
 * Scoped to tr.cwpdp-row specifically (not every tbody td) so this reset
 * cannot outrank .cwpdp-group td's own padding and background - the two rules
 * had equal-looking but different specificity (0,1,2 vs 0,1,1), and the
 * broader one was winning, which is why the group header rows ("Single
 * containers", "Buy a case...") were rendering with no padding or background
 * at all.
 */
.cwpdp-ladder tbody tr.cwpdp-row td {
	padding: 0;
	border-bottom: none;
	background: none;
}

.cwpdp-ladder tbody tr:last-child {
	border-bottom: none;
}

.cwpdp-row .cwpdp-pick {
	grid-column: 1;
	grid-row: 1 / span 2;
}

.cwpdp-row .cwpdp-size {
	grid-column: 2;
	grid-row: 1;
}

.cwpdp-row .cwpdp-price {
	grid-column: 3;
	grid-row: 1;
	text-align: right;
}

.cwpdp-row .cwpdp-ppu {
	grid-column: 2 / span 2;
	grid-row: 2;
}

/*
 * PER-VARIATION THUMBNAIL COLUMN.
 *
 * Scoped to .cwpdp-ladder.has-thumbs throughout, so the three-column grid
 * above stays the default: cw_pdp_ladder_thumbs() returns nothing for a
 * product whose variations share one photograph (174 of 671 variable products
 * on staging), and those ladders must render exactly as they did before this
 * column existed rather than reserving an empty gutter.
 *
 * 44px is a deliberate floor: a buffing pad, a mop head and a 25L drum have to
 * be tellable apart at a glance, and below about 40px they stop being.
 */
.cwpdp-ladder.has-thumbs tbody tr.cwpdp-row {
	grid-template-columns: 30px 44px 1fr auto;
	column-gap: 12px;
}

.cwpdp-ladder.has-thumbs .cwpdp-row .cwpdp-thumb {
	grid-column: 2;
	grid-row: 1 / span 2;
}

.cwpdp-ladder.has-thumbs .cwpdp-row .cwpdp-size {
	grid-column: 3;
	grid-row: 1;
}

.cwpdp-ladder.has-thumbs .cwpdp-row .cwpdp-price {
	grid-column: 4;
	grid-row: 1;
}

.cwpdp-ladder.has-thumbs .cwpdp-row .cwpdp-ppu {
	grid-column: 3 / span 2;
	grid-row: 2;
}

.cwpdp-thumb {
	width: 44px;
	height: 44px;
}

/*
 * object-fit: contain, not cover: these are packshots on white, and cropping
 * a 25L drum to a square would cut the container the row is describing.
 */
.cwpdp-thumb img {
	display: block;
	width: 44px;
	height: 44px;
	object-fit: contain;
	border-radius: 5px;
	background: #fff;
	border: 1px solid var(--cwpdp-line);
}

@media (max-width: 480px) {
	.cwpdp-ladder.has-thumbs tbody tr.cwpdp-row {
		grid-template-columns: 26px 38px 1fr auto;
		column-gap: 10px;
	}

	.cwpdp-thumb,
	.cwpdp-thumb img {
		width: 38px;
		height: 38px;
	}
}

.cwpdp-group {
	display: block;
}

.cwpdp-group td {
	background: var(--cwpdp-ground);
	font-size: 10.5px;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	font-weight: 800;
	color: var(--cwpdp-ink-2);
	padding: 8px 18px;
}

.cwpdp-group-note {
	text-transform: none;
	letter-spacing: 0;
	font-weight: 600;
	color: var(--cwpdp-grey);
	margin-left: 8px;
}

.cwpdp-row {
	cursor: pointer;
	transition: background 0.15s ease;
}

.cwpdp-row:hover {
	background: var(--cw-lime-row, #f9fcf0);
}

.cwpdp-row:focus-visible {
	outline: 3px solid rgba(128, 188, 0, 0.5);
	outline-offset: -3px;
}

.cwpdp-row.is-selected {
	background: var(--cwpdp-lime-row);
	box-shadow: inset 3px 0 0 var(--cwpdp-lime);
}

.cwpdp-row.is-oos {
	opacity: 0.55;
}

.cwpdp-pick {
	width: 34px;
}

.cwpdp-radio {
	display: inline-block;
	width: 17px;
	height: 17px;
	border-radius: 50%;
	border: 2px solid var(--cwpdp-line-2);
	position: relative;
	vertical-align: middle;
}

.cwpdp-row.is-selected .cwpdp-radio {
	border-color: var(--cwpdp-lime);
}

.cwpdp-row.is-selected .cwpdp-radio::after {
	content: "";
	position: absolute;
	inset: 3px;
	border-radius: 50%;
	background: var(--cwpdp-lime);
}

.cwpdp-size-name {
	font-weight: 800;
	font-size: 15px;
	white-space: nowrap;
}

/*
 * EMPHASIS ORDER, most to least: per-unit price, then the pack price, then the
 * saving. The per-unit figure is the whole factory-direct argument, so it is the
 * largest number in the row; the pack price steps back to a muted mid-size; the
 * saving is the quietest thing on the line. Near-black rather than lime keeps
 * lime reserved for the action button and the best-value badge.
 */
.cwpdp-price,
.cwpdp-ppu {
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

.cwpdp-price {
	font-size: 13.5px;
	font-weight: 600;
	color: var(--cwpdp-ink-2);
}

.cwpdp-ppu-value {
	font-size: 21px;
	font-weight: 800;
	letter-spacing: -0.02em;
	color: var(--cwpdp-ink);
	display: inline-block;
}

.cwpdp-ppu-value .woocommerce-Price-amount {
	font-weight: 800;
}

.cwpdp-unit {
	font-size: 10.5px;
	font-weight: 600;
	color: var(--cwpdp-grey);
	margin-left: 4px;
}

.cwpdp-save {
	font-size: 10.5px;
	font-weight: 700;
	color: var(--cwpdp-lime-dark);
	margin-left: 7px;
}

.cwpdp-save--none {
	color: var(--cwpdp-faint);
	font-weight: 600;
}

.cwpdp-best {
	background: var(--cwpdp-lime);
	color: var(--cwpdp-olive);
	font-size: 9.5px;
	font-weight: 800;
	letter-spacing: 0.05em;
	border-radius: 999px;
	padding: 2px 9px;
	margin-left: 8px;
	vertical-align: 2px;
	white-space: nowrap;
}

/*
 * THE ON-PROMO RUNG. Same pill geometry as BEST VALUE above, in orange - one
 * flag grammar, two meanings: lime is a permanent fact about the size ladder
 * ("this size is always the cheapest per litre"), orange is a temporary price
 * cut. A rung can honestly be both, so both print side by side.
 *
 * FILLED, exactly like BEST VALUE. An earlier version outlined it to stop two
 * filled flags competing, but that made the promo the quieter of the two on the
 * one row where a price has actually changed - and it broke the parallel with
 * the shop card, where the on-promo size pill is solid orange.
 */
.cwpdp-promo {
	background: var(--cwpdp-promo);
	color: var(--cwpdp-promo-ink);
	font-size: 9.5px;
	font-weight: 800;
	letter-spacing: 0.05em;
	border-radius: 999px;
	padding: 2px 9px;
	margin-left: 8px;
	vertical-align: 2px;
	white-space: nowrap;
}

/*
 * The size name goes orange too. The flag alone is easy to miss in a table
 * being read down the per-litre column, and this is the one row where the
 * headline number is temporarily not the whole story.
 */
.cwpdp-row.is-promo .cwpdp-size-name {
	color: var(--cwpdp-promo-deep);
}

.cwpdp-oos {
	font-size: 10.5px;
	font-weight: 700;
	color: var(--cwpdp-bad);
	margin-left: 8px;
}

.cwpdp-ladder-note {
	font-size: 12px;
	color: var(--cwpdp-grey);
	padding: 12px 18px;
	border-top: 1px dashed var(--cwpdp-line);
	margin: 0;
}

/* ==================================================================
   BUY ROW
   The ladder is the size selector in this design, so the swatch table
   is visually hidden - but it and its underlying <select> remain in the
   DOM because they are the input WooCommerce actually reads.
   ================================================================== */
.cwpdp-buy {
	flex: 0 1 370px;
	min-width: 300px;
	background: var(--cwpdp-card);
	border: 1px solid var(--cwpdp-line);
	border-radius: 14px;
	padding: 18px 20px;
}

.cwpdp-buy-label {
	font-size: 10px;
	text-transform: uppercase;
	letter-spacing: 0.09em;
	font-weight: 800;
	color: var(--cwpdp-grey);
	margin: 0;
}

.cwpdp-buy-name {
	font-weight: 800;
	font-size: 15px;
	margin: 5px 0 0;
}

.cwpdp-buy-price {
	font-weight: 800;
	font-size: 29px;
	letter-spacing: -0.022em;
	line-height: 1.1;
	color: var(--cwpdp-lime-deep);
	font-variant-numeric: tabular-nums;
	margin: 4px 0 0;
}

.cwpdp-buy-price .woocommerce-Price-amount {
	font-weight: 800;
}

.cwpdp-buy-ppu {
	font-size: 12px;
	color: var(--cwpdp-grey);
	margin: 1px 0 0;
}

.cwpdp-buy-actions {
	margin-top: 15px;
}

/* borrowed: WooCommerce variations form */
.cwpdp-buy form.cart {
	display: flex;
	align-items: center;
	gap: 9px;
	flex-wrap: wrap;
	margin: 0;
}

.cwpdp-fulfil {
	list-style: none;
	margin: 14px 0 0;
	padding: 12px 0 0;
	border-top: 1px dashed var(--cwpdp-line);
	font-size: 12px;
	color: var(--cwpdp-ink-2);
}

.cwpdp-fulfil li {
	margin: 0 0 5px;
	padding-left: 15px;
	position: relative;
}

.cwpdp-fulfil li:last-child {
	margin-bottom: 0;
}

.cwpdp-fulfil li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.5em;
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: var(--cwpdp-lime);
}

/*
 * The YITH barcode div is never customer-facing in ANY state - hidden
 * unconditionally. table.variations / .woocommerce-variation-price /
 * .woocommerce-variation-description are hidden ONLY in the 'ladder' state
 * (see the .cwpdp--ladder-scoped rule below) - in every other state that
 * table IS the selector, or does not exist at all.
 */
.cwpdp-buy .ywbc-barcode-container-product-page {
	position: absolute !important;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: inset(50%);
	white-space: nowrap;
	margin: -1px;
	padding: 0;
	border: 0;
}

.cwpdp--ladder .cwpdp-buy table.variations,
.cwpdp--ladder .cwpdp-buy .woocommerce-variation-price,
.cwpdp--ladder .cwpdp-buy .woocommerce-variation-description {
	position: absolute !important;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: inset(50%);
	white-space: nowrap;
	margin: -1px;
	padding: 0;
	border: 0;
}

.cwpdp-buy .woocommerce-variation-add-to-cart {
	display: flex;
	align-items: center;
	gap: 12px;
	flex-wrap: wrap;
}

.cwpdp-buy .single_variation_wrap {
	display: flex;
	align-items: center;
	gap: 12px;
	flex-wrap: wrap;
}

/* --- quantity stepper (wraps WooCommerce's own input) --- */
.cwpdp-stepper {
	display: inline-flex;
	align-items: center;
	border: 1.5px solid var(--cwpdp-line-2);
	border-radius: 999px;
	overflow: hidden;
	background: var(--cwpdp-card);
	flex: 0 0 auto;
}

.cwpdp-stepper button {
	border: none;
	background: transparent;
	font-size: 17px;
	font-weight: 700;
	color: var(--cwpdp-ink);
	width: 38px;
	height: 42px;
	line-height: 1;
	cursor: pointer;
	padding: 0;
	/*
	 * The bare button relies on the browser's own text centring by default,
	 * but this site's global button reset sets text-align:left - measured
	 * live as the "-"/"+" hugging the left edge of their 38px box instead of
	 * sitting centred (live-reported on the sticky bar). Explicit flex
	 * centring wins regardless of what a host stylesheet sets text-align to.
	 */
	display: flex;
	align-items: center;
	justify-content: center;
}

.cwpdp-stepper button:hover {
	background: var(--cwpdp-lime-wash);
}

.cwpdp-stepper > span {
	min-width: 30px;
	text-align: center;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
}

/* borrowed: WooCommerce quantity input, flattened into the pill */
.cwpdp-stepper--woo input.qty {
	width: 44px;
	border: none;
	background: transparent;
	text-align: center;
	font-weight: 700;
	font-size: 15px;
	padding: 0;
	box-shadow: none;
	-moz-appearance: textfield;
	appearance: textfield;
}

.cwpdp-stepper--woo input.qty::-webkit-outer-spin-button,
.cwpdp-stepper--woo input.qty::-webkit-inner-spin-button {
	-webkit-appearance: none;
	margin: 0;
}

.cwpdp-stepper--woo label {
	display: none;
}

/* borrowed: WooCommerce add-to-cart button */
.cwpdp-buy .single_add_to_cart_button {
	flex: 1 1 auto;
	background: var(--cwpdp-lime);
	color: var(--cwpdp-olive);
	font-weight: 800;
	border: none;
	border-radius: 999px;
	padding: 13px 20px;
	font-size: 14.5px;
	line-height: 1;
	cursor: pointer;
	white-space: nowrap;
	transition: background 0.15s ease, transform 0.12s ease;
}

.cwpdp-buy .single_add_to_cart_button:hover {
	background: var(--cw-lime-deep, #5f8c00);
	color: var(--cwpdp-olive);
}

.cwpdp-buy .single_add_to_cart_button:active {
	transform: scale(0.98);
}

.cwpdp-buy .single_add_to_cart_button.disabled,
.cwpdp-buy .single_add_to_cart_button:disabled {
	background: var(--cwpdp-line);
	color: var(--cwpdp-grey);
	cursor: not-allowed;
}

/* borrowed: TI wishlist button, restyled into a circular ghost control */
.cwpdp-wish {
	flex: 0 0 auto;
}

.cwpdp-wish .tinvwl_add_to_wishlist_button {
	width: 46px;
	height: 46px;
	border-radius: 50%;
	border: 1.5px solid var(--cwpdp-line-2);
	background: var(--cwpdp-card);
	color: var(--cwpdp-ink-2);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	margin: 0;
	font-size: 18px;
	transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}

.cwpdp-wish .tinvwl_add_to_wishlist_button:hover {
	border-color: var(--cwpdp-lime);
	background: var(--cwpdp-lime-row);
	color: var(--cwpdp-lime-deep);
}

.cwpdp-wish .tinvwl-tooltip {
	display: none;
}

/* --- rewards band: the only blue on the page --- */
.cwpdp-rewards {
	background: var(--cwpdp-blue-wash);
	border: 1px solid var(--cwpdp-blue-line);
	border-radius: 12px;
	padding: 13px 18px;
	margin-top: 14px;
	display: flex;
	gap: 12px;
	align-items: center;
	flex-wrap: wrap;
}

/*
 * The family mark replaces the old blue "MY FAMILY REWARDS" text pill. Sized
 * in px rather than em because it is artwork at a fixed rendered size, not
 * type - the source is a 180px WebP, so this is a 4x asset and stays sharp on
 * retina. flex: none keeps it from being squeezed when the sentence is long.
 */
.cwpdp-rewards-mark {
	flex: none;
	width: 44px;
	height: auto;
	display: block;
}

/*
 * flex: 1 + min-width: 0 makes the sentence wrap INSIDE its own column on a
 * narrow screen instead of dropping below the mark, which the band's
 * flex-wrap would otherwise do and which reads as two disconnected pieces.
 */
.cwpdp-rewards-txt {
	flex: 1;
	min-width: 0;
	color: var(--cwpdp-blue);
	font-size: 13.5px;
}

.cwpdp-rewards-eyebrow {
	display: block;
	margin-bottom: 1px;
	color: var(--cwpdp-blue-soft);
	font-size: 10.5px;
	font-weight: 800;
	letter-spacing: 0.07em;
}

/* --- why trust --- */
.cwpdp-trust {
	margin-top: 32px;
}

.cwpdp-trust h2 {
	font-size: 22px;
	font-weight: 800;
	letter-spacing: -0.015em;
	margin: 0 0 12px;
}

.cwpdp-trust ul {
	list-style: none;
	margin: 0;
	padding: 6px 20px;
	background: var(--cwpdp-card);
	border: 1px solid var(--cwpdp-line);
	border-radius: 12px;
}

.cwpdp-trust li {
	display: flex;
	gap: 12px;
	align-items: center;
	padding: 12px 0;
	border-bottom: 1px solid var(--cwpdp-line);
	font-size: 14.5px;
	color: var(--cwpdp-ink-2);
	margin: 0;
}

.cwpdp-trust li:last-child {
	border-bottom: none;
}

.cwpdp-trust b {
	color: var(--cwpdp-ink);
	font-weight: 800;
}

.cwpdp-tick {
	flex: 0 0 auto;
	width: 28px;
	height: 28px;
	border-radius: 9px;
	background: var(--cwpdp-lime-wash);
	color: var(--cwpdp-lime-dark);
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 13px;
	font-weight: 800;
}

/* --- about + details --- */
.cwpdp-details {
	display: flex;
	gap: 32px;
	flex-wrap: wrap;
	margin-top: 34px;
}

.cwpdp-about {
	flex: 1 1 400px;
	min-width: 290px;
}

.cwpdp-spec {
	flex: 1 1 300px;
	min-width: 270px;
}

.cwpdp-details h2 {
	font-size: 20px;
	font-weight: 800;
	letter-spacing: -0.01em;
	margin: 0 0 10px;
}

.cwpdp-about p {
	font-size: 14.5px;
	color: var(--cwpdp-ink-2);
	max-width: 64ch;
}

/* borrowed: WooCommerce attributes table */
.cwpdp-spec table.woocommerce-product-attributes {
	width: 100%;
	border-collapse: collapse;
	background: var(--cwpdp-card);
	border: 1px solid var(--cwpdp-line);
	border-radius: 12px;
	overflow: hidden;
	font-size: 13.5px;
}

.cwpdp-spec table.woocommerce-product-attributes th,
.cwpdp-spec table.woocommerce-product-attributes td {
	padding: 10px 16px;
	border-bottom: 1px solid var(--cwpdp-line);
	text-align: left;
	background: none;
}

.cwpdp-spec table.woocommerce-product-attributes tr:last-child th,
.cwpdp-spec table.woocommerce-product-attributes tr:last-child td {
	border-bottom: none;
}

.cwpdp-spec table.woocommerce-product-attributes th {
	color: var(--cwpdp-grey);
	font-weight: 600;
	width: 42%;
}

.cwpdp-spec table.woocommerce-product-attributes p {
	margin: 0;
}

/* --- reviews + related --- */
.cwpdp-reviews,
.cwpdp-related {
	margin-top: 36px;
}

.cwpdp-related h2,
.cwpdp-reviews h2 {
	font-size: 20px;
	font-weight: 800;
	letter-spacing: -0.01em;
}

/*
 * The review gate (2026-08-25): what stands in for the form when the visitor
 * is signed out, or is signed in but has not bought this product. Deliberately
 * quiet - a lime card here would compete with the buy panel - so it reads as
 * an explanation, with the sign-in action carrying the only colour.
 */
.cwpdp-rev-gate {
	background: var(--cwpdp-ground);
	border: 1px solid var(--cwpdp-line);
	border-radius: 12px;
	padding: 18px 20px;
	margin-top: 18px;
	max-width: 56ch;
}

.cwpdp-rev-gate-t {
	margin: 0;
	font-size: 15px;
	font-weight: 800;
	color: var(--cwpdp-ink);
}

.cwpdp-rev-gate-s {
	margin: 5px 0 0;
	font-size: 13.5px;
	line-height: 1.55;
	color: var(--cwpdp-ink-2);
}

.cwpdp-rev-signin {
	display: inline-block;
	margin-top: 13px;
	background: var(--cwpdp-lime);
	color: #fff;
	border-radius: 999px;
	padding: 10px 22px;
	font-size: 14px;
	font-weight: 800;
	text-decoration: none;
}

.cwpdp-rev-signin:hover,
.cwpdp-rev-signin:focus {
	background: var(--cwpdp-lime-deep);
	color: #fff;
}

/*
 * borrowed: WooCommerce's review/comment form. Square corners and a plain
 * button here read as unstyled next to the rounded cards around them - this
 * rounds the controls to the same corner language the rest of the page
 * already uses (10px inputs, 999px pill button, matching .single_add_to_
 * cart_button).
 */
.cwpdp-reviews #comment,
.cwpdp-reviews .comment-form-comment textarea,
.cwpdp-reviews .comment-form-author input,
.cwpdp-reviews .comment-form-email input {
	border: 1.5px solid var(--cwpdp-line-2);
	border-radius: 10px;
	padding: 10px 14px;
	font-size: 14px;
	font-family: inherit;
	color: var(--cwpdp-ink);
	background: var(--cwpdp-card);
	/*
	 * A site-wide form-field rule sets line-height:40px, which this box-sizing:
	 * border-box input inherits on top of the 10px vertical padding above -
	 * measured live on mobile at 62px tall, next to a textarea sized normally.
	 * A single-line input has no business being that tall.
	 */
	line-height: normal;
}

.cwpdp-reviews .comment-form-comment textarea {
	width: 100%;
	resize: vertical;
}

.cwpdp-reviews .form-submit input#submit,
.cwpdp-reviews .form-submit .submit {
	background: var(--cwpdp-lime);
	color: var(--cwpdp-olive);
	font-weight: 800;
	border: none;
	border-radius: 999px;
	padding: 12px 26px;
	font-size: 14px;
	cursor: pointer;
	transition: background 0.15s ease;
}

.cwpdp-reviews .form-submit input#submit:hover,
.cwpdp-reviews .form-submit .submit:hover {
	background: var(--cw-lime-deep, #5f8c00);
}

/* borrowed: WooCommerce related-products grid, restyled as Factory Fresh cards */
.cwpdp-related ul.products {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
	gap: 14px;
	list-style: none;
	margin: 16px 0 0;
	padding: 0;
}

/*
 * Card metrics below (name/price typography, pill radius, image box) are
 * pulled from the live shop grid's own card (assets/css/shop-simple-grid.css
 * .cwsg-*, the "same design as the shop pages" request, 2026-08-21) rather
 * than invented separately - a shopper should not be able to tell, by look
 * alone, whether a card sits on the shop grid or under a product page.
 */
.cwpdp-related ul.products li.product {
	position: relative; /* anchors the wishlist heart, matching .cwsg-card */
	background: var(--cwpdp-card);
	border: 1px solid var(--cwpdp-line);
	border-radius: 12px;
	padding: 14px;
	margin: 0;
	width: auto;
	float: none;
	text-align: left;
}

/*
 * Fixed 1:1 frame + object-fit:contain, same reasoning as the main gallery
 * fix above: this catalogue's photography is not shot to one ratio, and
 * height:auto scaling to the source's own proportions would let an odd crop
 * blow the card out just as it did the gallery.
 */
.cwpdp-related ul.products li.product img {
	aspect-ratio: 1 / 1;
	width: 100%;
	height: auto;
	object-fit: contain;
	border-radius: 8px;
	background: var(--cwpdp-card);
	margin-bottom: 10px;
}

.cwpdp-related ul.products li.product .woocommerce-loop-product__title {
	font-weight: 800;
	font-size: 14.5px;
	letter-spacing: -0.01em;
	line-height: 1.3;
	padding: 0;
	margin: 0;
	color: var(--cwpdp-ink);
}

.cwpdp-related ul.products li.product .price {
	font-weight: 700;
	font-size: 14px;
	color: var(--cwpdp-ink-2);
	margin: 0 0 10px;
	display: block;
}

.cwpdp-related ul.products li.product .price del {
	color: var(--cwpdp-faint);
	font-weight: 600;
}

.cwpdp-related ul.products li.product a.button {
	display: inline-block;
	width: 100%;
	text-align: center;
	margin-top: 10px;
	border-radius: 999px;
	padding: 9px 0;
	font-size: 12.5px;
	font-weight: 800;
	background: transparent;
	color: var(--cwpdp-ink);
	border: 1.5px solid var(--cwpdp-line-2);
	transition: background 0.15s, border-color 0.15s, color 0.15s;
}

.cwpdp-related ul.products li.product a.button:hover {
	background: var(--cwpdp-lime);
	color: var(--cwpdp-olive);
	border-color: var(--cwpdp-lime);
}

/*
 * Click feedback, pure CSS, no JS: related products span BOTH a native
 * WooCommerce simple-product button (WC core's own ajax_add_to_cart.js owns
 * that click, no theme JS attached) and this file's own variable-product
 * swatch-picker button (cw-pdp.js) - one CSS :active rule covers both
 * uniformly without adding a second click listener next to WC core's, or
 * duplicating cw-pdp.js's handler logic here. There is no "+" glyph on this
 * button to spin (it is a wide "Add to basket"/"Select options" pill, not
 * the shop card's round "+"), so the equivalent tactile response here is a
 * quick press-in rather than a rotation - same intent as shop-simple-
 * grid.css's .cwsg-addbtn spin (user request 2026-08-25), translated to
 * this button's own shape.
 */
@media (prefers-reduced-motion: no-preference) {
	.cwpdp-related ul.products li.product a.button {
		transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.1s ease-out;
	}

	.cwpdp-related ul.products li.product a.button:active {
		transform: scale(0.94);
	}
}

/* ==================================================================
   STICKY BUY BAR
   ================================================================== */
/*
 * MOBILE ONLY by design. With the buy panel sitting beside the ladder, the real
 * controls stay on screen while a desktop customer compares sizes, so a sticky
 * duplicate would only cover content. On mobile the two columns stack and the
 * buy panel drops well below the fold, which is where the bar earns its place.
 */
.cwpdp-sticky {
	display: block;
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 60;
	transform: translateY(115%);
	transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
	pointer-events: none;
}

.cwpdp-sticky.is-visible {
	transform: translateY(0);
	pointer-events: auto;
}

.cwpdp-sticky-inner {
	max-width: 1080px;
	margin: 0 auto;
	padding: 0 14px 12px;
}

.cwpdp-sticky-rewards {
	background: var(--cwpdp-blue-wash);
	border: 1px solid var(--cwpdp-blue-line);
	border-bottom: none;
	border-radius: 14px 14px 0 0;
	padding: 8px 18px;
	display: flex;
	gap: 10px;
	align-items: center;
	flex-wrap: wrap;
	font-size: 12.5px;
	color: var(--cwpdp-blue);
}

/*
 * The sticky strip is one line, so the mark shrinks and the eyebrow sits
 * INLINE beside the sentence rather than stacking above it the way it does in
 * the full band. Same two elements, same classes - only the arrangement
 * differs, so the two surfaces can never drift apart in wording.
 */
.cwpdp-sticky-rewards .cwpdp-rewards-mark {
	width: 22px;
}

.cwpdp-sticky-rewards .cwpdp-rewards-eyebrow {
	display: inline;
	margin-bottom: 0;
}

.cwpdp-sticky-buy {
	background: var(--cwpdp-card);
	border: 1px solid var(--cwpdp-line-2);
	border-radius: 0 0 16px 16px;
	box-shadow: 0 -6px 28px rgba(38, 50, 56, 0.16);
	padding: 12px 18px;
	display: flex;
	align-items: center;
	gap: 14px;
	flex-wrap: wrap;
}

.cwpdp-sticky-rewards + .cwpdp-sticky-buy {
	border-top: none;
}

.cwpdp-sticky-name {
	font-weight: 800;
	font-size: 14px;
	white-space: nowrap;
}

.cwpdp-sticky-price {
	font-weight: 800;
	font-size: 19px;
	color: var(--cwpdp-lime-deep);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

.cwpdp-sticky-ppu {
	font-size: 11.5px;
	color: var(--cwpdp-grey);
	white-space: nowrap;
}

.cwpdp-sticky-sizes {
	display: flex;
	gap: 6px;
	flex-wrap: wrap;
	list-style: none;
	margin: 0;
	padding: 0;
}

.cwpdp-sticky-sizes li {
	margin: 0;
}

.cwpdp-size-pill {
	font-size: 11.5px;
	font-weight: 700;
	border: 1.5px solid var(--cwpdp-line-2);
	background: var(--cwpdp-card);
	color: var(--cwpdp-ink-2);
	border-radius: 8px;
	padding: 5px 12px;
	white-space: nowrap;
	cursor: pointer;
	transition: border-color 0.12s ease, background 0.12s ease;
}

.cwpdp-size-pill:hover {
	border-color: var(--cwpdp-grey);
}

.cwpdp-size-pill.is-selected {
	border-color: var(--cwpdp-lime);
	background: var(--cwpdp-lime-row);
	color: var(--cwpdp-ink);
	box-shadow: 0 0 0 1px var(--cwpdp-lime);
}

.cwpdp-sticky-actions {
	display: flex;
	align-items: center;
	gap: 10px;
	margin-left: auto;
	flex-wrap: wrap;
}

.cwpdp-sticky-add {
	background: var(--cwpdp-lime);
	color: var(--cwpdp-olive);
	font-weight: 800;
	border: none;
	border-radius: 999px;
	padding: 12px 26px;
	font-size: 14.5px;
	cursor: pointer;
	transition: background 0.15s ease;
}

.cwpdp-sticky-add:hover {
	background: var(--cw-lime-deep, #5f8c00);
}

.cwpdp-sticky-wish {
	width: 42px;
	height: 42px;
	flex: 0 0 auto;
	border-radius: 50%;
	border: 1.5px solid var(--cwpdp-line-2);
	background: var(--cwpdp-card);
	color: var(--cwpdp-ink-2);
	font-size: 17px;
	line-height: 1;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 0;
	transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}

.cwpdp-sticky-wish:hover {
	border-color: var(--cwpdp-lime);
	background: var(--cwpdp-lime-row);
	color: var(--cwpdp-lime-deep);
}

.cwpdp .screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: inset(50%);
	white-space: nowrap;
}

/* ==================================================================
   WAVE 8 STATE 3: 'plain' - the real swatch/select table, visible.
   No ladder exists in this state to replace it, so - unlike 'ladder' -
   it stays in normal flow. The pills themselves keep whatever styling
   woo-variation-swatches-pro already gives them site-wide; this only
   tidies the table shell and the native price lines around it.
   ================================================================== */
.cwpdp--plain .cwpdp-buy > p.price {
	font-weight: 800;
	font-size: 29px;
	letter-spacing: -0.022em;
	line-height: 1.1;
	color: var(--cwpdp-lime-deep);
	font-variant-numeric: tabular-nums;
	margin: 4px 0 14px;
}

.cwpdp--plain .cwpdp-buy > p.price .woocommerce-Price-amount {
	font-weight: 800;
}

.cwpdp--plain .cwpdp-buy table.variations {
	width: 100%;
	border-collapse: collapse;
	margin: 0 0 14px;
}

.cwpdp--plain .cwpdp-buy table.variations th,
.cwpdp--plain .cwpdp-buy table.variations td {
	padding: 6px 0;
	text-align: left;
	border: none;
	background: none;
}

.cwpdp--plain .cwpdp-buy table.variations th {
	font-size: 11px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	color: var(--cwpdp-grey);
	width: 32%;
}

.cwpdp--plain .cwpdp-buy select {
	width: 100%;
	padding: 9px 12px;
	border: 1.5px solid var(--cwpdp-line-2);
	border-radius: 10px;
	background: var(--cwpdp-card);
	color: var(--cwpdp-ink);
	font-size: 14px;
}

.cwpdp--plain .cwpdp-buy .reset_variations {
	display: inline-block;
	margin-top: 6px;
	font-size: 11.5px;
	color: var(--cwpdp-grey);
}

.cwpdp--plain .cwpdp-buy .woocommerce-variation-price,
.cwpdp--plain .cwpdp-buy .woocommerce-variation-description {
	margin: 0 0 14px;
}

.cwpdp--plain .cwpdp-buy .woocommerce-variation-price .price {
	font-weight: 800;
	font-size: 22px;
	color: var(--cwpdp-lime-deep);
}

.cwpdp--plain .cwpdp-buy .woocommerce-variation-description p {
	margin: 4px 0 0;
	font-size: 13px;
	color: var(--cwpdp-ink-2);
}

/* ==================================================================
   WAVE 8 STATE 5: 'bundle' - grouped / woosb / woosg / hamper / unknown.
   Full-width chrome around whatever woocommerce_template_single_add_to_cart()
   renders for that type - deliberately NOT the two-column ladder/buy layout,
   since a grouped table or bundle configurator needs its own width and its
   own internal layout, not a 370px column.
   ================================================================== */
.cwpdp-bundle-buy {
	margin-top: 24px;
	background: var(--cwpdp-card);
	border: 1px solid var(--cwpdp-line);
	border-radius: 14px;
	padding: 20px 22px;
}

.cwpdp-bundle-buy .cwpdp-buy-name {
	font-weight: 800;
	font-size: 15px;
	margin: 0 0 14px;
}

/*
 * Overrides the later ".cwpdp-buy-actions { display:flex; flex-wrap:nowrap }"
 * rule (same base class, kept for the ladder/plain/simple states) - a wide
 * grouped table or bundle configurator must not be squeezed into one flex row
 * beside the wishlist icon.
 */
.cwpdp-bundle-buy .cwpdp-buy-actions.cwpdp-bundle-actions {
	display: block;
}

.cwpdp-bundle-actions .cwpdp-wish {
	margin-top: 14px;
}

.cwpdp-bundle-buy .cwpdp-rewards {
	margin-top: 18px;
}

.cwpdp-bundle-buy .cwpdp-fulfil {
	max-width: 46ch;
}

/* ==================================================================
   MOBILE
   Ladder rows stack instead of scrolling sideways; the sticky bar
   sheds its least important text rather than wrapping into three rows.
   ================================================================== */
/*
 * The ladder needs NO mobile overrides - the stacked row layout above is the
 * only layout. All that changes below is padding, the stacking of the choose
 * block, and the sticky bar switching on.
 */
@media (max-width: 640px) {
	/* Room for the sticky bar AND the 58px bottom nav underneath it. */
	.cwpdp {
		padding-bottom: calc(210px + env(safe-area-inset-bottom, 0px));
	}

	.cwpdp-product {
		padding: 0 14px 32px;
	}

	.cwpdp-hero {
		gap: 20px;
	}

	.cwpdp-choose {
		gap: 12px;
	}

	.cwpdp-ladder,
	.cwpdp-buy {
		flex: 1 1 auto;
		width: 100%;
		min-width: 0;
	}

	.cwpdp-ladder tbody tr.cwpdp-row {
		grid-template-columns: 26px 1fr auto;
		padding: 11px 14px;
	}

	.cwpdp-group td {
		padding: 8px 14px;
	}

	.cwpdp-buy {
		padding: 16px;
	}

	.cwpdp-sticky {
		display: block;
	}

	.cwpdp-sticky-inner {
		padding: 0 8px 8px;
	}

	.cwpdp-sticky-buy {
		padding: 10px 14px;
		gap: 10px;
	}

	/*
	 * Dropped on mobile ONLY in the 'ladder' state, where the size pills take
	 * over that space and identify what's selected instead. Wave 8's other
	 * states have no pills - 'simple' in particular has nothing else in the
	 * bar naming the product, so hiding the name there left a price with no
	 * identity above it (live-reported bug, 2026-08-21).
	 */
	.cwpdp--ladder .cwpdp-sticky-name,
	.cwpdp--ladder .cwpdp-sticky-ppu {
		display: none;
	}

	/* Size pills stay - switching size is the point of the bar. */
	.cwpdp-sticky-sizes {
		width: 100%;
		order: -1;
	}

	.cwpdp-sticky-actions {
		width: 100%;
		margin-left: 0;
	}

	.cwpdp-sticky-add {
		flex: 1;
	}
}

@media (prefers-reduced-motion: reduce) {
	.cwpdp *,
	.cwpdp-sticky {
		transition: none !important;
	}
}

/* ==================================================================
   THEME-PROVIDED QUANTITY CONTROLS
   This theme renders its own .action.minus / .action.plus spans inside
   .quantity. We adopt them rather than adding a second pair, so style
   them to match the pill instead of our own buttons.
   ================================================================== */
.cwpdp-stepper--theme .action.minus,
.cwpdp-stepper--theme .action.plus,
.cwpdp-stepper--theme .minus,
.cwpdp-stepper--theme .plus {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 42px;
	cursor: pointer;
	color: var(--cwpdp-ink);
	background: transparent;
	border: none;
	flex: 0 0 auto;
	order: 3;
}

.cwpdp-stepper--theme .action.minus,
.cwpdp-stepper--theme .minus {
	order: 1;
}

.cwpdp-stepper--theme input.qty {
	order: 2;
}

.cwpdp-stepper--theme .action.minus:hover,
.cwpdp-stepper--theme .action.plus:hover,
.cwpdp-stepper--theme .minus:hover,
.cwpdp-stepper--theme .plus:hover {
	background: var(--cwpdp-lime-wash);
}

.cwpdp-stepper--theme .action svg,
.cwpdp-stepper--theme .minus svg,
.cwpdp-stepper--theme .plus svg {
	width: 15px;
	height: 15px;
	display: block;
}

/* ==================================================================
   WISHLIST LABEL
   The [ti_wishlists_addtowishlist] shortcode emits a visible "Add to
   Wishlist" text label. The design calls for an icon-only circular
   control, so hide the text and keep the heart.
   ================================================================== */
.cwpdp-wish .tinvwl_add_to_wishlist_button {
	font-size: 0;
	gap: 0;
}

.cwpdp-wish .tinvwl_add_to_wishlist_button::before,
.cwpdp-wish .tinvwl_add_to_wishlist_button i,
.cwpdp-wish .tinvwl_add_to_wishlist_button svg {
	font-size: 18px;
	line-height: 1;
}

.cwpdp-wish .tinvwl-txt {
	position: absolute !important;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: inset(50%);
	white-space: nowrap;
}

.cwpdp-wish .tinv-wishlist-clear {
	display: none;
}

/* ==================================================================
   OVERRIDES FOR HOST STYLING
   Fixes for rules that reach our markup from the theme and plugins.
   ================================================================== */

/*
 * Our wrapper carries WooCommerce's .product class (required - swatches and
 * FunnelKit key off it), and the theme styles .product as a flex container.
 * That turned every section of the page into a flex item, so "Why trust" sat
 * beside "About", and Reviews beside Related products. Force block flow back.
 */
.cwpdp .cwpdp-product {
	display: block;
}

/*
 * Gallery layout. Flexslider is disabled for this template (see
 * cw_pdp_disable_flexslider), so there are no inline widths or transforms to
 * fight: WooCommerce emits the feature image followed by the remaining gallery
 * images as siblings, and this grid arranges them - feature image full width,
 * the rest as a thumbnail row beneath.
 */
.cwpdp-gallery .woocommerce-product-gallery__wrapper {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 8px;
	width: 100%;
	max-width: 100%;
	margin: 0;
	padding: 0;
	transform: none !important;
}

.cwpdp-gallery .woocommerce-product-gallery__image {
	width: auto !important;
	max-width: 100%;
	margin: 0 !important;
	padding: 0;
	float: none !important;
	overflow: hidden;
}

/*
 * The feature image takes the full width of the box, inside a fixed 1:1
 * frame rather than height:auto scaling to the source photo's own
 * proportions. This catalogue's photography is not shot to one consistent
 * ratio - a crop as extreme as 247x1024px (live-reported on Fozzis Foam For
 * Fun 340ML) blew height:auto out to 1200px+, pushing the whole page below
 * the fold. object-fit:contain inside the square frame below lets any
 * ratio - portrait, landscape, or square - sit predictably without ever
 * cropping the product out of frame; a non-square photo just gets even
 * padding on two sides, in the same card colour as the rest of the box.
 */
.cwpdp-gallery .woocommerce-product-gallery__image:first-of-type {
	grid-column: 1 / -1;
	aspect-ratio: 1 / 1;
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--cwpdp-card);
}

.cwpdp-gallery .woocommerce-product-gallery__image a,
.cwpdp-gallery .woocommerce-product-gallery__image img,
.cwpdp-gallery .wp-post-image {
	display: block;
	width: 100% !important;
	height: auto;
	max-width: 100%;
}

.cwpdp-gallery .woocommerce-product-gallery__image:first-of-type a {
	display: block;
	width: 100%;
	height: 100%;
}

.cwpdp-gallery .woocommerce-product-gallery__image:first-of-type img {
	height: 100%;
	object-fit: contain;
}

/*
 * A product with no real photo renders a COMPLETELY different markup path -
 * .woocommerce-product-gallery__image--placeholder, not ...__image - so none
 * of the rules above ever matched it. It fell through to the raw 4-column
 * thumbnail grid with no grid-column span, landing in one ~69px cell instead
 * of the full width (live-reported on Dust Pan Long Handle Metal: the CW
 * logo placeholder rendering tiny in a large white box). Same full-span +
 * square-frame + object-fit:contain treatment as the real feature image.
 */
.cwpdp-gallery .woocommerce-product-gallery__image--placeholder {
	grid-column: 1 / -1;
	aspect-ratio: 1 / 1;
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--cwpdp-card);
	width: auto !important;
	max-width: 100%;
	margin: 0 !important;
	padding: 0;
	overflow: hidden;
}

.cwpdp-gallery .woocommerce-product-gallery__image--placeholder img {
	width: 100% !important;
	height: 100% !important;
	object-fit: contain;
}

/*
 * jQuery.zoom injects a magnified copy (img.zoomImg) and sizes it itself. It
 * must keep its own dimensions or the hover zoom shows a squashed image, so it
 * is exempt from the width rule above.
 */
.cwpdp-gallery img.zoomImg {
	width: auto !important;
	max-width: none;
	border-radius: 0;
}

/*
 * Thumbnails read as thumbnails: quieter, and clearly clickable. Same
 * fixed-ratio + object-fit:contain treatment as the feature image above -
 * a thumbnail is a small enough box that an extreme source crop would
 * otherwise render as a sliver rather than a recognisable photo.
 */
.cwpdp-gallery .woocommerce-product-gallery__image:not(:first-of-type) {
	aspect-ratio: 1 / 1;
	display: flex;
	align-items: center;
	justify-content: center;
}

.cwpdp-gallery .woocommerce-product-gallery__image:not(:first-of-type) img {
	height: 100%;
	object-fit: contain;
	border: 1px solid var(--cwpdp-line);
	border-radius: 8px;
	cursor: pointer;
	transition: border-color 0.15s ease;
}

.cwpdp-gallery .woocommerce-product-gallery__image:not(:first-of-type) img:hover {
	border-color: var(--cwpdp-lime);
}

/* The photoswipe magnifier emoji is decorative clutter at this size. */
.cwpdp-gallery .woocommerce-product-gallery__trigger {
	display: none;
}

.cwpdp-gallery .flex-control-thumbs li {
	width: 52px;
}

.cwpdp-gallery .flex-control-thumbs img {
	width: 100%;
	height: auto;
	border-radius: 7px;
	border: 1px solid var(--cwpdp-line);
	cursor: pointer;
}

.cwpdp-gallery .flex-control-thumbs img.flex-active {
	border-color: var(--cwpdp-lime);
}

/*
 * The theme gives .quantity an explicit 200px width, which pushed the
 * add-to-cart button onto its own line inside the narrow buy panel.
 */
.cwpdp-buy .cwpdp-stepper--woo {
	width: auto !important;
	max-width: 132px;
	flex: 0 0 auto;
}

/*
 * Related-products buttons inherit white text from the theme's .button rule,
 * which made "Select options" invisible on our light card.
 */
.cwpdp-related ul.products li.product a.button,
.cwpdp-related ul.products li.product a.button:visited {
	color: var(--cwpdp-ink);
	background-color: transparent;
}

.cwpdp-related ul.products li.product a.button:hover,
.cwpdp-related ul.products li.product a.button:focus {
	color: var(--cwpdp-olive);
	background-color: var(--cwpdp-lime);
}

/*
 * The FunnelKit floating cart bubble only conflicts with OUR sticky bar on
 * mobile, where both are fixed to the bottom of a much narrower viewport and
 * physically overlap. On desktop there is room for both, and the cart bubble
 * is a control customers already rely on elsewhere on the site - hidden below
 * 767px only, matching the breakpoint our own sticky bar uses.
 */
@media (max-width: 767px) {
	#fkcart-floating-toggler,
	.fkcart-floating-icon {
		display: none !important;
	}
}

/*
 * Keep the stepper, the button and the heart on ONE row inside the buy panel.
 * WooCommerce nests the button inside .woocommerce-variation-add-to-cart, so the
 * row has to be established at each level, and the button must be allowed to
 * shrink (min-width:0) or it forces a wrap at this column width.
 */
.cwpdp-buy-actions {
	display: flex;
	align-items: center;
	gap: 9px;
	flex-wrap: nowrap;
}

.cwpdp-buy form.cart,
.cwpdp-buy .woocommerce-variation-add-to-cart,
.cwpdp-buy .single_variation_wrap {
	flex: 1 1 auto;
	min-width: 0;
	flex-wrap: nowrap;
}

.cwpdp-buy .single_add_to_cart_button {
	min-width: 0;
	padding-left: 14px;
	padding-right: 14px;
}

.cwpdp-wish {
	flex: 0 0 auto;
}

/*
 * An inline <style> block on this site sets `.add_to_cart_button { color: white
 * !important }`, which made "Select options" invisible on our light
 * related-product cards. Beating an !important inline-sheet rule needs
 * !important here - specificity alone cannot do it.
 */
.cwpdp .cwpdp-related ul.products li.product a.button,
.cwpdp .cwpdp-related ul.products li.product a.button:link,
.cwpdp .cwpdp-related ul.products li.product a.button:visited {
	color: var(--cwpdp-ink) !important;
	background: transparent;
	border: 1.5px solid var(--cwpdp-line-2);
}

.cwpdp .cwpdp-related ul.products li.product a.button:hover,
.cwpdp .cwpdp-related ul.products li.product a.button:focus {
	color: var(--cwpdp-olive) !important;
	background-color: var(--cwpdp-lime) !important;
	border-color: var(--cwpdp-lime);
}

/* ==================================================================
   STICKY BAR: NOW ON DESKTOP TOO
   Above 767px there is no mobile bottom nav, so the bar sits flush at
   bottom:0 with a modest z-index. At or below 767px cw-mobile-nav is
   fixed at bottom:0 (58px tall, z-index 999999), so the bar lifts
   clear of it and rises above it in the stack - mirroring that
   plugin's own convention for elements stacked over its bar.
   The breakpoint is 767px to match cw-mobile-nav exactly; using 640px
   here would leave a 641-767px band where the two overlap.
   ================================================================== */
@media (max-width: 767px) {
	.cwpdp-sticky {
		bottom: calc(58px + env(safe-area-inset-bottom, 0px));
		z-index: 999998;
		transform: translateY(calc(115% + 58px));
	}
}

/*
 * The wishlist heart TI auto-injects into every loop card (site-wide
 * "above_thumb" position) rendered here as a plain inline link before the
 * photo - on the shop grid it is repositioned into a circular top-right
 * overlay (.cwsg-wish/.cwsg-heart); this restyles the SAME real markup into
 * the same spot rather than building a second proxy system for one section.
 */
.cwpdp-related ul.products li.product .tinv-wraper {
	position: absolute;
	top: 20px;
	right: 20px;
	z-index: 5;
}

.cwpdp-related ul.products li.product .tinvwl_add_to_wishlist_button {
	width: 36px;
	height: 36px;
	border: 1.5px solid var(--cwpdp-line);
	background: var(--cwpdp-card);
	border-radius: 999px;
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--cwpdp-ink-2);
	font-size: 16px;
	box-shadow: 0 1px 4px rgba(38, 50, 56, 0.1);
	transition: border-color 0.14s ease, color 0.14s ease;
}

.cwpdp-related ul.products li.product .tinvwl_add_to_wishlist_button:hover {
	border-color: var(--cwpdp-bad);
	color: var(--cwpdp-bad);
}

.cwpdp-related ul.products li.product .tinvwl-tooltip {
	display: none;
}

/* ==================================================================
   RELATED PRODUCT CARDS: SWATCH -> TWO-STATE BUTTON
   ================================================================== */
.cwpdp-related ul.products li.product .variations,
.cwpdp-related ul.products li.product table.variations {
	display: none;
}

.cwpdp-rel-swatches {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	margin-top: 9px;
}

.cwpdp-related ul.products li.product .variable-item {
	font-size: 11.5px;
	font-weight: 800;
	border: 1.5px solid var(--cwpdp-line-2);
	background: var(--cwpdp-card);
	color: var(--cwpdp-ink-2);
	/* woo-variation-swatches-pro ships its own 2px !important radius on this
	   exact class - needs !important to win, same fight as the button colour
	   overrides further down this file. */
	border-radius: 6px !important;
	padding: 4px 9px;
	margin: 0;
	cursor: pointer;
	list-style: none;
	box-shadow: none;
	width: auto;
	height: auto;
	transition: border-color 0.12s ease, background 0.12s ease;
}

.cwpdp-related ul.products li.product .variable-item:hover {
	border-color: var(--cwpdp-grey);
}

.cwpdp-related ul.products li.product .variable-item.is-chosen {
	border-color: var(--cwpdp-lime);
	background: var(--cwpdp-lime-row);
	color: var(--cwpdp-ink);
	box-shadow: 0 0 0 1px var(--cwpdp-lime);
}

/* woo-variation-swatches wraps its label in extra spans; keep them inline. */
.cwpdp-related ul.products li.product .variable-item > * {
	display: inline;
	font: inherit;
	color: inherit;
}

/*
 * The ready (swatch chosen) state. An inline <style> on this site sets
 * `.add_to_cart_button:hover { background: initial !important }` - a SHORTHAND
 * with !important - so the hover fill has to be declared as the `background`
 * shorthand with !important too. Setting only background-color loses.
 */
.cwpdp .cwpdp-related ul.products li.product a.button.is-ready,
.cwpdp .cwpdp-related ul.products li.product a.button.is-ready:link,
.cwpdp .cwpdp-related ul.products li.product a.button.is-ready:visited {
	background: var(--cwpdp-lime);
	color: var(--cwpdp-olive) !important;
	border-color: var(--cwpdp-lime);
}

.cwpdp .cwpdp-related ul.products li.product a.button:hover,
.cwpdp .cwpdp-related ul.products li.product a.button:focus,
.cwpdp .cwpdp-related ul.products li.product a.button.is-hover {
	background: var(--cwpdp-lime) !important;
	color: var(--cwpdp-olive) !important;
	border-color: var(--cwpdp-lime) !important;
}

.cwpdp .cwpdp-related ul.products li.product a.button.is-ready:hover,
.cwpdp .cwpdp-related ul.products li.product a.button.is-ready:focus {
	background: var(--cw-lime-deep, #5f8c00) !important;
	color: var(--cwpdp-olive) !important;
}

.cwpdp-related ul.products li.product a.button.is-loading {
	opacity: 0.6;
	pointer-events: none;
}
