/**
 * Medlife Pharmaceuticals - page styles.
 *
 * EVERY RULE IS SCOPED TO `.mlp-page` OR `.mlp-footer`, and both only exist on
 * this one template. Nothing here can reach the shop grid, the loop card, the
 * cart, the checkout or the store footer - which is the point: the Healthcare
 * Store was signed off and this page must not be able to move it.
 *
 * The page keeps its own colour scope on `.mlp-page`. The three brand tokens it
 * borrows - cyan, white, the font - come from `style.css` unchanged; the deep
 * navy and the green are local to this division and are NOT added to the global
 * token set, because they are a page palette rather than a site one.
 *
 *     --mlp-navy    #082A46   division navy, darker than --ml-navy
 *     --mlp-green    #2E9E6B   restrained accent, used for one dot and one rule
 *     --mlp-tint    #F2F9FE   page wash
 *
 * The store header still renders above this page and is untouched.
 */

/*
 * WIDTH IS LOAD-BEARING, not tidiness. Astra wraps the template in
 * .ast-container, which is display:flex - so <main> is a FLEX ITEM at
 * flex: 0 1 auto and sizes to its max-content, i.e. the 1180px --mlp-wrap the
 * inner sections cap at. Every full-bleed band (the hero wash, the tinted
 * section, the closing band) therefore stopped 260px short of the viewport at
 * 1440 while the footer - which sits OUTSIDE main - ran edge to edge.
 *
 * Pre-existing; it predates the dedicated header and was simply less obvious
 * while the store header sat above it.
 */
.mlp-page {
	width: 100%;
	--mlp-navy: #082A46;
	--mlp-navy-soft: #123a5c;
	--mlp-green: #2E9E6B;
	--mlp-tint: #F2F9FE;
	--mlp-tint-deep: #E4F1FB;
	--mlp-line: #dbe6f0;
	--mlp-ink: #4a5c6d;
	--mlp-wrap: 1200px;

	background: var(--ml-white);
	font-family: var(--ml-font);
	color: var(--mlp-ink);
}

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

.mlp-section__inner,
.mlp-bar__inner,
.mlp-hero__inner {
	max-width: var(--mlp-wrap);
	margin: 0 auto;
	padding-left: 24px;
	padding-right: 24px;
}

.mlp-page .mlp-h2 {
	margin: 0;
	font-size: clamp(24px, 2.6vw, 32px);
	font-weight: 700;
	line-height: 1.2;
	letter-spacing: -0.01em;
	color: var(--mlp-navy);
}

/* ---------- division bar ---------- */

.mlp-bar {
	border-bottom: 1px solid var(--mlp-line);
	background: var(--ml-white);
}

/*
 * 90px, sized FROM THE LOGO rather than chosen: 62px of artwork plus 14px of
 * clear space above and below. align-items: center is what centres it, and the
 * row has nothing taller in it, so the lockup sets the header's height.
 */
.mlp-bar__inner {
	display: flex;
	align-items: center;
	gap: 20px;
	min-height: 90px;
	padding-top: 14px;
	padding-bottom: 14px;
	flex-wrap: wrap;
}

/*
 * The official division lockup, untouched. Only the box it sits in is sized -
 * no filter, no recolour, no crop: HEIGHT ALONE IS SET AND WIDTH IS auto, so
 * the browser derives the width from the file's own 796x401 and the aspect
 * ratio cannot drift. Do not add width, object-fit or a background here.
 */
.mlp-bar__brand {
	display: flex;
	align-items: center;
	gap: 10px;
	flex: 0 0 auto;
	text-decoration: none;
}

/*
 * 62px, and the number comes from the artwork rather than from taste. The
 * lockup is three tiers - leaves and figure, "MED LiFE", then
 * "Pharmaceuticals" - and that last word is only 57 of the file's 401 pixels
 * tall, i.e. 14.2% of the image. At 62px it renders at 8.8px, which reads; at
 * the old 42px it would have been 6.0px, which does not.
 *
 * RAISE THE HEIGHT, NEVER THE WIDTH, if it ever needs to be bigger.
 */
.mlp-bar__brand img {
	width: auto;
	height: 62px;
	max-width: 100%;
	display: block;
}

.mlp-bar__division {
	font-size: 13px;
	font-weight: 600;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--ml-cyan);
}

/*
 * The menu holds the five section links AND the Healthcare Store return link,
 * so one control collapses both on a phone. On desktop it is simply the rest of
 * the row, which is why the layout is unchanged above the breakpoint.
 */
/*
 * `display: contents` so the <details> wrapper has no box of its own and the
 * summary and the menu stay direct flex children of .mlp-bar__inner - the row
 * lays out exactly as it did when they were siblings.
 */
.mlp-bar__disclosure {
	display: contents;
}

/*
 * `display: contents` ON THE HOST IS NOT ENOUGH - CHROME PUTS A REAL BOX
 * BETWEEN THEM (found 2026-09-20, and it is why the desktop nav vanished).
 *
 * A <details> has a UA shadow tree, and current Chrome gives its non-summary
 * content a genuine block box addressable as ::details-content. Removing the
 * HOST's box with `display: contents` leaves that one standing, so
 * .mlp-bar__menu was never a flex item of .mlp-bar__inner: its `flex: 1 1 auto`
 * did nothing, it resolved to ZERO WIDTH, and .mlp-bar__nav's `flex-wrap: wrap`
 * then stacked all five links into a 273px column inside a 91px bar. Four of
 * the five rendered outside the bar entirely and a hit test on any of them
 * returned .mlp-bar__inner - present in the DOM, unclickable on screen.
 *
 * MEASURED, NOT REASONED: `display: flex` on the <details> itself changes
 * NOTHING (menu still 0x273) - the host was never the lever. This one rule
 * takes it to 1009x46 with all five links on one row and 5/5 hit tests.
 *
 * IT MUST STAY ITS OWN RULE. An unknown pseudo-element invalidates the whole
 * rule it appears in, so grouping this with a real selector would silently
 * drop that selector on every engine without ::details-content - and those are
 * precisely the engines where the old `display: contents` slot still works and
 * nothing needs fixing.
 */
.mlp-bar__disclosure::details-content {
	display: contents;
}

/*
 * The marker goes in both spellings: `list-style` is what current engines
 * honour, the ::-webkit- pseudo is what older WebKit needs.
 */
.mlp-bar__burger {
	list-style: none;
}

.mlp-bar__burger::-webkit-details-marker {
	display: none;
}

/*
 * DISPLAY IS ALWAYS STATED EXPLICITLY, never left to the UA's own closed-state
 * hiding. A <details> normally hides its non-summary children itself, but that
 * happens inside the shadow tree and `display: contents` on the host is exactly
 * the kind of thing that makes it engine-dependent. Setting `display` on the
 * menu in both states means our CSS decides, on every engine.
 */
.mlp-bar__menu {
	display: flex;
	align-items: center;
	gap: 20px;
	flex: 1 1 auto;
	min-width: 0;
}

.mlp-bar__nav {
	display: flex;
	align-items: center;
	gap: 22px;
	margin-inline: auto;
	flex-wrap: wrap;
}

/*
 * 44px square, and the padding reset is not optional: Astra's inline
 * Customizer CSS puts 10px/20px on every bare button, which would leave this
 * one a 2px content box. Every state is named because Astra repaints
 * button:hover and button:focus at (0,1,1).
 */
/*
 * DISPLAY IS NOT IN THE STATE LOCK, AND PUTTING IT BACK SEALS THE MOBILE MENU
 * (found 2026-09-20, by a real pointer click rather than element.click()).
 *
 * The lock below names :hover/:focus/:active because Astra repaints a bare
 * control in those states - but it used to carry `display: none` with them, at
 * (0,2,1). The <=1024 override that shows the burger is (0,2,0), so it lost to
 * every state variant: the instant the pointer arrived, :hover matched and the
 * summary went `display: none` UNDER THE CURSOR. mousePressed then landed on
 * whatever was behind it and the <details> never toggled. Focus did the same
 * thing to the keyboard, so Enter was dead too.
 *
 * IT LOOKED FINE IN EVERY WAY EXCEPT THE ONE THAT MATTERS. Resting styles were
 * correct, the summary measured 44x44 with pointer-events: auto, and
 * elementFromPoint at its centre returned the icon inside it - because none of
 * those force :hover. summary.click() worked for the same reason. Only a
 * dispatched pointer event reproduced it.
 *
 * So `display` lives in its own rules: none here, inline-flex at <=1024 with a
 * doubled class, one tier ABOVE anything the state lock can reach.
 */
.mlp-page .mlp-bar__burger {
	display: none;
}

.mlp-page .mlp-bar__burger,
.mlp-page .mlp-bar__burger:hover,
.mlp-page .mlp-bar__burger:focus,
.mlp-page .mlp-bar__burger:focus-visible,
.mlp-page .mlp-bar__burger:active {
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	margin-left: auto;
	padding: 0;
	border: 1px solid var(--mlp-line);
	border-radius: 10px;
	background: var(--ml-white);
	color: var(--mlp-navy);
	cursor: pointer;
	transition: background-color var(--ml-t-base) var(--ml-e-standard);
}

.mlp-page .mlp-bar__burger:hover,
.mlp-page .mlp-bar__burger:focus-visible {
	background: var(--mlp-tint);
}

.mlp-page .mlp-bar__burger:focus-visible {
	outline: 3px solid var(--ml-cyan);
	outline-offset: 3px;
}

/* The icon swap reads the OPEN ATTRIBUTE, so it needs no class and no script. */
.mlp-bar__burger-close,
.mlp-bar__disclosure[open] .mlp-bar__burger-open {
	display: none;
}

.mlp-bar__disclosure[open] .mlp-bar__burger-close {
	display: block;
}

/*
 * .mlp-bar__store USED TO SHARE THIS RULE and no longer does - it is a solid
 * CTA now, not a text link, and inheriting 500-weight navy would fight every
 * declaration in its own block.
 */
.mlp-bar__nav a {
	font-size: 14px;
	font-weight: 500;
	color: var(--mlp-navy);
	text-decoration: none;
}

.mlp-bar__nav a:hover,
.mlp-bar__nav a:focus-visible {
	color: var(--ml-cyan);
}

/*
 * THE ANIMATED UNDERLINE - pharma header nav only.
 *
 * HOVER-CAPABLE POINTERS ONLY, and that is a sizing decision as much as an
 * interaction one. Measured on the real page:
 *
 *     desktop   anchor width == label width exactly (slack 0.0px on all five)
 *     mobile    anchor is the full 328px row, label is 61-139px (slack ~267px)
 *
 * On desktop the anchor shrink-wraps its text, so an inset-0 pseudo-element IS
 * the label width with no wrapper span needed. On the stacked mobile menu the
 * same rule would paint a 328px bar under a 61px word. Touch has no hover
 * anyway, so the menu keeps its existing current-page marker (weight + colour)
 * and its 44px rows are untouched.
 *
 * The store link is NOT in here - it is a sibling of <nav>, outside this
 * selector, and keeps its own arrow treatment.
 */
@media (hover: hover) and (pointer: fine) {
	/*
	 * Only to anchor the pseudo-element. An absolutely positioned ::after adds
	 * no box to the flex row, so nothing moves, resizes or reflows - the
	 * labels sit exactly where they did.
	 */
	.mlp-page .mlp-bar__nav a {
		position: relative;
	}

	/*
	 * scaleX from the left edge: the line grows left-to-right rather than
	 * fading, which is what reads as "drawn". transform is composited, so it
	 * never triggers layout.
	 *
	 * 2px tall, 5px below the label - the anchor's border box is the text box
	 * here, so "below the box" and "below the text" are the same offset.
	 *
	 * The colour is #00AFF0 as specified. Note the naming: in this theme
	 * --ml-accent is #0077B6 and --ml-cyan is #00AFF0, so the token that
	 * carries the requested hex is --ml-cyan.
	 */
	/*
	 * MEASURED OFF nutrifactor.com.pk/collections/all-products, not guessed.
	 * Their nav puts the line on a ::after of an inner <span class="text
	 * p-relative"> - a span they need because their anchors carry 12px of side
	 * padding and the line has to be the LABEL's width, not the box's. Ours
	 * already shrink-wraps its text (slack 0.0px on all five links), so the
	 * pseudo-element sits on the anchor and needs no wrapper.
	 *
	 * What was copied - the motion, exactly:
	 *
	 *     transition       transform 0.35s ease-out
	 *     rest             scaleX(0), transform-origin RIGHT
	 *     hover            scaleX(1), transform-origin LEFT
	 *
	 * The origin SWAP is the whole trick and it is easy to miss. Origin is not
	 * a transitionable property, so it flips instantly: on the way in the
	 * origin is already left and the line grows left-to-right; on the way out
	 * it is already right and the line retracts to the right. One direction in,
	 * the other out - which is what makes it read as a sweep rather than a
	 * bar that just squashes back the way it came.
	 *
	 * What was NOT copied: their 1px line, -2px offset and #232323 ink. Ours
	 * stays 2px / -5px / --ml-cyan per the brief - behaviour only.
	 */
	.mlp-page .mlp-bar__nav a::after {
		content: '';
		position: absolute;
		left: 0;
		right: 0;
		bottom: -5px;
		height: 2px;
		border-radius: 1px;
		background: var(--ml-cyan);
		transform: scaleX(0);
		transform-origin: right center;
		transition: transform 350ms ease-out;
		pointer-events: none;
	}

	/*
	 * The current page is drawn at rest. It computes to scaleX(1) on first
	 * paint rather than transitioning from 0, so nothing animates in on load.
	 */
	.mlp-page .mlp-bar__nav a[aria-current="page"]::after {
		transform: scaleX(1);
		transform-origin: left center;
	}

	/*
	 * ONE UNDERLINE AT A TIME. The moment the nav is engaged, every line
	 * retracts - including the current page's. The link actually being pointed
	 * at gets it back in the rule below.
	 *
	 * WHY :has(a:focus-visible) AND NOT :focus-within - the choice matters.
	 * :focus-within fires for a MOUSE click too, and clicking "Our Products"
	 * (an in-page #anchor) leaves focus sitting on it: the nav would count as
	 * engaged, the current page's line would hide, and the clicked link would
	 * not show one either because a click sets :focus but never
	 * :focus-visible. Result: no underline at all until focus moved. :has()
	 * with :focus-visible only reacts to keyboard focus, so that dead state
	 * cannot happen.
	 *
	 * THE TWO SELECTORS ARE DELIBERATELY IN SEPARATE RULES, not comma-joined.
	 * An unsupported selector anywhere in a comma list invalidates the WHOLE
	 * rule, so pairing them would take the hover behaviour down with :has() on
	 * any engine that lacks it. Apart they degrade independently.
	 *
	 * Specificity is (0,3,2) for this rule and (0,3,2) for the one after it -
	 * :has() contributes its most specific argument, a:focus-visible, which is
	 * (0,1,1). They tie, so source order decides and the later rule wins. That
	 * is why "show the engaged link" must stay BELOW "retract everything".
	 */
	.mlp-page .mlp-bar__nav:hover a::after {
		transform: scaleX(0);
		transform-origin: right center;
	}

	.mlp-page .mlp-bar__nav:has(a:focus-visible) a::after {
		transform: scaleX(0);
		transform-origin: right center;
	}

	/*
	 * The one being pointed at or focused. .mlp-bar is in the selector purely
	 * for weight: :has(a:focus-visible) contributes its argument in FULL, the
	 * a as well as the :focus-visible, so the hide rule above measures (0,3,3)
	 * against this one at (0,3,2) and won outright - a focused link showed no
	 * underline at all. The extra ancestor class takes this to (0,4,2), which
	 * beats it on class count.
	 *
	 * Counting :has() as if it added only its pseudo-class is the easy mistake
	 * here; it does not.
	 */
	.mlp-page .mlp-bar .mlp-bar__nav a:hover::after,
	.mlp-page .mlp-bar .mlp-bar__nav a:focus-visible::after {
		transform: scaleX(1);
		transform-origin: left center;
	}

	@media (prefers-reduced-motion: reduce) {
		/*
		 * No sweep, but the current page still has to be marked - the states
		 * above are unchanged, only the animation between them is dropped.
		 */
		.mlp-page .mlp-bar__nav a::after {
			transition: none;
		}
	}
}

/*
 * ---------------------------------------------------------------------------
 * THE HEALTHCARE STORE CTA
 * ---------------------------------------------------------------------------
 *
 * CONTRAST, STATED RATHER THAN BURIED: white on --ml-cyan-dark (#0098D1)
 * measures 3.2751:1. The label is 14px/600, which is NOT "large text" under
 * WCAG (that starts at 18.66px bold), so the bar is 1.4.3's 4.5:1 and this
 * MISSES it. It clears 1.4.11's 3:1, so the shape and the arrow tile are fine;
 * the words are the part that falls short.
 *
 * It is the owner's approved colour, taken with this figure in hand, and it
 * sits with the brand-cyan trades this project already records - the top-bar
 * ink, the search icon, Astra's --ast-global-color-0 and the active tab's white
 * label. DO NOT quietly darken it. --mlp-navy on this fill would be 4.48:1 and
 * still short; a white label needs about #007BAA to reach 4.5:1.
 *
 * NO WIDTH, HEIGHT OR PADDING IS ANIMATED anywhere below, and that is the rule
 * this control lives by: it sits in a flex row beside the nav, so any animated
 * box metric would push its neighbours every time a pointer crossed it.
 */
.mlp-page .mlp-bar__store {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	flex: 0 0 auto;
	min-height: 46px;
	padding: 0 6px 0 14px;
	border: 0;
	border-radius: 10px;
	background: var(--ml-cyan-dark);
	color: var(--ml-white);
	font-family: var(--ml-font);
	font-size: 14px;
	font-weight: 600;
	line-height: 1.2;
	text-decoration: none;
	white-space: nowrap;
	transform: none;
	box-shadow: 0 6px 14px -8px rgba(var(--ml-shadow-tint), 0.7);
	transition: transform var(--ml-t-base) var(--ml-e-standard), box-shadow var(--ml-t-base) var(--ml-e-standard);
}

.mlp-bar__store-bag {
	flex: 0 0 auto;
}

.mlp-bar__store-label {
	flex: 0 1 auto;
}

/*
 * THE WHITE TILE. overflow: hidden is load-bearing - it is what keeps the
 * arrow's 3px travel INSIDE the square instead of letting it slide out over the
 * cyan. The tile itself never moves.
 */
.mlp-bar__store-go {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 30px;
	height: 30px;
	border-radius: 8px;
	background: var(--ml-white);
	color: var(--ml-cyan-dark);
	overflow: hidden;
}

.mlp-bar__store-go svg {
	transition: transform var(--ml-t-base) var(--ml-e-standard);
}

/*
 * THE :focus PIN, placed before the hover block. This is an <a>, so Astra's
 * inline a:focus { color: var(--ast-global-color-1); outline: thin dotted } at
 * (0,1,1) reaches it, and a pointer click sets :focus without :focus-visible.
 * Without this a clicked CTA kept a dotted ring and an Astra-blue label.
 */
.mlp-page .mlp-bar__store:focus:not(:focus-visible) {
	transform: none;
	color: var(--ml-white);
	box-shadow: 0 6px 14px -8px rgba(var(--ml-shadow-tint), 0.7);
	outline: none;
}

/*
 * HOVER-CAPABLE POINTERS ONLY. A lift that fires on a tap is a flicker, and on
 * touch there is no way to leave the state - the same gate the nav underline
 * and the pack-size pill already use on this site.
 */
@media (hover: hover) and (pointer: fine) {
	.mlp-page .mlp-bar__store:hover,
	.mlp-page .mlp-bar__store:focus-visible {
		transform: translateY(-2px);
		box-shadow: 0 12px 20px -10px rgba(var(--ml-shadow-tint), 0.85);
	}

	.mlp-page .mlp-bar__store:hover .mlp-bar__store-go svg,
	.mlp-page .mlp-bar__store:focus-visible .mlp-bar__store-go svg {
		transform: translateX(3px);
	}
}

/*
 * :active RETURNS TO REST - it sits after the hover block deliberately, because
 * a pressed control is almost always hovered too and both rules are (0,3,0).
 * The arrow goes home with it, so the press reads as the button settling rather
 * than as a second animation.
 */
.mlp-page .mlp-bar__store:active {
	transform: none;
	box-shadow: 0 6px 14px -8px rgba(var(--ml-shadow-tint), 0.7);
}

.mlp-page .mlp-bar__store:active .mlp-bar__store-go svg {
	transform: none;
}

