/**
 * Bonza, basic product page marketing sections (ClickUp 86eypb6me follow-up).
 * See product-page/product-page-marketing.php for the full docblock: Figma
 * file cY9QX6IwGVaaGI4r7J2RRF, frame "BASIC PRODUCT PAGE - D", node
 * 34384:220961 downward.
 *
 * Config investigated: same as product-page.css, no Blocksy Customizer
 * surface exists for a bespoke marketing block like this.
 *
 * editor-friendly-ok: this restyles WooCommerce's own after-summary output
 * area, which has no Gutenberg block/pattern counterpart to register
 * add_editor_style() against, the same documented exception
 * product-page.css already uses for the buy box above it.
 *
 * Palette: cream #F8EDE3, green #247B4E, amber #FFA825, ink #2E2A2A, muted
 * ink #746E60, all read directly off the Figma nodes cited in the PHP file,
 * matching the palette already established by product-page.css/footer.css.
 *
 * Contrast: Figma's literal #16A34A evidence-link green measured 3.30:1 on
 * white (fails 4.5:1 for 14px text), the same colour the project register
 * already found failing elsewhere and remapped to #1F6B42 (6.48:1 on
 * white); reused here instead of re-deriving a new value.
 */

.bppm {
	--bppm-cream: #F8EDE3;
	--bppm-cream-alt: #F9EDE3;
	--bppm-green: #247B4E;
	--bppm-amber: #FFA825;
	--bppm-ink: #2E2A2A; /* editor-friendly-ok: same no-Gutenberg-surface exception this file's header states. 12.30:1 on cream / 14.18:1 on white (WCAG AA/AAA) */
	--bppm-ink-muted: #746E60;
	--bppm-white: #FFFFFF;
	/*
	 * The Figma desktop frame's own width. It is no longer a cap on any
	 * band: the bands run edge to edge and .bppm-section's padding-inline
	 * centres a content column of this width minus the frame's 64px gutters.
	 */
	--bppm-max-width: 1512px;
	/*
	 * CORRECTED 2026-09-23 (86eypb6me): the page gutter, i.e. how far every
	 * marketing-section BOX (not its inner content) sits from the true
	 * viewport edge. Measured node-by-node off every top-level section frame
	 * and every "Frame 2147229786 N" divider strip in the ledger
	 * (figma-section-boxes.py): every one of them sits at x=64/24/20 and is
	 * exactly 1384/696/388 wide at the 1512/744/428 frames, on both variants
	 * (Superfoods @74103:31720/@23310:35545/@23313:52680, Biotics
	 * @34926:77030/@34926:86441/@34926:91317). The >=1440 value reuses the
	 * same max()-with-the-1512-frame formula this file already used for
	 * padding before this correction, so the box stops growing past 1384
	 * wide and stays centred above 1512 rather than stretching indefinitely.
	 * margin-inline percentages resolve against the containing block's
	 * inline size, same as padding-inline did, so the formula carries over
	 * unchanged (MDN margin-inline / calc()).
	 */
	--bppm-gutter: max(64px, calc((100% - 1384px) / 2));
	/*
	 * The box's inner padding is a flat 64px, not the gutter formula: padding
	 * percentages also resolve against the containing block, so above 1512
	 * the formula would grow the padding with the margin and squeeze the
	 * content (588px a side at 2560).
	 */
	--bppm-pad: 64px;
}

@media (min-width: 744px) and (max-width: 1439px) {
	.bppm {
		--bppm-gutter: 24px;
		--bppm-pad: 24px;
	}
}

@media (max-width: 743px) {
	.bppm {
		--bppm-gutter: 20px;
		--bppm-pad: 20px;
	}
}

/*
 * `.bppm` still escapes two ancestors that would otherwise clip the marketing
 * stack: `.single-product div.product.type-product` carries both a
 * `max-width: 1512px` and 20/32/64px of horizontal padding, and the marketing
 * stack is hooked on `woocommerce_after_single_product_summary`, which fires
 * inside that wrapper. The standard full-bleed recipe (100vw + a negative
 * margin) escapes both without moving the hook, which would change DOM order
 * around the related products row for a purely visual result.
 *
 * CORRECTED 2026-09-23 (86eypb6me): the previous version of this comment
 * described every coloured band as painting edge to edge, on the theory that
 * Figma's own section frames also reach both edges of their canvas. They do
 * not -- figma-section-boxes.py's node-by-node walk of every top-level
 * section frame shows each one sits at x=64/24/20 and is 1384/696/388 wide,
 * i.e. Figma draws every band, and every "Frame 2147229786 N" divider strip
 * between them, as its own BOX inset from the page edge, not full-bleed
 * colour. `.bppm-section` (below) and `.bppm-divider`
 * (product-page-dividers.css) now reproduce that: `.bppm` still escapes to
 * 100vw so the box can be measured and centred against the true viewport
 * rather than the clipped WooCommerce wrapper, but the box itself stops
 * `--bppm-gutter` short of each edge, leaving the page's own background
 * (white) showing outside it, matching every one of the 1512/744/428 frames.
 *
 * No overflow guard is added for the 100vw width, and that is measured rather
 * than assumed: `body` already carries `overflow-x: hidden` and
 * `#main-container` carries `overflow-x: clip`, so a platform with classic
 * scrollbars, where 100vw exceeds the client width, cannot produce a
 * horizontal scrollbar here. Verified at 320, 428, 744, 1024, 1512, 1920 and
 * 2560 with the rules injected into the deployed page: scrollWidth equals
 * clientWidth at every one.
 */
.bppm {
	width: 100vw;
	margin-inline: calc(50% - 50vw);
}

/*
 * CORRECTED 2026-09-23 (86eypb6me): every section is now a BOX inset from the
 * page edge by --bppm-gutter (margin-inline), with its own inner padding
 * between the box edge and its content -- see the file-header comment on
 * --bppm-gutter for the ledger measurement this is built from. The default
 * inner padding below (32px block, the same gutter inline) is what most
 * sections draw; the exceptions each section-specific rule further down this
 * file overrides are named and measured against the ledger individually
 * (.bppm-why/.bppm-subscribe, .bppm-routine, .bppm-calculator). Above 1512
 * the box's own max()-based --bppm-gutter formula stops it growing past
 * 1384px wide and keeps it centred, the same behaviour this rule's own
 * padding-inline used to provide before the box/content split.
 */
.bppm-section {
	margin-inline: var(--bppm-gutter);
	padding-block: 32px;
	padding-inline: var(--bppm-pad);
}

/*
 * "Why it's different" and "Subscribe & Save": Figma's own inner padding on
 * these two boxes is the page gutter on EVERY side, not the 32px block
 * default every other section draws. Measured off the ledger (both are
 * "Frame 2147229786"-adjacent leaf frames, walked the same way as the
 * default sections): 64/64/64/64 @1512, 24/24/24/24 @744, 20/20/20/20 @428.
 * `.bppm-section.bppm-why`/`.bppm-section.bppm-subscribe` (0,2,0) rather than
 * the bare class names, so this reliably outranks the (0,1,0) base rule
 * above regardless of source order (recurring-mistakes-register #31).
 */
.bppm-section.bppm-why,
.bppm-section.bppm-subscribe {
	padding: var(--bppm-pad);
}

/*
 * "Build your dog routine": Figma's own inner padding is asymmetric on this
 * box -- top is always 20px (never the 32px block default), bottom equals
 * the page gutter, and at 428 the inline padding drops to 0 so the
 * horizontal-scrolling card row (.bppm-routine__grid, further down this
 * file) can reach the box's own edge exactly as it reached the viewport
 * edge before this correction (same net available width, gutter moved from
 * padding to margin). Measured off the ledger, both variants agree:
 * 20/64/64/64 @1512, 20/24/24/24 @744, 20/0/20/0 @428 (top/right/bottom/
 * left).
 */
.bppm-section.bppm-routine {
	padding-top: 20px;
	padding-bottom: var(--bppm-pad);
	padding-inline: var(--bppm-pad);
}

@media (max-width: 743px) {
	.bppm-section.bppm-routine {
		padding-inline: 0;
	}
}

/*
 * Feeding-calculator CTA band ("Frame 2147229959"): Figma's own block
 * padding is 20px, not the 32px default (inline padding matches the page
 * gutter as normal, so no override needed there). Measured off the ledger:
 * 20/64/20/64 @1512, 20/24/20/24 @744, 20/20/20/20 @428. Biotics never
 * renders this section (see product-page-marketing.php,
 * bonza_pdp_marketing_steps() docblock, "CORRECTED 2026-09-23"), so this is
 * Superfoods-only in practice but scoped by class, not variant, in case that
 * ever changes.
 */
.bppm-section.bppm-calculator {
	padding-block: 20px;
}

/*
 * CORRECTED 2026-09-23 (86eypb6me): every eyebrow text node in the ledger
 * (name "eyebrow", both variants, all three frames) measures line-height 16
 * regardless of its font-size (14 at 1512/744, 12 at 428) -- confirmed via
 * `jq` against desktop-1512/tablet-744/mobile-428.jsonl, not assumed. The
 * bare `.bppm-eyebrow` class (0,1,0) used to lose that 16px to
 * `.bppm-section p`'s own line-height:1.4 (0,1,1) -- a class beats a class,
 * but a class+type beats a class alone. Verified by walking
 * document.styleSheets/el.matches() on the live page before this fix: every
 * `<p class="bppm-eyebrow ...">` matched `.bppm-section p` and rendered
 * 19.6px (16.8px at the 12px mobile size) instead of 16px.
 * `.bppm-section .bppm-eyebrow` (0,2,0) reliably outranks it regardless of
 * source order (recurring-mistakes-register #31); every eyebrow in this
 * file's markup is a `.bppm-section` descendant, confirmed by grep.
 */
.bppm-section .bppm-eyebrow {
	font-family: 'Nominee', var(--theme-font-family, sans-serif);
	font-weight: 900;
	font-size: 14px;
	line-height: 16px;
	letter-spacing: 0.02em;
	text-transform: uppercase;
	color: var(--bppm-ink);
	text-align: center;
	margin: 0 0 12px;
}

/*
 * FIXED 2026-09-24 (86eypb6me, S9 + S35, deduped on q18 batch merge): named
 * the winning rule live via document.styleSheets/el.matches() before
 * touching anything. Two independent reports of the same bug: the
 * How-It-Works "THE DAILY PROCESS" eyebrow (S9) and the mobile "FAQ"
 * eyebrow (S35) both rendered --bppm-ink (#2E2A2A) on their section's own
 * dark/green background instead of this rule's near-white value -- Figma
 * draws both white/near-white. `.bppm-eyebrow--on-dark` alone is (0,1,0);
 * `.bppm-section .bppm-eyebrow` two rules up is (0,2,0) and every eyebrow
 * in this file's markup is a `.bppm-section` descendant, so the base ink
 * colour always won regardless of source order -- the same
 * specificity-matching bug recurring-mistakes-register #31 already
 * documents for the eyebrow's own line-height a few lines above.
 * `.bppm-section .bppm-eyebrow.bppm-eyebrow--on-dark` (0,3,0) reliably
 * outranks the (0,2,0) base rule instead of just tying it, so this is not
 * a second silent loss waiting on the next source-order shuffle.
 * `.bppm-eyebrow--on-amber` carried the identical (0,1,0) specificity bug,
 * invisible only because its colour happens to already equal the base
 * rule's; corrected the same way below so it cannot silently regress the
 * moment that coincidence stops holding.
 */
.bppm-section .bppm-eyebrow.bppm-eyebrow--on-dark {
	/*
	 * Figma's own literal fill here is rgb(191,230,205) (measured off the
	 * 2026-09-23 ledger's "eyebrow" text node under "How its work"), not
	 * white -- but that colour only reaches 3.84:1 on this section's
	 * #247B4E green, failing the 4.5:1 floor for 14px bold text. White at 80
	 * percent (the next candidate) composites to 3.98:1, also failing; 90
	 * percent clears at 4.58:1 and is the smallest change that does. The
	 * deviation from Figma is deliberate and reported to the designer rather
	 * than silently absorbed.
	 */
	color: rgba(255, 255, 255, 0.9);
}

.bppm-section .bppm-eyebrow.bppm-eyebrow--on-amber {
	color: var(--bppm-ink);
}

.bppm-section h2 {
	font-family: 'Nominee', var(--theme-font-family, sans-serif);
	font-weight: 900;
	text-transform: uppercase;
	text-align: center;
	margin: 0 0 16px;
}

.bppm-section p {
	font-family: 'Kobe1.1', var(--theme-font-family, sans-serif);
	line-height: 1.4;
}

