/* ===========================================================================
   Round 7 · NAEM-SPEC #5 (four points on more pages) and #6 (flashlight)

   Loaded by inc/round7-points.php on the four routes that carry the block: the
   real front page, product pages, the cart and the prepared checkout. It is
   enqueued after every Round 5/6 sheet, so nothing here needs !important.

   Part 1 carries the block to routes that never load round5-home.css.
   Part 2 is the flashlight: two glow layers and the tokens that tune them.
   The pointer tracker is assets/js/round7-flashlight.js; it only ever writes
   --fx / --fy and one class, and everything visible is decided here.
   ========================================================================= */


/* ---------------------------------------------------------------------------
   Flashlight tunables. One place to turn the effect up, down or off.

   The owner's word is "subtle": a soft radial glow, not a beam. The two fill
   alphas are the peak of each gradient, at the pointer, and have ceilings that
   were set against text contrast, not taste:
     cards  <= 16%   (the glow passes behind 14px --muted body copy)
     hero   <= 22%   (the glow lives inside the masked molecular field only)
   Composited, not guessed: --muted body copy on --band, with the section's
   static bloom at its 10% peak AND the full card glow directly behind it,
   measures 6.0:1 at 13% and 5.6:1 at the 16% ceiling (7.8:1 with no glow; AA
   asks for 4.5:1). Raise a ceiling and that arithmetic has to be redone.

   --r7-flash-edge-alpha is a different thing: a 1px catch-light on each card's
   existing top hairline. No text ever sits on it, so it is allowed to be bright
   enough to read as light landing on an edge.
   ------------------------------------------------------------------------- */
:root {
	--r7-flash-card-alpha: 13%;
	--r7-flash-card-radius: 320px;
	--r7-flash-edge-alpha: 62%;
	--r7-flash-edge-radius: 240px;
	--r7-flash-hero-alpha: 19%;
	--r7-flash-hero-radius: clamp(240px, 27vw, 430px);
	--r7-flash-fade: 320ms;
}


/* ===========================================================================
   Part 1 · the block, wherever it is printed
   ========================================================================= */

/* The grid, the cards, the numerals and the 64px/52px icon sizing are global
   (pharma-pass.css, round2.css) and already reach every route. What does NOT
   reach them is the section's static bloom: it lives in round5-home.css, which
   is a front-page-only sheet. It is restated here value for value so the band
   on a product page is the same band, not a flatter cousin. On the home page
   both sheets say the same thing and nothing changes. */
.r7-points {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	overflow: clip;
	/* The cart prints this block inside .body-copy, which mutes its text. */
	color: var(--text);

	/* Two routes re-tint the pictogram family for their own rows: the prepared
	   checkout (.pc) draws them in --text on a glass plate, the product page's
	   trust row in --accent-bright. If this block is ever printed inside either
	   scope it would inherit that tint and stop being "the same icons" (#5).
	   `initial` makes each property invalid at computed-value time, which is what
	   sends the SVG's var() back to the family defaults the home page shows. */
	--r5-ico-plate: initial;
	--r5-ico-ring: initial;
	--r5-ico-bevel: initial;
	--r5-ico-emboss: initial;
	--r5-ico-ink: initial;
	--r5-ico-mark: initial;
}
.r7-points::before {
	content: "";
	position: absolute;
	z-index: -1;
	top: -18%;
	left: 50%;
	width: min(1180px, 130%);
	height: 116%;
	transform: translateX(-50%);
	pointer-events: none;
	background:
		radial-gradient(52% 50% at 50% 42%, rgba(0, 212, 200, .10), rgba(0, 212, 200, .042) 48%, rgba(0, 212, 200, 0) 74%);
}

/* Same reason as the token reset: `.pc .r5-ico` pins the family to 40px. */
.r7-points .purchase-item .step-icon .r5-ico { display: block; width: 64px; height: 64px; flex: none; }

/* Off the home page the block is a supporting note under a product, a cart or a
   form, not a chapter of the page, so the heading steps down to the scale the
   FAQ echo aside and the PDP section heads use. Same <h2>, same words. */