/*
 * Stated on the control rather than left to the page-wide rule - and
 * border-radius IS RESTATED, which is not redundancy.
 *
 * The shared ".mlp-page a:focus-visible" block carries "border-radius: 4px" so
 * a focused text link gets a rounded ring. This rule outranks it at (0,3,0)
 * against (0,2,1), but A RULE WINS ONLY THE PROPERTIES IT NAMES - so the 4px
 * still applied and the CTA's corners visibly snapped 10px -> 4px the moment a
 * keyboard reached it. Measured, not guessed. Same shape as the shared focus
 * rule that once squared the modal's circular close button.
 */
.mlp-page .mlp-bar__store:focus-visible {
	outline: 3px solid var(--ml-cyan);
	outline-offset: 3px;
	border-radius: 10px;
}

.mlp-page a:focus-visible,
.mlp-page button:focus-visible,
.mlp-page input:focus-visible,
.mlp-page select:focus-visible,
.mlp-footer a:focus-visible {
	outline: 3px solid var(--ml-cyan);
	outline-offset: 3px;
	border-radius: 4px;
}

/*
 * The shared ring above squares corners to 4px, and a rule wins only the
 * properties it names - so boxed controls restate their own radius, the same
 * fix .mlp-bar__store carries. (0,3,0).
 */
.mlp-page .mlp-btn:focus-visible {
	border-radius: 8px;
}

.mlp-page .mlp-finder__sort:focus-visible {
	border-radius: 9px;
}

/*
 * ASTRA'S a:focus TRAP. Its inline Customizer CSS carries
 * a:focus { color: var(--ast-global-color-1) } at (0,1,1), which repaints any
 * footer link the moment it is clicked - and a click leaves :focus set, so it
 * stays repainted afterwards. Every link type in this footer is pinned back to
 * its rest colour at (0,2,1) or better.
 *
 * Colour only. No box, border or transform is touched, so rest, hover, focus
 * and active all occupy exactly the same geometry and nothing shifts.
 */
.mlp-footer .mlp-footer__col a:focus,
.mlp-footer .mlp-footer__contact a:focus,
.mlp-footer .mlp-footer__logo:focus {
	color: rgba(255, 255, 255, 0.82);
}

.mlp-footer .mlp-footer__social a:focus {
	color: var(--ml-white);
}

/*
 * THE OTHER HALF OF ASTRA'S a:focus - `outline: thin dotted`. The pins above
 * restate colour only, so a mouse click on any footer anchor left a thin dotted
 * ring behind until focus moved (measured 2026-09-13, all 16 anchors, both
 * pharma pages, 360 and 1440).
 *
 * :not(:focus-visible) IS LOAD-BEARING. `.mlp-footer .mlp-footer__col a:focus`
 * is (0,3,1) and the keyboard ring below is (0,2,1), so putting outline: none
 * straight into the colour pins would erase the keyboard ring too. Scoped to
 * pointer focus only, the two can never meet.
 */
.mlp-footer .mlp-footer__col a:focus:not(:focus-visible),
.mlp-footer .mlp-footer__logo:focus:not(:focus-visible),
.mlp-footer .mlp-footer__social a:focus:not(:focus-visible) {
	outline: none;
}

/*
 * The pin must not swallow the keyboard ring, so :focus-visible restores the
 * hover ink and the ring is stated separately below. It sits AFTER the pin,
 * which is what lets it win at equal specificity.
 */
.mlp-footer .mlp-footer__col a:focus-visible,
.mlp-footer .mlp-footer__contact a:focus-visible {
	color: var(--ml-white);
}

/*
 * --ml-cyan on navy, per this project's focus-ring rule for dark surfaces.
 *
 * THE WHOLE outline HAS TO BE STATED, not just its colour. Setting
 * outline-color alone left the browser's own outline:auto ring in place,
 * and Chrome IGNORES outline-color when the style is auto - the measured ring
 * came back rgba(81, 201, 245, .98), the UA's adaptive colour, not the token.
 */
.mlp-footer a:focus-visible,
.mlp-footer .mlp-footer__logo:focus-visible {
	outline: 2px solid var(--ml-cyan);
	outline-offset: 3px;
}

/* ---------- hero ---------- */

/*
 * FULL-WIDTH ANIMATED SCIENTIFIC BACKDROP, 2026-09-19 - replaces the split
 * copy | photograph layout. The copy, the button and the anchor are unchanged;
 * only their ink moved from dark-on-light to light-on-dark.
 *
 * SECOND PASS, same day: THE IMAGE IS THE BASE. The backdrop is the
 * owner's laboratory image (attachment 2480, pharma-hero-lab-2400.webp, via
 * medlife_pharma_hero_image) at every width; nothing re-draws it in CSS. The
 * first pass's SVG molecules, glass panels and lab-glass drawing were removed
 * because the image already carries all three.
 *
 * Layers, bottom up: the gradient (a fallback colour under the image), the
 * image (.mlp-hero__bg), the video over it inside the same layer (see "the
 * video" below), the left overlay (::before), then the copy.
 *
 * EVERY VALUE HERE IS COMPONENT-LOCAL. The navy is the --ml-navy token; the
 * owner's #062A4D would go in --mlp-hero-navy, never in :root. The green is
 * the pharma logo's leaf note, the same #2E9E6B as --mlp-green, used only as
 * a particle and glow colour. Durations are 20-40s loops, far beyond the
 * longest motion token (--ml-t-enter, 420ms), so they live here too.
 *
 * PERFORMANCE: only transform and opacity animate. The rays carry a STATIC
 * blur(48px) and mix-blend-mode: screen; neither is animated, so the blur is
 * rasterised once into the ray's own layer. No backdrop-filter, no animated
 * box-shadow or background. will-change sits on the rays and molecules only.
 */
.mlp-hero {
	--mlp-hero-navy: var(--ml-navy);
	--mlp-hero-navy-rgb: 10, 37, 64;
	--mlp-hero-cyan-rgb: 0, 175, 240;
	--mlp-hero-green-rgb: 46, 158, 107;
	--mlp-hero-t-ray: 26s;
	position: relative;
	isolation: isolate;
	overflow: hidden;
	display: flex;
	align-items: center;
	/*
	 * NOT a flat 740px. The copy is 356px tall; on a 1440 x 900 laptop a 740px
	 * hero under the 91px bar is 831px and pushes the next section wholly below
	 * the fold. 76vh keeps ~125px of it in view there, and the 740px cap is
	 * reached on screens 974px tall and up. 560px is the floor.
	 */
	min-height: min(740px, max(560px, 76vh));
	padding: 56px 0;
	background: linear-gradient(100deg, var(--mlp-hero-navy) 0%, var(--mlp-hero-navy) 40%, var(--ml-cyan-dark) 82%, var(--ml-cyan) 100%);
}

/* The left 48% overlay - 0.75 fading to 0 at 48%, so the lab on the right stays clear. The copy's contrast is measured on it. */
.mlp-hero::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	/*
	 * THE FADE ENDS AT 51%, NOT 48% (2026-09-20) - width only, the two alphas
	 * are the shipped ones.
	 *
	 * "Trusted Healthcare." is 210px wider than the "Our Science." it replaced,
	 * and its first line now ends at **724px of the 1440px hero = 50.28%**. The
	 * overlay reached zero at 48% = 691px, so the last 33px of the line sat
	 * outside it. 51% = 734px clears the measured edge with 10px to spare.
	 *
	 * **THE 21px FIGURE THIS FILE CARRIED WAS STALE.** It came from a 712px
	 * right edge; re-measured from the rendered page the line is 724px, so a
	 * 21px extension would have stopped 12px short - a fix that looks applied
	 * and leaves the defect. Measure the line box, do not carry the number.
	 */
	background: linear-gradient(90deg, rgba(var(--mlp-hero-navy-rgb), 0.75) 0%, rgba(var(--mlp-hero-navy-rgb), 0.5) 28%, rgba(var(--mlp-hero-navy-rgb), 0) 51%);
}

.mlp-hero__inner {
	position: relative;
	z-index: 2;
	width: 100%;
}

.mlp-hero__copy {
	max-width: 580px;
}

.mlp-hero__eyebrow {
	margin: 0 0 8px;
	font-size: 12.5px;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ml-cyan);
}

.mlp-hero__title {
	margin: 0 0 14px;
	font-size: clamp(34px, 5vw, 58px);
	font-weight: 700; /* 800 has no hosted face - it always rendered as 700 */
	line-height: 1.06;
	letter-spacing: -0.02em;
	color: var(--ml-white);
}

/* The single green note in the type - a full stop, nothing more. */
.mlp-hero__dot {
	color: var(--mlp-green);
}

/*
 * 46ch, NOT 48ch, and the two characters are doing real work (2026-09-20).
 *
 * The cap is what sets where the three lines turn - there is no <br> in this
 * paragraph, deliberately, because a hard break would still be there at 360
 * where the line holds about half as many words. At 48ch (482px) line 2
 * measured 470px and pulled "across" up onto it; 46ch (462px) is below that
 * and above line 1's 442px, so the turn lands where the copy was written to
 * turn. It stays in `ch` rather than px so it tracks the font, and it binds
 * only where the container is wider than the cap - at 360 the paragraph wraps
 * naturally and this value never applies.
 */
.mlp-hero__lead {
	margin: 0 0 22px;
	max-width: 46ch;
	font-size: 16px;
	line-height: 1.6;
	color: rgba(255, 255, 255, 0.88);
}

.mlp-hero__strap {
	display: flex;
	align-items: center;
	gap: 12px;
	margin: 22px 0 0;
	font-size: 12px;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.82);
}

.mlp-hero__rule {
	width: 34px;
	height: 3px;
	border-radius: 2px;
	background: var(--mlp-green);
}

/* ---- the image backdrop, every width ---- */

.mlp-hero__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
}

.mlp-hero__bg img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	/* The flask and molecules sit on the right; the empty navy left is where the copy goes. */
	object-position: right center;
}

/* ---- the video (2026-09-19, sixth pass) - the hero's ONLY animation ---- */

/*
 * A seamless 1080p H.264 loop - forward then reversed, 0.85x speed baked in,
 * 23.4s - sits over the image inside .mlp-hero__bg, so it is
 * under the ::before overlay and the copy. Every earlier overlay - molecule PNG
 * and SVG, rays, shimmer, particles, the pan/breathing - is gone from the DOM
 * and from this file.
 *
 * It never downloads where it will not play: both <source>s carry
 * media="(min-width: 769px) and (prefers-reduced-motion: no-preference)", so at
 * <=768px or with reduced motion no source is selected and nothing is fetched.
 * This rule then hides the element too, so its poster cannot sit over the image
 * forever. What shows instead is the <img> underneath - the same picture the
 * poster uses. No script at any width.
 */
/* the <picture> around the desktop still must not become a box of its own */
.mlp-hero__bg .mlp-hero__picture {
	display: contents;
}

.mlp-hero__video {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: right center;
	pointer-events: none;
}

@media (max-width: 768px), (prefers-reduced-motion: reduce) {
	.mlp-hero__video {
		display: none;
	}
}

/*
 * <=1024px: the copy runs wider than 48% here, so the overlay is the stronger
 * full-width one, unchanged from before the video.
 */
@media (max-width: 1024px) {
	.mlp-hero {
		min-height: 0;
		padding: 48px 0;
	}

	.mlp-hero::before {
		background: linear-gradient(90deg, rgba(var(--mlp-hero-navy-rgb), 0.9) 0%, rgba(var(--mlp-hero-navy-rgb), 0.8) 55%, rgba(var(--mlp-hero-navy-rgb), 0.6) 100%);
	}
}

@media (max-width: 640px) {
	.mlp-hero {
		padding: 40px 0;
	}

	.mlp-hero::before {
		/*
		 * 0.9, raised from 0.86 on 2026-09-19: with the image right-anchored, a
		 * phone puts its bright flask and light rays behind the copy, and the cyan
		 * eyebrow's worst pixel measured 4.36:1 at 0.86.
		 */
		background: rgba(var(--mlp-hero-navy-rgb), 0.9);
	}
}

/* ---------- buttons ---------- */

.mlp-page .mlp-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	min-height: 50px;
	padding: 0 22px;
	border-radius: 8px;
	border: 1px solid transparent;
	font-family: var(--ml-font);
	font-size: 15px;
	font-weight: 600;
	text-decoration: none;
	cursor: pointer;
	transition: background-color var(--ml-t-base) var(--ml-e-standard), color var(--ml-t-base) var(--ml-e-standard);
}

/*
 * Astra's inline `button:hover / button:focus` is (0,1,1) and repaints any bare
 * control, so both states are named here at (0,2,0) or better - the same lock
 * every custom control in this theme carries.
 */
.mlp-page .mlp-btn--primary,
.mlp-page .mlp-btn--primary:hover,
.mlp-page .mlp-btn--primary:focus,
.mlp-page .mlp-btn--primary:active {
	background: var(--ml-cyan);
	border-color: var(--ml-cyan);
	color: var(--ml-white);
}

.mlp-page .mlp-btn--primary:hover {
	background: var(--ml-cyan-dark);
	border-color: var(--ml-cyan-dark);
}

.mlp-page .mlp-btn--ghost,
.mlp-page .mlp-btn--ghost:hover,
.mlp-page .mlp-btn--ghost:focus,
.mlp-page .mlp-btn--ghost:active {
	background: var(--ml-white);
	border-color: var(--mlp-navy);
	color: var(--mlp-navy);
}

.mlp-page .mlp-btn--ghost:hover {
	background: var(--mlp-navy);
	color: var(--ml-white);
}

/* ---------- sections ---------- */

.mlp-section {
	padding: clamp(34px, 5vw, 64px) 0;
}

.mlp-section--tint {
	background: var(--mlp-tint);
}

/*
 * The hero CTA jumps to #mlp-products. scroll-margin-top stops the section's
 * own heading landing hard against the top edge of the viewport - without it
 * "Find a Product" sits flush at y=0 and reads as cut off. The bar is not
 * sticky, so nothing overlays it; this is breathing room, not clearance.
 */
#mlp-products {
	scroll-margin-top: 24px;
}

/*
 * The "About Medlife Pharmaceuticals" intro that sat here from 2026-09-20 was
 * REMOVED the same day at the owner's request - its copy moved into the hero
 * lead instead. Both the .mlp-about-* rules and the template section are in
 * astra-child\_backups\pharma-hero-copy-2026-09-20\ if it is ever wanted back.
 */

/* ---------- finder ---------- */

/*
 * Heading hard left, the three controls hard right, one row. justify-content
 * does the balancing; flex-wrap is what stacks them once the row runs out,
 * which happens around 860px with the search at its natural width.
 */
.mlp-finder__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 18px 24px;
	flex-wrap: wrap;
	margin-bottom: 20px;
}

/*
 * Poppins, like every other heading - owner decision 2026-09-14. This was a
 * deliberate Georgia serif, the only non-Poppins text on the site. The family
 * is NAMED rather than deleted, so nothing upstream can hand it a serif again.
 */
.mlp-page .mlp-finder__head .mlp-h2 {
	font-family: var(--ml-font);
	font-size: clamp(28px, 3vw, 38px);
	font-weight: 700;
	letter-spacing: -0.015em;
	color: var(--mlp-navy);
}

.mlp-finder__tools {
	display: flex;
	align-items: center;
	gap: 10px;
	flex-wrap: wrap;
}

/* 48px - the one field height sitewide (2026-09-14); clears the 44px floor too. */
.mlp-page .mlp-finder__search input,
.mlp-page .mlp-finder__select select,
.mlp-page .mlp-finder__sort {
	min-height: 48px;
}

.mlp-finder__search,
.mlp-finder__select {
	position: relative;
	display: flex;
	align-items: center;
}

.mlp-finder__search svg,
.mlp-finder__select svg {
	position: absolute;
	pointer-events: none;
	color: var(--mlp-ink);
}

.mlp-finder__search svg {
	left: 14px;
}

.mlp-finder__select svg {
	right: 12px;
}

.mlp-page .mlp-finder__search input,
.mlp-page .mlp-finder__select select {
	width: 100%;
	height: 48px;
	border: 1px solid var(--mlp-line);
	border-radius: 9px;
	background: var(--ml-white);
	font-family: var(--ml-font);
	font-size: 14px;
	color: var(--mlp-navy);
	appearance: none;
	-webkit-appearance: none;
}

/*
 * 300px, measured rather than guessed: the placeholder "Search by brand or
 * generic name" needs 290px including the field padding, so at the old 260px
 * it was clipped mid-word at every desktop width. The toolbar has ~300px of
 * slack at 1440 and ~177px at 1024, and the row wraps below that anyway.
 */
.mlp-page .mlp-finder__search input {
	min-width: 300px;
	padding: 0 14px 0 40px;
}

.mlp-page .mlp-finder__select select {
	min-width: 210px;
	padding: 0 38px 0 14px;
	cursor: pointer;
}

/*
 * The store field focus: the BORDER is the indicator, plus the .16 halo - one
 * field language sitewide (2026-09-14). :focus, as on every store field.
 * (0,3,1) names outline, so the page-wide 3px ring rule at (0,2,1) no longer
 * draws a second indicator round the field.
 */
.mlp-page .mlp-finder__search input:focus,
.mlp-page .mlp-finder__select select:focus {
	outline: none;
	border-color: var(--ml-cyan);
	box-shadow: 0 0 0 3px rgba(0, 175, 240, 0.16);
}

.mlp-page .mlp-finder__sort,
.mlp-page .mlp-finder__sort:hover,
.mlp-page .mlp-finder__sort:focus,
.mlp-page .mlp-finder__sort:active {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	height: 48px;
	padding: 0 14px;
	border: 1px solid var(--mlp-line);
	border-radius: 9px;
	background: var(--ml-white);
	font-family: var(--ml-font);
	font-size: 14px;
	font-weight: 600;
	color: var(--mlp-navy);
	cursor: pointer;
}

.mlp-page .mlp-finder__sort:hover {
	border-color: var(--ml-cyan);
}

.mlp-page .mlp-finder__sort[aria-pressed="true"],
.mlp-page .mlp-finder__sort[aria-pressed="true"]:hover {
	background: var(--mlp-tint-deep);
	border-color: var(--ml-cyan);
}

/* ---------- filter pills ---------- */

.mlp-filters {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin-bottom: 18px;
}

/*
 * TABS, NOT PILLS. Softly rounded rectangles at 10px rather than the 999px
 * capsule they were, which is what makes a row of nine read as one control
 * strip instead of nine loose badges.
 *
 * THE ACTIVE TAB'S INK IS NAVY, NOT WHITE, and that is measured rather than
 * chosen: white on #00AFF0 is 2.50:1 and fails WCAG 1.4.3 outright, while
 * --mlp-navy on the same cyan is 5.87:1. The brief asked for #00AFF0 with
 * readable contrasting text, and navy is the only ink that delivers both.
 * The count bubble inside the active tab is white-on-navy for the same reason.
 */
/*
 * PARITY WITH THE STORE'S .ml-shop__pill, measured off /shop/ rather than
 * copied from its stylesheet. What was matched:
 *
 *     radius       999px capsule (was a 10px rectangle)
 *     padding      9px 18px, 14px/500 - so the two are the same size
 *     transition   transform, box-shadow, border-color, background-color,
 *                  color at --ml-t-base / --ml-e-standard (0.18s ease)
 *     hover        translateY(-2px) + cyan border + cyan ink + drop shadow
 *     active       cyan fill, weight 600, its own stronger shadow
 *     active+hover keeps the fill AND takes the lift
 *
 * ONE THING WAS DELIBERATELY NOT COPIED. On /shop/ the pill at :focus - which
 * a mouse click leaves set - turns --ml-cyan-dark with a 1px dotted outline.
 * That is not the store's design; it is Astra's a:focus trap leaking through,
 * because .ml-shop__pill never pins :focus back. Reproducing it here would be
 * copying a bug. The pin below is what this file does instead.
 *
 * box-shadow HAS TO BE NAMED IN THE REST RULE. Astra's inline Customizer CSS
 * puts 0 1px 2px rgba(0,0,0,.05) on every bare button and the old rule never
 * mentioned it - measured on the live page before this change, the tabs were
 * carrying a stray drop shadow at rest that nothing in this file asked for.
 */