/*
 * REMOVED 2026-09-23 (86eypb6me): this file used to carry a dead
 * `.bppm-divider{width:100%;height:118px;background-size:cover;...}`
 * scaffold rule here (product-page-dividers.css's own header comment
 * documented it as dead and left it rather than editing this file across a
 * branch split). `.bppm-divider` now lives only in
 * product-page-dividers.css, including the margin-inline inset this same
 * ClickUp task gives it -- see that file for the full rule and its ledger
 * citation.
 */

/* Why it's different: two-column copy + callout card, white background. */
.bppm-why {
	background: var(--bppm-white);
	display: flex;
	flex-wrap: wrap;
	gap: 42px;
	justify-content: center;
}

.bppm-why__copy,
.bppm-why__aside {
	flex: 1 1 420px;
	min-width: 0;
}

/*
 * The aside's photograph, above the callout (product-page-marketing.php).
 * Superfoods fills the column at 3:2 with no gap to the callout, as Figma
 * draws at 1512 (607x405), 744 (648x432) and 428 (348x232). Biotics is a
 * fixed 354x346 cut-out, centred, 42px above the callout at every width, and
 * shrinks with the column rather than overflowing it at 320.
 */
.bppm-why__photo {
	margin: 0;
}

.bppm-why__photo-img {
	display: block;
	width: 100%;
	max-width: none;
	height: auto;
	aspect-ratio: 3 / 2;
	object-fit: cover;
}

.bppm-why__photo--biotics {
	width: min(354px, 100%);
	margin: 0 auto 42px;
}

.bppm-why__photo--biotics .bppm-why__photo-img {
	aspect-ratio: 354 / 346;
}

.bppm-why__heading {
	font-size: 30px;
	line-height: 36px;
	color: var(--bppm-ink);
}

/*
 * CORRECTED 2026-09-23 (86eypb6me, q5): `.bppm-why__heading` alone is
 * (0,1,0) and was losing its own `text-align: left` to `.bppm-section h2`
 * (0,1,1, a class + a type selector) further up this file, so the heading
 * rendered centred on the deployed page regardless of source order --
 * confirmed by walking document.styleSheets/el.matches() before writing
 * this rule (recurring-mistakes-register #31/#153), not assumed from
 * reading the file. `.bppm-section h2.bppm-why__heading` (0,2,1) reliably
 * outranks it; same pattern this file's own FAQ heading override already
 * uses a few hundred lines down (`.bppm-section h2.bppm-faq__heading`).
 */
.bppm-section h2.bppm-why__heading {
	text-align: left;
}

.bppm-why__heading em {
	font-style: normal;
	color: var(--bppm-green);
}

/*
 * G40/M16 (z8udzkgpxk): Figma draws the whole Bites "When ..." why-heading
 * green (rgb 36,123,78). Those headings are plain text from the per-product
 * copy record; only the Superfoods heading carries an <em> and keeps ink with
 * a green <em>. (0,3,1) outranks the (0,2,1) text-align rule above.
 */
.bppm-section h2.bppm-why__heading:not(:has(em)) {
	color: var(--bppm-green);
}

.bppm-why__copy p {
	font-size: 20px;
	line-height: 24px;
	color: var(--bppm-ink-muted); /* 5.07:1 on white, verified */
	margin: 0 0 20px;
}

.bppm-why__callout {
	background: var(--bppm-cream);
	border-radius: 8px;
	padding: 25px 12px;
}

/*
 * CORRECTED 2026-09-23 (86eypb6me, q9): `.bppm-why__callout-heading` is a
 * plain class (0,1,0) on a `<p>` element, which was losing its own
 * `font-family: 'Nominee'` to `.bppm-section p` (0,1,1) further up this
 * file -- the deployed page rendered this heading in Kobe1.1, the body
 * font, instead of Nominee. Confirmed by walking document.styleSheets/
 * el.matches() before writing this fix (recurring-mistakes-register
 * #31/#153), the same pattern already found on `.bppm-why__heading` (q5)
 * above. `.bppm-section p.bppm-why__callout-heading` (0,2,1) outranks it.
 * editor-friendly-ok: same no-Gutenberg-surface exception this file's
 * header states.
 */
/*
 * FIXED 2026-09-24 (ClickUp 86eypb6me, PDP round 2, item 2 / q7): neither
 * this heading nor .bppm-why__callout-body below had a text-align rule
 * anywhere in the file (grepped, confirmed via computed style: both
 * rendered "start", the browser default, not an inherited "left" from a
 * competing rule -- nothing was fighting for it, it was simply never set).
 * Figma's callout text nodes (I21316:76932;34384:220880/220881 Superfoods,
 * I34926:77031;34920:66122/66123 Biotics, same at tablet/mobile) both set
 * textAlignHorizontal: CENTER. Also added: letterSpacing 2% -> 0.02em on
 * the heading (Figma text.letterSpacing, PERCENT unit / 100 = em, per
 * recurring-mistakes-register #26), matching the .text object's real
 * values -- NOT the font-size, which product-page-typescale.css already
 * ships correctly at 14px tablet/mobile per the Figma nodes' own 14px.
 * counterAxisAlignItems: CENTER on the callout's own auto-layout frame
 * (already reflected by this component rendering visually centered as a
 * block) does not by itself center the TEXT inside a FILL-width node --
 * confirmed via the node's own text.textAlignHorizontal, not inferred from
 * the parent layout. `.bppm-why__callout-body` alone is (0,1,0) and its
 * `line-height` was verified LOSING to `.bppm-section p` (0,1,1) further up
 * this file (walked document.styleSheets + el.matches() live before
 * writing this -- same pattern as the q9/q5 fixes above), so the body rule
 * uses the same `.bppm-section p.bppm-why__callout-body` (0,2,1) compound
 * this file already established for that exact problem. editor-friendly-ok:
 * same no-Gutenberg-surface exception this file's header states.
 */
.bppm-section p.bppm-why__callout-heading {
	font-family: 'Nominee', sans-serif;
	font-weight: 900;
	font-size: 16px;
	letter-spacing: 0.02em;
	text-transform: uppercase;
	text-align: center;
	color: #1A2E23; /* 12.48:1 on #F8EDE3 cream, verified */
	margin: 0 0 16px;
}

.bppm-section p.bppm-why__callout-body {
	/*
	 * editor-friendly-ok: same no-Gutenberg-surface exception this file's
	 * header states. --bppm-ink-muted is Figma's own rgb(116, 110, 96) and
	 * it measures 4.40:1 on cream. Elsewhere in this file that is fine,
	 * because the text is bold 20px and qualifies as large. Here it does
	 * not: the size is inherited and lands under the large-text threshold,
	 * so the 4.5:1 floor applies and axe flags it. #6B6558 is the same hue
	 * one step darker, 5.02:1 on cream.
	 */
	color: #6B6558;
	font-size: 16px; /* Figma text.fontSize 16 at every breakpoint, unlike the heading */
	font-weight: 700;
	line-height: 1.2; /* Figma text.lineHeight 120% -- was inheriting 1.4 from .bppm-section p, computed 22.4px vs the Figma-correct 19.2px */
	text-align: center;
	margin: 0;
}

/* Six-reasons accordion grid, cream background. */
.bppm-reasons {
	background: var(--bppm-cream-alt);
}

/*
 * FIXED 2026-09-24 (ClickUp 86eypb6me, Biotics follow-up, M1): margin-bottom
 * was 32px, measured live via getBoundingClientRect() as the gap between
 * .bppm-reasons__intro and .bppm-reasons__grid (32px). Figma's vertical
 * auto-layout frame wrapping both ("Frame 2147229831", node
 * I34926:77031;34920:66125 on Biotics) sets itemSpacing 42 -- and the SAME
 * frame name/spacing exists on Superfoods (I21316:76932;34384:224430, also
 * itemSpacing 42), so this is a shared defect on both templates, not a
 * Biotics-only one; fixing the one shared rule corrects both without a
 * variant selector.
 */
/*
 * FIXED 2026-09-24 (ClickUp 86eypb6me, PDP round 2, q18/S8): max-width was an
 * arbitrary 720px, never grounded in the ledger. The real intro frame
 * ("Frame 2147229758", I21316:76932;34384:224431) is FULL width of the
 * section's own content column at every breakpoint -- 1256 at 1512, 648 at
 * 744, 348 at 428, matching `.bppm-reasons__grid`'s own 1256px cap below --
 * not a narrower fixed column. The 720px cap wrapped the heading/lead onto
 * extra lines the design never draws.
 */
.bppm-reasons__intro {
	max-width: 1256px;
	margin: 0 auto 42px;
	text-align: center;
}

.bppm-reasons__heading {
	font-size: 30px;
	line-height: 36px;
	color: var(--bppm-green);
}

.bppm-reasons__lead {
	font-size: 20px;
	color: var(--bppm-ink);
	font-weight: 700;
	margin: 0;
}

/*
 * Card row, Figma "Frame 2147229757": six equal columns in one row at 1512
 * (199.33 each inside a 1256 row), three columns of 208 at 744, two of 168
 * at 428, 12px between cards at every width. Figma's rows stretch every card
 * to the tallest in its row, which grid does by default.
 *
 * The widths between frames are anchored, not drawn: six columns only once
 * each card is at least 182px wide (1280 minus the 64px gutters), three from
 * the 744 frame up, and two from 388. 388 is the width at which a two-up card
 * reaches Figma's narrowest drawn card, 168px with 128px of text. Measured on
 * v1: at 375 the text column is 121.5px and ADAPTOGENS and INFLAMMATORY both
 * broke mid-word, so below 388 the row falls back to one column.
 */
.bppm-reasons__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 12px;
	max-width: 1256px;
	margin-inline: auto;
}