.r7-points--compact { padding-block: clamp(44px, 4.4vw, 68px); }
.r7-points--compact .sec-head { margin-bottom: var(--s5); }
.r7-points--compact .sec-head .eyebrow { margin-bottom: var(--s3); }
.r7-points--compact .sec-head h2 {
	max-width: 34ch;
	margin-bottom: 0;
	font-size: clamp(22px, 2vw, 28px);
	line-height: 1.15;
	letter-spacing: -.01em;
	text-wrap: balance;
}

/* No button under the grid: drop the margin that was holding it off. */
.r7-points--no-cta .purchase-grid { margin-bottom: 0; }

/* Printed INSIDE a .wrap (the cart always is; a template may choose to be).
   A band cannot be full-bleed from in there, and a second gutter on top of the
   outer one would indent the four columns away from everything above them. So
   the block gives up the band fill and the inner gutter and becomes a ruled
   section that lines up with the content it follows. */
.wrap .r7-points {
	margin-top: var(--s7);
	padding-block: var(--s7) 0;
	border-top: 1px solid var(--line);
	background: none;
	overflow: visible;
}
.wrap .r7-points::before { content: none; }
.wrap .r7-points > .wrap { width: auto; max-width: none; padding-inline: 0; }

@media (max-width: 680px) {
	.r7-points .purchase-item .step-icon .r5-ico { width: 52px; height: 52px; }
	.r7-points--compact { padding-block: clamp(36px, 10vw, 48px); }
	.r7-points--compact .sec-head h2 { font-size: clamp(22px, 6.4vw, 26px); line-height: 1.12; }
	.wrap .r7-points { margin-top: var(--s6); padding-block: var(--s6) 0; }
}

/* Phones: the four points become four rows, not four stacked cards.

   round2.css R11 set the column geometry ("a 64px icon plate, 20px above a
   20/600 title, in a column") after measuring beyond-peptides.com — the
   reference this whole block is modelled on. That measurement was taken at
   desktop. Re-measured on the same reference at 375 on 2026-09-20, its
   equivalent block is NOT a column there: it is a flex ROW per item — 50px
   icon at x=18, title and body sharing a text column at x=88, body 251px
   wide, item 97px tall, 470px for all four. So switching to rows here is not a
   departure from the reference, it is the half of the reference the column
   rule never covered.

   Why it matters: stacked, one item is 196px and the block is 834px, which on
   the product and prepared-checkout routes is most of a phone screen of trust
   copy between the reader and the next real thing on the page. As rows at 375
   it is 108px an item (132 where the body runs to three lines) and 505px for
   the block — the reference's own proportion — with the body copy still 279px
   wide, so nothing is traded for the space.

   Bounded at 680px, which is not a new breakpoint: it is the exact width where
   `.category-grid, .purchase-grid, .storage-grid` already collapses to
   `minmax(0, 1fr)` in the block directly above. So the rule is simply "one
   column means rows", with no width where the grid is single-column but the
   items are still stacked. I first bounded this at 520 on the theory that
   `repeat(auto-fill, minmax(min(100%, 240px), 1fr))` governed the column count
   here; it does not — that pattern is used elsewhere, this grid is explicit —
   and measuring at 560 caught it: one 524px column of 196px stacked cards,
   an 811px block, exactly the problem this rule exists to fix. Measured with
   the 680 bound: 560 → 108px items / 459px block, 680 → 85px / 413px, and 700
   is untouched at two 314px columns of 210px cards.

   The icon lands at 48px (reference 50) and the `.r5-ico` line must be
   restated because the 680px block above sets 52px at the same bound; this one
   wins only by being later in source order. */