.mlp-page .mlp-pill,
.mlp-page .mlp-pill:hover,
.mlp-page .mlp-pill:focus,
.mlp-page .mlp-pill:focus-visible,
.mlp-page .mlp-pill:active {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	min-height: 0;
	padding: 9px 18px;
	border: 1px solid var(--mlp-line);
	border-radius: 999px;
	background: var(--ml-white);
	box-shadow: none;
	font-family: var(--ml-font);
	font-size: 14px;
	font-weight: 500;
	/*
	 * 1.65 is Astra body line-height, which the store pill inherits because it
	 * is an <a>. A <button> gets line-height: normal instead (~1.34), so the
	 * two controls measured 43.1px and 38.7px tall on identical padding. This
	 * is the only reason they were different sizes.
	 */
	line-height: 1.65;
	color: var(--mlp-navy);
	transform: none;
	cursor: pointer;
	transition:
		transform var(--ml-t-base) var(--ml-e-standard),
		box-shadow var(--ml-t-base) var(--ml-e-standard),
		border-color var(--ml-t-base) var(--ml-e-standard),
		background-color var(--ml-t-base) var(--ml-e-standard),
		color var(--ml-t-base) var(--ml-e-standard);
}

/*
 * The lift. Shadows use rgba(var(--ml-shadow-tint), a) - the raw-channel token
 * this project keeps precisely because a custom property cannot carry a
 * variable alpha. The store hard-codes a navy tint here; the tokenised cyan
 * tint is within a hair of it at this blur and alpha, and it keeps the rule
 * inside the token system.
 */
.mlp-page .mlp-pill:hover,
.mlp-page .mlp-pill:focus-visible {
	transform: translateY(-2px);
	border-color: var(--ml-cyan);
	color: var(--ml-cyan);
	box-shadow: 0 10px 18px -12px rgba(var(--ml-shadow-tint), 0.6);
}

/*
 * THE ACTIVE TAB'S INK IS WHITE, matching the store pill exactly - the owner's
 * decision of 2026-09-10, taken with the measurement in hand.
 *
 * It was --mlp-navy, and that was chosen on contrast: navy on #00AFF0 is
 * 5.87:1 and PASSES WCAG 1.4.3, while white on the same cyan is 2.50:1 and
 * FAILS it. This is a filter control's own label, so it is real text held to
 * 4.5:1, not a non-text indicator held to 3:1.
 *
 * The trade was made for one brand language across both divisions, and it is
 * the same call already recorded for the top-bar ink, the search icon and
 * Astra's --ast-global-color-0. --mlp-navy is the value to return to if it
 * ever has to pass. See CLAUDE.md, "THE FOCUS-RING RULE" and this note.
 *
 * THE COUNT BADGE IS WHAT KEEPS THE NUMBER READABLE - it stays a white chip
 * with navy digits (15.54:1) inside the cyan capsule, so the figure a visitor
 * actually reads off the tab never depended on the label's contrast.
 */
.mlp-page .mlp-pill.is-active,
.mlp-page .mlp-pill.is-active:hover,
.mlp-page .mlp-pill.is-active:focus,
.mlp-page .mlp-pill.is-active:focus-visible,
.mlp-page .mlp-pill.is-active:active {
	background: var(--ml-cyan);
	border-color: var(--ml-cyan);
	color: var(--ml-white);
	font-weight: 600;
	box-shadow: 0 10px 20px -12px rgba(var(--ml-shadow-tint), 0.9);
}

/* The selected tab lifts too, exactly as the store's active pill does. */
.mlp-page .mlp-pill.is-active:hover,
.mlp-page .mlp-pill.is-active:focus-visible {
	transform: translateY(-2px);
}

/*
 * THE :focus PIN. Astra's inline button:focus is (0,1,1) and a mouse click
 * leaves :focus set, so without this a clicked tab stays repainted. The rest
 * rule above already lists :focus at (0,2,0) and wins; this only has to stop
 * the hover lift firing on a pointer click, which :focus-visible does not
 * cover. Placed before the ring so the ring still wins its own state.
 */
.mlp-page .mlp-pill:focus:not(:focus-visible) {
	transform: none;
	box-shadow: none;
	border-color: var(--mlp-line);
	color: var(--mlp-navy);
}

.mlp-page .mlp-pill.is-active:focus:not(:focus-visible) {
	border-color: var(--ml-cyan);
	color: var(--ml-white);
	box-shadow: 0 10px 20px -12px rgba(var(--ml-shadow-tint), 0.9);
}

.mlp-page .mlp-pill:focus-visible {
	outline: 3px solid var(--ml-cyan);
	outline-offset: 3px;
}

/*
 * The badge sits INSIDE the capsule, so it gets its own pill rather than
 * floating as dimmed text - at 999px the two nest cleanly and the number stops
 * reading as part of the label.
 */
.mlp-page .mlp-pill .mlp-pill__n {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 20px;
	padding: 1px 6px;
	border-radius: 999px;
	background: var(--mlp-tint-deep);
	font-size: 11.5px;
	font-weight: 600;
	line-height: 1.45;
	color: var(--ml-cyan);
	opacity: 1;
	transition: background-color var(--ml-t-base) var(--ml-e-standard), color var(--ml-t-base) var(--ml-e-standard);
}

/* On the cyan fill the badge inverts to white so it keeps its own edge. */
.mlp-page .mlp-pill.is-active .mlp-pill__n {
	background: var(--ml-white);
	color: var(--mlp-navy);
	opacity: 1;
}

.mlp-count {
	margin: 0 0 22px;
	font-size: 13.5px;
	color: var(--mlp-ink);
}

/* ---------- product grid ---------- */

.mlp-grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 20px;
	margin: 0;
	padding: 0;
	list-style: none;
}

/*
 * NO HEIGHT IS SET ANYWHERE ON THIS CARD. Its height is the media panel's
 * aspect ratio plus whatever the text needs; the grid row stretches the short
 * ones to match the tallest, and margin-top:auto on the button is what keeps
 * the action line level across a row. Adding a min-height here would reopen
 * the too-tall card this pass was asked to fix.
 */
.mlp-card {
	display: flex;
	flex-direction: column;
	border: 1px solid var(--mlp-line);
	border-radius: 12px;
	background: var(--ml-white);
	overflow: hidden;
	transition: border-color var(--ml-t-base) var(--ml-e-standard), box-shadow var(--ml-t-base) var(--ml-e-standard), transform var(--ml-t-base) var(--ml-e-standard);
}

/*
 * THE hidden ATTRIBUTE ONLY WORKS IF NOTHING OVERRIDES IT. The UA sheet says
 * [hidden] { display: none } at (0,0,0); the rule above says display: flex at
 * (0,1,0) and wins, so every filtered-out card kept painting. The filters and
 * the pager were setting the attribute correctly the whole time - the cards
 * simply never went away.
 *
 * It hid from every check that read card.hidden instead of measuring the
 * rendered box. Verify this one by counting boxes with a height, never by
 * counting the attribute.
 *
 * .mlp-pager[hidden] and .mlp-card__details[hidden] already carry the same
 * reset; this element was the one that was missed.
 */
.mlp-card[hidden] {
	display: none;
}

.mlp-card:hover {
	border-color: var(--ml-cyan);
	box-shadow: 0 4px 14px rgba(var(--ml-shadow-tint), 0.10);
	transform: translateY(-2px);
}

/*
 * THE IMAGE SLOT - LANDSCAPE 16:9, held whether or not a photograph exists, so
 * the day a real packshot arrives the card does not change height and the grid
 * does not reflow. The ratio is the whole reason the composition reads as
 * landscape: the panel is wider than it is tall, not the page.
 */
.mlp-card__media {
	display: flex;
	align-items: center;
	justify-content: center;
	aspect-ratio: 16 / 9;
	padding: 14px;
	background: linear-gradient(160deg, var(--mlp-tint-deep) 0%, var(--mlp-tint) 100%);
}

/*
 * READY FOR REAL PACKSHOTS. object-fit: contain with both maxima at 100% means
 * a carton of any proportion is letterboxed inside the panel rather than
 * cropped - nothing is ever cut off the edge of a pack. Do not switch this to
 * cover to "fill" the panel; that is exactly the crop this avoids.
 */
.mlp-card__img {
	width: 100%;
	height: 100%;
	max-width: 100%;
	max-height: 100%;
	object-fit: contain;
	object-position: center;
}

.mlp-card__placeholder {
	display: flex;
	align-items: center;
	gap: 10px;
	color: var(--mlp-navy);
	opacity: 0.34;
}

.mlp-card__initial {
	font-size: 40px;
	font-weight: 700; /* 800 has no hosted face - it always rendered as 700 */
	line-height: 1;
	letter-spacing: -0.02em;
}

.mlp-card__leaf {
	color: var(--mlp-green);
	opacity: 0.85;
}

/*
 * flex: 1 is what lets margin-top:auto on the button reach the bottom - the
 * body has to own the card's spare height for the auto margin to have anything
 * to absorb.
 */
.mlp-card__body {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	flex: 1 1 auto;
	gap: 6px;
	padding: 16px;
}

.mlp-page .mlp-card__name {
	margin: 0;
	font-size: 19px;
	font-weight: 700;
	line-height: 1.25;
	color: var(--mlp-navy);
}

.mlp-card__generic,
.mlp-card__meta {
	margin: 0;
	font-size: 14.5px;
	line-height: 1.5;
	color: var(--mlp-ink);
}

.mlp-card__meta {
	font-size: 13px;
	opacity: 0.85;
}

/*
 * margin-bottom is what separates the badge from View Details. The body's 6px
 * gap alone put the button's box 6px under the badge, which read as one stacked
 * block; 6 + 6 plus the button's own 10px of top padding gives the two clear
 * daylight without adding to the card's height.
 */
.mlp-card__chip {
	margin-top: 6px;
	margin-bottom: 6px;
	padding: 5px 11px;
	border-radius: 6px;
	background: var(--mlp-tint-deep);
	font-size: 11.5px;
	font-weight: 600;
	color: var(--ml-cyan);
}

/* The one place the green accent carries meaning rather than decoration. */
.mlp-card__chip.mlp-chip--bone-joint-health {
	background: #e8f6ef;
	color: #1d7a51;
}

.mlp-empty {
	margin: 8px 0 0;
	padding: 22px;
	border: 1px dashed var(--mlp-line);
	border-radius: 12px;
	text-align: center;
	font-size: 14px;
	color: var(--mlp-ink);
}

/* ---------- therapeutic area tiles ---------- */

/*
 * Heading and subtitle stack on the left. They used to sit at opposite ends of
 * the row - the subtitle was flung to the far right, a whole container away
 * from the heading it belongs to, and at narrow widths it wrapped underneath
 * anyway, so the arrangement only held on the widest screens.
 */
.mlp-areas__head {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 14px;
	margin-bottom: 22px;
}

/*
 * 28-34px, scoped to this heading. The shared .mlp-h2 clamp floors at 24px,
 * which is smaller than this section's own cards want to sit under.
 */
.mlp-page .mlp-areas__head .mlp-h2 {
	font-size: clamp(28px, 2.4vw, 34px);
	line-height: 1.2;
}

/*
 * ONE LINE ON A PHONE. Measured, not guessed: "Explore Therapeutic Areas" at
 * the clamp floor of 28px needs 370.7px, and a 360px viewport leaves 328px
 * inside the section padding - so it wrapped to two lines. 24px needs 316.8px
 * and fits with 11.2px to spare.
 *
 * 420px is the crossover, worked out rather than picked: available width is
 * vw - 32, so 28px stops fitting below about 403px. Above 420 nothing here
 * applies, which is why tablet and desktop are untouched.
 *
 * ONLY THE FONT SIZE CHANGES. The other lever - the section padding - is on
 * .mlp-section__inner, which also sets the card width (this grid is a single
 * column at 360, so the card is exactly the 328px above). Trimming it would
 * have widened every card, and card spacing is out of scope here.
 */
@media (max-width: 420px) {
	.mlp-page .mlp-areas__head .mlp-h2 {
		font-size: 24px;
	}
}

.mlp-areas__sub {
	margin: 0;
	font-size: 14.5px;
	line-height: 1.5;
	color: var(--mlp-ink);
}

/*
 * THREE COLUMNS, THREE ROWS. Nine areas in four columns produced 4 + 4 + 1,
 * which left Immunology stranded on its own row looking like an afterthought.
 * Three divides nine exactly.
 */
.mlp-areas {
	/*
	 * 3D ICON TILE TINTS, 2026-09-19 - COMPONENT-LOCAL, not global tokens.
	 * Each is 11% of its icon's dominant colour over white (the mean of the
	 * most saturated 40% of opaque pixels, measured on the source PNG):
	 *   pain #F56336  neurology #561EC0  bone-joint #53B69F  gastro #F3710A
	 *   anti-infectives #088543  cardio #BA021B  womens #DC367B
	 *   diabetes #0191BC  immunology #2549A6
	 * They exist only while an area shows its 3D icon; the line-art fallback
	 * keeps --mlp-tint-deep.
	 */
	--mlp-area-tint-pain-management: #FEEEE9;
	--mlp-area-tint-neurology: #ECE6F8;
	--mlp-area-tint-bone-joint-health: #ECF7F4;
	--mlp-area-tint-gastroenterology: #FEEFE4;
	--mlp-area-tint-anti-infectives: #E4F2EA;
	--mlp-area-tint-cardiovascular: #F7E3E6;
	--mlp-area-tint-womens-health: #FBE9F0;
	--mlp-area-tint-diabetes-care: #E3F3F8;
	--mlp-area-tint-immunology: #E7EBF5;
	/* The hover border: one step deeper than the resting --ml-line. */
	--mlp-area-line-hover: #c9d8e6;
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 18px;
	margin: 0;
	padding: 0;
	list-style: none;
}

/* Which tint a tile takes - keyed on the data attribute already in the markup. */
.mlp-area__btn[data-mlp-area-jump="pain-management"] { --mlp-area-tint: var(--mlp-area-tint-pain-management); }
.mlp-area__btn[data-mlp-area-jump="neurology"] { --mlp-area-tint: var(--mlp-area-tint-neurology); }
.mlp-area__btn[data-mlp-area-jump="bone-joint-health"] { --mlp-area-tint: var(--mlp-area-tint-bone-joint-health); }
.mlp-area__btn[data-mlp-area-jump="gastroenterology"] { --mlp-area-tint: var(--mlp-area-tint-gastroenterology); }
.mlp-area__btn[data-mlp-area-jump="anti-infectives"] { --mlp-area-tint: var(--mlp-area-tint-anti-infectives); }
.mlp-area__btn[data-mlp-area-jump="cardiovascular"] { --mlp-area-tint: var(--mlp-area-tint-cardiovascular); }
.mlp-area__btn[data-mlp-area-jump="womens-health"] { --mlp-area-tint: var(--mlp-area-tint-womens-health); }
.mlp-area__btn[data-mlp-area-jump="diabetes-care"] { --mlp-area-tint: var(--mlp-area-tint-diabetes-care); }
.mlp-area__btn[data-mlp-area-jump="immunology"] { --mlp-area-tint: var(--mlp-area-tint-immunology); }

.mlp-page .mlp-area__btn,
.mlp-page .mlp-area__btn:hover,
.mlp-page .mlp-area__btn:focus,
.mlp-page .mlp-area__btn:active {
	/*
	 * icon | text | arrow, in one centred row. No min-height: the card is as
	 * tall as its content, and the grid row stretches the short ones to match
	 * so a wrapped two-line title never leaves a ragged row.
	 *
	 * The 46px of right padding is gone with the absolutely positioned arrow -
	 * see .mlp-area__go below.
	 */
	display: flex;
	align-items: center;
	gap: 14px;
	width: 100%;
	height: 100%;
	padding: 20px;
	/*
	 * --ml-line (#e3e8ee), as specified 2026-09-19. The reference's #DCEAF5 is
	 * closer to this page's own --mlp-line (#dbe6f0) - swap the token here if
	 * the bluer edge is wanted.
	 */
	border: 1px solid var(--ml-line);
	border-radius: 18px;
	background: var(--ml-white);
	/*
	 * box-shadow: none IS LOAD-BEARING, and its absence was measurable. Astra's
	 * inline rule for bare buttons supplies "box-shadow: 0 1px 2px
	 * rgba(0,0,0,.05)", and this rest rule never NAMED box-shadow - so the card
	 * carried a faint grey hairline shadow at rest while the therapeutic tab,
	 * whose rest rule does say none, carried nothing. Measured side by side:
	 * card rgba(0,0,0,0.05) 0px 1px 2px, pill none.
	 *
	 * A rule wins only the properties it names - the trap this project keeps
	 * relearning. Naming it here is also what makes the hover shadow read as a
	 * change rather than a thickening.
	 */
	box-shadow: none;
	font-family: var(--ml-font);
	text-align: left;
	cursor: pointer;
	transition: transform var(--ml-t-base) var(--ml-e-standard), border-color var(--ml-t-base) var(--ml-e-standard), box-shadow var(--ml-t-base) var(--ml-e-standard);
}

/*
 * PARITY WITH THE THERAPEUTIC TAB, not a new gesture: cyan border, a 2px lift
 * and the tab's own shadow, all on --ml-t-base / --ml-e-standard. The card used
 * to change border-color and nothing else, so the two controls on this page
 * answered a pointer in two different languages.
 *
 * THE SHADOW IS THE TAB'S, 0 10px 18px -12px at 0.6 - deeper and further down
 * than the 0 4px 14px at 0.10 it replaces, because a control that rises 2px
 * needs a shadow that reads as distance rather than a hairline glow.
 *
 * ONLY THE CARD MOVES. The transform is on .mlp-area__btn, so the icon tile,
 * the title, the count and the arrow travel with it as one piece - none of them
 * carries a transform, a scale or a transition of its own, and none must gain
 * one. The point of the lift is that the card comes toward you, not that its
 * contents rearrange.
 *
 * :focus-visible IS LISTED HERE so a keyboard visitor gets the same answer a
 * pointer does; the ring rule below adds the outline on top.
 */
.mlp-page .mlp-area__btn:hover,
.mlp-page .mlp-area__btn:focus-visible {
	/*
	 * 2026-09-19: a 3px lift, a softer and wider shadow, and the border one
	 * step deeper rather than cyan - the 3D icon carries the colour now, so the
	 * frame stays quiet. No gradient and no full-card colour.
	 */
	transform: translateY(-3px);
	border-color: var(--mlp-area-line-hover);
	box-shadow: 0 16px 28px -18px rgba(var(--ml-shadow-tint), 0.45);
}

/*
 * Astra's inline a:focus / button:focus repaints any bare control at (0,1,1);
 * the rest rule above is the pin and already lists :focus and :active at
 * (0,2,0), so the card keeps its white face when clicked. This adds the ring
 * on top - --ml-accent because the section sits on a pale surface.
 */
.mlp-page .mlp-area__btn:focus-visible {
	outline: 3px solid var(--ml-cyan);
	outline-offset: 3px;
	/* Restated - a rule wins only the properties it names. */
	border-radius: 18px;
}

/*
 * 46px tile. align-self: center rather than the flex default, so a card whose
 * title wraps to two lines keeps its icon on the text's optical centre instead
 * of stretching the tile down the card.
 */
.mlp-area__icon {
	display: flex;
	align-items: center;
	justify-content: center;
	align-self: center;
	flex: 0 0 auto;
	width: 60px;
	height: 60px;
	border-radius: 12px;
	background: var(--mlp-tint-deep);
	color: var(--ml-cyan);
}

/* The 3D icon's own tint. :has() so the line-art fallback keeps its tile. */
.mlp-area__icon:has(> img) {
	background: var(--mlp-area-tint, var(--mlp-tint-deep));
}

/*
 * 40px in a 60px tile. The files are pre-normalised - 160 x 160, artwork long
 * side 88%, centred - so no per-icon scale is needed or allowed here.
 */
.mlp-area__icon img {
	display: block;
	width: 40px;
	height: 40px;
	object-fit: contain;
	flex: 0 0 auto;
}

/*
 * The SVGs are emitted at a uniform 26px by medlife_pharma_icon(), so they are
 * already one size. This pins the painted box and the stroke so none of them
 * can be stretched by the flex row or inherit a different weight - the artwork
 * itself is untouched.
 */
.mlp-area__icon svg {
	width: 26px;
	height: 26px;
	flex: 0 0 auto;
	stroke-width: 1.7;
}

.mlp-area__text {
	display: flex;
	flex-direction: column;
	gap: 4px;
	min-width: 0;
}

/*
 * Long names wrap rather than truncate - no clamp, no ellipsis.
 *
 * THE TWO LABELS SHARE ONE DECLARATION BLOCK ON PURPOSE. Written apart, the
 * short one silently inherited Astra's bare-button `color:
 * var(--ast-global-color-0)` and rendered BRAND CYAN among eight navy tiles -
 * a rule wins only the properties it names, and that rule named no colour.
 * Only the screenshot caught it. Grouped, they cannot drift again.
 */