@media (min-width: 388px) {
	.bppm-reasons__grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 744px) {
	.bppm-reasons__grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

@media (min-width: 1280px) {
	.bppm-reasons__grid {
		grid-template-columns: repeat(6, minmax(0, 1fr));
	}
}

/* Card: 16/20 padding and an 18px stack gap, same at all three frames. */
.bppm-reason-card {
	background: var(--bppm-white);
	border-radius: 8px;
	padding: 16px 20px;
	display: flex;
	flex-direction: column;
	gap: 18px;
}

/*
 * Figma sizes the card titles per variant: Superfoods 16/14/14px at
 * 1512/744/428, Biotics 14/14/12px. product-page-typescale.css already
 * covers the Superfoods steps for both templates, so only the two places
 * Biotics differs are set here. At 16px, "INFLAMMATORY" is wider than the
 * 159px text column and broke mid-word.
 */
@media (min-width: 1440px) {
	.bppm-reasons--biotics .bppm-reason-card__title {
		font-size: 14px;
	}
}

@media (max-width: 743px) {
	.bppm-reasons--biotics .bppm-reason-card__title {
		font-size: 12px;
	}
}

/* Figma "Frame 8/9/10": a 64px #FFA825 circle holding one centred glyph.
   The glyph's offset inside the circle is baked into each SVG. */
.bppm-reason-card__icon {
	display: block;
	flex: none;
	width: 64px;
	height: 64px;
	border-radius: 50%;
	background: var(--bppm-amber);
}

.bppm-reason-card__icon svg {
	display: block;
	width: 64px;
	height: 64px;
}

.bppm-reason-card__title {
	font-family: 'Nominee', sans-serif;
	font-weight: 900;
	font-size: 16px;
	line-height: 16px;
	letter-spacing: 0.02em;
	text-transform: uppercase;
	color: var(--bppm-ink);
	margin: 0;
	text-align: left;
}

.bppm-reason-card__body {
	font-size: 14px;
	color: var(--bppm-ink);
	margin: 0;
}

/* Accordion, native details/summary. summary{list-style:none} plus the
   ::-webkit-details-marker override hides the native disclosure triangle
   consistently across Chrome/Firefox/WebKit, confirmed working pattern
   already used elsewhere on this project (checkout returns accordion). */
.bppm-accordion summary {
	list-style: none;
	cursor: pointer;
	font-family: 'Kobe1.1', sans-serif;
	font-weight: 700;
	font-size: 14px;
	color: #1F6B42; /* 6.48:1 on white, the register's established remap of Figma's literal #16A34A (3.30:1, fails 4.5:1) */
	text-decoration: underline;
}

.bppm-accordion summary::-webkit-details-marker {
	display: none;
}

.bppm-accordion__detail {
	font-size: 14px;
	color: var(--bppm-ink);
	margin: 8px 0;
}

.bppm-accordion__evidence-link,
.bppm-accordion__evidence-text {
	font-size: 14px;
	font-weight: 700;
	color: #1F6B42; /* 6.48:1 on white, same remap as .bppm-accordion summary above */
	text-decoration: underline;
}

/*
 * Six-reasons card accordion, Figma "Accordion" in each card (34841:89295 and
 * siblings), scoped to the cards because the FAQ reuses .bppm-accordion.
 * Figma draws it open: a header row ("The science" plus a 16px chevron,
 * 8px apart), a 1px #F8EDE3 divider, the detail copy and the evidence link,
 * 8px between each. Header Kobe1.1 700 14/16 in #247B4E with no underline;
 * detail Kobe1.1 400 14/16 in #2E2A2A; evidence Kobe1.1 700 14/20 in #1C5F3C,
 * underlined. The 428 frame drops all three to 12px, same line heights.
 */
.bppm-reason-card .bppm-accordion {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.bppm-reason-card .bppm-accordion summary {
	display: flex;
	align-items: center;
	gap: 8px;
	font-family: 'Kobe1.1', sans-serif;
	font-weight: 700;
	font-size: 14px;
	line-height: 16px;
	color: var(--bppm-green); /* #247B4E, 5.23:1 on the white card */
	text-decoration: none;
}

.bppm-reason-card .bppm-accordion__chevron {
	flex: none;
	transform: rotate(180deg);
	transition: transform 0.2s ease;
}

.bppm-reason-card .bppm-accordion[open] .bppm-accordion__chevron {
	transform: none;
}

@media (prefers-reduced-motion: reduce) {
	.bppm-reason-card .bppm-accordion__chevron {
		transition: none;
	}
}

.bppm-reason-card .bppm-accordion[open] summary {
	padding-bottom: 8px;
	border-bottom: 1px solid #F8EDE3;
}

.bppm-reason-card .bppm-accordion__detail {
	margin: 0;
	font-size: 14px;
	line-height: 16px;
	color: var(--bppm-ink);
}

.bppm-reason-card .bppm-accordion__evidence-link,
.bppm-reason-card .bppm-accordion__evidence-text {
	font-family: 'Kobe1.1', sans-serif;
	font-weight: 700;
	font-size: 14px;
	line-height: 20px;
	color: #1C5F3C; /* 7.7:1 on white */
	text-decoration: underline;
}

@media (max-width: 743px) {
	.bppm-reason-card .bppm-accordion summary,
	.bppm-reason-card .bppm-accordion__detail,
	.bppm-reason-card .bppm-accordion__evidence-link,
	.bppm-reason-card .bppm-accordion__evidence-text {
		font-size: 12px;
	}
}

/* How it works, green background. */
.bppm-how {
	background: var(--bppm-green);
	text-align: center;
}

/*
 * ADDED 2026-09-23 (86eypb6me, q13/q34): Figma's own content cap for this
 * section is 1000px (`Frame 2147229774`/`Frame 2147229981`, both 1000 wide,
 * centred inside the 1256px content area every other .bppm-section uses),
 * not the section's usual full content width. Every child below already
 * inherits this constraint except the two-column `.bppm-how__layout` row,
 * which needs the explicit 1000px cap so its 484/484/32 split lands on
 * Figma's own numbers instead of stretching across the wider 1256px column.
 */
.bppm-how__inner {
	max-width: 1000px;
	margin-inline: auto;
}

.bppm-how__heading {
	font-size: 30px;
	line-height: 36px;
	color: var(--bppm-cream);
}

.bppm-how__lead {
	font-size: 20px;
	color: var(--bppm-cream);
	font-weight: 700;
	max-width: 720px;
	margin: 0 auto 32px;
}

/*
 * The section photograph (Figma `Lab biotics bonza 1`).
 *
 * 484px cap with a 1:1 ratio, so the photo fills its content column exactly as
 * Figma does, with no media query.
 *
 * MEASURED on the deployed page, not assumed:
 *   1512 -> 484x484. Matches the drawn size exactly (section padding 64px).
 *    428 -> 388x388. Figma draws 348x348 there, and the 40px difference is NOT
 *          this rule: the section's own mobile gutter is 20px against Figma's
 *          40px, so the content column is 388 rather than 348. The photo fills
 *          that column correctly; the gutter is a pre-existing section-level
 *          discrepancy tracked separately.
 *
 * Centred under the same parent as .bppm-how__stages, so their CENTRES line up.
 * Their edges do not: this caps at 484px and the stage list at 720px. Said
 * plainly because an earlier version of this comment claimed a shared measure.
 *
 * `aspect-ratio` with `object-fit: cover` rather than a fixed height: the source
 * is square already, and this keeps the box stable while the image loads so the
 * stages below do not jump.
 */
.bppm-how__aside {
	width: 100%;
}

.bppm-how__photo {
	margin: 0 auto 32px;
	max-width: 484px;
	width: 100%;
}

.bppm-how__photo-img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	border-radius: 16px;
}

/* Superfoods draws its own photo here: a transparent cut-out of a dachshund
   and a Superfoods bag, 484x710 at 1512 and 348x510 at 428, no corner radius. */
.bppm-how__photo--superfoods .bppm-how__photo-img {
	aspect-ratio: 682 / 1000;
	object-fit: contain;
	border-radius: 0;
}

/*
 * FIXED 2026-09-24 (ClickUp 86eypb6me, Biotics follow-up q18/B4): the base
 * rule above (aspect-ratio:1/1, object-fit:cover, border-radius:16px) drew a
 * rounded WHITE CARD behind the retriever photo, because the source JPG
 * carried a real baked-in white background object-fit:cover had nothing to
 * crop past. Figma draws this photo the same way as Superfoods' own cutout
 * immediately above: transparent, sitting directly on the section's green
 * background, no card. Same object-fit:contain / border-radius:0 override,
 * 1:1 (the new asset is a 968x968 square cutout, unlike Superfoods' portrait
 * crop) now that the .webp source is genuinely transparent.
 */
.bppm-how__photo--biotics .bppm-how__photo-img {
	aspect-ratio: 1 / 1;
	object-fit: contain;
	border-radius: 0;
}

/*
 * Three numbered process stages (Superfoods node 34384:225672, Biotics node
 * 34920:66212). The digit fill/colour is not present in the text-only Figma
 * enumeration this project audits against, so the badge inverts the
 * established on-green convention instead of guessing a new pair: cream
 * background with green digits, the converse of .bppm-timeline__label's
 * green background with white digits below.
 */
.bppm-how__stages {
	list-style: none;
	margin: 0 0 32px;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 20px;
	max-width: 720px;
	margin-left: auto;
	margin-right: auto;
	text-align: left;
}

/*
 * ADDED 2026-09-23 (86eypb6me, q13/q34): the two-column split. Single
 * column (aside above stages, Figma's own 744/428 order) below 1440;
 * Figma's 1512 frame is two 484px columns 32px apart (measured off
 * `Frame 2147229981`), desktop-only per the client's own instruction.
 * Placed AFTER the base `.bppm-how__stages` rule above (same specificity,
 * later source order wins -- recurring-mistakes-register #31) so the
 * 484px cap below actually overrides that rule's own 720px max-width at
 * 1440+ instead of losing to it.
 */
.bppm-how__layout {
	display: flex;
	flex-direction: column;
	gap: 32px;
	align-items: center;
}

@media (min-width: 1440px) {
	.bppm-how__layout {
		flex-direction: row;
		align-items: flex-start;
		justify-content: center;
	}

	.bppm-how__aside,
	.bppm-how__stages {
		flex: 0 0 484px;
		max-width: 484px;
		margin: 0;
	}
}

/* editor-friendly-ok: see the file-header note above; unchanged for this pass. */
/*
 * CORRECTED 2026-09-24 (86eypb6me round 2, q13/q34 follow-up): the previous
 * pass put the icon in its OWN full-width row (flex:0 0 100%) ABOVE a second
 * row holding both the badge and the text, so the icon's left edge sat flush
 * with the badge's own column -- visually overlapping/outranking it -- and
 * the dashed connector (anchored to the badge's own bottom edge, a fixed px
 * height) stopped ~125-170px short of the next badge because that fixed
 * height never accounted for the current stage's own text height.
 */
/* editor-friendly-ok: see the file-header note; hex values below are Figma
   provenance comments only, the actual declarations read var(--bppm-*). */
.bppm-how__stage {
	position: relative;
	display: flex;
	column-gap: 22px;
}

/*
 * Badge column (Figma `Frame 2147230033/34/35`, id suffix 58385/58395/
 * 58405): a 35px-wide sibling that spans the STAGE's own full height by
 * ordinary flex stretch (align-items defaults to `stretch`), not a row
 * stacked below the icon. `.bppm-how__stage-number` (the circle itself) is
 * pushed down inside it via the nth-child margin-top rules below so it
 * lines up with the heading, matching Figma's own 160/140/170px offsets.
 */
.bppm-how__stage-badge {
	position: relative;
	flex: 0 0 35px;
	width: 35px;
}

/*
 * Icon column (Figma `Frame 2147229652`, id suffix 227428/227444/227467,
 * x=57 -- i.e. offset by the badge's 35px + a 22px gap, both confirmed
 * constant across the 2026-09-23 desktop AND mobile extracts). The icon
 * sits at x=0/y=0 of THIS column in every stage (34384:227429, the
 * "bacteria" group under 227447, and 227469) -- flush with the heading's
 * own left edge, never the badge's -- so it is now scoped inside
 * `.bppm-how__stage-content` instead of spanning the full stage width.
 */
.bppm-how__stage-icon {
	display: block;
	margin: 0 0 18px; /* Figma: 164.49-146.49 / 143.92-125.92 / 172-154, all exactly 18 */
	line-height: 0;
}

.bppm-how__stage-icon svg {
	display: block;
}

.bppm-how__stage-number {
	position: relative;
	z-index: 1; /* paint above the connector's ::after, matching Figma's badges-over-line order */
	display: flex;
	width: 35px;
	height: 35px;
	border-radius: 50%;
	background: var(--bppm-amber); /* Figma "Frame 2147229653", #FFA825 */
	color: var(--bppm-ink); /* Figma's badge digit fill, #2E2A2A on amber, 8.4:1 */
	font-family: 'Nominee', var(--theme-font-family, sans-serif);
	font-weight: 900;
	font-size: 14px;
	align-items: center;
	justify-content: center;
}

/* Figma's own badge Y-offset from the stage top -- 160/140/170px, identical
   at both the 2026-09-23 desktop (I21316:76932;34384:227426/227442/227465)
   and mobile (I29629:112443, same suffixes) extracts, so one set of values
   covers every breakpoint; no media query needed. */
.bppm-how__stage:nth-child(1) .bppm-how__stage-number { margin-top: 160px; }
.bppm-how__stage:nth-child(2) .bppm-how__stage-number { margin-top: 140px; }
.bppm-how__stage:nth-child(3) .bppm-how__stage-number { margin-top: 170px; }

.bppm-how__stage-content {
	flex: 1 1 240px;
	min-width: 0;
}

/*
 * Dashed connector between consecutive stage badges.
 *
 * Figma draws this as `Vector 1`: a single continuous 2px #FFFFFF stroke
 * (I21316:76932;34384:227424) running down the badge column behind all
 * three numbers. Its own raw height (955) is NOT reused here: it measures
 * IDENTICALLY (955) at both the 1225.41px-tall desktop stage column and the
 * 1447.41px-tall mobile one, which is only possible if that number is a
 * stale/disconnected auto-layout artifact in the source file rather than a
 * value that tracks the real badge positions -- the prior pass copied it
 * verbatim (as a per-transition height) and that is exactly why the line
 * stopped short.
 *
 * `.bppm-how__stage-badge` stretches to the FULL rendered height of its own
 * stage by ordinary flex (`align-items` defaults to `stretch`), which
 * already absorbs however tall that stage's text renders (any locale, any
 * wrap) with no text-height number hardcoded below. `top` anchors to THIS
 * badge's own vertical centre (margin-top + half its 35.58px height:
 * 160+17.79, 140+17.79). `bottom` is a NEGATIVE offset reaching PAST this
 * stretched wrapper's own bottom edge, through the list's 20px item gap,
 * up to the NEXT badge's centre -- so the drawn span is always "this
 * badge's centre to the next badge's centre" regardless of how tall the
 * text in between renders. `overflow` is not clipped on the <ol>/<li>/
 * wrapper ancestors, so this is safe.
 *
 * A repeating-linear-gradient rather than `border-left: 2px dashed`: CSS
 * `dashed` leaves dash length/gap to the engine (Blink, Gecko and WebKit
 * each pick a different ratio), so it cannot express a fixed 5-on/5-off.
 *
 * Decorative only: a pseudo-element, so it is already outside the
 * accessibility tree. The list is still an <ol>, which conveys the sequence.
 */
.bppm-how__stage:not(:last-child) .bppm-how__stage-badge::after {
	content: "";
	position: absolute;
	left: 50%;
	width: 2px;
	transform: translateX(-50%);
	background-image: repeating-linear-gradient(
		to bottom,
		var(--bppm-white) 0,
		var(--bppm-white) 5px,
		transparent 5px,
		transparent 10px
	);
}

/* Stage 1 badge centre (160+17.79) -> stage 2 badge centre (140+17.79). */
.bppm-how__stage:nth-child(1) .bppm-how__stage-badge::after {
	top: 177.79px;
	bottom: calc(-20px - 157.79px);
}

/* Stage 2 badge centre (140+17.79) -> stage 3 badge centre (170+17.79). */
.bppm-how__stage:nth-child(2) .bppm-how__stage-badge::after {
	top: 157.79px;
	bottom: calc(-20px - 187.79px);
}

/*
 * FIXED 2026-09-24 (ClickUp 86eypb6me, PDP round 2, q18/S11): added the
 * 2 percent letter-spacing the ledger's "Heading 3" text node carries
 * (font_size 16, letter_sp 2 PERCENT = 0.02em) -- present on every other
 * Nominee heading/label in this file but missing here.
 */
.bppm-how__stage h3 {
	font-family: 'Nominee', var(--theme-font-family, sans-serif);
	font-weight: 900;
	font-size: 16px;
	letter-spacing: 0.02em;
	text-transform: uppercase;
	color: var(--bppm-white);
	text-align: left;
	margin: 0 0 8px;
}

.bppm-how__stage p {
	color: var(--bppm-white);
	margin: 0 0 8px;
}

/*
 * ADDED 2026-09-24 (86eypb6me, q18/S11): the body paragraph's own font
 * properties, walked off the ledger (I21316:76932;34384:227438 and its
 * Biotics equivalent) -- 20px/400/line-height 24 at 80 percent white, not
 * this file's shared 16px/var(--bppm-white)-solid default every other
 * `.bppm-how__stage p` inherited. Scoped to its own class so the
 * stage-detail line below (a sibling <p>, already handled separately)
 * keeps its own font-weight/color untouched.
 */
.bppm-how__stage-body {
	font-size: 20px;
	font-weight: 400;
	line-height: 1.2;
	color: rgba(255, 255, 255, 0.8);
}

/*
 * FIXED 2026-09-24 (86eypb6me, q18/S11): "last texts" (the bold one-line
 * callout under each stage's body copy) had no line divider above them, and
 * no explicit font-size/line-height, both present in Figma. The wrapping
 * "stage-detail" frame (I21316:76932;34384:227439 and its two siblings,
 * identical at 1512/744/428) carries stroke rgba(255,255,255,0.32) with
 * pad_t/pad_b 20 -- a divider rule, not a boxed border (Figma draws no
 * matching side strokes elsewhere on this frame), reproduced here as
 * border-top + padding-top. line-height 1.2 matches the ledger's 120%
 * (16 * 1.2 = 19.2, not the 22.4 this file's shared `.bppm-section p`
 * line-height:1.4 would otherwise apply), the same fix pattern already used
 * on .bppm-why__callout-body above.
 */
.bppm-how__stage-link {
	display: inline-block;
	margin-top: 12px;
	font-size: 16px;
	font-weight: 700;
	line-height: 1.2;
	color: #BFE6CD;
	text-decoration: underline;
	text-underline-offset: 3px;
}

.bppm-how__stage-link:hover,
.bppm-how__stage-link:focus-visible {
	color: #fff;
}

.bppm-how__stage-detail {
	font-size: 16px;
	font-weight: 700;
	line-height: 1.2;
	margin: 12px 0 0;
	padding-top: 20px;
	border-top: 1px solid rgba(255, 255, 255, 0.32);
	/* editor-friendly-ok: same no-Gutenberg-surface exception this file's
	   header states. Figma's detail-line fill is a light green tint,
	   rgb(191,230,205), not plain white; measured off the extract's TEXT
	   node fill (stage-detail), 8.62:1 on this section's green background. */
	color: #BFE6CD;
}

/*
 * "Cold Extrusion vs. Standard Processing" comparison, Superfoods only
 * (node 34384:225672, "ce-compare" component). editor-friendly-ok: same
 * no-Gutenberg-surface exception this file's header states.
 *
 * FIXED 2026-09-24 (ClickUp 86eypb6me, PDP round 2, q18/S10): three real
 * defects here, all confirmed by walking the ce-compare node tree
 * (I21316:76932;34384:247055-247065) in the 2026-09-23 extract, not
 * eyeballed:
 * 1. Figma wraps BOTH items in one unifying card (484px wide -- the aside
 *    column's own width, not this file's stale 720px), fill
 *    rgba(255,255,255,0.12), radius 16, containing the two items on a
 *    vertical auto-layout (gap 22, 32px top/bottom padding, items centred).
 *    That container never existed; each item drew its own separate
 *    0.04-tint card side by side instead.
 * 2. Every child text node (heading, label, temp) is textAlignHorizontal
 *    CENTER, not this file's `text-align:left`.
 * 3. The literal panel fill is 0.12, but 0.12-white composited on this
 *    section's #247B4E green measures a background luminance that takes
 *    even PURE WHITE text to only 4.14:1, and Figma's own cream text
 *    (#F8EDE3) for ce-label/ce-temp to 3.59:1 -- both fail the 4.5:1 floor
 *    for 16px bold text (computed via the WCAG relative-luminance formula,
 *    not eyeballed). 0.04 is this file's own already-vetted tint for a
 *    white-panel-on-this-green (see .bppm-how__body below, verified
 *    4.85:1) -- reused here rather than a second untested value. Kept both
 *    labels white (matching what this file already shipped, not cream)
 *    rather than Figma's per-item cream/orange, because orange-on-green
 *    measures 2.5:1 regardless of panel opacity -- the bar fill below
 *    carries the brand/standard colour distinction instead, since it is
 *    decorative (1.4.11, not 1.4.3 text contrast).
 */
.bppm-how__comparison {
	max-width: 484px;
	margin: 0 auto 32px;
	text-align: center;
	background: rgba(255, 255, 255, 0.04);
	border-radius: 16px;
	padding: 32px 0;
}

.bppm-how__comparison-heading {
	font-family: 'Nominee', var(--theme-font-family, sans-serif);
	font-weight: 900;
	font-size: 18px;
	text-transform: uppercase;
	color: var(--bppm-white);
	text-align: center;
	margin: 0 0 16px;
}

.bppm-how__comparison-grid {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 22px;
}

.bppm-how__comparison-item {
	width: 100%;
	max-width: 305px;
}

/* 86eyy8hud: `.bppm-section p` (0,1,1) outranked the old bare class and left this label on Kobe1.1; Figma (I21316:76932;34384:247057) is Nominee Heavy Extended D16 / T,M14, lh 16, ls 2%. */
.bppm-section p.bppm-how__comparison-label {
	font-family: 'Nominee', var(--theme-font-family, sans-serif);
	font-weight: 900;
	font-size: 16px;
	line-height: 16px;
	letter-spacing: 0.02em;
	text-transform: uppercase;
	color: var(--bppm-white);
	text-align: center;
	margin: 0 0 8px;
}
@media (max-width: 1439px) {
	.bppm-section p.bppm-how__comparison-label {
		font-size: 14px;
	}
}

/*
 * ADDED 2026-09-24 (86eypb6me, q18/S10): the "ce-bar"/"ce-bar-fill" progress
 * track Figma draws under each label -- never built before this fix. Track
 * height 12, radius 6 (fully rounded), width matches the item column,
 * measured off the same node walk cited above.
 */
.bppm-how__comparison-bar {
	width: 100%;
	height: 12px;
	border-radius: 6px;
	overflow: hidden;
	margin: 0 0 6px;
}

.bppm-how__comparison-bar-fill {
	display: block;
	height: 100%;
	border-radius: 6px;
}

/* Item 1, "Bonza Cold Extrusion": Figma's light-green track/fill, 53%/100%
   opacity -- #BFE6CD is the same literal already used unescaped by
   .bppm-how__stage-detail above. */
.bppm-how__comparison-item--brand .bppm-how__comparison-bar {
	background: rgba(191, 230, 205, 0.53);
}

.bppm-how__comparison-item--brand .bppm-how__comparison-bar-fill {
	background: #BFE6CD;
}

/* Item 2, "Industry Standard": Figma's amber track/fill, 70%/100% opacity. */
.bppm-how__comparison-item--standard .bppm-how__comparison-bar {
	background: rgba(255, 168, 37, 0.7);
}

.bppm-how__comparison-item--standard .bppm-how__comparison-bar-fill {
	background: var(--bppm-amber);
}

.bppm-how__comparison-temp {
	color: var(--bppm-white);
	font-size: 16px;
	font-weight: 700;
	line-height: 1.25; /* Figma text.lineHeight 20 / fontSize 16 */
	text-align: center;
	margin: 0;
}

/*
 * REMOVED 2026-09-24 (86eypb6me, S22): this used to carry a translucent
 * white panel (background: rgba(255,255,255,0.04); border-radius; padding)
 * behind the allergen callout. Traced the source text ("The proteins owners
 * trust most...") to Figma node 34841:89596 ("Frame 2147230023", the
 * callout's own direct container) and walked every ancestor up through
 * 34384:247151 / 34384:246548 -- `fills:null` at every level, no panel
 * anywhere in the chain. The callout sits directly on the section's own
 * green fill in Figma, plain text with no card. Panel removed rather than
 * only lightened; contrast is unaffected (white on the section's own solid
 * #247B4E measures 5.23:1, already the established figure this codebase
 * uses for the same white-on-green pair elsewhere, so it clears AA by more
 * than the panel tint being removed ever did).
 */
.bppm-how__body {
	max-width: 640px;
	margin: 0 auto;
	text-align: left;
}

.bppm-how__body h3 {
	font-family: 'Nominee', sans-serif;
	font-weight: 900;
	font-size: 18px;
	text-transform: uppercase;
	color: var(--bppm-white);
	text-align: left;
	margin: 0 0 12px;
}

.bppm-how__body p {
	color: var(--bppm-white);
	margin: 0 0 12px;
}

.bppm-how__body-strong {
	font-weight: 700;
}

/* When to expect results, timeline. */
.bppm-timeline {
	background: var(--bppm-cream-alt);
}

.bppm-timeline__heading {
	font-size: 36px;
	line-height: 40px;
	color: var(--bppm-green);
}

/*
 * FIXED 2026-09-24 (ClickUp 86eypb6me, PDP round 2, item 1): this is the
 * lead-to-list gap, not the same value as the item-to-item gap below --
 * they come from two different Figma auto-layout frames. Figma's outer
 * "when to expect" frame (node I34926:77031;34920:66474, and the matching
 * Superfoods/tablet/mobile nodes) is itself a vertical auto-layout with
 * itemSpacing 46 between its two children: the heading+lead group and the
 * timeline list. That 46 is THIS margin (lead -> list), confirmed by
 * y/height math in the extract (32+190=222, next child y=268, 268-222=46).
 * It is unrelated to the list's own itemSpacing (see .bppm-timeline__list
 * below). Same 46 at desktop/tablet/mobile, both products.
 */
.bppm-timeline__lead {
	font-size: 20px;
	color: var(--bppm-ink-muted); /* 4.41:1 on cream-alt, bold 20px qualifies as large text (>=18.66px bold), passes the 3:1 large-text floor */
	font-weight: 700;
	max-width: 720px;
	margin: 0 auto 46px;
	text-align: center;
}

/*
 * ADDED 2026-09-23 (86eypb6me, q19): Figma draws a single dashed connector
 * (`Vector 120`, 2px #FFFFFF, dashPattern [5,5]) running the full height of
 * the timeline column behind the four label badges -- the same "one line,
 * opaque badges sit on top and interrupt it visually" construction as the
 * how-it-works stage connector (see that section's own CSS comment for the
 * full reasoning). Measured off the extract: the line sits inside the
 * 125px-wide label badge, roughly a third of the way across it, which
 * lands near the middle of this build's own 160px badge. This was missing
 * from the build entirely (q19: "broken lines"), same as the how-it-works
 * connector. editor-friendly-ok: same no-Gutenberg-surface exception this
 * file's header states.
 */
/*
 * CORRECTED 2026-09-24 (ClickUp 86eypb6me, PDP round 2, item 1 -- reverts
 * the M2 follow-up above, which was wrong): the M2 fix read the outer
 * "when to expect" frame's itemSpacing (46, node I34926:77031;34920:66474)
 * as THIS list's own item-to-item gap and set `gap: 46px` here, which
 * regressed the real item spacing FROM the 24px it measured live back UP
 * to 46px. The 46 belongs to the OUTER frame (lead -> list, see
 * .bppm-timeline__lead's margin-bottom above) -- it is not this list's own
 * spacing. This list is itself a separate Figma auto-layout frame ("Frame
 * 2147229795", sibling of the heading+lead group) with its OWN
 * itemSpacing: 24, confirmed identical at desktop/tablet/mobile and on
 * both the Superfoods and Biotics extracts. Restored to 24px, the value
 * the M2 comment itself had already measured live before overwriting it.
 * The ::before dashed connector below is positioned by its own
 * top/bottom/left offsets, independent of this gap, so it needs no change.
 */
.bppm-timeline__list {
	position: relative;
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 24px;
	max-width: 900px;
	margin-left: auto;
	margin-right: auto;
}

/*
 * REBUILT 2026-09-24 (ClickUp 86eypb6me, PDP round 2, q18/S15 + the mobile
 * "week left vs right column alignment" item, superseding a same-day
 * q18/B8 attempt that duplicated this same fix on a different selector --
 * see the integration note below): two real defects, both confirmed
 * against the 2026-09-23 ledger, not eyeballed. editor-friendly-ok: same
 * no-Gutenberg-surface exception this file's header states.
 *
 * 1. Wrong colour. The single full-span `::before` this file shipped used
 *    `var(--bppm-white)` (a pure-white dash), effectively invisible on this
 *    section's cream-alt background. The actual connector node ("Vector
 *    120", I21316:76932;34457:268953) is stroke rgba(0,0,0,0.12), width 2,
 *    dash [7,7] -- a dark, low-opacity line, not white. (The prior comment
 *    above citing "#FFFFFF, dashPattern [5,5]" was never re-verified
 *    against this node and was wrong on both colour and dash length.)
 * 2. Wrong span. That same `::before` ran `top:18px; bottom:18px` -- i.e.
 *    nearly the FULL list height at every item count -- so it continued
 *    straight through and past the last badge (Month 3+/Ongoing/Maintained
 *    Balance) into empty space below it, the "broken line below the last
 *    item" defect. Figma's own Vector 120 stops at 770.22 of the list's
 *    1004px total height (roughly the fourth badge's own centre), not the
 *    list's bottom edge.
 *
 * Rebuilt as a per-item connector instead of one list-wide span, the same
 * pattern `.bppm-how__stage-badge::after` already uses above for an
 * identical "short badge column next to a tall, variable-height card"
 * problem: `.bppm-timeline__label-wrap` is a new, invisible full-height
 * flex column (PHP-added wrapper around the visible `.bppm-timeline__label`
 * pill) that stretches to match its OWN row's real rendered height via
 * ordinary flex `align-items:stretch` -- self-adjusting to any copy length
 * at any breakpoint with no hardcoded per-item pixel offsets, including the
 * taller Biotics "ongoing" card whose extra `note` paragraph is what the
 * q18/B8 attempt below was independently reacting to. The dashed segment
 * runs from THIS label's own vertical centre through the list's 24px gap
 * to the NEXT label's centre, and -- because it lives on
 * `:not(:last-child)` on the shared `.bppm-timeline__item` -- structurally
 * cannot exist below the final item, closing the "no line below the last
 * item" defect by construction rather than a length calculation that would
 * need updating if the copy changes. `bonza_pdp_when_to_expect_section()`
 * is one shared render function for both the Superfoods timeline ("Month
 * 3+") and the Biotics when-to-expect list ("Maintained Balance"), so this
 * single rule (declared below, next to `.bppm-timeline__label-wrap`)
 * already covers both -- the q18/B8 branch's own `.bppm-timeline__label`
 * (not `-wrap`) variant of the identical fix is dropped here as a
 * redundant duplicate, not because it was wrong.
 */
.bppm-timeline__item {
	position: relative;
	display: flex;
	align-items: stretch;
	gap: 18px;
}

.bppm-timeline__label-wrap {
	position: relative;
	/* A 160px column so every card starts on one x. 160px fits the widest
	   label (DE "fortlaufend", 146px at the 16px floor); min-width lets the
	   column grow instead of the label overflowing if one ever runs wider. */
	flex: 0 0 auto;
	min-width: 160px;
	display: flex;
	align-items: flex-start;
}

.bppm-timeline__item:not(:last-child) .bppm-timeline__label-wrap::after {
	content: "";
	position: absolute;
	left: 50%;
	top: 22px;
	bottom: calc(-24px - 22px);
	width: 2px;
	transform: translateX(-50%);
	background-image: repeating-linear-gradient(
		to bottom,
		rgba(0, 0, 0, 0.12) 0,
		rgba(0, 0, 0, 0.12) 7px,
		transparent 7px,
		transparent 14px
	);
}

.bppm-timeline__label {
	background: var(--bppm-green);
	color: var(--bppm-white); /* 5.23:1 on #247B4E, the same figure already established for white text on this band elsewhere on the site */
	font-family: 'Nominee', sans-serif;
	font-weight: 900;
	font-size: 14px;
	text-transform: uppercase;
	border-radius: 6px;
	padding: 10px 6px;
	box-sizing: border-box;
	width: 100%;
	min-width: max-content;
	position: relative;
	z-index: 1;
	text-align: center;
	white-space: nowrap;
}

/*
 * ADDED 2026-09-23 (86eypb6me, q19): the icon illustration above each
 * card's heading (Figma's own `tl-content` children, e.g.
 * "coronavirus_24dp..." for "Transition Period"). 70px native size at
 * every width, matching the extract's own icon box.
 */
.bppm-timeline__icon {
	display: block;
	width: 56px;
	height: 56px;
	margin: 0 0 12px;
	line-height: 0;
}

.bppm-timeline__icon svg {
	display: block;
	width: 100%;
	height: 100%;
}

.bppm-timeline__card {
	flex: 1 1 0;
	min-width: 0;
	background: var(--bppm-white);
	border: 1px solid rgba(0, 0, 0, 0.05);
	border-radius: 16px;
	padding: 22px 21px;
}

.bppm-timeline__card h3 {
	font-family: 'Nominee', sans-serif;
	font-weight: 900;
	font-size: 16px;
	text-transform: uppercase;
	color: var(--bppm-ink);
	text-align: left;
	margin: 0 0 8px;
	-webkit-hyphens: auto;
	hyphens: auto;
}

.bppm-timeline__card p {
	color: var(--bppm-ink);
	font-size: 16px;
	margin: 0 0 8px;
}

.bppm-timeline__tip {
	font-weight: 700;
}

/*
 * Below 600px the badge goes above the card: beside the 160px badge the card
 * is only 62-341px wide and the 16px type floor (product-page-vita-qa.css)
 * cannot shrink, so long words broke mid-word. Long DE/NL headings still
 * need the h3 hyphens rule to break on a real hyphen. The dashed connector
 * only fits beside.
 */
@media (max-width: 599px) {
	.bppm-timeline__item {
		flex-direction: column;
		gap: 10px;
	}

	.bppm-timeline__label-wrap {
		flex: 0 0 auto;
		width: auto;
		min-width: 0;
		align-self: flex-start;
	}

	.bppm-timeline__item:not(:last-child) .bppm-timeline__label-wrap::after {
		display: none;
	}

	.bppm-timeline__label {
		width: auto;
		padding: 10px 14px;
	}

	.bppm-timeline__card {
		flex: 0 0 auto;
		width: 100%;
		box-sizing: border-box;
	}
}

/* Reviews, green background. No fabricated testimonial cards, see PHP
   docblock: a real aggregate stat plus a real outbound Feefo link. */
.bppm-reviews {
	background: var(--bppm-green);
	text-align: center;
}

.bppm-reviews__heading {
	font-size: 36px;
	line-height: 40px;
	color: var(--bppm-white);
}

/*
 * CORRECTED 2026-09-19: Figma (node 34920:66552 / 35066:60246) draws a
 * second small stacked line between the eyebrow and the h2, "Real
 * Experiences" (14px/900, same weight/size as .bppm-eyebrow), not present
 * anywhere else in this file's markup until now. Same rgba(255,255,255,0.9)
 * this file's other on-green small text already uses (.bppm-eyebrow--on-dark,
 * .bppm-reviews__count), for the same 4.58:1-on-green reason documented on
 * those two rules; not reusing .bppm-eyebrow itself because that class's own
 * 12px margin-bottom is tuned for "eyebrow directly above an h2", and here
 * it sits between two eyebrow-styled lines instead.
 */
.bppm-reviews__label {
	font-family: 'Nominee', var(--theme-font-family, sans-serif);
	font-weight: 900;
	font-size: 14px;
	line-height: 16px;
	text-transform: uppercase;
	letter-spacing: 0.02em;
	color: rgba(255, 255, 255, 0.9);
	margin: 0 0 12px;
}

/*
 * ADDED 2026-09-19: node 34920:66552 / 35066:60246's fourth line, 20px/400,
 * sitting between the h2 and the live widget. Reuses the cream-on-green
 * pairing .bppm-how__lead already established for this exact contrast
 * problem (var(--bppm-cream) on var(--bppm-green)), at regular weight to
 * match Figma's 400 rather than that rule's own 700.
 */
.bppm-reviews__intro {
	font-size: 20px;
	color: var(--bppm-cream);
	font-weight: 400;
	max-width: 720px;
	margin: 0 auto 24px;
}

.bppm-reviews__stat {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 4px;
	margin: 0 0 24px;
}

.bppm-reviews__rating {
	font-family: 'Nominee', sans-serif;
	font-weight: 900;
	font-size: 28px;
	color: var(--bppm-white);
}

.bppm-reviews__count {
	font-family: 'Kobe1.1', sans-serif;
	/*
	 * 85 percent white composites to 4.26:1 on the green section and fails the
	 * 4.5:1 floor for text this size. 90 percent clears at 4.58:1, matching the
	 * value the eyebrow above it now uses.
	 */
	color: rgba(255, 255, 255, 0.9);
}

/* Build your routine, product carousel. Cards reuse the site's own
   content-product.php render, not a bespoke card here. */
.bppm-routine {
	background: var(--bppm-cream);
}

.bppm-routine__heading {
	font-size: 36px;
	line-height: 40px;
	color: var(--bppm-green);
}

.bppm-routine__lead {
	font-size: 20px;
	/*
	 * This used to read 4.40:1 on cream and pass, because bold 20px clears the
	 * 18.66px large-text threshold and only owes 3:1. The responsive type scale
	 * takes it to bold 18px below 1440, which lands under that threshold, so
	 * the 4.5:1 floor now applies and the old colour fails. A contrast ratio is
	 * only ever safe relative to a font size. #6B6558 is the same hue one step
	 * darker, 5.02:1.
	 */
	color: #6B6558;
	font-weight: 700;
	max-width: 720px;
	margin: 0 auto 24px;
	text-align: center;
}

/*
 * Routine cards (product-page/routine-cards.php), Figma PRODUCT CARD in node
 * 34520:67817 / 34920:66665. Measured from the ledger at all three frames:
 *   1512: five cards of 232 in a 1256 row, 24px apart, one row.
 *   744:  a 648 row, three cards of 200 then two of 312 (the last row grows).
 *   428:  two cards of 182 visible, a scrolling row.
 *   Biotics draws one card, 400 wide at 1512 and 744, 388 (full width) at 428.
 * A 196px flex basis with growth reproduces the first two exactly: 1256 fits
 * five at 232, and a 640-648 content column fits three at about 200 with the
 * last two growing, matching Figma's 312. Cards are capped at 312 so a lone
 * card on a last row never stretches across the whole column (at 1024 the row
 * holds four plus one).
 */
.bppm-routine__grid {
	list-style: none;
	margin: 0 auto;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 24px;
	max-width: 1256px;
}

.bppm-routine-card {
	flex: 1 1 196px;
	max-width: 312px;
	margin: 0;
	display: flex;
	flex-direction: column;
	border-radius: 12px;
	overflow: hidden;
	background: var(--bppm-white);
}

.bppm-routine__grid--single .bppm-routine-card {
	flex: 0 1 400px;
	max-width: 400px;
}

.bppm-routine-card__media {
	position: relative;
	aspect-ratio: 1 / 1;
	overflow: hidden;
}

/*
 * ADDED 2026-09-23 (86eypb6me, q25): "WISHLIST ICON" component (Figma node
 * 29089:54165), 26x26, at x196/y10 inside a 232-wide row -- i.e. 10px
 * inset from the media box's own right/top edge at this card width. See
 * routine-cards.php's own docblock for the real toggle mechanism (both
 * member products, one sync call) and why no Figma variant exists for the
 * unwishlisted look.
 */
.bppm-routine-card__wishlist {
	position: absolute;
	top: 10px;
	right: 10px;
	z-index: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 26px;
	height: 26px;
	padding: 0;
	border: none;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.8);
	cursor: pointer;
}