@media (max-width: 680px) {
	.r7-points .purchase-item {
		grid-template-columns: auto minmax(0, 1fr);
		column-gap: 18px;
		row-gap: 2px;
		align-items: center;
	}
	.r7-points .purchase-item > .step-icon {
		grid-column: 1;
		grid-row: 1 / span 3;
		margin-bottom: 0;
	}
	.r7-points .purchase-item .step-icon .r5-ico { width: 48px; height: 48px; }
	.r7-points .purchase-item > .pi { grid-column: 2; grid-row: 1; }
	.r7-points .purchase-item > b  { grid-column: 2; grid-row: 2; }
	.r7-points .purchase-item > p  { grid-column: 2; grid-row: 3; margin: 0; }
}


/* ===========================================================================
   Part 2 · flashlight (#6)

   Everything below is inside one media query: a device that hovers with a fine
   pointer, and a reader who has not asked for reduced motion. Outside it no
   layer exists at all — not hidden, absent — so touch devices and reduced
   motion pay nothing, and the script (which tests the same two queries) never
   writes a property that nothing reads.

   Nothing here changes layout: every layer is an absolutely positioned pseudo
   element with pointer-events: none, and the only animated property is opacity.
   ========================================================================= */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {

	/* --- the cards ---------------------------------------------------------
	   The four points are open columns under a hairline, not boxed cards. A glow
	   clipped to each column would show the column's rectangle — four lit
	   slabs with dark gutters between them, which is the "hard beam" the owner
	   ruled out. So the light is ONE gradient behind the whole grid, and each
	   column only adds what an edge would do in real light: its top hairline
	   brightens where the pointer is near it. Move across the row and the
	   neighbours catch the light on their rule before the pointer reaches them.

	   z-index -1 inside an isolated grid puts the fill above the band's
	   background and bloom, and strictly behind every glyph of text. */
	.r7-points .purchase-grid {
		position: relative;
		isolation: isolate;
		--fx: 50%;
		--fy: 50%;
		--r7-bleed-x: 40px;
		--r7-bleed-y: 56px;
	}
	/* Inside a .wrap there is only that wrap's gutter to bleed into. */
	.wrap .r7-points .purchase-grid { --r7-bleed-x: 16px; }
	.r7-points .purchase-grid::before {
		content: "";
		position: absolute;
		z-index: -1;
		/* Bleeds past the grid so the light can fall off naturally; the mask
		   takes it to nothing before the box ends, so no edge is ever drawn,
		   whatever the section around it does with overflow. */
		inset: calc(var(--r7-bleed-y) * -1) calc(var(--r7-bleed-x) * -1);
		pointer-events: none;
		opacity: 0;
		transition: opacity var(--r7-flash-fade) var(--ease);
		background:
			radial-gradient(
				circle var(--r7-flash-card-radius) at calc(var(--fx) + var(--r7-bleed-x)) calc(var(--fy) + var(--r7-bleed-y)),
				color-mix(in srgb, var(--accent) var(--r7-flash-card-alpha), transparent) 0%,
				color-mix(in srgb, var(--accent) calc(var(--r7-flash-card-alpha) * .42), transparent) 42%,
				transparent 100%
			);
		-webkit-mask-image:
			linear-gradient(to right, transparent 0, #000 calc(var(--r7-bleed-x) * 2), #000 calc(100% - var(--r7-bleed-x) * 2), transparent 100%),
			linear-gradient(to bottom, transparent 0, #000 calc(var(--r7-bleed-y) * 1.5), #000 calc(100% - var(--r7-bleed-y) * 1.5), transparent 100%);
		mask-image:
			linear-gradient(to right, transparent 0, #000 calc(var(--r7-bleed-x) * 2), #000 calc(100% - var(--r7-bleed-x) * 2), transparent 100%),
			linear-gradient(to bottom, transparent 0, #000 calc(var(--r7-bleed-y) * 1.5), #000 calc(100% - var(--r7-bleed-y) * 1.5), transparent 100%);
		-webkit-mask-composite: source-in;
		mask-composite: intersect;
	}
	.r7-points .purchase-grid.is-r7-lit::before { opacity: 1; }

	/* The catch-light. It is drawn exactly over the column's own 1px border-top
	   (top: -1px), in the column's coordinate space: the script gives every
	   column its offset inside the grid once per hover (--r7-ix / --r7-iy), and
	   the subtraction happens here, so a frame costs two property writes on the
	   grid however many columns there are. */
	.r7-points .purchase-item { position: relative; --r7-ix: 0px; --r7-iy: 0px; }
	.r7-points .purchase-item::before {
		content: "";
		position: absolute;
		top: -1px;
		left: 0;
		right: 0;
		height: 1px;
		pointer-events: none;
		opacity: 0;
		transition: opacity var(--r7-flash-fade) var(--ease);
		background:
			radial-gradient(
				circle var(--r7-flash-edge-radius) at calc(var(--fx) - var(--r7-ix)) calc(var(--fy) - var(--r7-iy)),
				color-mix(in srgb, var(--accent-bright) var(--r7-flash-edge-alpha), transparent) 0%,
				transparent 100%
			);
	}
	.r7-points .purchase-grid.is-r7-lit .purchase-item::before { opacity: 1; }

	/* --- the home hero -----------------------------------------------------
	   The layer is .molecular-field::after, and that choice is the whole safety
	   argument:
	     - it is INSIDE the field, so it inherits the composition mask from
	       round5-hero.css. That mask is fully transparent across the copy
	       column, which means the glow cannot appear behind the headline or the
	       buttons no matter where the pointer is;
	     - the field is z-index 1. The contrast washes (.hero::before,
	       .hero-split::after) are 2 and the copy/product grid is 3, so the glow
	       is under the copy, under the scrim and under the bestseller stage;
	     - it sits at z-index 0 with the field's static atmosphere, BEHIND the
	       canvas. The helix is lit from behind and stays crisp; nothing is ever
	       painted over the strands, so they are never fogged.
	   ::before on the field, and both pseudo elements of .hero / .hero-split, are
	   already taken; ::after here was the one free slot.

	   "Pause molecular motion" adds .is-paused to the field. Paused means
	   nothing in the hero moves, so the glow is switched off here as well as in
	   the script — CSS makes it immediate, the script stops the work. There is
	   deliberately no static fallback glow: the field already has a static
	   atmosphere, and a second fixed lobe would just be a brighter hero. */
	.hero-split .molecular-field { --fx: 66%; --fy: 46%; }
	.hero-split .molecular-field::after {
		content: "";
		position: absolute;
		inset: 0;
		z-index: 0;
		pointer-events: none;
		opacity: 0;
		transition: opacity var(--r7-flash-fade) var(--ease);
		background:
			radial-gradient(
				circle var(--r7-flash-hero-radius) at var(--fx) var(--fy),
				color-mix(in srgb, var(--accent) var(--r7-flash-hero-alpha), transparent) 0%,
				color-mix(in srgb, var(--accent) calc(var(--r7-flash-hero-alpha) * .4), transparent) 44%,
				transparent 100%
			);
	}
	.hero-split .molecular-field.is-r7-lit::after { opacity: 1; }
	.hero-split .molecular-field.is-paused::after { opacity: 0; }
}

/* Side-by-side hero only. The field's own mask is already at .30 by 40% x and
   .82 by 50%, because the helix is meant to reach toward the copy; but the copy
   column can run to ~55% x, so the right-hand end of a long sub-headline line
   sits over a part of the field that is not masked out. The helix passing behind
   a few words is the composition. A pointer-driven glow doing it would be this
   round lowering the contrast of existing text, so the glow gets a stricter
   mask of its own: nothing before 44% x, full strength only from 60%. */
@media (min-width: 901px) and (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
	.hero-split .molecular-field::after {
		-webkit-mask-image: linear-gradient(to right, transparent 0%, transparent 44%, #000 60%, #000 100%);
		mask-image: linear-gradient(to right, transparent 0%, transparent 44%, #000 60%, #000 100%);
	}
}

/* Windows High Contrast and friends replace backgrounds; a translucent gradient
   there is noise at best. */
@media (forced-colors: active) {
	.r7-points .purchase-grid::before,
	.r7-points .purchase-item::before,
	.hero-split .molecular-field::after { display: none; }
}