.mlp-area__name,
.mlp-area__name-short {
	font-size: 17px;
	font-weight: 700;
	line-height: 1.3;
	color: var(--ml-navy);
	overflow-wrap: anywhere;
}

/*
 * THE PHONE TILE'S SHORTER LABEL - DESKTOP NEVER SHOWS IT.
 *
 * Rendered only for an area whose record carries `label_short` (one of the
 * nine today), and `display: none` here so the desktop card is byte-identical
 * to what it was. The <= 768px block swaps the two.
 */
.mlp-area__name-short {
	display: none;
}

.mlp-area__tag {
	font-size: 13.5px;
	line-height: 1.4;
	color: var(--ml-muted);
}

/*
 * IN THE FLOW, NOT ABSOLUTE. It used to be pinned to the card's bottom-right
 * corner, so on a two-line card it sat lower than on a one-line card and the
 * arrows across a row did not line up. As the last flex item with an auto
 * left margin it is always on the text's centre line.
 */
.mlp-area__go {
	display: flex;
	align-items: center;
	justify-content: center;
	align-self: center;
	flex: 0 0 auto;
	margin-left: auto;
	width: 28px;
	height: 28px;
	border-radius: 50%;
	background: var(--ml-stage);
	color: var(--ml-cyan);
	/* Colour only - the arrow never moves; the whole card lifts instead. */
	transition: background-color var(--ml-t-base) var(--ml-e-standard), color var(--ml-t-base) var(--ml-e-standard);
}

.mlp-page .mlp-area__btn:hover .mlp-area__go,
.mlp-page .mlp-area__btn:focus-visible .mlp-area__go {
	background: var(--ml-cyan);
	color: var(--ml-white);
}

/* ---------- division band ---------- */

.mlp-band {
	display: grid;
	grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
	gap: 24px;
	align-items: center;
	padding: clamp(22px, 3vw, 34px);
	border: 1px solid var(--mlp-line);
	border-radius: 16px;
	background: linear-gradient(120deg, var(--mlp-tint) 0%, var(--mlp-tint-deep) 100%);
}

.mlp-band__copy p {
	margin: 14px 0 22px;
	font-size: 15px;
	color: var(--mlp-ink);
}

.mlp-band__copy .mlp-btn + .mlp-btn {
	margin-left: 10px;
}

.mlp-band__words {
	margin: 0;
	display: flex;
	flex-direction: column;
	gap: 4px;
	font-size: clamp(14px, 1.5vw, 17px);
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--mlp-navy);
	opacity: 0.5;
}

/* ---------- section 5: the "Learn more about Medlife" CTA (2026-09-19) ---------- */

/*
 * The panel fills the section container (no outer margin of its own), 20px
 * radius, navy on the left running to brand cyan on the right. The copy and the
 * buttons sit on the navy end; PEOPLE / HEALTH / POSSIBILITIES sit on the cyan
 * end over a radial shade that buys them their contrast.
 *
 * Everything decorative lives in .mlp-cta__visual: a wireframe globe, three
 * molecules, a grid, 14 particles and a soft glow - inline SVG, aria-hidden,
 * pointer-events: none, z-index below the copy. Only transform and opacity
 * animate; will-change is on the animated layers only. All of it is CSS: there
 * is no script on this section.
 */
.mlp-cta {
	--mlp-cta-navy: var(--ml-navy);
	--mlp-cta-cyan: var(--ml-cyan);

	position: relative;
	isolation: isolate;
	overflow: hidden;
	grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
	gap: 22px;
	/*
	 * 56px, the top of the 48-56 band, keeps the panel as substantial as that
	 * band allows. The words column is no longer the tallest thing in here once
	 * it is ~50px (see below) - the COPY column is, at 175.6px at 1440 - so the
	 * panel height is copy + 2 x padding and nothing else. 340px would need
	 * 82px of padding; the padding band was the explicit instruction, so the
	 * panel lands at ~288px. Do not chase a height number by re-inflating this.
	 */
	padding: 56px clamp(28px, 4vw, 64px);
	border: 0;
	border-radius: 20px;
	align-items: center;
	background: linear-gradient(100deg, var(--mlp-cta-navy) 0%, #0d3c66 34%, #0d67a4 62%, #0a8fd4 82%, var(--mlp-cta-cyan) 100%);
}

.mlp-cta__visual {
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	color: var(--ml-white);
}

.mlp-cta__svg {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
}

/*
 * THE SHADE IS A CONTRAST DEVICE, NOT DECORATION - see the note in CLAUDE.md.
 * Cyan words on the gradient's cyan end are ~1.8:1 on their own. This radial,
 * centred on the words, darkens that end until HEALTH clears 3:1 for large text.
 */
/*
 * THE SHADE SITS ABOVE THE ARTWORK, not under it - it is last in the visual
 * layer. Under the SVG it veiled only the gradient, and a molecule or particle
 * crossing the copy still brought the worst pixel behind the heading to 4.4:1.
 */
.mlp-cta__shade {
	position: absolute;
	inset: 0;
	background:
		/* over the words - takes HEALTH from 2.9:1 on bare cyan to over 4 */
		radial-gradient(42% 64% at 71% 50%, rgba(10, 37, 64, 0.92) 0%, rgba(10, 37, 64, 0.84) 52%, rgba(10, 37, 64, 0) 100%),
		/* over the copy - the particles and glow brighten patches behind it */
		linear-gradient(90deg, rgba(10, 37, 64, 0.72) 0%, rgba(10, 37, 64, 0.55) 38%, rgba(10, 37, 64, 0) 66%);
}

.mlp-cta__glow {
	position: absolute;
	top: -30%;
	right: -10%;
	width: 70%;
	height: 160%;
	background: radial-gradient(closest-side, rgba(120, 220, 255, 0.5) 0%, rgba(0, 175, 240, 0) 100%);
	opacity: 0.22;
	will-change: opacity;
	animation: mlp-cta-glow 12s ease-in-out infinite;
}

/*
 * EVERY DECORATIVE OPACITY IS 25% BELOW WHAT IT WAS (2026-09-19) so the words
 * carry the panel. Timings, delays and paths are untouched.
 *
 * THE KEYFRAME OPACITIES HAD TO COME DOWN WITH THEM. A running animation sets
 * `opacity` outright, so the dots' and the glow's base values are inert while
 * they animate - lowering only the base would have changed nothing on screen.
 */
.mlp-cta__grid { opacity: 0.09; }
.mlp-cta__globe { opacity: 0.11; will-change: transform; animation: mlp-cta-spin 40s linear infinite; transform-box: fill-box; transform-origin: center; }
.mlp-cta__mol { opacity: 0.1; will-change: transform; }
.mlp-cta__mol--1 { animation: mlp-cta-float-a 14s ease-in-out infinite alternate; }
.mlp-cta__mol--2 { animation: mlp-cta-float-b 17s ease-in-out -4s infinite alternate; }
.mlp-cta__mol--3 { animation: mlp-cta-float-a 20s ease-in-out -9s infinite alternate; }
.mlp-cta__dots circle { opacity: 0.18; will-change: transform, opacity; }

.mlp-cta__dots circle:nth-child(3n + 1) { animation: mlp-cta-dot-a 8s ease-in-out infinite alternate; }
.mlp-cta__dots circle:nth-child(3n + 2) { animation: mlp-cta-dot-b 11s ease-in-out infinite alternate; }
.mlp-cta__dots circle:nth-child(3n + 3) { animation: mlp-cta-dot-a 7s ease-in-out infinite alternate; }
.mlp-cta__dots circle:nth-child(4n + 1) { animation-duration: 12s; animation-delay: -3s; }
.mlp-cta__dots circle:nth-child(5n + 2) { animation-duration: 9s; animation-delay: -6s; }

@keyframes mlp-cta-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes mlp-cta-glow { 0%, 100% { opacity: 0.16; } 50% { opacity: 0.31; } }
@keyframes mlp-cta-float-a { from { transform: translateY(-10px); } to { transform: translateY(10px); } }
@keyframes mlp-cta-float-b { from { transform: translateY(9px); } to { transform: translateY(-9px); } }
@keyframes mlp-cta-dot-a { from { transform: translate3d(0, 0, 0); opacity: 0.15; } to { transform: translate3d(6px, -14px, 0); opacity: 0.28; } }
@keyframes mlp-cta-dot-b { from { transform: translate3d(0, 0, 0); opacity: 0.28; } to { transform: translate3d(-7px, 12px, 0); opacity: 0.15; } }

/* ---- the copy, on the navy end ---- */

.mlp-cta .mlp-band__copy {
	position: relative;
	z-index: 2;
}

.mlp-cta .mlp-h2 {
	color: var(--ml-white);
}

.mlp-cta .mlp-band__copy p {
	margin: 14px 0 22px;
	max-width: 34ch;
	font-size: 16px;
	line-height: 1.6;
	color: rgba(255, 255, 255, 0.85);
}

/* the ghost button is white-outlined here - its site rule is navy on white */
.mlp-page .mlp-cta .mlp-btn--ghost,
.mlp-page .mlp-cta .mlp-btn--ghost:focus,
.mlp-page .mlp-cta .mlp-btn--ghost:active {
	background: transparent;
	border-color: rgba(255, 255, 255, 0.75);
	color: var(--ml-white);
}

.mlp-page .mlp-cta .mlp-btn--ghost:hover,
.mlp-page .mlp-cta .mlp-btn--ghost:focus-visible {
	background: var(--ml-white);
	border-color: var(--ml-white);
	color: var(--mlp-cta-navy);
}

/* ---- the three words, on the cyan end ---- */

/*
 * 58px -> 50px at 1440 (-13.8%) and 45 -> 39 at 1024, so the vw term comes down
 * with the cap: 3.8vw is what puts 1024 on 39. line-height 0.98 and a 5px gap
 * set the three words as one block rather than three lines.
 */
.mlp-cta .mlp-band__words {
	position: relative;
	z-index: 2;
	gap: 5px;
	font-size: clamp(30px, 3.8vw, 50px);
	font-weight: 700;
	line-height: 0.98;
	letter-spacing: 0.01em;
	color: var(--ml-white);
	opacity: 1;
}

.mlp-cta .mlp-band__words span:nth-child(2) {
	color: var(--ml-cyan);
}

/*
 * REDUCED MOTION: every animated layer named at the specificity of the rule
 * that animates it, later in the file. The visual stays, still.
 */
@media (prefers-reduced-motion: reduce) {
	.mlp-cta__glow,
	.mlp-cta__globe,
	.mlp-cta__mol,
	.mlp-cta__mol--1,
	.mlp-cta__mol--2,
	.mlp-cta__mol--3,
	.mlp-cta__dots circle,
	.mlp-cta__dots circle:nth-child(3n + 1),
	.mlp-cta__dots circle:nth-child(3n + 2),
	.mlp-cta__dots circle:nth-child(3n + 3) {
		animation: none;
	}
}

/* <=1024: gradient, shade and 5 still particles - the globe, molecules, grid and glow go */
@media (max-width: 1024px) {
	.mlp-cta {
		padding: 56px clamp(24px, 4vw, 40px);
	}

	.mlp-cta__globe,
	.mlp-cta__grid,
	.mlp-cta__mol,
	.mlp-cta__glow,
	.mlp-cta__dots circle:nth-child(n + 6) {
		display: none;
	}

	.mlp-cta__dots circle,
	.mlp-cta__dots circle:nth-child(3n + 1),
	.mlp-cta__dots circle:nth-child(3n + 2),
	.mlp-cta__dots circle:nth-child(3n + 3) {
		animation: none;
		opacity: 0.26;
	}
}

/*
 * 641-768: the section inner pads 24px, so -8 leaves the 16px side margin this
 * panel asks for. At <=640 that padding is ALREADY 16px (see the section rule),
 * so the pull would make it 8 - hence the lower bound.
 */
@media (min-width: 641px) and (max-width: 768px) {
	.mlp-cta {
		margin-inline: -8px;
	}
}

@media (max-width: 768px) {
	.mlp-cta {
		padding: 36px 24px;
		gap: 22px;
	}

	.mlp-cta .mlp-band__words {
		flex-direction: column;
		gap: 5px;
		font-size: clamp(26px, 7vw, 30px);
	}

	.mlp-cta .mlp-band__copy p {
		max-width: none;
	}

	.mlp-cta__shade {
		background:
			radial-gradient(95% 62% at 58% 78%, rgba(10, 37, 64, 0.88) 0%, rgba(10, 37, 64, 0.7) 55%, rgba(10, 37, 64, 0.3) 100%),
			linear-gradient(180deg, rgba(10, 37, 64, 0.5) 0%, rgba(10, 37, 64, 0.25) 100%);
	}
}

/* ---------- pharma footer ---------- */

.mlp-footer {
	--mlp-navy: #082A46;
	--mlp-navy-soft: #123a5c;

	background: var(--mlp-navy);
	color: rgba(255, 255, 255, 0.82);
	font-family: var(--ml-font);
}

/*
 * FOUR COLUMNS: brand, Our Portfolio, Information, Get In Touch. The brand
 * column is given more room because it carries the lockup and the social row;
 * the three text columns share the rest evenly.
 */
.mlp-page ~ .mlp-footer .mlp-footer__inner,
.mlp-footer .mlp-footer__inner {
	grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr));
}

/*
 * THE LOGO SITS ON A WHITE PANEL, and that is a readability requirement rather
 * than decoration. The division lockup's "Pharmaceuticals" line is charcoal
 * and its figure is a blue gradient - on --mlp-navy the first vanishes and the
 * second goes muddy. The artwork is used exactly as supplied: height is set,
 * width stays auto, so the 796x401 proportions hold and nothing is stretched
 * or clipped.
 */
.mlp-footer .mlp-footer__logo {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: fit-content;
	max-width: 100%;
	padding: 12px 16px;
	border-radius: var(--ml-radius);
	background: var(--ml-white);
}

.mlp-footer .mlp-footer__logo img {
	width: auto;
	height: 54px;
	max-width: 100%;
	display: block;
}

/* ---- the prescription row ---- */

.mlp-footer__legal {
	border-top: 1px solid rgba(255, 255, 255, 0.10);
}

.mlp-footer__legal-inner {
	max-width: var(--mlp-wrap, 1200px);
	margin: 0 auto;
	/* Bottom padding is half the note-to-copyright gap; the bar supplies the rest. */
	padding: 20px 24px 6px;
}

.mlp-footer .mlp-footer__note {
	margin: 0;
	max-width: 78ch;
	font-size: 12.5px;
	line-height: 1.6;
	color: rgba(255, 255, 255, 0.62);
}

/* ---- long addresses must wrap, not push the column ---- */

.mlp-footer__contact a span,
.mlp-footer__contact li {
	min-width: 0;
	overflow-wrap: anywhere;
}

/*
 * ---- WHATSAPP CLEARANCE ----
 *
 * THE BUTTON IS NOT TOUCHED. .wa-float lives in the Code Snippets table, not
 * in this theme, and it keeps its size, position, destination and z-index of
 * 9999. All that happens here is that the footer reserves room under its own
 * last line so the button has nothing to sit on at the page bottom.
 *
 * The numbers are measured from the button itself, not guessed:
 *
 *     <=767px   58x58 at right 18 / bottom 18   -> occupies the bottom  76px
 *     >=768px   66x66 at right 24 / bottom 100  -> occupies the bottom 166px
 *
 * Base is the desktop case plus ~20px of comfort. See the note above the
 * 1380px query for why that one is different.
 */
.mlp-footer__inner {
	display: grid;
	grid-template-columns: 1.5fr repeat(3, 1fr) 1.2fr;
	gap: 28px;
	max-width: 1180px;
	margin: 0 auto;
	/*
	 * 36px top / 28px bottom, flat rather than clamped. The clamp reached 54px
	 * of top padding at 1440 and grew the block for no reason - the columns are
	 * the content, and they do not need more air as the viewport widens.
	 */
	padding: 36px 24px 28px;
}

/* The white knockout, at its own proportions. */
/*
 * THE ANCHOR HAS TO HUG THE IMAGE. An inline <a> holding a block-level <img>
 * gets an anonymous block box, so its rect spans the whole grid column - 268px
 * at 1440 and 328px at 360 against a 103px logo, i.e. up to 225px of invisible
 * clickable area to the right of the artwork. Confirmed with elementFromPoint,
 * not inferred. inline-block sizes the box to its content.
 */
.mlp-footer__logo {
	display: inline-block;
}

.mlp-footer__logo img {
	width: auto;
	height: 56px;
	display: block;
}

.mlp-footer__tagline {
	margin: 14px 0 16px;
	font-size: 14px;
	line-height: 1.6;
	max-width: 30ch;
}

.mlp-footer__social {
	display: flex;
	gap: 10px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.mlp-footer__social a {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	border: 1px solid rgba(255, 255, 255, 0.28);
	border-radius: 50%;
	color: var(--ml-white);
	text-decoration: none;
	transition: background-color var(--ml-t-base) var(--ml-e-standard), border-color var(--ml-t-base) var(--ml-e-standard);
}

.mlp-footer__social a:hover {
	background: var(--ml-cyan);
	border-color: var(--ml-cyan);
}

.mlp-footer__title {
	margin: 0 0 8px;
	font-size: 13px;
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--ml-white);
}

.mlp-footer__title::after {
	content: "";
	display: block;
	width: 26px;
	height: 3px;
	margin-top: 8px;
	border-radius: 2px;
	background: var(--ml-cyan);
}

.mlp-footer__col ul {
	margin: 0;
	padding: 0;
	list-style: none;
}

.mlp-footer__col li + li {
	margin-top: 8px;
}

.mlp-footer__col a {
	display: flex;
	align-items: center;
	gap: 8px;
	font-size: 14px;
	color: rgba(255, 255, 255, 0.82);
	text-decoration: none;
}

.mlp-footer__col a:hover {
	color: var(--ml-cyan);
}

/*
 * ASTRA'S INLINE `a { transition: all .2s linear }` - the trap recorded in
 * CLAUDE.md under "Product detail pages". "all" includes outline, so any footer
 * anchor that names no transition of its own slid and faded its focus ring in
 * from the text colour instead of showing it at once. Named here at (0,2,x)
 * against Astra's (0,0,1):
 *
 *   column + contact links   colour only - their ink changes on hover
 *   logo panel               none - nothing about it changes on hover
 *
 * The social circles already name their own transition (background and
 * border) and need nothing. Colour-only fades need no reduced-motion entry:
 * nothing moves.
 */
.mlp-footer .mlp-footer__col a {
	transition: color var(--ml-t-base) var(--ml-e-standard);
}

.mlp-footer .mlp-footer__logo {
	transition: none;
}

.mlp-footer__col a svg {
	flex: 0 0 auto;
	color: var(--ml-cyan);
}

.mlp-footer__note {
	margin: 16px 0 0;
	font-size: 12px;
	line-height: 1.6;
	color: rgba(255, 255, 255, 0.62);
}

/*
 * NO BORDER HERE. .mlp-footer__legal already draws the single divider above
 * this whole lower area; a second line between the prescription note and the
 * copyright split one block into two and was most of the 37px that used to sit
 * between them.
 */
.mlp-footer__bar {
	border-top: 0;
}

/*
 * ---- WHATSAPP CLEARANCE, HORIZONTAL NOT VERTICAL ----
 *
 * THE BUTTON IS NOT TOUCHED. .wa-float lives in the Code Snippets table, not
 * in this theme, and keeps its size, position, destination and z-index 9999.
 *
 * The previous attempt reserved a tall BOTTOM band - 186px, 96px on a phone -
 * and it was the wrong axis twice over. It made the footer 186px taller than
 * its content for no visual purpose, and it could not work anyway: the button
 * is fixed to the viewport, so every part of the footer passes under it while
 * you scroll. Padding at the bottom only ever protected the final resting
 * position. Measured then: 10 of 48 scroll positions still overlapped at 360.
 *
 * Reserving the RIGHT-HAND side instead solves it at every scroll position,
 * because the content simply never enters the column the button occupies.
 *
 *     <=767px   58 wide at right 18  ->  button starts at vw - 76
 *     >=768px   66 wide at right 24  ->  button starts at vw - 90
 *
 * So the gutter has to be at least that. Above 1380px the existing gutter
 * already is: the 1200px container centres, its right edge sits at
 * (vw + 1200) / 2, and that clears vw - 90 from 1380 up - measured 30px of
 * clear air at 1440, so nothing is added there.
 *
 * Applied to all three wrappers so the columns, the prescription note and the
 * copyright are inset together and none of them can pass behind the button.
 */