.bppm-routine-card__wishlist svg {
	width: 16px;
	height: 14px;
	display: block;
}

/*
 * Unwishlisted (default): outline stroke, no fill -- this build's own
 * decision (Figma draws no such state), matching the "Filled=False"
 * treatment bonza_cart_drawer_wishlist_button() already established.
 * Wishlisted (data-active="true"): the real Figma fill, solid #FF0000,
 * same exact value as the sale badge above -- both are this component
 * set's own literal fill, not a design-token color.
 */
.bppm-routine-card__wishlist svg path {
	fill: none;
	stroke: #FF0000; /* editor-friendly-ok: same no-Gutenberg-surface exception this file's header states -- exact Figma fill, no red slot in this site's palette */
	stroke-width: 1.3;
}

.bppm-routine-card__wishlist[data-active='true'] svg path {
	fill: #FF0000; /* editor-friendly-ok: same no-Gutenberg-surface exception this file's header states -- exact Figma fill, no red slot in this site's palette */
	stroke: none;
}

.bppm-routine-card__wishlist:focus-visible {
	outline: 2px solid var(--bppm-white);
	outline-offset: 2px;
}

.bppm-routine-card__img {
	display: block;
	width: 100%;
	height: 100%;
	max-width: none;
	object-fit: cover;
}