.mlp-footer__bar-inner {
	max-width: 1180px;
	margin: 0 auto;
	padding: 6px 24px 26px;
}

@media (max-width: 1379px) {
	.mlp-footer .mlp-footer__inner,
	.mlp-footer .mlp-footer__legal-inner,
	.mlp-footer .mlp-footer__bar-inner {
		/* 90 is the button edge exactly; +6 keeps a visible sliver of air. */
		padding-right: 96px;
	}
}

/*
 * 76px on a phone rather than 90px - the button is smaller and sits closer to
 * the edge there. TRADE-OFF: at 360 this leaves the footer 268px of content
 * width instead of 328. The single column simply wraps into it; nothing is
 * clipped and nothing overflows.
 */
@media (max-width: 767px) {
	.mlp-footer .mlp-footer__inner,
	.mlp-footer .mlp-footer__legal-inner,
	.mlp-footer .mlp-footer__bar-inner {
		padding-right: 82px;
	}
}

.mlp-footer__bar p {
	margin: 0;
	font-size: 13px;
	color: rgba(255, 255, 255, 0.62);
}

/* ---------- responsive ---------- */

/*
 * 1024 KEEPS THREE PRODUCT COLUMNS. Dropping to two here gave 478px cards -
 * wider than the 364px they get at 1440, which read as stretched rather than
 * roomy. Three columns at 1024 is ~312px, in line with the desktop card.
 */
@media (max-width: 1024px) {
	.mlp-footer .mlp-footer__inner {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 900px) {
	.mlp-grid,
	.mlp-areas {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 860px) {

	.mlp-band {
		grid-template-columns: minmax(0, 1fr);
	}

	.mlp-band__words {
		flex-direction: row;
		flex-wrap: wrap;
		gap: 14px;
	}
}

@media (max-width: 640px) {
	.mlp-section__inner,
	.mlp-bar__inner,
	.mlp-hero__inner,
	.mlp-footer__inner,
	.mlp-footer__bar-inner {
		padding-left: 16px;
		padding-right: 16px;
	}

	.mlp-grid,
	.mlp-areas {
		grid-template-columns: minmax(0, 1fr);
	}

	/*
	 * Written with the .mlp-footer ancestor because the base rule was raised to
	 * (0,2,0) for the four-column layout; at (0,1,0) this lost to it and the
	 * phone kept two columns. The checklist item this project already keeps:
	 * raise a selector's specificity, raise its responsive overrides with it.
	 */
	.mlp-footer .mlp-footer__inner {
		grid-template-columns: minmax(0, 1fr);
	}

	.mlp-bar__inner {
		gap: 12px;
		min-height: 78px;
		padding-top: 11px;
		padding-bottom: 11px;
	}

	/*
	 * 54px on a phone - "Pharmaceuticals" at 7.7px, still legible at the 2-3x
	 * device pixel ratios these screens actually have, and 107px wide against
	 * the 44px burger leaves the row over 150px of clear space at 360.
	 */
	.mlp-bar__brand img {
		height: 54px;
	}


	.mlp-finder__tools {
		width: 100%;
	}

	/* The search takes the row; the select and the sort share the next one. */
	.mlp-page .mlp-finder__search {
		width: 100%;
	}

	.mlp-page .mlp-finder__search input {
		min-width: 0;
	}

	.mlp-page .mlp-finder__select {
		flex: 1 1 auto;
	}

	.mlp-page .mlp-finder__select select {
		min-width: 0;
	}

	.mlp-band__copy .mlp-btn {
		width: 100%;
	}

	.mlp-band__copy .mlp-btn + .mlp-btn {
		margin: 10px 0 0;
	}
}

/* ---------- pagination ---------- */

/*
 * ONE PILL, NOT A ROW OF BOXES. The controls used to be individually bordered
 * white buttons; the bar is now the only bordered surface and everything inside
 * it is transparent until it is hovered or current.
 *
 * --ml-stage-soft (#f5fafd), not --ml-stage (#e9f4fb): the mockup's container
 * is a hint of blue away from white, and --ml-stage is the value the hover
 * state needs so a hovered number has somewhere to go. Using the darker one
 * here would leave hover with no contrast against its own container.
 *
 * width: max-content + auto margins is what centres it under the grid without
 * stretching the pill across the container.
 *
 * flex-wrap: nowrap - a pill whose contents wrap onto a second line is not a
 * pill. The mobile block below is what makes it fit instead.
 */
.mlp-pager {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 4px;
	flex-wrap: nowrap;
	width: max-content;
	max-width: 100%;
	margin: 26px auto 0;
	padding: 5px 8px;
	border: 1px solid var(--ml-line);
	border-radius: 999px;
	background: var(--ml-stage-soft);
}

.mlp-pager[hidden] {
	display: none;
}

/*
 * THE TWO DIVIDERS ARE PSEUDO-ELEMENTS ON THIS CONTAINER, which is why they
 * need no markup and stay out of the accessibility tree entirely - they are
 * decoration, not separators anyone has to hear about.
 *
 * A border-inline on this element would have been simpler and wrong: it paints
 * the full 44px of the row, while the mockup's rules are short and centred. A
 * 22px absolutely positioned line gives exactly that.
 */
.mlp-pager__pages {
	position: relative;
	display: flex;
	align-items: center;
	gap: 2px;
	flex-wrap: nowrap;
	justify-content: center;
	padding-inline: 9px;
	margin-inline: 3px;
}

.mlp-pager__pages::before,
.mlp-pager__pages::after {
	content: '';
	position: absolute;
	top: 50%;
	width: 1px;
	height: 22px;
	background: var(--ml-line);
	transform: translateY(-50%);
}

.mlp-pager__pages::before { left: 0; }
.mlp-pager__pages::after  { right: 0; }

/*
 * TRANSPARENT AND UNBORDERED AT REST - the bar is the surface now, so an
 * individual border on every control would put a box inside a box, which is the
 * nested-card shape this project has already had to unpick twice.
 *
 * EVERY STATE IS NAMED, and this is the :focus pin as well as the rest rule:
 * Astra's inline Customizer CSS repaints any bare <button> on :hover and
 * :focus at (0,1,1), and a mouse click leaves :focus set. At (0,2,0) this holds
 * through all of them. It also names border-radius, background AND box-shadow -
 * Astra supplies a radius of 30px, a padding and a 0 1px 2px shadow to bare
 * buttons, and a rule wins only the properties it names.
 */
.mlp-page .mlp-pager__step,
.mlp-page .mlp-pager__step:hover,
.mlp-page .mlp-pager__step:focus,
.mlp-page .mlp-pager__step:focus-visible,
.mlp-page .mlp-pager__step:active,
.mlp-page .mlp-pager__num,
.mlp-page .mlp-pager__num:hover,
.mlp-page .mlp-pager__num:focus,
.mlp-page .mlp-pager__num:focus-visible,
.mlp-page .mlp-pager__num:active {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 7px;
	min-height: 44px;
	min-width: 44px;
	padding: 0 14px;
	border: 0;
	border-radius: 8px;
	background: transparent;
	box-shadow: none;
	font-family: var(--ml-font);
	font-size: 14px;
	font-weight: 600;
	color: var(--mlp-navy);
	cursor: pointer;
	transition: background-color var(--ml-t-base) var(--ml-e-standard), color var(--ml-t-base) var(--ml-e-standard);
}

/* A number is a square target; only the steps carry a word beside the chevron. */
.mlp-page .mlp-pager__num {
	padding: 0 6px;
}

.mlp-page .mlp-pager__step svg,
.mlp-page .mlp-pager__num svg {
	flex: 0 0 auto;
	transition: transform var(--ml-t-base) var(--ml-e-standard);
}

/*
 * HOVER DARKENS: --ml-cyan-dark fill, white label, white chevron - the way the
 * theme's buttons behave, where the pointer takes a control one step deeper.
 *
 * TWO CYANS, ONE LADDER - REVERSED 2026-09-11, and the step between them is
 * measured rather than assumed:
 *
 *     current --ml-cyan       #00AFF0   L* 67.2   <- the leaf mark
 *     hover   --ml-cyan-dark  #0098D1   L* 59.0
 *     pressed --ml-cyan-dark  #0098D1
 *
 *     dE76 between them  9.35   against a just-noticeable difference of ~2.3
 *
 * Distance is symmetric, so swapping which state wears which cyan does not
 * change the separation: a hovered number and the current chip stay four times
 * past the threshold where an eye tells two colours apart, and the row never
 * looks like it has two current pages.
 *
 * CONTRAST, BOTH FIGURES, STATED RATHER THAN BURIED:
 *
 *     white on #00AFF0  2.5029:1   the CURRENT chip
 *     white on #0098D1  3.2751:1   HOVER
 *
 * The label is 14px/600, which is not "large text" under WCAG (that starts at
 * 18.66px bold), so the bar is 1.4.3's 4.5:1 and BOTH miss it. Against the
 * --ml-stage-soft bar the chips measure 2.3808:1 (current) and 3.1153:1
 * (hover), so the current chip is also under 1.4.11's 3:1 as a non-text
 * boundary.
 *
 * THE REVERSAL PUT THE WEAKER FIGURE ON THE PERSISTENT STATE. The current chip
 * is on screen the whole time; hover is transient. Before the swap the
 * always-visible state carried 3.28:1 and the transient one 2.50:1 - it is now
 * the other way round. That is the cost of the leaf cyan marking the current
 * page, and it was the owner's call with both numbers in hand.
 *
 * These are the owner's colours, and they belong with the brand-cyan trades
 * this project already records: the top-bar ink, the search icon's active ink,
 * the store CTA, the active filter tab and Astra's --ast-global-color-0.
 * --mlp-navy on #00AFF0 would be 5.87:1 and pass; it is not what was asked
 * for. DO NOT quietly darken either of them.
 *
 * The fill stays OUTSIDE the (hover: hover) gate on purpose - it is a colour,
 * not motion, and on touch a tap that tints briefly is useful feedback. Only
 * the chevron's travel is gated below.
 */
.mlp-page .mlp-pager__step:not([disabled]):hover,
.mlp-page .mlp-pager__step:not([disabled]):focus-visible,
.mlp-page .mlp-pager__num:not([aria-current="page"]):hover,
.mlp-page .mlp-pager__num:not([aria-current="page"]):focus-visible {
	background: var(--ml-cyan-dark);
	color: var(--ml-white);
}

/*
 * THE CHEVRON IS AN SVG WITH stroke: currentColor, so it follows the label
 * without a rule of its own - but fill/stroke are NOT in the button's
 * transition list, and naming colour here keeps the two in step rather than
 * letting the stroke snap while the text fades.
 */
.mlp-page .mlp-pager__step:not([disabled]):hover svg,
.mlp-page .mlp-pager__step:not([disabled]):focus-visible svg {
	color: var(--ml-white);
}

@media (hover: hover) and (pointer: fine) {
	.mlp-page .mlp-pager__step[data-mlp-page-next]:not([disabled]):hover svg,
	.mlp-page .mlp-pager__step[data-mlp-page-next]:not([disabled]):focus-visible svg {
		transform: translateX(2px);
	}

	/*
	 * :not([disabled]) IS THE WHOLE POINT ON PREVIOUS. It is disabled on page 1,
	 * which is the state most visitors meet first, and a chevron that slides
	 * under the pointer while the control does nothing is a promise the button
	 * cannot keep.
	 */
	.mlp-page .mlp-pager__step[data-mlp-page-prev]:not([disabled]):hover svg,
	.mlp-page .mlp-pager__step[data-mlp-page-prev]:not([disabled]):focus-visible svg {
		transform: translateX(-2px);
	}
}

/*
 * PRESSED IS --ml-cyan WITH transition: none, and both halves of that are
 * doing a job.
 *
 * transition: none makes it SNAP rather than ease - a press that fades in has
 * already finished by the time the eye reads it.
 *
 * --ml-cyan is THE CURRENT CHIP'S OWN COLOUR, so pressing an inactive number
 * shows it wearing exactly what it will wear once the page changes: the press
 * previews its own destination. It also LIGHTENS out of the hover fill
 * (#0098D1 -> #00AFF0) rather than matching it, which is what gives the press
 * a state of its own.
 *
 * The two are separated by the same measured dE76 of 9.35 that keeps the
 * hovered chip and the current chip apart - four times the ~2.3 an eye needs.
 * The full ladder now reads:
 *
 *     rest     transparent      --mlp-navy ink
 *     hover    --ml-cyan-dark   #0098D1
 *     pressed  --ml-cyan        #00AFF0   <- and the current chip's colour
 *     current  --ml-cyan        #00AFF0
 *
 * CONTRAST: white on #00AFF0 is 2.5029:1, the weaker of the two cyans - see
 * the figures above. It is momentary here, unlike the current chip.
 *
 * NOTHING MOVES. A deeper fill only - no transform, no padding, no border
 * width. The bar is a centred flex row, so any box metric that changed on
 * press would nudge every sibling for the length of a click.
 */
.mlp-page .mlp-pager__step:not([disabled]):active,
.mlp-page .mlp-pager__num:not([aria-current="page"]):active {
	background: var(--ml-cyan);
	color: var(--ml-white);
	transition: none;
}

.mlp-page .mlp-pager__step:not([disabled]):active svg,
.mlp-page .mlp-pager__num:not([aria-current="page"]):active svg {
	color: var(--ml-white);
	transition: none;
}

/*
 * THE CURRENT PAGE: white on --ml-cyan-dark, the Healthcare Store CTA's fill.
 *
 * CONTRAST, STATED PLAINLY: white on #0098D1 is 3.2751:1. The number is
 * 14px/600, which is not "large text" under WCAG (18.66px bold), so the bar is
 * 1.4.3's 4.5:1 and this MISSES it; it clears 1.4.11's 3:1, so the filled chip
 * as a shape is fine and the digit is the part that falls short.
 *
 * It is the owner's approved colour, and it replaces --mlp-navy on --ml-cyan,
 * which measured 5.87:1 and passed. That trade was made deliberately for one
 * brand language across the page - the same call recorded for the store CTA,
 * the active filter tab, the top-bar ink and Astra's --ast-global-color-0.
 * --mlp-navy on this fill would be 4.48:1 and still short.
 *
 * aria-current is the non-visual half of this and is set by the renderer, so a
 * screen reader never depends on the fill.
 */
/*
 * EVERY STATE IS LISTED, and since the hover rule above now paints a cyan chip
 * that matters more than it did: without :hover here the current page would
 * LIGHTEN under the pointer - #0098D1 going to #00AFF0 - which reads as the
 * chip losing its selection exactly when someone points at it. It holds
 * cyan-dark throughout.
 *
 * This rule is (0,3,0) against the hover rule's (0,3,0) and sits later in the
 * file, so it wins its own states on order within one stylesheet - the one
 * place this project treats a tie as safe.
 */
.mlp-page .mlp-pager__num[aria-current="page"],
.mlp-page .mlp-pager__num[aria-current="page"]:hover,
.mlp-page .mlp-pager__num[aria-current="page"]:focus,
.mlp-page .mlp-pager__num[aria-current="page"]:focus-visible,
.mlp-page .mlp-pager__num[aria-current="page"]:active {
	background: var(--ml-cyan);
	color: var(--ml-white);
	cursor: default;
}

/*
 * border-radius IS RESTATED HERE. The shared ".mlp-page button:focus-visible"
 * block carries border-radius: 4px, and although this rule outranks it at
 * (0,3,0) against (0,2,1), a rule wins only the properties it names - so the
 * 4px applied and a focused number's corners snapped 8px -> 4px. Same shape as
 * the shared rule that once squared the modal's circular close button and the
 * store CTA's 10px corners.
 */
.mlp-page .mlp-pager__step:focus-visible,
.mlp-page .mlp-pager__num:focus-visible {
	outline: 3px solid var(--ml-cyan);
	outline-offset: 3px;
	border-radius: 8px;
}

/*
 * MUTED, NOT HIDDEN. --ml-muted at 4.39:1 on the bar carries the label, and the
 * opacity takes it below that on purpose - a disabled control is meant to read
 * as unavailable, and WCAG 1.4.3 exempts inactive components. The chevron stays
 * so the row keeps its shape.
 */
/*
 * DISABLED ANSWERS NOTHING. :hover and :active are listed so the cyan chip
 * cannot reach a control that does nothing - the hover rules above already
 * carry :not([disabled]), and this is the second lock that makes it true even
 * if one of them is ever edited. The chevron is held muted too, since it would
 * otherwise inherit whatever colour the button ends up with.
 */
.mlp-page .mlp-pager__step[disabled],
.mlp-page .mlp-pager__step[disabled]:hover,
.mlp-page .mlp-pager__step[disabled]:focus,
.mlp-page .mlp-pager__step[disabled]:active {
	background: transparent;
	color: var(--ml-muted);
	opacity: 0.55;
	cursor: default;
}

.mlp-page .mlp-pager__step[disabled] svg,
.mlp-page .mlp-pager__step[disabled]:hover svg,
.mlp-page .mlp-pager__step[disabled]:active svg {
	color: var(--ml-muted);
	transform: none;
}

/* Decorative and non-interactive - the renderer already sets aria-hidden. */
.mlp-pager__gap {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 22px;
	padding: 0;
	color: var(--ml-muted);
	letter-spacing: 0.06em;
	user-select: none;
	pointer-events: none;
}

/*
 * THE LABELS GO, THE TARGETS DO NOT. "Previous" and "Next" are clipped with the
 * standard visually-hidden pattern rather than display: none, so the accessible
 * name survives - the button still announces as "Previous", it just shows only
 * its chevron. Both keep 44px.
 *
 * THE TEXT IS NEVER SHRUNK. 14px stays 14px; what gives way is the two words,
 * because a 12px pager on a phone is the thing the brief rules out and the
 * words are recoverable from the chevrons' direction.
 */
@media (max-width: 560px) {
	.mlp-page .mlp-pager__step span {
		position: absolute;
		width: 1px;
		height: 1px;
		overflow: hidden;
		clip-path: inset(50%);
		white-space: nowrap;
	}

	.mlp-page .mlp-pager__step,
	.mlp-page .mlp-pager__num {
		min-width: 44px;
		padding: 0 4px;
	}

	.mlp-pager {
		gap: 2px;
		padding: 5px 6px;
	}

	.mlp-pager__pages {
		gap: 0;
		padding-inline: 6px;
		margin-inline: 2px;
	}

	.mlp-pager__gap {
		min-width: 16px;
	}
}

/* ---------- the bar on small screens ---------- */

/*
 * 900px, not 640: the five links plus the store link stop fitting beside the
 * logo well before the phone breakpoint, and a row that has visibly run out of
 * space is the moment to collapse it - not the moment the rest of the page
 * goes single-column.
 *
 * NOTHING HERE IS GATED ON A SCRIPT ANY MORE (2026-09-20). The collapse is the
 * <details> element's own, so the bar is 79px from the first paint instead of
 * 339px until pharma.js ran - which is the whole of the 0.2992 CLS this page
 * used to carry. The honest-state contract still holds, and more cheaply: with
 * no JavaScript the summary is still focusable, still toggles, and every link
 * is still reachable.
 */
/*
 * THE BAR COLLAPSES AT 1024, NOT 900 - moved 2026-09-20 on the owner's brief.
 *
 * This block is the ONLY one of the three `max-width: 900px` blocks in this
 * file that holds bar rules; the other two size the product grid and the detail
 * grid and deliberately stay at 900. Do not merge them.
 *
 * Above this width the base rules already lay the bar out as one row, with no
 * script involved - the menu is `display: flex` at the top level and the burger
 * `display: none`. That is what makes the desktop nav render on the first paint
 * and survive JavaScript being off entirely.
 */
@media (max-width: 1024px) {
	/*
	 * The doubled class is (0,3,0) on purpose - see the note beside the state
	 * lock. At (0,2,0) this rule lost to `.mlp-bar__burger:hover` and the
	 * control vanished under the pointer it was waiting for.
	 */
	.mlp-page .mlp-bar__burger.mlp-bar__burger {
		display: inline-flex;
	}

	.mlp-bar__disclosure > .mlp-bar__menu {
		display: none;
		order: 3;
		width: 100%;
		flex-direction: column;
		align-items: stretch;
		gap: 0;
		padding: 6px 0 10px;
		border-top: 1px solid var(--mlp-line);
	}

	.mlp-bar__disclosure[open] > .mlp-bar__menu {
		display: flex;
	}

	.mlp-bar__disclosure .mlp-bar__nav {
		flex-direction: column;
		align-items: stretch;
		gap: 0;
		margin-inline: 0;
	}

	/*
	 * 44px rows. A stacked menu is thumb-driven, so every row is a target in
	 * its own right rather than a line of text that happens to be tappable.
	 */
	.mlp-bar__disclosure .mlp-bar__nav a {
		display: flex;
		align-items: center;
		min-height: 44px;
		padding: 0 2px;
		font-size: 15px;
	}

	/*
	 * IT STAYS A BUTTON IN THE STACKED MENU, not a bordered text row.
	 *
	 * align-self: flex-start is what stops it - the menu is a column with
	 * align-items: stretch, which would pull a solid CTA to the full menu width
	 * and make it the loudest thing on a 360px screen. Content width instead,
	 * so it reads as one control among the links rather than a banner.
	 *
	 * The old border-top separator is gone and replaced by margin. A hairline
	 * ABOVE a filled cyan button separates the same group twice; the fill does
	 * that job on its own.
	 */
	.mlp-bar__disclosure .mlp-bar__store {
		align-self: flex-start;
		margin-top: 12px;
		padding: 0 6px 0 14px;
		border-top: 0;
		font-size: 14px;
	}

	.mlp-bar__disclosure .mlp-bar__nav a[aria-current="page"] {
		font-weight: 600;
		color: var(--ml-cyan);
	}
}

/* ---------- card: view details ---------- */

/*
 * Astra repaints any bare <button> on :hover and :focus from its inline
 * Customizer CSS at (0,1,1), and a mouse click leaves :focus set - so the
 * resting appearance is named in every state at (0,2,0) or better, which is the
 * lock every custom control in this theme carries.
 */
.mlp-page .mlp-card__details,
.mlp-page .mlp-card__details:hover,
.mlp-page .mlp-card__details:focus,
.mlp-page .mlp-card__details:focus-visible,
.mlp-page .mlp-card__details:active {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	/*
	 * AUTO, so the action line sits level across every card in a row whatever
	 * the title wraps to - and the slack collects here, under the badge, rather
	 * than opening a hole in the middle of the card. The 10px is the floor when
	 * there is no slack to absorb, which keeps the badge clearly separated.
	 */
	margin-top: auto;
	padding-top: 10px;
	/*
	 * 44px, not the 24px WCAG 2.5.8 asks for. The button sits inside a card in
	 * a dense grid and is the only control on it, so it gets the comfortable
	 * target rather than the minimum one.
	 */
	min-height: 44px;
	padding: 0;
	border: 0;
	/*
	 * BORDER-RADIUS AND BOX-SHADOW HAVE TO BE NAMED, and that is the whole bug
	 * this rule existed to fix and did not. Astra's inline Customizer CSS puts
	 *
	 *     button, .ast-button, .button, ... { border-radius: 4px;
	 *                                         box-shadow: 0 1px 2px rgba(0,0,0,.05) }
	 *     .menu-toggle, button, ...         { border-*-radius: 30px }
	 *
	 * on every bare <button>. This block already set border: 0 and
	 * background: none, so the control READ as flat - but a rule only wins the
	 * properties it names, and neither radius nor shadow was named. The result
	 * was a 30px pill outline and a 1px drop shadow around transparent text.
	 *
	 * Resolved from the served CSS, not from reading this file: computed
	 * border-radius was 30px and box-shadow rgba(0,0,0,.05) 0 1px 2px.
	 */
	border-radius: 0;
	box-shadow: none;
	background: none;
	font-family: var(--ml-font);
	font-size: 13.5px;
	font-weight: 600;
	line-height: 1.4;
	color: var(--ml-cyan);
	text-decoration: none;
	cursor: pointer;
	transition: color var(--ml-t-base) var(--ml-e-standard);
}

.mlp-page .mlp-card__details[hidden] {
	display: none;
}

/*
 * Underline is the hover affordance now the pill is gone. text-decoration
 * paints outside the box model, so nothing reflows and the control neither
 * moves nor resizes - which is what the arrow slide below used to break.
 *
 * :focus-visible gets it too, so a keyboard user sees the same state a mouse
 * user does rather than the outline alone.
 */
.mlp-page .mlp-card__details:hover,
.mlp-page .mlp-card__details:focus-visible {
	color: var(--mlp-navy);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
}

/*
 * The arrow used to slide 3px on hover. Removed: the brief asks for hover to
 * underline WITHOUT moving the control, and a nudging arrow is movement inside
 * it. The glyph now only takes the colour change with the text.
 */
.mlp-page .mlp-card__details svg {
	flex: 0 0 auto;
}

/*
 * THE RING IS NAMED HERE, not left to the page-wide button:focus-visible rule.
 * That rule is (0,2,1) and these controls are locked at (0,2,0)/(0,3,0); it
 * still wins outline today only because the lock never names outline. Stating
 * it removes the dependency, and --ml-accent is the token the focus-ring rule
 * designates for light surfaces - brand cyan is 2.50:1 and misses 1.4.11.
 */
/*
 * NO border-radius HERE. It used to force 4px on both controls, which squared
 * the modal's circular close button the moment it took focus and rounded the
 * details link for no reason. A modern outline already follows the element's
 * own radius, so each keeps its shape: the link stays square, the close button
 * stays a circle.
 */
.mlp-page .mlp-card__details:focus-visible,
.mlp-page .mlp-modal__close:focus-visible {
	outline: 3px solid var(--ml-cyan);
	outline-offset: 3px;
}

/* ---------- details dialog ---------- */

/*
 * A native <dialog>. showModal() supplies Escape, the focus trap, the inert
 * background and focus restoration; none of that is reimplemented here.
 *
 * The element must be laid out by this rule ONLY when open - a <dialog> is
 * display:none until then, and setting display here unconditionally would
 * paint it on the page as ordinary content.
 */
.mlp-modal {
	width: min(92vw, 460px);
	max-height: 86vh;
	padding: 0;
	border: 0;
	border-radius: 16px;
	background: var(--ml-white);
	color: var(--mlp-ink);
	font-family: var(--ml-font);
	box-shadow: 0 24px 60px rgba(8, 42, 70, 0.24);
	overflow: auto;
}

.mlp-modal::backdrop {
	background: rgba(8, 42, 70, 0.55);
}

.mlp-modal[open] {
	animation: mlp-modal-in var(--ml-t-panel) var(--ml-e-enter);
}

@keyframes mlp-modal-in {
	from { opacity: 0; transform: translateY(8px); }
	to   { opacity: 1; transform: none; }
}

.mlp-modal__inner {
	position: relative;
	padding: 30px 28px 26px;
}

.mlp-page .mlp-modal__close,
.mlp-page .mlp-modal__close:hover,
.mlp-page .mlp-modal__close:focus,
.mlp-page .mlp-modal__close:focus-visible,
.mlp-page .mlp-modal__close:active {
	position: absolute;
	top: 12px;
	right: 12px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* 44px square - a modal's only dismiss control should not be a small one. */
	width: 44px;
	height: 44px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: var(--mlp-tint);
	color: var(--mlp-navy);
	cursor: pointer;
	transition: background-color var(--ml-t-base) var(--ml-e-standard);
}

.mlp-page .mlp-modal__close:hover,
.mlp-page .mlp-modal__close:focus-visible {
	background: var(--mlp-tint-deep);
}

.mlp-modal__eyebrow {
	margin: 0 0 8px;
	/* Clears the 44px close button plus its 12px inset. */
	padding-right: 48px;
	font-size: 11.5px;
	font-weight: 600;
	letter-spacing: 0.13em;
	text-transform: uppercase;
	color: var(--ml-cyan);
}

.mlp-modal__title {
	margin: 0 0 4px;
	padding-right: 48px;
	font-size: 24px;
	font-weight: 700;
	line-height: 1.2;
	color: var(--mlp-navy);
}

.mlp-modal__generic {
	margin: 0 0 20px;
	font-size: 15px;
	color: var(--mlp-ink);
}

.mlp-modal__generic:empty {
	display: none;
}

.mlp-modal__specs {
	margin: 0;
	padding: 18px 20px;
	border: 1px solid var(--mlp-line);
	border-radius: 12px;
	background: var(--mlp-tint);
}

.mlp-modal__row {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
	gap: 12px;
	padding: 7px 0;
}

.mlp-modal__row + .mlp-modal__row {
	border-top: 1px solid var(--mlp-line);
}

.mlp-modal__row[hidden] {
	display: none;
}

.mlp-modal__specs dt {
	margin: 0;
	font-size: 13px;
	font-weight: 600;
	color: var(--mlp-ink);
}

.mlp-modal__specs dd {
	margin: 0;
	font-size: 14px;
	font-weight: 600;
	color: var(--mlp-navy);
	overflow-wrap: anywhere;
}

.mlp-modal__note {
	margin: 18px 0 0;
	font-size: 12.5px;
	line-height: 1.6;
	color: var(--mlp-ink);
}

@media (max-width: 480px) {
	.mlp-modal__inner {
		padding: 26px 20px 22px;
	}

	.mlp-modal__title {
		font-size: 21px;
	}

	.mlp-modal__row {
		grid-template-columns: minmax(0, 1fr);
		gap: 2px;
	}
}

/* ---------- dialog: full details link ---------- */

/*
 * AN <a>, SO IT IS ASTRA'S ANCHOR TRAP, NOT THE BUTTON ONE:
 * a:focus { color: var(--ast-global-color-1); outline: thin dotted } at (0,1,1).
 * The rest group lists :focus at (0,3,0), so a mouse click keeps the rest ink
 * and no dotted ring. Placement is the one CLAUDE.md specifies for anchors:
 * rest + pin -> :hover -> :focus-visible.
 *
 * SHIPS hidden AND WITHOUT AN href. pharma.js adds both only when the card
 * carries a data-url, i.e. only when a published detail page exists.
 *
 * Reduced motion needs nothing here, and that is a decision: only colour
 * transitions and nothing moves (CLAUDE.md, "Reduced motion").
 */
.mlp-page .mlp-modal__more,
.mlp-page .mlp-modal__more:hover,
.mlp-page .mlp-modal__more:focus,
.mlp-page .mlp-modal__more:active {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	min-height: 44px;
	margin-top: 8px;
	font-family: var(--ml-font);
	font-size: 14px;
	font-weight: 600;
	line-height: 1.4;
	color: var(--ml-cyan);
	text-decoration: none;
	outline: none;
	transition: color var(--ml-t-base) var(--ml-e-standard);
}

.mlp-page .mlp-modal__more[hidden] {
	display: none;
}

.mlp-page .mlp-modal__more:hover,
.mlp-page .mlp-modal__more:focus-visible {
	color: var(--mlp-navy);
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
}

.mlp-page .mlp-modal__more:focus-visible {
	outline: 3px solid var(--ml-cyan);
	outline-offset: 3px;
	border-radius: 4px;
}

/* ---------- product detail page - PHASE 1 FOUNDATION ---------- */

/*
 * STRUCTURE ONLY. Every value here is either borrowed from the dialog and the
 * card (same tokens, same spec-row pattern) or is the plainest layout that
 * reads correctly at 360 and 1440. Visual polish is Phase 2 - do not mistake
 * these numbers for design decisions.
 *
 * Every selector is two classes deep under .mlp-page. Astra's inline CSS
 * reaches h1, p, dl/dd and a at (0,0,1)-(0,1,1), and a rule wins only the
 * properties it names - so margin, colour, size and line-height are named on
 * every text element rather than left to inherit.
 */
.mlp-page .mlp-detail {
	padding-top: clamp(20px, 3vw, 34px);
}

.mlp-page .mlp-detail__crumbs ol {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	margin: 0 0 clamp(18px, 3vw, 28px);
	padding: 0;
	list-style: none;
	font-size: 13px;
	line-height: 1.5;
	color: var(--mlp-ink);
}

/*
 * THE SEPARATOR TRAILS ITS ITEM, IT DOES NOT LEAD THE NEXT ONE. It was
 * `li + li::before`, so when the trail wrapped at 360 the "/" travelled with
 * the item that wrapped and a line opened with a bare slash. As `::after` on
 * every item but the last it stays at the end of the line it belongs to, and a
 * wrapped line always starts with a crumb.
 *
 * WRAP, NOT TRUNCATE: the last crumb is the product's own name, and an ellipsis
 * would hide exactly the words that say where you are. min-width: 0 plus
 * overflow-wrap lets a long trademark break inside its item instead of pushing
 * the trail past the viewport.
 */
.mlp-page .mlp-detail__crumbs li {
	display: inline;
	min-width: 0;
	margin: 0;
	overflow-wrap: anywhere;
}

.mlp-page .mlp-detail__crumbs li:not(:last-child)::after {
	content: "/";
	margin: 0 8px;
	color: var(--mlp-ink);
	opacity: 0.6;
}

/* Anchor pin: rest + :focus -> :hover -> :focus-visible. */
.mlp-page .mlp-detail__crumbs a,
.mlp-page .mlp-detail__crumbs a:focus,
.mlp-page .mlp-detail__crumbs a:active {
	color: var(--mlp-ink);
	text-decoration: none;
	outline: none;
}

.mlp-page .mlp-detail__crumbs a:hover,
.mlp-page .mlp-detail__crumbs a:focus-visible {
	color: var(--mlp-navy);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.mlp-page .mlp-detail__crumbs a:focus-visible {
	outline: 3px solid var(--ml-cyan);
	outline-offset: 3px;
	border-radius: 4px;
}

.mlp-page .mlp-detail__crumbs [aria-current="page"] {
	font-weight: 600;
	color: var(--mlp-navy);
	overflow-wrap: anywhere;
}

.mlp-page .mlp-detail__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: clamp(28px, 4vw, 56px);
	align-items: start;
}

/*
 * 16:10, ALWAYS, filled or not - the slot a real packshot drops into. contain,
 * never cover: a carton of any proportion is letterboxed, not cropped. Same
 * contract as .mlp-card__media.
 */
.mlp-page .mlp-detail__media {
	display: flex;
	align-items: center;
	justify-content: center;
	aspect-ratio: 16 / 10;
	max-width: 100%;
	padding: 18px;
	border: 1px solid var(--mlp-line);
	border-radius: 14px;
	background: linear-gradient(160deg, var(--mlp-tint-deep) 0%, var(--mlp-tint) 100%);
	overflow: hidden;
}

.mlp-page .mlp-detail__img {
	width: 100%;
	height: 100%;
	max-width: 100%;
	max-height: 100%;
	object-fit: contain;
}

.mlp-page .mlp-detail__placeholder {
	display: flex;
	align-items: center;
	gap: 14px;
	color: var(--mlp-navy);
	opacity: 0.34;
}

/* 700, not 800: Poppins is self-hosted at 400-700 only, so 800 is a no-op. */
.mlp-page .mlp-detail__initial {
	font-size: clamp(56px, 8vw, 88px);
	font-weight: 700;
	line-height: 1;
	letter-spacing: -0.02em;
}

.mlp-page .mlp-detail__leaf {
	color: var(--mlp-green);
	opacity: 0.85;
}

.mlp-page .mlp-detail__title {
	margin: 0;
	font-family: var(--ml-font);
	font-size: clamp(26px, 3.4vw, 38px);
	font-weight: 700;
	line-height: 1.15;
	letter-spacing: -0.01em;
	color: var(--mlp-navy);
	overflow-wrap: anywhere;
}

.mlp-page .mlp-detail__generic {
	margin: 14px 0 0;
	font-size: 17px;
	line-height: 1.5;
	color: var(--mlp-ink);
}

.mlp-page .mlp-detail__chip {
	display: inline-block;
	margin: 14px 0 0;
	padding: 6px 12px;
	border-radius: 6px;
	background: var(--mlp-tint-deep);
	font-size: 12.5px;
	font-weight: 600;
	line-height: 1.3;
	color: var(--ml-cyan);
}

.mlp-page .mlp-detail__specs {
	margin: 22px 0 0;
	padding: 4px 20px;
	border: 1px solid var(--mlp-line);
	border-radius: 12px;
	background: var(--mlp-tint);
}

.mlp-page .mlp-detail__row {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
	gap: 12px;
	padding: 11px 0;
}

.mlp-page .mlp-detail__row + .mlp-detail__row {
	border-top: 1px solid var(--mlp-line);
}

.mlp-page .mlp-detail__specs dt {
	margin: 0;
	font-size: 13.5px;
	font-weight: 600;
	line-height: 1.4;
	color: var(--mlp-ink);
}

.mlp-page .mlp-detail__specs dd {
	margin: 0;
	font-size: 15px;
	font-weight: 600;
	line-height: 1.4;
	color: var(--mlp-navy);
	overflow-wrap: anywhere;
}

.mlp-page .mlp-detail__note {
	margin: 18px 0 0;
	font-size: 13px;
	line-height: 1.6;
	color: var(--mlp-ink);
}

/* Anchor pin: rest + :focus -> :hover -> :focus-visible. Colour never changes. */
.mlp-page .mlp-detail__back,
.mlp-page .mlp-detail__back:hover,
.mlp-page .mlp-detail__back:focus,
.mlp-page .mlp-detail__back:active {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	min-height: 44px;
	margin-top: 12px;
	font-size: 14px;
	font-weight: 600;
	line-height: 1.4;
	color: var(--mlp-navy);
	text-decoration: none;
	outline: none;
}

.mlp-page .mlp-detail__back:hover,
.mlp-page .mlp-detail__back:focus-visible {
	text-decoration: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
}

.mlp-page .mlp-detail__back:focus-visible {
	outline: 3px solid var(--ml-cyan);
	outline-offset: 3px;
	border-radius: 4px;
}

/*
 * ASTRA'S INLINE `a { transition: all .2s linear }` REACHES EVERY ANCHOR THAT
 * DOES NOT NAME ITS OWN transition - and "all" includes outline. Measured
 * 2026-09-13 with :focus-visible forced: at 0ms the back link's ring read
 * 3px rgb(7,53,84) offset 1px, at 600ms 3px rgb(0,175,240) offset 3px - the
 * ring was sliding and fading in from the text colour. The dialog link never
 * showed it because its rest group already names a colour-only transition.
 *
 * So the transition is named here, at (0,2,1) against Astra's (0,0,1): colour
 * only on the crumbs (their ink changes on hover), none at all on the back link
 * (its ink never changes - only the underline does).
 */
.mlp-page .mlp-detail__crumbs a {
	transition: color var(--ml-t-base) var(--ml-e-standard);
}

.mlp-page .mlp-detail__back {
	transition: none;
}

@media (max-width: 900px) {
	.mlp-page .mlp-detail__grid {
		grid-template-columns: minmax(0, 1fr);
		gap: 24px;
	}
}

@media (max-width: 480px) {
	.mlp-page .mlp-detail__media {
		padding: 14px;
		border-radius: 12px;
	}

	.mlp-page .mlp-detail__row {
		grid-template-columns: minmax(0, 1fr);
		gap: 2px;
	}
}

/* ---------- reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
	.mlp-card,
	.mlp-card:hover,
	.mlp-page .mlp-area__btn,
	.mlp-page .mlp-area__btn:hover,
	/*
	 * :focus-visible IS NAMED SEPARATELY, and it has to be. The lift now lives
	 * on the grouped rule ".mlp-area__btn:hover, .mlp-area__btn:focus-visible";
	 * suppressing one half of a group suppresses one state, which is exactly
	 * how .ml-shop__pill left a keyboard visitor still getting the rise. A
	 * grouped selector hides this, because the control's name IS in the block.
	 */
	.mlp-page .mlp-area__btn:focus-visible,
	.mlp-page .mlp-btn,
	.mlp-page .mlp-pill,
	.mlp-footer__social a,
	.mlp-page .mlp-card__details,
	.mlp-page .mlp-card__details svg,
	.mlp-page .mlp-bar__burger,
	.mlp-page .mlp-pager__step,
	.mlp-page .mlp-pager__num,
	.mlp-page .mlp-modal__close {
		transition: none;
		transform: none;
	}

	/*
	 * THE PAGER CHEVRONS - :hover AND :focus-visible NAMED SEPARATELY, on the
	 * nested svg. The slide lives on grouped rules two levels down
	 * (".mlp-pager__step[...]:hover svg"), and the entry above only reaches the
	 * BUTTON: suppressing a parent's transform does nothing to a child's. That
	 * is the grouped-selector trap in its most easily missed form, since the
	 * control's own name is already in the block above.
	 */
	.mlp-page .mlp-pager__step svg,
	.mlp-page .mlp-pager__num svg,
	.mlp-page .mlp-pager__step:hover svg,
	.mlp-page .mlp-pager__step:focus-visible svg,
	.mlp-page .mlp-pager__step[data-mlp-page-next]:not([disabled]):hover svg,
	.mlp-page .mlp-pager__step[data-mlp-page-next]:not([disabled]):focus-visible svg,
	.mlp-page .mlp-pager__step[data-mlp-page-prev]:not([disabled]):hover svg,
	.mlp-page .mlp-pager__step[data-mlp-page-prev]:not([disabled]):focus-visible svg {
		transition: none;
		transform: none;
	}

	/*
	 * THE COLOUR STILL CHANGES UNDER REDUCED MOTION - only its timing goes.
	 * WCAG 2.3.3 is about motion, and this file already says so: "19 selectors
	 * are still unnamed in any reduced-motion block and that is deliberate:
	 * they fade colour and nothing moves." Suppressing the cyan chip here would
	 * take away the only hover feedback the pager has, which is an
	 * accessibility loss dressed as an accessibility setting.
	 *
	 * So: transition-duration 0, background and colour untouched.
	 */
	.mlp-page .mlp-pager__step,
	.mlp-page .mlp-pager__step:hover,
	.mlp-page .mlp-pager__step:focus-visible,
	.mlp-page .mlp-pager__step:active,
	.mlp-page .mlp-pager__num,
	.mlp-page .mlp-pager__num:hover,
	.mlp-page .mlp-pager__num:focus-visible,
	.mlp-page .mlp-pager__num:active {
		transition: none;
	}

	/*
	 * THE STORE CTA - :hover AND :focus-visible NAMED SEPARATELY, plus the arrow
	 * inside each. The lift lives on a grouped rule, and suppressing one half of
	 * a group suppresses one state: that is precisely how .ml-shop__pill left a
	 * keyboard visitor still getting the rise. The arrow's slide is on a nested
	 * element, so it needs its own entries or it keeps travelling while the
	 * button stands still.
	 */
	.mlp-page .mlp-bar__store,
	.mlp-page .mlp-bar__store:hover,
	.mlp-page .mlp-bar__store:focus-visible,
	.mlp-page .mlp-bar__store:active,
	.mlp-page .mlp-bar__store .mlp-bar__store-go svg,
	.mlp-page .mlp-bar__store:hover .mlp-bar__store-go svg,
	.mlp-page .mlp-bar__store:focus-visible .mlp-bar__store-go svg {
		transition: none;
		transform: none;
	}

	/*
	 * THE PILL HOVER NEEDED ITS OWN ENTRY, and this was a measured failure
	 * rather than a precaution: the list above names .mlp-page .mlp-pill at
	 * (0,2,0), while the lift lives on .mlp-page .mlp-pill:hover at (0,2,1)
	 * and .mlp-page .mlp-pill.is-active:hover at (0,3,1). A pseudo-class
	 * outranks the base selector, so transform: none lost and the tab STILL
	 * ROSE 2px under prefers-reduced-motion. Confirmed in a headless browser
	 * with the media feature emulated - the store pill suppressed correctly,
	 * this one did not.
	 *
	 * shop.css already solves it the same way: name the hover selectors
	 * separately at matching specificity, later in the file. This is
	 * checklist item 1 - raise a selector and its reduced-motion twin has to
	 * move with it.
	 */
	.mlp-page .mlp-pill:hover,
	.mlp-page .mlp-pill:focus-visible,
	.mlp-page .mlp-pill:active,
	.mlp-page .mlp-pill.is-active:hover,
	.mlp-page .mlp-pill.is-active:focus-visible,
	.mlp-page .mlp-pill.is-active:active {
		transform: none;
	}

	/*
	 * The dialog's entrance animates opacity AND transform, so suppressing the
	 * transform alone would leave it sliding. It is named separately because it
	 * is an animation rather than a transition.
	 */
	.mlp-modal[open] {
		animation: none;
	}
}

/*
 * POINTER FOCUS - ASTRA a:focus { outline: thin dotted } (main.min.css L3).
 * A mouse click leaves :focus set, so every anchor that names no outline of its
 * own kept a thin dotted ring until focus moved. Measured 2026-09-13 by the
 * sitewide anchor sweep (CLAUDE.md, "Anchor pointer-focus sweep").
 *
 * :not(:focus-visible) IS LOAD-BEARING: this only ever applies to pointer focus,
 * so the keyboard ring each family already has is untouched. Outline only -
 * nothing moves, so there is no reduced-motion twin.
 */
.mlp-page .mlp-bar__nav a:focus:not(:focus-visible),
.mlp-page a.mlp-bar__brand:focus:not(:focus-visible),
.mlp-page a.mlp-btn:focus:not(:focus-visible) {
	outline: none;
}

/* <= 768px: parity half of the shop pill's 44px tap target - see shop.css. */
@media (max-width: 768px) {
	.mlp-page .mlp-pill {
		min-height: 44px;
	}
}

/*
 * <= 768px tap targets in the DIVISION footer.
 *
 * The store footer and this one are separate components with separate
 * classes, so the store's pass did not reach here - measured 277 x 23.1 on
 * the column links and 36 x 36 on the social circles.
 */
@media (max-width: 768px) {
	.mlp-footer .mlp-footer__col a {
		min-height: 44px;
		display: inline-flex;
		align-items: center;
	}

	.mlp-footer .mlp-footer__social a {
		width: 44px;
		height: 44px;
	}
}

/* ===========================================================================
   THE PRODUCT FINDER IS A COMPACT LIST ON A PHONE  (<= 768px)  2026-09-22

   EVERY RULE BELOW LIVES INSIDE `@media (max-width: 768px)`, which is the
   desktop guarantee rather than a tidiness preference: there is no selector
   here a viewport above 768px can match, so "desktop is unchanged" is true by
   construction and the geometry fingerprint only has to confirm it.

   The MARKUP IS THE SAME CARD. `product-card.php` already emits media, name,
   generic, strength/pack and the area chip in that order, so the row is a
   re-layout of what was there - one template still feeds the desktop grid and
   the phone list, and a second copy could not drift out of step with it. The
   only template change is a <span> around the button's label, so this file can
   clip the words without touching the accessible name.
   =========================================================================== */

@media (max-width: 768px) {

	/*
	 * THE GUTTER IS READ FROM THE SECTION, NOT TYPED.
	 *
	 * `.mlp-section__inner` pads 24px, dropping to 16px at <= 640 - so a
	 * hard-coded pull would tear the list off the container edge by 8px across
	 * the whole 641-768 band. The rows pull out by exactly this value and pad
	 * back in by 16, which is what makes the dividers reach the screen edges
	 * while the text sits 16px in at EVERY width. Change the section's padding
	 * and this follows it.
	 */
	.mlp-page [data-mlp-finder] .mlp-section__inner {
		--mlp-row-gutter: 24px;
	}

	/* ------------------------------------------- the area filter: one strip */

	/*
	 * NINE CHIPS WRAPPED ONTO FOUR ROWS AND ATE THE FOLD. They are one
	 * horizontally scrolled line now. The 44px tap target is NOT traded away
	 * for it - `min-height: 44px` from the existing <= 768 rule still applies
	 * and is measured after; what got smaller is the type and the padding, so
	 * nine of them read as a control strip rather than as nine buttons.
	 */
	.mlp-page .mlp-filters {
		flex-wrap: nowrap;
		overflow-x: auto;
		overscroll-behavior-x: contain;
		scrollbar-width: none;
		margin-inline: calc(var(--mlp-row-gutter) * -1);
		padding-inline: var(--mlp-row-gutter);
		/*
		 * The pills' 3px ring sits at `outline-offset: 3px`, so it needs 6px of
		 * room inside a scroll container or the strip clips it. The bottom
		 * margin gives back what the padding adds, leaving the rhythm below the
		 * strip where it was.
		 */
		padding-block: 6px;
		margin-bottom: 12px;
	}

	.mlp-page .mlp-filters::-webkit-scrollbar {
		display: none;
	}

	.mlp-page .mlp-filters .mlp-pill {
		flex: 0 0 auto;
		padding: 0 12px;
		font-size: 13px;
	}

	.mlp-page .mlp-filters .mlp-pill .mlp-pill__n {
		font-size: 11px;
	}

	/* ------------------------------------------------------------- the list */

	.mlp-page .mlp-grid {
		grid-template-columns: minmax(0, 1fr);
		gap: 0;
		margin-inline: calc(var(--mlp-row-gutter) * -1);
		border-top: 1px solid var(--mlp-line);
	}

	/*
	 * THE DIVIDER IS ON EVERY ROW, INCLUDING THE LAST, AND THAT IS DELIBERATE.
	 *
	 * `:last-child` would name the last row in the DOM, which is almost never
	 * the last VISIBLE one - the pager hides all but twelve of the 44, so the
	 * rule would land on a `display: none` card and no visible row would lose
	 * its border. A closing line above the pager reads as the list's own edge,
	 * and it cannot go wrong whichever twelve are on screen.
	 */
	.mlp-page .mlp-grid .mlp-card {
		position: relative;
		flex-direction: row;
		align-items: center;
		gap: 12px;
		min-height: 84px;
		padding: 12px 16px;
		border: 0;
		border-bottom: 1px solid var(--mlp-line);
		border-radius: 0;
		background: var(--ml-white);
	}

	/*
	 * The desktop card lifts and glows on hover. A phone has no hover, but a
	 * tap can leave `:hover` stuck on some engines - and `border-color` has to
	 * be named or the hover rule repaints the divider cyan, because a rule wins
	 * only the properties it names.
	 */
	.mlp-page .mlp-grid .mlp-card:hover {
		border-color: var(--mlp-line);
		box-shadow: none;
		transform: none;
	}

	/* ------------------------------------------------- the 56px packshot box */

	/*
	 * A 16:9 PANEL WITH A 40px LETTER IN IT WAS THE WHOLE COMPLAINT. The slot
	 * is a 56px square now, white-backed and `contain`, so the day a real
	 * packshot lands it drops straight into this box with nothing cropped and
	 * no layout change - the same contract the desktop panel keeps, at a size
	 * a list row can carry.
	 */
	.mlp-page .mlp-grid .mlp-card__media {
		flex: 0 0 56px;
		width: 56px;
		height: 56px;
		aspect-ratio: auto;
		padding: 5px;
		border: 1px solid var(--mlp-line);
		border-radius: 8px;
		background: var(--ml-white);
	}

	.mlp-page .mlp-grid .mlp-card__placeholder {
		gap: 0;
		opacity: 0.38;
	}

	.mlp-page .mlp-grid .mlp-card__initial {
		font-size: 18px;
	}

	/* One glyph is the placeholder at this size; two is clutter in 46px. */
	.mlp-page .mlp-grid .mlp-card__leaf {
		display: none;
	}

	/* ------------------------------------------------------------- the text */

	/*
	 * STRENGTH/PACK AND THE AREA TAG SHARE THE LAST LINE, and that is what
	 * keeps the row inside the 80-90px the brief asks for. Stacked, the four
	 * blocks measure ~100px however tightly they are set; side by side they
	 * measure ~84. The two full-width items are named rather than relying on
	 * wrapping, so the name and the generic can never end up beside each other.
	 */
	.mlp-page .mlp-grid .mlp-card__body {
		flex-direction: row;
		flex-wrap: wrap;
		align-items: center;
		column-gap: 8px;
		row-gap: 2px;
		min-width: 0;
		/* 18px chevron + 8px of daylight - see the stretched button below. */
		padding: 0 26px 0 0;
	}

	.mlp-page .mlp-grid .mlp-card__name,
	.mlp-page .mlp-grid .mlp-card__generic {
		flex: 0 0 100%;
	}

	.mlp-page .mlp-grid .mlp-card__meta {
		flex: 0 1 auto;
	}

	.mlp-page .mlp-grid .mlp-card__chip {
		flex: 0 0 auto;
		margin: 0;
		padding: 2px 7px;
		border-radius: 5px;
		font-size: 10.5px;
	}

	/*
	 * ONE LINE EACH. `min-width: 0` on the body is what lets these shrink at
	 * all - a flex item's default `min-width: auto` is its content's width, so
	 * without it a long generic name pushes the row wider than the screen
	 * instead of ellipsing.
	 */
	.mlp-page .mlp-grid .mlp-card__name,
	.mlp-page .mlp-grid .mlp-card__generic,
	.mlp-page .mlp-grid .mlp-card__meta {
		max-width: 100%;
		overflow: hidden;
		white-space: nowrap;
		text-overflow: ellipsis;
	}

	.mlp-page .mlp-grid .mlp-card__name {
		font-size: 15px;
		line-height: 1.25;
	}

	.mlp-page .mlp-grid .mlp-card__generic {
		font-size: 12.5px;
		line-height: 1.3;
	}

	.mlp-page .mlp-grid .mlp-card__meta {
		font-size: 12px;
		line-height: 1.3;
		opacity: 1;
	}

	/* ------------------------------------------- the whole row is the control */

	/*
	 * THE BUTTON IS STRETCHED OVER THE ROW RATHER THAN THE ROW BEING MADE
	 * CLICKABLE, and the difference is the accessibility tree.
	 *
	 * An `<li>` with a click handler is not a control: no role, no keyboard,
	 * nothing announced. Here the real `<button>` simply grows to `inset: 0`,
	 * so tapping anywhere on the row activates the same control that already
	 * opens the dialog - `pharma.js` binds `[data-mlp-details]` and needed no
	 * change at all. The label is clipped, so what is left on screen is the
	 * chevron; what is left in the accessibility tree is "View Details".
	 *
	 * Specificity: the rest rule is `.mlp-page .mlp-card__details` (0,2,0) and
	 * its states (0,2,1). These are (0,3,0) and (0,3,1) - one tier above each,
	 * so nothing here depends on source order.
	 */
	.mlp-page .mlp-grid .mlp-card__details {
		position: absolute;
		inset: 0;
		z-index: 1;
		display: flex;
		align-items: center;
		justify-content: flex-end;
		gap: 0;
		min-height: 0;
		margin: 0;
		padding: 0 16px 0 0;
		background: none;
		box-shadow: none;
		border: 0;
		border-radius: 0;
	}

	.mlp-page .mlp-grid .mlp-card__details-label {
		position: absolute;
		width: 1px;
		height: 1px;
		overflow: hidden;
		clip-path: inset(50%);
		white-space: nowrap;
	}

	.mlp-page .mlp-grid .mlp-card__details svg {
		width: 18px;
		height: 18px;
		color: var(--mlp-ink);
		opacity: 0.55;
	}

	/*
	 * The desktop hover underlines the label. There is no label to underline
	 * here and no hover on a phone, so both states are pinned back to rest -
	 * `text-decoration` included, because a stuck `:hover` after a tap would
	 * otherwise underline a clipped word nobody can see.
	 */
	.mlp-page .mlp-grid .mlp-card__details:hover,
	.mlp-page .mlp-grid .mlp-card__details:focus,
	.mlp-page .mlp-grid .mlp-card__details:active {
		background: none;
		box-shadow: none;
		text-decoration: none;
	}

	/* pointer focus leaves nothing behind - the house pin */
	.mlp-page .mlp-grid .mlp-card__details:focus:not(:focus-visible) {
		outline: none;
	}

	/*
	 * THE RING IS INSET, AND BRAND CYAN. It is drawn on a control that spans
	 * the row edge to edge, so a positive offset would be clipped by the row
	 * above and below and would paint over both dividers - less visible, which
	 * is the opposite of the intent. Six other controls in this theme draw
	 * inside their box for the same reason.
	 */
	.mlp-page .mlp-grid .mlp-card__details:focus-visible {
		outline: 3px solid var(--ml-cyan);
		outline-offset: -3px;
		border-radius: 0;
	}

	/* --------------------------------------------------------- the pager */

	/*
	 * 44px on BOTH axes. The <= 560 block already sets `min-width: 44px`; the
	 * height was whatever the bar's padding left, so the target was 44 wide and
	 * short. Stated here for every width the phone layout covers.
	 */
	.mlp-page .mlp-pager__step,
	.mlp-page .mlp-pager__num {
		min-height: 44px;
	}

	/* ------------------------------------------------------- reduced motion */

	/*
	 * Nothing in this block animates - the lift and the glow are removed rather
	 * than suppressed, and the chevron does not move. The existing
	 * `prefers-reduced-motion` block still names `.mlp-card`, `.mlp-card:hover`
	 * and `.mlp-card__details`, so it keeps winning what it always won; there
	 * is deliberately no new twin here, because padding a block with selectors
	 * that move nothing is what this theme's own rule warns against.
	 */
}

@media (max-width: 640px) {
	/* the section's own padding drops to 16 here, so the pull must too */
	.mlp-page [data-mlp-finder] .mlp-section__inner {
		--mlp-row-gutter: 16px;
	}
}

/* ===========================================================================
   THERAPEUTIC AREAS ARE A 3-UP TILE GRID ON A PHONE  (<= 768px)  2026-09-22

   EVERY RULE IS INSIDE `@media (max-width: 768px)` - the same desktop
   guarantee the finder list uses. There is no selector here a viewport above
   768px can match, so "desktop is unchanged" is true by construction and the
   geometry fingerprint only has to confirm it.

   THE SECTION IS NOT REMOVED. `#mlp-areas` is the browse section, and the
   pill strip above the list is the *filter* - this file already records why
   the two are different things. What changes is the card's shape: the desktop
   row (60px tile | text | arrow) becomes a centred tile.
   =========================================================================== */

@media (max-width: 768px) {

	/*
	 * SIDE PADDING MATCHES THE LIST ROW'S TEXT INSET, which is 16px at every
	 * width the phone layout covers. The section's own padding is 24px down to
	 * 640 and 16px below it, so without this the tiles would sit 8px further
	 * in than the rows directly above them across the whole 641-768 band - the
	 * exact defect the list's `--mlp-row-gutter` was written to avoid, in the
	 * section next door.
	 *
	 * Scoped to #mlp-areas: the finder section keeps its own arrangement.
	 */
	.mlp-page #mlp-areas .mlp-section__inner {
		padding-left: 16px;
		padding-right: 16px;
	}

	/*
	 * THREE COLUMNS, AND THE (0,2,0) IS WHY IT HOLDS.
	 *
	 * The pre-existing `@media (max-width: 640px) { .mlp-areas { ... 1fr } }`
	 * sits LATER in this file at (0,1,0). A rule written here at the same tier
	 * would lose on source order below 640 - i.e. on every phone. One class
	 * above it wins wherever it is placed, which is the standing rule for
	 * every override in this theme.
	 */
	.mlp-page .mlp-areas {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: 10px;
	}

	/*
	 * A CENTRED TILE, NOT A ROW. At 375 each card is ~105px wide, and the
	 * desktop arrangement (60px icon + gap + text + 28px arrow) needs ~120px
	 * of fixed furniture before a single letter is set - so the row cannot be
	 * shrunk into this column, it has to become a column itself.
	 *
	 * `height: 100%` stays from the rest rule, so the grid row still stretches
	 * every card in a row to the tallest, and a two-line name cannot leave a
	 * ragged edge.
	 */
	.mlp-page .mlp-area__btn,
	.mlp-page .mlp-area__btn:hover,
	.mlp-page .mlp-area__btn:focus,
	.mlp-page .mlp-area__btn:active {
		flex-direction: column;
		align-items: center;
		justify-content: flex-start;
		gap: 8px;
		/* 4px, not 6: every side pixel is column for a 16-character name. */
		padding: 12px 4px;
		border-radius: 14px;
		text-align: center;
	}

	/*
	 * THE RING'S RADIUS HAS TO MOVE WITH THE CARD'S. The ring rule restates
	 * `border-radius: 18px` precisely because a rule wins only the properties
	 * it names - so leaving it alone would draw an 18px ring around a 14px
	 * card. Same tier as the rule it corrects, later in the file.
	 */
	.mlp-page .mlp-area__btn:focus-visible {
		border-radius: 14px;
	}

	/* 48px tile, 32px artwork - the desktop 60/40 proportion, scaled. */
	.mlp-page .mlp-area__icon {
		width: 48px;
		height: 48px;
		border-radius: 10px;
	}

	.mlp-page .mlp-area__icon img {
		width: 32px;
		height: 32px;
	}

	.mlp-page .mlp-area__icon svg {
		width: 22px;
		height: 22px;
	}

	.mlp-page .mlp-area__text {
		align-items: center;
		gap: 2px;
		width: 100%;
	}

	/*
	 * TWO LINES, CLAMPED. The desktop card lets a name wrap freely because it
	 * has a whole row to wrap into; here a third line would push one tile
	 * taller than its neighbours and the grid would stretch all three.
	 *
	 * ⚑ ONE NAME STILL BREAKS MID-WORD AT 375, AND IT IS THE LAST ONE THAT
	 * CAN. "Gastroenterology" is 16 characters; at 12px it needs ~105px and
	 * the content box is 97.7px (card 107.7 less 4+4 padding and 2 border).
	 * It reads "Gastroenterolo / gy". Everything else is whole, at both
	 * widths, and nothing paints outside its tile - the spill check is 0.
	 *
	 * THE 4px PADDING AND THE 12px TYPE ARE WHAT BOUGHT THE REST. Trialled on
	 * the live page before being written here: 6px/12.5px broke both
	 * "Gastroenterology" and "Cardiovascular" at 375 and Gastro again at 414;
	 * 4px/12px leaves the one above and none at 414.
	 *
	 * Three alternatives were tried on the page and all three are worse:
	 *
	 *   `text-wrap: balance` and `text-wrap: pretty` - NO effect at either
	 *     width, measured. The name is a `-webkit-box` for the line clamp, and
	 *     that layout ignores them.
	 *
	 *   `overflow-wrap: break-word` - keeps the word whole until it cannot
	 *     fit, which put it on its own line and then let it OVERFLOW the card
	 *     on both sides. Visibly outside the tile; strictly worse than a break.
	 *
	 *   `hyphens: auto` - did nothing, with `anywhere` and again with
	 *     `break-word`, although <html lang="en-US"> is set and was checked.
	 *     Chrome's hyphenation dictionary ships through the component updater
	 *     and is simply absent in a fresh profile, so it may well work on a
	 *     real visitor's browser - which is exactly why it is not shipped: it
	 *     cannot be verified here, and an unverifiable fix is not a fix.
	 *
	 * So `anywhere` (inherited) stays: the break is ugly on one of nine tiles
	 * at one width, and it is CONTAINED, which overflow is not. The real fix
	 * is a shorter display label for that one area - a content change in
	 * inc/pharma-data.php, and the owner's call.
	 */
	.mlp-page .mlp-area__name,
	.mlp-page .mlp-area__name-short {
		font-size: 12px;
		line-height: 1.25;
		display: -webkit-box;
		-webkit-line-clamp: 2;
		-webkit-box-orient: vertical;
		overflow: hidden;
	}

	/*
	 * THE SWAP, AND WHY IT IS A CLIP RATHER THAN `display: none`.
	 *
	 * A tile whose record carries a `label_short` shows it here and hides the
	 * full label - but hiding it with `display: none` would take it out of the
	 * ACCESSIBILITY TREE as well, and the button's name is computed from its
	 * contents. The clip keeps the full label in the tree and out of the
	 * layout, so the accessible name is byte-identical at 375 and 1440 while
	 * the tile reads "Gastro Care".
	 *
	 * `:has()` keys on the markup that is already there, so no second class or
	 * state has to be kept in step with the data - the day another area gets a
	 * `label_short`, this rule covers it with nothing else to edit. The two
	 * rules must sit AFTER the shared type rule above, which sets `display` on
	 * both spans.
	 */
	.mlp-page .mlp-area__text:has(> .mlp-area__name-short) > .mlp-area__name {
		position: absolute;
		width: 1px;
		height: 1px;
		overflow: hidden;
		clip-path: inset(50%);
		white-space: nowrap;
	}

	.mlp-page .mlp-area__name-short {
		display: -webkit-box;
	}

	.mlp-page .mlp-area__tag {
		font-size: 11px;
		line-height: 1.3;
	}

	/*
	 * THE ARROW GOES. It is `aria-hidden` decoration - the button's own
	 * screen-reader text still reads "Show N products in <area>" - and at a
	 * 105px card a 28px chip beside a 12.5px label is the loudest thing on the
	 * tile. The hover rule that recolours it simply stops matching anything.
	 */
	.mlp-page .mlp-area__go {
		display: none;
	}

	/*
	 * No reduced-motion twin is added here, and that is checked rather than
	 * assumed: nothing in this block animates. The lift and the shadow are the
	 * base rule's, at (0,2,0)/(0,2,1), and the existing reduced-motion block
	 * already names `.mlp-page .mlp-area__btn`, `:hover` and `:focus-visible`
	 * at those same tiers - so it keeps winning exactly what it won before.
	 * Padding a block with selectors that move nothing is what this theme's
	 * own rule warns against.
	 */
}