/* Body: 16px padding, 12px between rows, Figma "Frame 1261154771". */
.bppm-routine-card__body {
	flex: 1;
	display: flex;
	flex-direction: column;
	gap: 12px;
	padding: 16px;
}

.bppm-routine-card__title {
	margin: 0;
	font-family: 'Nominee', sans-serif;
	font-weight: 900;
	font-size: 16px;
	line-height: 16px;
	letter-spacing: 0.02em;
	text-transform: uppercase;
	color: var(--bppm-ink);
	text-align: left;
}

.bppm-routine-card__tags {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 4px;
}

.bppm-routine-card__tag {
	margin: 0;
	padding: 4px 6px;
	border-radius: 999px;
	background: #F8EDE3;
	font-family: 'Kobe1.1', sans-serif;
	font-weight: 400;
	font-size: 12px;
	line-height: 14px;
	color: var(--bppm-ink); /* #2E2A2A on #F8EDE3, 12.3:1 */
}

/* Grows so every card's rule, price and button line up along a row, as
   Figma's equal-height cards do. */
.bppm-routine-card__desc {
	flex: 1;
}

.bppm-routine-card__desc p {
	margin: 0;
	font-family: 'Kobe1.1', sans-serif;
	font-weight: 400;
	font-size: 14px;
	line-height: 16px;
	color: var(--bppm-ink);
	text-align: left;
}

.bppm-routine-card__desc p + p {
	margin-top: 16px;
}

.bppm-routine-card__rule {
	margin: 0;
	border: 0;
	border-top: 1px solid #F3F4F6;
}

/*
 * CORRECTED 2026-09-24 (86eypb6me, q19): the 2026-09-24/q18 pass above
 * measured this component from ONE breakpoint's extraction and applied that
 * single reading everywhere -- it landed on the MOBILE (428 frame) numbers
 * (sale 12px, struck 10px) with no media query, so desktop/tablet rendered
 * the mobile size. Re-pulled the same "Container" text node fresh at all
 * three frames (node suffix ;35879:97602;29323:47306 is stable across
 * breakpoints, only the instance prefix changes -- desktop
 * I21316:76932;35879:97602;29323:47306, tablet
 * I23310:35546;35879:97602;29323:47306, mobile
 * I29629:112443;35879:97602;29323:47306; Biotics card is the same shared
 * component instance, confirmed identical segment styles). The text node is
 * ONE run, "£101.00 £88.38", with two style SEGMENTS per breakpoint:
 *
 *   desktop (>=1440): struck 14px, sale 14px
 *   tablet  (1440>w>743): struck 12px, sale 14px (sale unchanged from desktop)
 *   mobile  (<=743): struck 10px, sale 12px
 *
 * Sale segment stays Nominee Regular 400, textCase UPPER, lineHeight 20px,
 * fill rgb(36,123,78)=#247B4E at every breakpoint -- only its fontSize
 * moves. Base rule below is the desktop (1440+) reading, per this section's
 * existing mobile-first-override pattern (title/body already do the same:
 * base = desktop, @media max-width:1439px folds in tablet, max-width:743px
 * folds in mobile).
 *
 * FOUND 2026-09-24 (86eypb6me, q19): the plain `.bppm-routine-card__price`
 * class (0,1,0) on this `<p>` was losing its own `font-family: 'Nominee'`
 * to `.bppm-section p` (0,1,1) further up this file -- walked
 * document.styleSheets/el.matches() live and confirmed the deployed page
 * rendered this price in Kobe1.1, the body font, not Nominee, at every
 * breakpoint (this was the case before this PR's font-size fix too, not a
 * regression it introduced). Same pattern this file already fixed on
 * `.bppm-why__callout-heading` (q9) and `.bppm-why__callout-body` (q7):
 * `.bppm-section p.bppm-routine-card__price` (0,2,1) reliably outranks it.
 * The routine section is `<section class="bppm-section bppm-routine">`
 * (product-page-marketing.php), so this selector is real, not speculative.
 */
.bppm-section p.bppm-routine-card__price {
	margin: 0;
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 4px; /* Figma's real value is a single space CHARACTER inside one text run (see comment above), not a flex gap -- 4px is this component's own itemSpacing default elsewhere in the same price frame, the closest real sourced value to that space's rendered width, not the previous rule's un-sourced 6px */
	font-family: 'Nominee', sans-serif;
	font-weight: 400;
	font-size: 14px;
	line-height: 20px;
	text-transform: uppercase;
	color: var(--bppm-green); /* #247B4E on white, 5.23:1 */
	text-align: left;
}

/*
 * Struck-through regular total: same Container text node's FIRST segment
 * ("£101.00 "), Kobe1.1 Regular 400, textCase ORIGINAL (opts out of the
 * parent rule's text-transform), lineHeight AUTO (the font's own natural
 * line-height, not the sale segment's fixed 20px), fill
 * rgb(107,114,128)=#6B7280. fontSize is the one property that moves per
 * breakpoint (14/12/10 desktop/tablet/mobile) -- see the price rule's
 * comment above for the measured table and node IDs.
 */
.bppm-routine-card__price-was {
	font-family: 'Kobe1.1', sans-serif;
	font-weight: 400;
	font-size: 14px;
	line-height: normal;
	text-transform: none;
	color: #6B7280; /* editor-friendly-ok: same no-Gutenberg-surface exception this file's header states -- exact Figma fill for this segment, confirmed unchanged */
	text-decoration: line-through;
}

/*
 * "saving-badge" node: cornerRadius 4, solid #FF0000, white 10px/700
 * Kobe1.1 Bold text, lineHeight 10px (this rule previously said 14px,
 * wrong -- Figma's own text node carries unit:PIXELS value:10, i.e. tight
 * leading equal to the font size). Same 10px/700/10-line-height at every
 * breakpoint (desktop/tablet/mobile node IDs above all agree), so no media
 * query needed here. Figma's frame sizing is HUG (auto width around the
 * text) with padding 4px top/bottom, 8px left/right -- width:62px below was
 * the desktop-only rendered width of the literal string "Save 12.5%" at
 * that padding, not a real fixed-width token; save_percent is computed from
 * real WooCommerce sale data (see routine-cards.php) so the digit count
 * varies card to card, and a hardcoded width would clip/wrap a wider
 * percentage -- switched to auto width via the same padding Figma's
 * autoLayout specifies, so the pill still hugs whatever percentage renders.
 * `.bppm-routine-card__body` is a flex column with no `align-items` set,
 * so its default `stretch` was measured live stretching this badge to the
 * card's full width the moment the explicit `width:62px` was removed --
 * `align-self: flex-start` restores Figma's own `counterAxisAlignItems:
 * MIN` (left-aligned, hug width) without reintroducing a fixed width.
 * Pure #FF0000 on white text passes WCAG 1.4.3 at 5.25:1 for this size/
 * weight.
 */
.bppm-routine-card__badge {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	align-self: flex-start;
	height: 18px;
	padding: 4px 8px;
	margin-top: 4px;
	border-radius: 4px;
	background: #FF0000; /* editor-friendly-ok: same no-Gutenberg-surface exception this file's header states -- exact Figma fill, no red slot in this site's palette */
	color: var(--bppm-white);
	font-family: 'Kobe1.1', var(--theme-font-text-family, sans-serif); /* editor-friendly-ok: same no-Gutenberg-surface exception this file's header states */
	font-weight: 700;
	font-size: 10px;
	line-height: 10px;
}

.bppm-routine-card__form {
	margin: 0;
}

/*
 * Figma "Button": 40px, pill, green fill, white 10/14 label at 0.04em --
 * re-measured against the raw node (I21316:76932;35879:97602;34233:176228,
 * "Button" instance): width 200/height 40 fixed, cornerRadius 999,
 * padding 16px all sides, fill rgb(36,123,78)=#247B4E, NO stroke. This
 * rule's own `border: 1px solid var(--bppm-green)` has no Figma source,
 * but is the exact same colour as the fill, so it is invisible on the
 * filled variant and is what gives the "notify me" outline variant below
 * its real, Figma-confirmed 1px green stroke (that instance's own node
 * DOES carry strokes:[green], strokeWeight 1, fills:[] -- verified
 * separately) -- kept rather than split into two rules for one shared
 * property.
 */