/* =========================================================================
   PRODUCT DETAIL PAGE - PHASE 2 (2026-09-23)
   =========================================================================

   Appended, so every rule here sits LATER in the file than the Phase 1 block
   it refines and wins at equal specificity without raising anyone's tier. That
   matters: the Phase 1 selectors carry `@media` twins at 900 and 480 further
   up, and raising a base would have stranded them - the mistake this project
   made twice in one day on 2026-09-23 (the account sidebar and the track-order
   aside) and wrote a checklist about.

   NOTHING HERE ANIMATES A TRANSFORM. Every transition below names colour or
   background only, so there is no reduced-motion twin to write - and this
   file's own rule says not to pad those blocks with selectors that move
   nothing. The reduced-motion block sits above this one; if a lift is ever
   added here it must be named there too, which means moving it.
   ---------------------------------------------------------------------- */

/*
 * THE STAGE IS WHITE, AND IT IS A SQUARE.
 *
 * Phase 1 gave it a 16:10 box on the page's own blue-tinted gradient, which
 * was right for a placeholder letter and wrong for a packshot: a carton is
 * taller than it is wide, so 16:10 letterboxes it into a strip. The store's
 * product page shows its main image on a near-square white field, and this is
 * the same layout deliberately - one product page language across both
 * divisions.
 *
 * `contain`, never `cover`, is unchanged and is the load-bearing half: a
 * packshot of any proportion is letterboxed, never cropped. Cropping a carton
 * cuts the brand lockup off the top, which is the failure this project has
 * already spent four rejected files on. Verified rather than assumed - a 3:1
 * image injected into this stage paints at 3.00 inside it at both widths.
 *
 * 4:3 AND NOT THE SQUARE IT WAS FIRST BUILT AS. A 548px square at 1440 sat
 * beside a right column about 330px tall, so two thirds of the stage was empty
 * white with the letter tile adrift in it - and that is what this page looks
 * like TODAY, because all 44 records carry image = 0. The store's product page
 * carries a near-square stage because its right column is full: price,
 * quantity, buttons, assurances, an accordion. This one has six lines and a
 * button. 4:3 is the honest fit for the content that exists, and a packshot is
 * still shown large.
 */