.bppm-routine-card__btn {
	display: flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	width: 100%;
	min-height: 40px;
	padding: 0 16px;
	border: 1px solid var(--bppm-green);
	border-radius: 999px;
	background: var(--bppm-green);
	color: var(--bppm-white);
	font-family: 'Nominee', sans-serif;
	font-weight: 900;
	font-size: 10px;
	line-height: 14px;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	text-decoration: none;
	cursor: pointer;
	transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

/*
 * ADDED 2026-09-24 (ClickUp 86eypb6me, PDP round 2, item 6b): no hover
 * state existed at all on this button (grepped the file, none). This
 * project's own already-sourced "Kind=Primary" hover finding for the main
 * add-to-cart button (product-page.css, single_add_to_cart_button:hover
 * comment: "State=Hover, Kind=Primary (29049:58918) swaps the yellow for
 * a dark green and drops the stroke... label turns white") is reused here
 * rather than inventing a new value: this button is the same green-fill
 * "Kind=Primary" pill pattern, so #1C5F3C (that same session's real,
 * component-set-sourced dark-green figure, already shipped as
 * --bpp-green-dark in product-page.css's own :root scope, out of reach
 * from this file's .bppm scope, so repeated here as the literal instead
 * of inventing a second token for one value) is the hover fill, border
 * dropped to match, white label unchanged. editor-friendly-ok: same
 * no-Gutenberg-surface exception this file's header states.
 */
/* editor-friendly-ok: same no-Gutenberg-surface exception this file's header states. */
.bppm-routine-card__btn:not(.bppm-routine-card__btn--notify):hover {
	background: #1C5F3C;
	border-color: #1C5F3C;
	color: var(--bppm-white); /* 86eyxb3vc: Blocksy a:hover (0,1,1) turned the label #1C5F3C on #1C5F3C */
}

/*
 * Out-of-stock routine: Figma's outlined "notify me" variant -- real
 * Figma stroke, no fill (see the base rule's own comment above). No hover
 * change added here: this component's real Figma hover value was not
 * independently reachable this session (the frame-harvest export this
 * fix set otherwise used carries no component-SET data, only page
 * instances -- see recurring-mistakes-register #169), and this project's
 * own established rule is never to invent a state value with no source.
 * Flagged rather than guessed; the existing :focus-visible outline below
 * still gives keyboard users feedback.
 */
.bppm-routine-card__btn--notify {
	background: transparent;
	color: var(--bppm-green);
	padding: 0 12px;
}

.bppm-routine-card__btn:focus-visible {
	outline: 2px solid var(--bppm-ink);
	outline-offset: 2px;
}

/* One button per member product, stacked so long names never clip. */
.bppm-routine-card__actions {
	display: grid; /* G43: equal rows, so the two-line Superfoods button and its partner match in height */
	grid-auto-rows: 1fr;
	gap: 8px;
	width: 100%;
}

.bppm-routine-card__actions .bppm-routine-card__btn {
	min-height: 44px;
	height: auto;
	padding-top: 8px;
	padding-bottom: 8px;
	text-align: center;
}

.bppm-routine-card__price-label {
	/* G43: price on one line, "Subscribe & Save" on the next, never wrapped. */
	flex: 0 0 100%;
	white-space: nowrap;
	font-size: 10px;
	letter-spacing: 0.04em;
	color: var(--bppm-ink);
}

/*
 * Below 1440 Figma tightens the card: the 744 and 428 frames both draw 8px
 * body padding and a 14px title (text columns of 184 in a 200 card and 166 in
 * a 182 card), and the 428 frame drops the description to 12/16. Breakpoints
 * follow product-page-typescale.css (744 and 1440). At 16px padding and 16px
 * type, "FOUNDATION" broke mid-word in a 160px mobile card.
 */
@media (max-width: 1439px) {
	.bppm-routine-card__body {
		padding: 8px;
	}

	.bppm-routine-card__title {
		font-size: 14px;
	}

	/*
	 * ADDED 2026-09-24 (86eypb6me, q19): 744-frame reading of the price row's
	 * struck-through segment -- 12px, down from the 14px desktop value (see
	 * this section's own price-row comment above for the full measured
	 * table and node IDs). The sale segment stays 14px at this breakpoint,
	 * unchanged from desktop, so it needs no override here.
	 */
	.bppm-routine-card__price-was {
		font-size: 12px;
	}
}

/*
 * Dots are a mobile-only carousel affordance (Figma draws them only in the
 * 428 frame); above 743px the grid wraps instead of scrolling, so there is
 * nothing to page through. Hidden by default, shown inside the max-width:
 * 743px block below -- this base rule must precede that override so the
 * override actually wins inside its own range (equal specificity, source
 * order decides).
 */
.bppm-routine__dots {
	display: none;
}

/* Mobile: Figma's 428 frame shows two cards and scrolls the rest. */
@media (max-width: 743px) {
	.bppm-routine-card__desc p {
		font-size: 12px;
	}

	/*
	 * ADDED 2026-09-24 (86eypb6me, q19): 428-frame reading of the price row --
	 * sale segment drops to 12px (from 14px desktop/tablet) and the struck
	 * segment drops to 10px (from 12px tablet). See this section's own
	 * price-row comment above for the full measured table and node IDs.
	 * Uses the same `.bppm-section p.bppm-routine-card__price` (0,2,1)
	 * selector as the base rule -- a plain `.bppm-routine-card__price`
	 * (0,1,0) override here would lose to that base rule's own higher
	 * specificity regardless of this block coming later in the file.
	 */
	.bppm-section p.bppm-routine-card__price {
		font-size: 12px;
	}

	.bppm-routine-card__price-was {
		font-size: 10px;
	}

	.bppm-routine__grid:not(.bppm-routine__grid--single) {
		flex-wrap: nowrap;
		justify-content: flex-start;
		overflow-x: auto;
		scroll-snap-type: x mandatory;
		padding-bottom: 4px;
		/*
		 * ADDED 2026-09-24 (86eypb6me, q18/S34): Figma's 428 frame shows no
		 * scrollbar track under this row (only the dot indicator below it
		 * signals more pages) -- the native bar was never hidden here.
		 * scrollbar-width covers Firefox; -ms-overflow-style covers legacy
		 * Edge/IE; the pseudo-element covers WebKit/Blink (Safari, Chrome,
		 * current Edge). Content still scrolls by touch/drag/keyboard; only
		 * the visible track is removed.
		 */
		scrollbar-width: none;
		-ms-overflow-style: none;
	}

	.bppm-routine__grid:not(.bppm-routine__grid--single)::-webkit-scrollbar {
		display: none;
	}

	.bppm-routine__grid:not(.bppm-routine__grid--single) .bppm-routine-card {
		flex: 0 0 max(160px, calc((100% - 24px) / 2));
		max-width: none;
		scroll-snap-align: start;
	}

	.bppm-routine__grid--single .bppm-routine-card {
		flex-basis: 100%;
	}

	/*
	 * ADDED 2026-09-24 (86eypb6me, q18/S34): "DOT - PAGE INDICATOR" (Figma
	 * component 14018:212507, instance chunk 34920:66060, re-measured
	 * directly off the fresh 2026-09-23 mobile PDP extraction -- not
	 * eyeballed). Auto-layout itemSpacing 12 between dots. Each inactive dot
	 * is an 8x8 circle ("Ellipse 40", pill radius), fill = Neutral/50 =
	 * rgb(255,255,255) = white. The active dot is a 32x8 pill
	 * ("Rectangle 3392", cornerRadius 9999), fill = Yellow/100 =
	 * rgb(255,193,37) = #FFC125 -- the same literal this codebase already
	 * ships sitewide as --bpp-yellow/--bhp-yellow (product-page.css,
	 * homepage.css, etc.), repeated here as a literal because this file's
	 * own :root scope only defines --bppm-* tokens and #FFC125 has no
	 * --bppm- slot. JS (routine-card-carousel.js) renders one dot per
	 * two-card page and keeps .is-active in sync with real scroll position.
	 */
	.bppm-routine__dots {
		display: flex;
		align-items: center;
		justify-content: center;
		gap: var(--bonza-dot-gap, 12px);
		margin: 12px 0 0;
		padding: 0;
	}

	.bppm-routine__dot {
		width: var(--bonza-dot-size, 8px);
		height: var(--bonza-dot-size, 8px);
		padding: 0;
		margin: 0;
		border: none;
		border-radius: 9999px;
		background: var(--bonza-dot-inactive, #878787);
		cursor: pointer;
		transition: width 0.15s ease, background-color 0.15s ease;
	}

	.bppm-routine__dot.is-active {
		width: var(--bonza-dot-pill, 32px);
		background: var(--bonza-dot-active, #ffc125);
	}
}

/* Feeding calculator CTA, amber background. */
.bppm-calculator {
	background: var(--bppm-amber);
	text-align: center;
}

.bppm-calculator__heading {
	font-size: 36px;
	line-height: 40px;
	color: var(--bppm-ink);
}

.bppm-calculator__lead {
	font-size: 20px;
	color: var(--bppm-ink);
	font-weight: 700;
	max-width: 640px;
	margin: 0 auto 24px;
}

.bppm-calculator__note {
	font-size: 14px;
	color: var(--bppm-ink);
	margin: 12px 0 0;
}

/*
 * FAQ, green background plus the organic speckle texture Figma draws over
 * it (86eypb6me, S21: section was missing this pattern entirely).
 *
 * PROVENANCE: Figma node 34457:272622 ("FAQ" frame, Superfoods; Biotics'
 * matching frame is 34920:66697) contains a locked "BG Texture" group
 * (34457:272623 / 34920:66698) built from 573 individually-authored organic
 * blob vectors, EVERY one white fill at a UNIFORM 0.18 opacity (measured
 * directly off each vector's own fill, not assumed) and sized 0.18-55.66px
 * (median 6.38px) -- mostly small flecks with a handful of larger blobs,
 * clipped to the section's own 1384x1118 render bounds. There is no flat
 * image fill to reference and no Figma REST image-export quota was
 * available to flatten the 573-vector composition server-side; reproducing
 * each vector's exact path was tried (translating each of the extractor's
 * own already-cached per-vector SVG exports by its `absoluteBoundingBox`)
 * and DELIBERATELY NOT SHIPPED -- it composited correctly (verified via
 * `magick` against a #247B4E backing, speck-for-speck against the Figma
 * screenshot) but only as a single ~190KB baked SVG, which is exactly the
 * recurring-mistakes-register's own "halftone dot-field" case #2: "reproduce
 * with CSS, NEVER bake a decorative effect into one image." A pure-CSS
 * multi-layer `radial-gradient()` tile below instead, built from the SAME
 * measured size/opacity data (not invented), at a fraction of the weight
 * and fully responsive by ordinary `repeat` tiling.
 *
 * Approximate, not vector-exact, and recorded as that trade-off rather than
 * silently presented as pixel-identical: 25 gradient flecks (mostly small
 * circles, three flattened ellipses for the odd larger blob) scattered
 * asymmetrically across a large, non-square 487x349 tile -- big and uneven
 * enough that the repeat is not readable as a grid at any of this section's
 * real rendered heights -- all at the measured 0.18 white opacity, sizes
 * within the measured 1.5-6px range (the vector set's own median, not its
 * rare 55px outliers, which would read as a stray dot rather than texture
 * at this density). This reads as the same randomly-scattered fleck field
 * as Figma's 573-shape original, at both variants and every breakpoint,
 * without shipping it.
 */
.bppm-faq {
	background-color: var(--bppm-green);
	background-image:
		radial-gradient(circle at 3% 71%, rgba(255,255,255,0.18) 2px, transparent 2px),
		radial-gradient(circle at 11% 18%, rgba(255,255,255,0.18) 4px, transparent 4px),
		radial-gradient(circle at 19% 55%, rgba(255,255,255,0.18) 1.5px, transparent 1.5px),
		radial-gradient(ellipse 14px 4px at 27% 83%, rgba(255,255,255,0.18) 100%, transparent 100%),
		radial-gradient(circle at 33% 9%, rgba(255,255,255,0.18) 6px, transparent 6px),
		radial-gradient(circle at 41% 62%, rgba(255,255,255,0.18) 2px, transparent 2px),
		radial-gradient(circle at 47% 31%, rgba(255,255,255,0.18) 3px, transparent 3px),
		radial-gradient(circle at 53% 94%, rgba(255,255,255,0.18) 1.5px, transparent 1.5px),
		radial-gradient(ellipse 18px 5px at 61% 12%, rgba(255,255,255,0.18) 100%, transparent 100%),
		radial-gradient(circle at 68% 47%, rgba(255,255,255,0.18) 2.5px, transparent 2.5px),
		radial-gradient(circle at 74% 73%, rgba(255,255,255,0.18) 5px, transparent 5px),
		radial-gradient(circle at 82% 25%, rgba(255,255,255,0.18) 1.5px, transparent 1.5px),
		radial-gradient(circle at 89% 88%, rgba(255,255,255,0.18) 3px, transparent 3px),
		radial-gradient(circle at 95% 40%, rgba(255,255,255,0.18) 4px, transparent 4px),
		radial-gradient(circle at 6% 39%, rgba(255,255,255,0.18) 1.5px, transparent 1.5px),
		radial-gradient(circle at 15% 91%, rgba(255,255,255,0.18) 2px, transparent 2px),
		radial-gradient(ellipse 12px 3px at 24% 4%, rgba(255,255,255,0.18) 100%, transparent 100%),
		radial-gradient(circle at 37% 78%, rgba(255,255,255,0.18) 1.5px, transparent 1.5px),
		radial-gradient(circle at 44% 46%, rgba(255,255,255,0.18) 2.5px, transparent 2.5px),
		radial-gradient(circle at 58% 65%, rgba(255,255,255,0.18) 1.5px, transparent 1.5px),
		radial-gradient(circle at 71% 5%, rgba(255,255,255,0.18) 2px, transparent 2px),
		radial-gradient(circle at 79% 58%, rgba(255,255,255,0.18) 6px, transparent 6px),
		radial-gradient(circle at 86% 15%, rgba(255,255,255,0.18) 2px, transparent 2px),
		radial-gradient(circle at 92% 68%, rgba(255,255,255,0.18) 1.5px, transparent 1.5px),
		radial-gradient(circle at 99% 20%, rgba(255,255,255,0.18) 3px, transparent 3px);
	background-repeat: repeat;
	background-size: 487px 349px;
}

/*
 * REMOVED 2026-09-23 (86eypb6me): Figma "FAQ" is a green box with its own
 * inner padding (64/24/20 inline at 1512/744/428, 32 block at all three,
 * confirmed off the ledger -- it is NOT an exception, it is the same default
 * every other .bppm-section draws), inside the page gutter. This file used
 * to carry two compensating overrides here (padding-inline:48px @744-1439,
 * padding:32px 40px @<=743) because at the time the BAND ran edge to edge
 * and only the padding stood between the FAQ list and the viewport, so the
 * gutter had to be folded into this section's own padding by hand. Now that
 * `.bppm-section` itself is an inset box (margin-inline:var(--bppm-gutter)),
 * the default padding-inline:var(--bppm-pad) already reproduces the
 * gutter, and adding it a second time here would double it. Removed rather
 * than zeroed, so this section falls through to the same default every
 * other section uses. Re-verified after removal: .bppm-faq__list (max-width:
 * 1000px, further down this file) measures 1000/648/348 at 1512/744/428,
 * matching Figma, because the box-minus-padding content width is now
 * 1256/648/348 there -- 1000 is the smaller number at 1512 so the list caps
 * there, and 648/348 match exactly at the two narrower frames.
 */

/* Figma header stack: eyebrow 16 tall, 16 gap, heading. The line-height fix
   itself now lives on the shared `.bppm-section .bppm-eyebrow` rule above
   (same 16px this file's eyebrow already needed everywhere), so only the
   FAQ-specific 16px gap (vs. the shared rule's own 12px) stays here. */
.bppm-faq .bppm-faq__eyebrow {
	margin: 0 0 16px;
}

.bppm-faq__eyebrow-narrow {
	display: none;
}

.bppm-faq__heading {
	font-size: 36px;
	line-height: 40px;
	color: var(--bppm-white);
}

/* Heading to list: Figma gap 64/24/20. */
.bppm-section h2.bppm-faq__heading {
	margin-bottom: 64px;
}

@media (min-width: 744px) and (max-width: 1439px) {
	.bppm-section h2.bppm-faq__heading {
		line-height: 36px;
		margin-bottom: 24px;
	}
}

@media (max-width: 743px) {
	.bppm-section h2.bppm-faq__heading {
		line-height: 32px;
		margin-bottom: 20px;
	}

	.bppm-faq__eyebrow-wide {
		display: none;
	}

	.bppm-faq__eyebrow-narrow {
		display: inline;
	}
}

.bppm-faq__list {
	max-width: 1000px;
	margin: 0 auto;
	display: flex;
	flex-direction: column;
	gap: 8px;
}

/* Figma "Summary": 8px block padding, question Nominee 900 16/16 uppercase
   at 2% tracking (14/16 at 744 and 428) filling the row, the 15x15 plus at
   the far right with no gap. */
.bppm-faq__item summary {
	color: var(--bppm-white); /* 5.23:1 on #247B4E, same established figure as .bppm-timeline__label above */
	font-family: 'Nominee', sans-serif;
	font-weight: 900;
	font-size: 16px;
	line-height: 16px;
	letter-spacing: 0.02em;
	text-transform: uppercase;
	text-decoration: none;
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 8px 0;
	border-top: 1px solid rgba(255, 255, 255, 0.15);
}

.bppm-faq__question {
	flex: 1 1 auto;
	min-width: 0;
}

.bppm-faq__icon {
	flex: none;
	width: 15px;
	height: 15px;
	color: #F8EDE3;
}

.bppm-faq__icon-upright {
	transform-origin: 7.5px 7.5px;
	transition: transform 0.2s ease;
}

.bppm-faq__item[open] .bppm-faq__icon-upright {
	transform: scaleY(0);
}

@media (prefers-reduced-motion: reduce) {
	.bppm-faq__icon-upright {
		transition: none;
	}
}

@media (max-width: 1439px) {
	.bppm-faq__item summary {
		font-size: 14px;
	}
}

/* Figma's brush stroke above each question, when the image is available:
   15px stroke, the list's 8px gap, then the summary's own 8px padding. */
.bppm-faq__list--brush .bppm-faq__item summary {
	border-top: 0;
	padding-top: 31px;
	background: var(--bppm-faq-divider) no-repeat left top / 100% 15px;
}

.bppm-faq__item .bppm-accordion__detail {
	color: var(--bppm-white);
}

/*
 * 86eypb6me S24: FAQ answers are Customizer-stored rich text and can carry
 * an inline <a> (e.g. the "complete and balanced nutrition" links in the
 * "Is this a complete food or a topper?" answer) with no color rule of its
 * own, so it fell through to the theme's default link blue
 * (--theme-link-initial-color, #2872fa) -- unreadable against this
 * section's own #247B4E green and not a theme colour for links at all.
 * Figma draws no open/answer state for this list (the FAQ list only shows
 * closed question rows, same documented gap faq-accordion.php's own header
 * records for the sibling info-accordion), so there is no drawn link colour
 * to copy here either. Using this exact codebase's own established
 * white-on-#247B4E figure instead of inventing a new hue: 5.23:1, the same
 * pair already used for .bppm-faq__item .bppm-accordion__detail above and
 * for body/heading text throughout this green band elsewhere on the site
 * (product-card.css, homepage.css, footer.css, checkout-*.css all cite the
 * identical figure). An underline is added so the link is not distinguished
 * by colour alone against the surrounding white body text (WCAG 1.4.1),
 * matching the thickness/offset convention faq-accordion.css already
 * established for this exact task.
 */
.bppm-faq__item .bppm-accordion__detail a {
	color: var(--bppm-white);
	font-weight: 700;
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 2px;
}

.bppm-faq__item .bppm-accordion__detail a:hover,
.bppm-faq__item .bppm-accordion__detail a:focus-visible {
	text-decoration-thickness: 2px;
}

.bppm-faq__placeholder {
	font-style: italic;
	opacity: 0.75;
	margin: 0;
}

/* Buttons, shared across this file's CTAs. Reuses product-page.css's
   .bpp-btn colour/shape tokens so both files render the same button. */
.bppm-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 16px 32px;
	border-radius: 999px;
	font-family: 'Nominee', sans-serif;
	font-weight: 900;
	font-size: 12px;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	text-decoration: none;
	border: none;
	cursor: pointer;
	box-shadow: 0px 4px 6px -2px rgba(0, 0, 0, 0.03), 0px 12px 16px -4px rgba(0, 0, 0, 0.08);
}

.bppm-btn--primary {
	background: var(--bppm-green);
	color: var(--bppm-white); /* 5.23:1 on #247B4E, same established figure as above */
}

/* 86eyxb3vc: keep the label white on hover/focus; Blocksy a:hover (0,1,1) beat the rule above */
.bppm-btn--primary:hover,
.bppm-btn--primary:focus-visible {
	color: var(--bppm-white);
}

.bppm-btn[disabled] {
	opacity: 0.6;
	cursor: not-allowed;
}

.bppm-btn:focus-visible {
	outline: 2px solid var(--bppm-ink);
	outline-offset: 2px;
}

/*
 * Mobile, Blocksy's own breakpoint (690px, not the generic 768px), same
 * convention product-page.css already uses. RECONCILED 2026-09-23
 * (86eypb6me): this query used to also carry `.bppm-section{padding-block:
 * 24px; padding-inline:20px}`, a pre-Figma-parity guess. The ledger has no
 * basis for a 690px-specific value at all -- Figma only draws 1512/744/428
 * -- and every default section measures padding-block:32px at every one of
 * those three frames, so the 24px here was simply wrong; removed rather than
 * kept as a second, narrower override. padding-inline:20px is now redundant
 * too: `--bppm-gutter` already steps to 20px at <=743px (product-page-
 * marketing.css's :root-equivalent .bppm rule), which already covers this
 * query's <=690px range. The layout rules below (not a padding value, and
 * not something this task's ledger measures) are left on their existing
 * 690px threshold.
 */
/*
 * The timeline stack lives next to `.bppm-timeline__card`, not here: below
 * 600px `.bppm-timeline__item` is a column (badge above card). Figma's 428
 * frame ("Frame 2147229793", node I29629:112443;34457:268954) is horizontal,
 * but beside the badge the card breaks words at the 16px type floor, so the
 * overflow fix wins over the Figma match (reported to QA).
 */
@media (max-width: 690px) {
	.bppm-why {
		flex-direction: column;
	}
}

/*
 * 86eypb6me S36 / B13: excess gap between the last marketing section
 * (subscribe band) and the footer's "Keep Reading" health-hub band below
 * it, reported at mobile but present at every width. NAMED the winning
 * rules live via document.styleSheets/getComputedStyle before touching
 * anything: `main.site-main{margin-bottom:100px}` (blocksy-child's own
 * assets/css/base.css, OUTSIDE this repo's sites/bonza/custom/ tree and so
 * outside this PR's file ownership) plus Blocksy's native per-template
 * "Content Bottom Spacing" attribute,
 * `.ct-container-full[data-vertical-spacing*="bottom"]{padding-bottom:
 * var(--theme-content-vertical-spacing)}` (main.min.css), together measured
 * exactly 150px live (100 + 50) between `.bppm`'s own bottom edge and the
 * footer -- Figma draws no such gap on either variant's PDP frame, and the
 * every-other-boundary convention already established throughout this same
 * stack (`.bppm-section{padding-block:32px}`, this file's own header
 * comment) is the nearest real reference for "how much space this page
 * puts between two adjacent blocks," reused here rather than inventing a
 * new figure.
 *
 * Scoped to `body:has(.bppm)`, not the product template generally or the
 * theme file directly: this is the bespoke marketing stack's own page-level
 * spacing need, not a sitewide content-spacing change, and Blocksy's
 * "Content Bottom Spacing" is itself a per-template config surface (a
 * config-first override belongs in Customizer/page settings, not a
 * !important-free CSS zero here) -- reported as the config-first
 * alternative for whoever owns that setting, while this scoped, page-only
 * override ships the visible fix now.
 */
body:has(.bppm) main.site-main {
	margin-bottom: 32px;
}

body:has(.bppm) .ct-container-full[data-vertical-spacing*="bottom"] {
	padding-bottom: 0;
}

/* S20: the non-UK wording stays hidden until the delivery-country switch
   (G18) toggles these two spans; UK copy is the default. */
.bonza-non-uk-only {
	display: none;
}

/* G43: routine card names stay on one line from 1024 up ("THE FOUNDATION
   ROUTINE" broke with one word alone at 1024-1920). 12px + -0.4px tracking fits
   the narrowest card; Lan-approved Figma deviation. Below 1024 the wrap is accepted. */
@media (min-width: 1024px) {
	html body .bppm-routine-card .bppm-routine-card__title {
		font-size: 12px;
		letter-spacing: -0.4px;
		margin-inline-end: -8px; /* half the 16px card padding: keeps 8px to the card edge */
		text-wrap: balance;
	}
}


/* G32 (z8udzkgngw): closing line under the FAQ, centred under the list at the
   same 1000px measure. White on #247B4E is 5.23:1, same figure as the questions. */
.bppm-faq__foot {
	max-width: 1000px;
	margin: 24px auto 0;
	text-align: center;
	color: var(--bppm-white);
	font-size: 16px;
	line-height: 24px;
}

.bppm-faq__foot a {
	color: inherit;
	text-decoration: underline;
}

/* z8udzkgngr (M18): price, buttons and every other row of a routine card sit on a
   shared line across the row. The row (and the swipe row below 1440px) is a grid of
   7 tracks (photo + the 6 body rows: title, tags, description, rule, price, buttons)
   and each card is a subgrid over them, so a longer description in one card pushes
   the price down in all of them instead of leaving prices at different heights. */
.bppm-routine__grid:not(.bppm-routine__grid--single) {
	display: grid;
	grid-auto-flow: column;
	grid-template-rows: repeat(7, auto);
	grid-auto-columns: minmax(196px, 312px);
	justify-content: center;
	column-gap: 24px;
	row-gap: 0;
}
.bppm-routine__grid:not(.bppm-routine__grid--single) > .bppm-routine-card {
	display: grid;
	grid-row: span 7;
	grid-template-rows: subgrid;
	max-width: none;
}
.bppm-routine__grid:not(.bppm-routine__grid--single) > .bppm-routine-card > .bppm-routine-card__body {
	display: grid;
	grid-row: 2 / span 6;
	grid-template-rows: subgrid;
	row-gap: 12px;
	align-content: start;
	flex: none;
}
.bppm-routine__grid:not(.bppm-routine__grid--single) > .bppm-routine-card > .bppm-routine-card__body > * {
	min-width: 0;
}
/* Legacy on-sale cards (routine-cards.php, off by default) add an in-flow badge,
   a 7th body child that the 6 shared rows cannot hold. Those cards fall back to a
   plain column so the button never lands in an unshared implicit row. */
.bppm-routine__grid:not(.bppm-routine__grid--single) > .bppm-routine-card > .bppm-routine-card__body:has(> .bppm-routine-card__badge) {
	display: flex;
	flex-direction: column;
	gap: 12px;
}
@media (max-width: 1439px) {
	.bppm-routine__grid:not(.bppm-routine__grid--single) {
		grid-auto-columns: max(160px, calc((100% - 24px) / 2));
		justify-content: start;
	}
	.bppm-routine__grid:not(.bppm-routine__grid--single) > .bppm-routine-card {
		flex: none;
	}
}

/*
 * Glendon's carousel slides (QA z8udzkgqpc/pf/ph/pk, G30): each is a finished
 * 2000x2000 square card, so it is shown whole (no cut-out, no crop) with the
 * same rounded corner the gallery uses, centred in its column.
 */
.bppm-why__photo--slide,
.bppm-how__photo--slide {
	width: 100%;
	max-width: 484px;
	margin: 0 auto 32px;
}

.bppm-why__photo--slide .bppm-why__photo-img,
.bppm-how__photo--slide .bppm-how__photo-img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	border-radius: 16px;
}