.mlp-page .mlp-detail__media {
	aspect-ratio: 4 / 3;
	padding: clamp(22px, 3vw, 40px);
	border-radius: 16px;
	background: var(--ml-white);
}

/*
 * The chip leads the column now, above the h1, so it reads as the product's
 * category the way a store product page's breadcrumb-category does. It was
 * under the generic name in Phase 1, where it read as an afterthought.
 */
.mlp-page .mlp-detail__chip {
	margin: 0;
}

.mlp-page .mlp-detail__title {
	margin: 12px 0 0;
}

/*
 * THE CHIP IS A LINK NOW, so it needs the theme's four-state idiom in the
 * documented order - rest, pointer pin, hover, ring. Astra reaches every
 * anchor with `a:hover, a:focus { color: var(--ast-global-color-1) }` and
 * `a:focus { outline: thin dotted }`, both (0,1,1); the rest rule below is
 * (0,2,0) and wins colour, but a rule only wins the properties it names, so
 * the outline needs its own pin or a click leaves a dotted ring behind.
 */
.mlp-page a.mlp-detail__chip,
.mlp-page a.mlp-detail__chip:focus,
.mlp-page a.mlp-detail__chip:active {
	color: var(--ml-cyan);
	text-decoration: none;
	transition: background-color var(--ml-t-base) var(--ml-e-standard);
}

.mlp-page a.mlp-detail__chip:focus:not(:focus-visible) {
	outline: none;
}

.mlp-page a.mlp-detail__chip:hover,
.mlp-page a.mlp-detail__chip:focus-visible {
	background: var(--mlp-tint);
	color: var(--mlp-navy);
}

.mlp-page a.mlp-detail__chip:focus-visible {
	outline: 3px solid var(--ml-cyan);
	outline-offset: 3px;
}

/*
 * Description - renders only when `_mlp_description` holds something, which is
 * no product today. See the flag in single-medlife_pharma.php: the block is
 * wired rather than omitted so real copy appears with no template change, and
 * it is deliberately not filled with anything the page has to hand.
 */
.mlp-page .mlp-detail__desc {
	margin: 22px 0 0;
	font-size: 16px;
	line-height: 1.7;
	color: var(--mlp-ink);
}

.mlp-page .mlp-detail__desc p {
	margin: 0 0 14px;
}

.mlp-page .mlp-detail__desc p:last-child {
	margin-bottom: 0;
}

/* ---------- WhatsApp ---------- */

/*
 * #075E54 IS CHOSEN ON CONTRAST, not on familiarity, and the familiar
 * #25D366 is exactly what it replaces.
 *
 *   white on #25D366   2.1:1   fails 1.4.3 outright
 *   white on #128C7E   4.22:1  fails by a margin too small to notice and too
 *                              real to ship
 *   white on #075E54   7.67:1  passes AA and AAA for this size
 *
 * All three are WhatsApp's own brand colours, so this stays inside the
 * "eleven social brand colours" carve-out this theme already keeps - it is the
 * readable one of the set rather than a colour invented here. Hover goes
 * DARKER (8.9:1); going lighter towards #128C7E would have dropped a passing
 * control below the line on hover, which is the trap the search icon's ink
 * already fell into once.
 *
 * Geometry is the site's own primary-CTA scale - 50px, radius 8, 15px/600, no
 * uppercase, no tracking - set by the 2026-09-14 owner decision. A one-off
 * size here would be the twelfth button scale on this site.
 */
.mlp-page .mlp-detail__wa,
.mlp-page .mlp-detail__wa:focus,
.mlp-page .mlp-detail__wa:active {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	margin: 22px 0 0;
	min-height: 50px;
	padding: 0 26px;
	border: 0;
	border-radius: 8px;
	background: #075e54;
	font-family: var(--ml-font);
	font-size: 15px;
	font-weight: 600;
	line-height: 1.3;
	color: var(--ml-white);
	text-decoration: none;
	transition: background-color var(--ml-t-base) var(--ml-e-standard);
}

.mlp-page .mlp-detail__wa:focus:not(:focus-visible) {
	outline: none;
}

.mlp-page .mlp-detail__wa:hover,
.mlp-page .mlp-detail__wa:focus-visible {
	background: #043f39;
	color: var(--ml-white);
	text-decoration: none;
}

.mlp-page .mlp-detail__wa:focus-visible {
	outline: 3px solid var(--ml-cyan);
	outline-offset: 3px;
}

.mlp-page .mlp-detail__wa svg {
	flex: 0 0 auto;
}

/* ---------- related strip ---------- */

.mlp-page .mlp-detail__related-inner > .mlp-h2 {
	margin-bottom: 22px;
}

/*
 * FOUR COLUMNS, BECAUSE THE STRIP PULLS FOUR. The finder's grid is three, and
 * three columns holding four cards leaves one card alone on a second row - a
 * ragged block that reads as a layout fault rather than as a count. Four fit
 * one clean row.
 *
 * An area with fewer than four is the normal case, not an edge: Women's Health
 * holds two products, so its strip shows ONE related card. `repeat(4, …)`
 * keeps that card the same width as every other related card on the site
 * rather than stretching it across the row, which `auto-fit` would have done
 * and which would have made a single sibling look like a feature banner.
 */
@media (min-width: 1025px) {
	.mlp-page .mlp-detail__related .mlp-grid {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}
}

/*
 * "See all <area> products" - the same outline-secondary the store's View All
 * links use, so the two divisions do not grow two vocabularies for one job.
 */
.mlp-page .mlp-detail__related-all,
.mlp-page .mlp-detail__related-all:focus,
.mlp-page .mlp-detail__related-all:active {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	margin: 22px 0 0;
	min-height: 44px;
	padding: 0 22px;
	border: 1px solid var(--mlp-line);
	border-radius: 9px;
	background: var(--ml-white);
	font-family: var(--ml-font);
	font-size: 14px;
	font-weight: 600;
	line-height: 1.25;
	color: var(--ml-cyan);
	text-decoration: none;
	transition: background-color var(--ml-t-base) var(--ml-e-standard),
		border-color var(--ml-t-base) var(--ml-e-standard);
}

.mlp-page .mlp-detail__related-all:focus:not(:focus-visible) {
	outline: none;
}

.mlp-page .mlp-detail__related-all:hover,
.mlp-page .mlp-detail__related-all:focus-visible {
	border-color: var(--ml-cyan);
	background: var(--mlp-tint);
}

.mlp-page .mlp-detail__related-all:focus-visible {
	outline: 3px solid var(--ml-cyan);
	outline-offset: 3px;
}

/* ---------- the card link, now that it is an <a> ---------- */

/*
 * IT WAS A <button> UNTIL TODAY, AND THAT CHANGES WHICH ASTRA RULE REACHES IT.
 *
 * The lock further up this file was written against Astra's `button:hover` and
 * `button:focus` at (0,1,1). An anchor is reached by a DIFFERENT pair -
 * `a:hover, a:focus { color }` and `a:focus { outline: thin dotted }` - and
 * while the lock still wins `color` on specificity, it never names `outline`.
 * So a mouse click on a card left Astra's dotted ring painted over the control
 * until focus moved: the "stuck box after tapping" this pass was asked to fix,
 * arriving by a new route on the same day the element changed element type.
 *
 * `:not(:focus-visible)` is the whole mechanism - it can only ever match
 * POINTER focus, so the keyboard ring named above is untouchable by this rule.
 */
.mlp-page .mlp-card__details:focus:not(:focus-visible) {
	outline: none;
}

/*
 * AND THE TAP HIGHLIGHT, which is not the focus ring and is not CSS the page
 * asked for. Mobile engines paint their own translucent rectangle over a
 * tapped link; at <= 768px this link is stretched across the WHOLE row, so
 * that rectangle is a grey panel the width of the screen. The header logo
 * needed the same line for the same reason on 2026-09-23.
 */
.mlp-page .mlp-card__details {
	-webkit-tap-highlight-color: transparent;
}

@media (max-width: 900px) {
	/*
	 * Only the corner softens here now. The ratio used to change too - the
	 * stage was 1:1 on desktop and this block took it to 4:3 - but the base is
	 * 4:3 at every width since the desktop square was measured against the
	 * right column and found to be two thirds empty. A rule that restates the
	 * value it inherits is one more place to forget.
	 */
	.mlp-page .mlp-detail__media {
		border-radius: 14px;
	}
}

@media (max-width: 768px) {
	/*
	 * THE RELATED STRIP GETS THE FINDER'S OWN GUTTER VARIABLE.
	 *
	 * At <= 768px a `.mlp-card` is a full-bleed list row that pulls out by
	 * exactly its container's padding - and that pull reads
	 * `calc(var(--mlp-row-gutter) * -1)`. The variable is declared on
	 * `[data-mlp-finder] .mlp-section__inner`, which this strip is not inside,
	 * so without these two lines the calc resolves against nothing, the whole
	 * declaration is invalid, and this would be the one list on the site whose
	 * dividers stop short of the screen edges.
	 *
	 * The values mirror the finder's exactly, including the step down at 640 -
	 * they are two copies of one number and have to be edited together, which
	 * is the price of the variable living on a different container.
	 */
	.mlp-page .mlp-detail__related-inner {
		--mlp-row-gutter: 24px;
	}

	.mlp-page .mlp-detail__related-all {
		width: 100%;
	}
}

@media (max-width: 640px) {
	.mlp-page .mlp-detail__related-inner {
		--mlp-row-gutter: 16px;
	}
}

/* =========================================================================
 * THE WHOLE CARD IS THE LINK - DESKTOP ONLY (2026-09-23)
 *
 * EVERY RULE HERE IS INSIDE `min-width: 769px`, AND THAT IS THE WHOLE REASON
 * THE PHONE LIST IS SAFE. At <= 768px the card is already a compact row whose
 * `.mlp-card__details` is itself `position: absolute; inset: 0; z-index: 1` -
 * stretched over the row, clickable end to end, with its own inset ring. None
 * of that is touched, because no selector below can match at that width.
 *
 * The store's loop card does the same thing with a `::after` on the title's
 * link; here the link that already exists is the one stretched, so the card
 * gains no second destination and the accessibility tree is unchanged -
 * `::after` is not in it.
 * ====================================================================== */

@media (min-width: 769px) {

	/*
	 * THE POSITIONING ANCHOR. `inset: 0` resolves against the nearest
	 * positioned ancestor, so without this the overlay would stretch to the
	 * page rather than the card. Measured before writing it: the desktop card
	 * computes `position: static`, so there was nothing to anchor to.
	 */
	.mlp-page .mlp-grid .mlp-card {
		position: relative;
	}

	/*
	 * ONE ANCHOR, NO NESTING. The overlay is a pseudo-element on the link that
	 * was already there, so there is exactly one tab stop per card and the
	 * accessible name stays the link's own `aria-label`. A second <a> wrapping
	 * the card would have given screen readers two links to the same page and
	 * doubled the tab stops - which is what "nested link nahi" rules out.
	 *
	 * `overflow: hidden` on the card does not clip this: the overlay is a
	 * descendant and sits inside the border box by construction.
	 */
	.mlp-page .mlp-grid .mlp-card__details::after {
		content: "";
		position: absolute;
		inset: 0;
		z-index: 1;
	}

	/*
	 * THE RING MOVES TO THE CARD, so the outline frames what the link actually
	 * activates. `:has()` is what makes that possible without a second class
	 * or a line of JavaScript - the state already lives on the link.
	 *
	 * IT IS KEYBOARD-ONLY BY CONSTRUCTION, not by a second rule. A pointer
	 * click on an <a> sets `:focus` and NOT `:focus-visible`, which this file
	 * records in half a dozen places, so `:has(... :focus-visible)` simply
	 * cannot match a click. That is the "atka hua cyan box" gone at the source
	 * rather than pinned away afterwards.
	 *
	 * `:focus-within` would have been the wrong tool: it is true for ANY
	 * focused descendant, so the card would also ring when something else
	 * inside it took focus. `:has()` names the one control.
	 */
	.mlp-page .mlp-grid .mlp-card:has(.mlp-card__details:focus-visible) {
		outline: 3px solid var(--ml-cyan);
		outline-offset: 3px;
		border-radius: 12px;
	}

	/*
	 * ...AND THE LINK ITSELF STOPS DRAWING ONE, or the card would carry two
	 * rings, the inner one around a line of text that is no longer the target.
	 * (0,4,1) against the shared `.mlp-page .mlp-card__details:focus-visible`
	 * at (0,2,1) - one tier above, so this does not depend on source order.
	 *
	 * The <= 768px ring is a DIFFERENT rule inside its own query and keeps
	 * drawing: there the link IS the row, so ringing it is correct.
	 */
	.mlp-page .mlp-grid .mlp-card .mlp-card__details:focus-visible {
		outline: none;
	}

	/*
	 * ASTRA'S TWO ANCHOR TRAPS, pinned on the element they reach.
	 *
	 *     a:hover, a:focus { color: var(--ast-global-color-1) }   (0,1,1)
	 *     a:focus          { outline: thin dotted }               (0,1,1)
	 *
	 * The rest lock earlier in this file already names `color` in every state,
	 * and the top-level `:focus:not(:focus-visible) { outline: none }` already
	 * kills the dotted ring on a click. Both are restated here at (0,4,1) for
	 * one reason: this element's job changed today. It is now the whole card's
	 * hit area, so a dotted 1px rectangle drawn across it is the width of the
	 * card rather than the width of two words, and it must not come back
	 * through a future edit to either of those rules.
	 */
	.mlp-page .mlp-grid .mlp-card .mlp-card__details:focus:not(:focus-visible) {
		outline: none;
		color: var(--ml-cyan);
	}

	/*
	 * THE LIFT AND THE SHADOW ALREADY EXIST on `.mlp-card:hover`, measured
	 * before anything was written: `translateY(-2px)`, a cyan border and
	 * `0 4px 14px rgba(var(--ml-shadow-tint), .10)`, all on the documented
	 * motion tokens. They are deliberately NOT restated - a second copy is the
	 * drift this file keeps recording. The only thing missing was that the
	 * card had no hit area to hover across, which the overlay supplies.
	 *
	 * Reduced motion is likewise already covered: the existing block names
	 * `.mlp-card` and `.mlp-card:hover` with `transition: none; transform:
	 * none`, so the lift is suppressed and the colour change is kept - a tint
	 * is not motion, per this theme's own rule.
	 */
}
