/*
Theme Name:  Origin EOS
Theme URI:   https://origineos.com
Author:      Origin EOS
Description: Premium WooCommerce block theme for a gated laboratory research-materials catalog.
Version: 2.24.0
Requires at least: 6.7
Tested up to: 7.1
Requires PHP: 8.1
License:     GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: oe
Tags:        block-templates, full-site-editing, e-commerce, accessibility-ready
*/

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

html {
	scroll-behavior: smooth;
}

body {
	caret-color: var(--wp--preset--color--accent);
	font-feature-settings: "kern" 1, "liga" 1;
	text-rendering: optimizeLegibility;
}

::selection {
	background: var(--wp--preset--color--accent-deep);
	color: var(--wp--preset--color--surface);
}

::-webkit-scrollbar {
	width: 12px;
}

::-webkit-scrollbar-track {
	background: var(--wp--preset--color--base);
}

::-webkit-scrollbar-thumb {
	background: #a8a8ad;
	background-clip: padding-box;
	border: 3px solid transparent;
	border-radius: 999px;
}

:focus-visible {
	outline: 3px solid var(--wp--preset--color--accent);
	outline-offset: 3px;
}

a,
button,
input,
select,
textarea {
	transition: color 180ms ease, background-color 180ms ease, border-color 180ms ease, box-shadow 180ms ease, transform 180ms ease;
}

p a,
li a,
.wp-block-post-content a {
	text-decoration-line: underline;
	text-decoration-thickness: 1px;
	text-underline-offset: 0.22em;
}

.wp-block-heading {
	max-width: 18ch;
	text-wrap: balance;
}

p {
	text-wrap: pretty;
}

.wp-element-button:hover,
.wp-block-button__link:hover,
button:hover:not(:disabled) {
	transform: translateY(-1px);
}

.wp-element-button:active,
.wp-block-button__link:active,
button:active:not(:disabled) {
	transform: translateY(0);
}

.wp-block-button.is-style-outline > .wp-block-button__link {
	background: transparent;
	border: 1px solid var(--wp--preset--color--contrast);
	color: var(--wp--preset--color--contrast);
}

.wp-block-button.is-style-outline > .wp-block-button__link:hover {
	background: var(--wp--preset--color--contrast);
	color: var(--wp--preset--color--surface);
}

button:disabled,
input:disabled,
.is-loading .wp-element-button {
	cursor: not-allowed;
	opacity: 0.55;
}

input:not([type="checkbox"]):not([type="radio"]),
select,
textarea {
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--wp--preset--color--divider);
	border-radius: 12px;
	color: var(--wp--preset--color--contrast);
	font: inherit;
	/*
	 * iOS Safari zooms the whole page when a focused control is under 16px,
	 * and never zooms back out. The theme's body text is 15px on a phone, so
	 * `font: inherit` above was handing every field, select and textarea a
	 * size that triggers it -- including the three checkout card fields. This
	 * has to come after the shorthand, or the shorthand resets it.
	 */
	font-size: max(16px, 1rem);
	min-height: 48px;
	padding: 11px 14px;
}

/*
 * The variation selector's line box and its vertical padding.
 *
 * Three stylesheets meet on this one control. WooCommerce loads
 * woocommerce-blocktheme.css on every block theme, and it sets
 * `.woocommerce table.variations tr td select { height: 3em; padding: .9em 1.1em }`
 * at (0,2,4), which outranks the bare `select` rule above at (0,0,1). Neither
 * the 48px floor nor the 11px padding written there reaches this control. The
 * iOS font-size floor at the end of this file is !important, so that `3em`
 * resolves against 16px: a locked 48px box with 14.4px of padding above and
 * below the text, leaving 17.2px of content.
 *
 * Into those 17.2px, `font: inherit` copies the cell's line-height, and the
 * cell takes `line-height: 2em` from WooCommerce's own
 * `.woocommerce div.product form.cart .variations td`. That selector matches
 * because WooCommerce wraps the product in `<div class="wp-block-group
 * woocommerce product">`, so 2em against the cell's ~15px is a ~30px line in a
 * 17.2px box. The 13px of overflow comes off both ends at once, which is why
 * "One Vial 10mg" arrives with its top flattened and its descenders cut.
 *
 * Both halves are needed. `line-height: normal` brings the line box down to
 * 19px, which still overflows 17.2px by enough to shave the tail off the g;
 * restoring the theme's own 11px opens the content box to 24px and clears it.
 * `height: 3em` is deliberately left alone -- at 16px it is already the same
 * 48px tap target the rule above asks for.
 *
 * The selector reaches for `td.value` (0,3,3) rather than the `tr td`
 * WooCommerce uses (0,2,4) so that it wins on specificity rather than on which
 * stylesheet happens to be enqueued last. Padding is set on the block axis
 * only: the 3em of padding-right that keeps the dropdown arrow off the text
 * comes from a different WooCommerce rule and has to survive.
 *
 * This replaces a `line-height: normal` that was gated behind
 * `min-width: 601px`. The gate was never right -- the box is the same 17.2px at
 * every width -- and it left the phone with the whole 13px of overflow.
 */
.woocommerce table.variations td.value select {
	line-height: normal;
	padding-block: 11px;
}

@media (min-width: 600px) {
	.oe-site-header {
		backdrop-filter: saturate(150%) blur(18px);
	}
}

input:not([type="checkbox"]):not([type="radio"]):focus,
select:focus,
textarea:focus {
	border-color: var(--wp--preset--color--accent);
	box-shadow: 0 0 0 3px rgb(0 113 227 / 16%);
	outline: 0;
}

.oe-notice {
	font-size: 0.82rem;
	letter-spacing: 0.01em;
	padding-block: 8px;
}

.oe-notice p {
	margin: 0;
}

.oe-header-template {
	display: contents;
}

.oe-site-header {
	background: rgb(255 255 255 / 90%) !important;
	border-bottom: 1px solid rgb(29 29 31 / 9%);
	position: sticky;
	top: 0;
	z-index: 50;
}

.oe-site-nav {
	min-height: 56px;
}

.oe-brand-navigation,
.oe-nav-actions {
	gap: clamp(14px, 2.4vw, 34px);
}

.oe-brand {
	display: flex;
	flex: 0 0 auto;
	line-height: 0;
}

.oe-brand img {
	height: auto;
	width: clamp(126px, 11vw, 154px);
}

.oe-primary-navigation .wp-block-navigation-item__content,
.oe-nav-actions a {
	align-items: center;
	color: var(--wp--preset--color--contrast);
	display: flex;
	font-weight: 400;
	min-height: 44px;
	text-decoration: none;
}

.oe-nav-actions a,
.oe-nav-actions button {
	justify-content: center;
	min-width: 44px;
}

.oe-primary-navigation .wp-block-navigation-item__content:hover,
.oe-nav-actions a:hover {
	color: var(--wp--preset--color--accent-text);
}

/*
 * Header search.
 *
 * Two controls rather than one, because a single field cannot be in the
 * action row and in a panel under it at the same time, and the two sizes want
 * different things. Above 900px the field is inline in the row: the width is
 * there, and putting the main way through the catalog behind a click costs
 * more than the space it saves. At 900px and below the row is already
 * carrying a logo, a menu button, an account icon and a cart, so the field
 * steps out of it and leaves a button behind. Only one of the two is ever
 * rendered, so there is never a second search landmark or a duplicate field.
 *
 * Everything that hides the panel is written under .oe-search-js, a class the
 * head script adds and then takes back if assets/js/site-search.js never
 * reports in. Without it the panel is an ordinary always-open row and the
 * button is not shown at all, so the field survives a script that fails.
 */
.oe-search-form {
	align-items: center;
	background: var(--wp--preset--color--base);
	border: 1px solid var(--wp--preset--color--divider);
	border-radius: 999px;
	display: flex;
	gap: 2px;
	min-width: 0;
}

.oe-search-form:focus-within {
	background: var(--wp--preset--color--surface);
	border-color: var(--wp--preset--color--accent);
}

/*
 * Suggestions hang off the form rather than the field, because the form is the
 * pill and its edges are the ones the list should line up with.
 */
.oe-search-form {
	position: relative;
}

/*
 * Above the header's own stacking, or the list would be drawn behind the row
 * below it. The panel form sits inside a header that is already raised, so
 * this only has to beat its siblings.
 */
.oe-suggest {
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--wp--preset--color--divider);
	border-radius: 14px;
	box-shadow: 0 18px 44px rgb(0 26 65 / 16%);
	left: 0;
	list-style: none;
	margin: 6px 0 0;
	/*
	 * Six rows and the see-all row fit inside this; anything taller would run
	 * off a short landscape phone, so the list scrolls instead of the page.
	 */
	max-height: min(58vh, 420px);
	overflow-y: auto;
	padding: 6px;
	position: absolute;
	right: 0;
	top: 100%;
	z-index: 30;
}

.oe-suggest-item {
	align-items: center;
	border-radius: 10px;
	color: var(--wp--preset--color--contrast);
	cursor: pointer;
	display: flex;
	gap: 10px;
	/* The tap-target floor, which a 40px thumbnail alone would sit under. */
	min-height: 44px;
	padding: 6px 8px;
}

.oe-suggest-item.is-active,
.oe-suggest-item:hover {
	background: var(--wp--preset--color--mist);
}

.oe-suggest-thumb {
	border-radius: 8px;
	flex: 0 0 auto;
	height: 40px;
	object-fit: cover;
	width: 40px;
}

.oe-suggest-text {
	display: flex;
	flex-direction: column;
	gap: 1px;
	min-width: 0;
}

/*
 * A compound name that outruns the row is truncated rather than wrapped: the
 * distinguishing part of these names is the front, and a wrapped row changes
 * height as the visitor types, which makes the list jump under the pointer.
 */
.oe-suggest-name {
	font-size: var(--wp--preset--font-size--medium);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.oe-suggest-price {
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--small);
}

/*
 * The last row is a different kind of thing — it runs the search rather than
 * opening a product — so it reads as a link and is separated from the results.
 */
.oe-suggest-all {
	border-top: 1px solid var(--wp--preset--color--divider);
	color: var(--wp--preset--color--accent-text);
	font-size: var(--wp--preset--font-size--small);
	margin-top: 4px;
	padding-top: 12px;
}

/*
 * The field takes its width out of whatever the brand, the links and the two
 * shop icons leave, down to nothing rather than pushing the row wider. At
 * 901px that is about 170px, which still shows a compound name.
 */
.oe-search-inline {
	flex: 0 1 340px;
}

/*
 * The global input rule owns background, border, radius and a 48px floor. In
 * the pill the field is only the text and the pill carries the shape, so all
 * four have to be undone at a weight that beats it.
 */
.oe-search-form input.oe-search-field {
	background: none;
	border: 0;
	border-radius: 999px;
	flex: 1 1 auto;
	min-height: 42px;
	min-width: 0;
	padding: 0 6px 0 14px;
	width: 100%;
}

/*
 * That same rule zeroes the outline on a focused input and answers with a
 * shadow. The shadow spreads outside the field, which inside the pill puts a
 * blue smudge across the pill's own edge and under the submit button, so it
 * goes; the pill's :focus-within border is the mouse-focus state instead.
 */
.oe-search-form input.oe-search-field:focus {
	box-shadow: none;
}

/*
 * With the shadow gone the keyboard ring has to be the field's own, written
 * heavy enough to beat the outline: 0 the same rule sets.
 */
.oe-search-form input.oe-search-field:focus-visible {
	outline: 3px solid var(--wp--preset--color--accent);
	outline-offset: 2px;
}

.oe-search-submit {
	align-items: center;
	background: var(--wp--preset--color--accent);
	border: 0;
	border-radius: 999px;
	color: var(--wp--preset--color--surface);
	cursor: pointer;
	display: inline-flex;
	flex: 0 0 auto;
	justify-content: center;
	min-height: 42px;
	min-width: 44px;
	padding: 0;
}

.oe-search-submit:hover {
	background: var(--wp--preset--color--accent-text);
}

.oe-search-toggle {
	align-items: center;
	background: none;
	border: 0;
	color: var(--wp--preset--color--contrast);
	cursor: pointer;
	display: none;
	justify-content: center;
	min-height: 44px;
	min-width: 44px;
	padding: 0;
}

.oe-search-toggle:hover {
	color: var(--wp--preset--color--accent-text);
}

/* The panel belongs to the small sizes; above them the inline field is the
   header's only search. */
.oe-search-panel {
	display: none;
}

/*
 * The panel is a direct child of the constrained header, so the layout would
 * cap it at the 720px content size and centre it there. It is a row of the
 * header rather than content inside it, and the header's own gutters are the
 * only inset it should have.
 */
.oe-site-header .oe-search-panel {
	margin-block: 0;
	margin-inline: 0;
	max-width: none;
}

@media (min-width: 901px) {

	/*
	 * The field is paid for out of the action row, and the row can only give
	 * it what the brand and the links do not need. Letting the brand cluster
	 * shrink instead wraps the four links onto a second line and makes the
	 * whole header taller, which is a worse trade than a shorter field.
	 */
	.oe-site-nav > .oe-brand-navigation {
		flex: 0 0 auto;
	}

	.oe-site-nav > .oe-nav-actions {
		flex: 1 1 auto;
		justify-content: flex-end;
		min-width: 0;
	}
}

.oe-visually-hidden {
	clip-path: inset(50%);
	height: 1px;
	overflow: hidden;
	position: absolute;
	white-space: nowrap;
	width: 1px;
}

.oe-home {
	padding-bottom: clamp(72px, 9vw, 132px);
}

.oe-hero {
	padding-block: clamp(56px, 7vw, 100px) clamp(40px, 5vw, 64px);
}

.oe-hero h1 {
	margin-inline: auto;
	max-width: 18ch;
}

.oe-hero-copy {
	line-height: 1.35;
	margin-inline: auto;
	max-width: 650px;
}

.oe-hero .wp-block-buttons {
	margin-top: clamp(26px, 3vw, 38px);
}

/*
 * The two hero calls to action read as a pair and should stay on one line.
 * With the theme's own spacing scale in force the row's gap is 32px, which
 * pushed them 14px past the gutters on a 390px screen and wrapped them.
 *
 * Between 360px and 600px they share the row equally rather than sizing to
 * their labels: two even buttons look deliberate where two odd ones look
 * broken, and equal flex basis guarantees they fit whatever the label lengths.
 * Below 360px the labels alone need more room than the gutters leave, so they
 * stack at full width there -- a bigger tap target, and honest about the space.
 */
@media (max-width: 359px) {
	.oe-hero .wp-block-buttons .wp-block-button,
	.oe-hero .wp-block-buttons .wp-block-button__link {
		width: 100%;
	}
}

@media (min-width: 360px) {
	.oe-hero .wp-block-buttons {
		flex-wrap: nowrap;
		gap: 12px;
	}

	.oe-hero .wp-block-buttons .wp-block-button {
		flex: 1 1 0;
		min-width: 0;
	}

	.oe-hero .wp-block-buttons .wp-block-button__link {
		align-items: center;
		display: flex;
		justify-content: center;
		/* 44px is the tap-target floor; the label is shorter than the button
		   at every width in this band, so it never sets the height. */
		min-height: 44px;
		padding-inline: 14px;
		white-space: nowrap;
		width: 100%;
	}
}

@media (min-width: 600px) {
	/* Past the narrow band there is room to spare, so let each button size to
	   its own label again and give the pair back its breathing room. */
	.oe-hero .wp-block-buttons {
		gap: clamp(14px, 2vw, 24px);
	}

	.oe-hero .wp-block-buttons .wp-block-button {
		flex: 0 0 auto;
	}

	.oe-hero .wp-block-buttons .wp-block-button__link {
		display: inline-flex;
		padding-inline: 22px;
		width: auto;
	}
}

.oe-hero-stage {
	animation: oe-stage-reveal 900ms cubic-bezier(0.16, 1, 0.3, 1) both;
	position: relative;
}

.oe-hero-media {
	border-radius: 16px;
	box-shadow: 0 22px 58px rgb(0 26 65 / 13%);
	margin: 0;
	overflow: hidden;
	position: relative;
}

.oe-hero-media img {
	aspect-ratio: 16 / 10;
	display: block;
	height: auto;
	object-fit: cover;
	width: 100%;
}

.oe-hero-media figcaption {
	background: var(--wp--preset--color--surface);
	color: var(--wp--preset--color--muted);
	font-size: 0.78rem;
	margin: 0;
	padding: 10px 14px;
	text-align: center;
}

.oe-hero-data {
	backdrop-filter: saturate(135%) blur(18px);
	background: rgb(255 255 255 / 90%);
	border: 1px solid rgb(255 255 255 / 55%);
	border-radius: 14px;
	bottom: 52px;
	box-shadow: 0 14px 40px rgb(0 26 65 / 14%);
	gap: 18px 30px;
	left: 22px;
	padding: 18px 22px;
	position: absolute;
	right: 22px;
}

.oe-hero-data p {
	display: grid;
	font-size: var(--wp--preset--font-size--small);
	gap: 2px;
	margin: 0;
}

.oe-hero-data strong {
	font-weight: 600;
}

.oe-hero-data span {
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--small);
}

/*
 * Hero motion arming.
 *
 * `oe-motion` goes on <html> from the inline head script, and only when the
 * sequence in assets/js/hero-motion.js can actually run. Without it — no
 * JavaScript, a reduced-motion preference, or a script that never arrived —
 * none of this applies and the hero renders normally behind the CSS stage
 * reveal. hero-motion.js writes each element's real start state as an inline
 * style before it lifts this gate, then removes the class when it finishes.
 */
.oe-motion .oe-hero,
.oe-motion .oe-hero-media,
.oe-motion .oe-hero-data {
	opacity: 0;
}

/* anime.js drives the stage while armed; the keyframe is the fallback. */
.oe-motion .oe-hero-stage {
	animation: none;
}

/*
 * The word spans anime.js splits the headline into: an outer span clipping
 * the word and an inner span carrying it. Both need a block box for the clip
 * to hold and the transform to read, and the pair only exists while the
 * splitter is mounted — it reverts the markup once the sequence ends.
 */

/*
 * Cold-chain stage layer.
 *
 * hero-motion.js builds this over the photograph while the sequence runs and
 * removes it at the end; none of it exists in the served markup, so the hero
 * without JavaScript is the plain figure. Its box is set inline to match the
 * part of the photograph the figure actually shows, which lets everything
 * inside be positioned as a percentage of the shot's own 1600x1067 frame.
 */
.oe-hero-fx {
	pointer-events: none;
	position: absolute;
}

/*
 * The plate — the same photograph with the rack empty — and the three vial
 * sprites that stand back in on top of it. Held at zero until the plate has
 * decoded, since it is the only thing hiding the vials in the shot below.
 */
.oe-hero-fx-plate-layer {
	inset: 0;
	opacity: 0;
	position: absolute;
}

.oe-hero-fx-plate-layer.is-ready {
	opacity: 1;
}

/*
 * These sit inside the figure, so `.oe-hero-media img` reaches them and would
 * force the storefront's 16/10 crop onto artwork that is neither the figure
 * nor 16/10. Both are reset here, and scoped under .oe-hero-fx so they
 * actually outrank that rule rather than tying with it on specificity.
 */
.oe-hero-fx .oe-hero-fx-plate,
.oe-hero-fx .oe-hero-fx-vial {
	aspect-ratio: auto;
	display: block;
	object-fit: fill;
	position: absolute;
}

.oe-hero-fx .oe-hero-fx-plate {
	height: 100%;
	inset: 0;
	width: 100%;
}

.oe-hero-fx .oe-hero-fx-vial {
	height: auto;
}

.oe-hero-fx-helix {
	height: 100%;
	inset: 0;
	overflow: visible;
	position: absolute;
	width: 100%;
}

/*
 * The helix reads as a helix rather than a woven ribbon because the arcs on
 * the far side of each turn are drawn first, thinner and in the deep navy,
 * and the near arcs last in Origin Blue. Hairlines, not rules: the stroke
 * keeps its width at every figure size.
 */
.oe-hero-fx-strand {
	fill: none;
	stroke-linecap: round;
	vector-effect: non-scaling-stroke;
}

.oe-hero-fx-strand.is-near {
	opacity: 0.88;
	stroke: var(--wp--preset--color--accent);
	stroke-width: 2.4;
}

.oe-hero-fx-strand.is-far {
	opacity: 0.32;
	stroke: var(--wp--preset--color--accent-deep);
	stroke-width: 1.5;
}

.oe-hero-fx-rung {
	stroke: var(--wp--preset--color--accent-text);
	stroke-linecap: round;
	stroke-width: 1.1;
	vector-effect: non-scaling-stroke;
}

.oe-hero h1 span {
	display: inline-block;
}


.oe-assurance-rail {
	border-bottom: 1px solid var(--wp--preset--color--divider);
	gap: 24px;
	margin-top: clamp(38px, 5vw, 66px);
	padding: 0 4px 30px;
}

.oe-assurance-rail p {
	flex: 1 1 220px;
	font-size: 0.96rem;
	line-height: 1.45;
	margin: 0;
}

.oe-assurance-rail span {
	color: var(--wp--preset--color--muted);
}

.oe-proof-stage {
	border-radius: 16px;
	overflow: hidden;
	padding: clamp(44px, 7vw, 96px);
}

.oe-proof-stage,
.oe-order-journey,
.oe-catalog-preview,
.oe-closing-stage {
	margin-top: clamp(92px, 11vw, 156px);
}

.oe-proof-stage {
	box-shadow: 0 24px 64px rgb(0 26 65 / 16%);
	position: relative;
}

/*
 * Leader lines from the specification rows to the vial they describe, drawn
 * into the stage by assets/js/proof-stage.js once the section scrolls into
 * view. The section is authored without them; nothing here is load-bearing.
 */
.oe-proof-leads {
	height: 100%;
	inset: 0;
	pointer-events: none;
	position: absolute;
	width: 100%;

	/*
	 * The stage is a constrained-layout group, so WordPress caps and centres
	 * every direct child at the 720px content size. This one is an overlay on
	 * the whole stage, not content inside it.
	 */
	margin: 0;
	max-width: none;
}

.oe-proof-lead {
	fill: none;
	stroke: rgb(255 255 255 / 38%);
	stroke-linecap: round;
	stroke-linejoin: round;
	stroke-width: 1.25;
	vector-effect: non-scaling-stroke;
}

.oe-proof-lead-dot {
	fill: var(--wp--preset--color--accent);
	stroke: rgb(255 255 255 / 55%);
	stroke-width: 1;
	vector-effect: non-scaling-stroke;
}

/* Reduced motion and no-IntersectionObserver: placed, not drawn. */
.oe-proof-leads.is-settled .oe-proof-lead,
.oe-proof-leads.is-settled .oe-proof-lead-dot {
	opacity: 1;
}

.oe-proof-stage .wp-block-columns {
	gap: clamp(48px, 8vw, 120px);
}

.oe-proof-stage p {
	color: #d7e8ff;
}

.oe-proof-stage p a {
	color: #ffffff;
}

.oe-proof-list {
	list-style: none;
	margin: clamp(28px, 4vw, 48px) 0 0;
	padding: 0;
}

.oe-proof-list li {
	border-top: 1px solid rgb(255 255 255 / 20%);
	display: grid;
	gap: 3px;
	padding: 22px 0;
}

.oe-proof-list li:last-child {
	border-bottom: 1px solid rgb(255 255 255 / 20%);
}

.oe-proof-list strong {
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 600;
}

.oe-proof-list span {
	color: #b9d6f4;
	font-size: var(--wp--preset--font-size--small);
}

.oe-proof-media {
	border: 1px solid rgb(255 255 255 / 16%);
	border-radius: 12px;
	box-shadow: 0 24px 58px rgb(0 0 0 / 22%);
	margin: 0;
	overflow: hidden;
}

.oe-proof-media img {
	aspect-ratio: 4 / 5;
	display: block;
	height: auto;
	object-fit: cover;
	object-position: 68% center;
	width: 100%;
}

.oe-proof-media figcaption {
	background: rgb(0 9 24 / 82%);
	color: #b9d6f4;
	font-size: var(--wp--preset--font-size--small);
	margin: 0;
	padding: 10px 12px;
}

.oe-order-journey > .wp-block-columns {
	gap: clamp(48px, 9vw, 132px);
}

.oe-order-path {
	counter-reset: order-step;
	list-style: none;
	margin: 0;
	padding: 0;
}

.oe-order-path li {
	border-top: 1px solid var(--wp--preset--color--divider);
	counter-increment: order-step;
	display: grid;
	gap: 3px 20px;
	grid-template-columns: 42px 1fr;
	padding: 22px 0;
}

.oe-order-path li:last-child {
	border-bottom: 1px solid var(--wp--preset--color--divider);
}

/*
 * The step number owns the first column; everything else is placed in the
 * second, explicitly. Relying on auto-placement meant any extra inline
 * element inside the item — the Site Editor leaves a stray whitespace span
 * behind when a line is rewritten — pushed the description onto a third
 * row, where auto-placement put it back in the 42px number column and
 * broke it to roughly one syllable a line.
 */
.oe-order-path li::before {
	color: var(--wp--preset--color--accent-text);
	content: counter(order-step, decimal-leading-zero);
	font-variant-numeric: tabular-nums;
	grid-column: 1;
	grid-row: 1;
}

.oe-order-path li > * {
	grid-column: 2;
}

.oe-order-path strong {
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 600;
}

.oe-order-path span {
	color: var(--wp--preset--color--muted);
}

.oe-catalog-preview > .wp-block-group:first-child {
	align-items: flex-end;
	border-bottom: 1px solid var(--wp--preset--color--divider);
	margin-bottom: 36px;
	padding-bottom: 24px;
}

.oe-catalog-preview > .wp-block-group:first-child p {
	margin: 0;
}

.wp-block-woocommerce-product-collection .wc-block-product,
.wp-block-post-template.products-block-post-template > li {
	background: transparent;
}

.oe-product-media,
.wp-block-woocommerce-product-image {
	background: var(--wp--preset--color--surface);
	border-radius: 16px;
	overflow: hidden;
}

.oe-product-media img,
.wp-block-woocommerce-product-image img {
	aspect-ratio: 1;
	object-fit: contain;
	transition: transform 400ms cubic-bezier(0.16, 1, 0.3, 1);
}

.wc-block-product:hover .oe-product-media img,
.wc-block-product:hover .wp-block-woocommerce-product-image img,
.oe-search-results > li:hover .oe-product-media img {
	transform: scale(1.025);
}

.wp-block-post-title a {
	color: var(--wp--preset--color--contrast);
	text-decoration: none;
}

.wp-block-woocommerce-product-price,
.wc-block-components-product-price {
	font-variant-numeric: tabular-nums;
	font-weight: 600;
}

.oe-empty-catalog {
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--wp--preset--color--divider);
	border-radius: 16px;
	padding: clamp(40px, 6vw, 72px);
	text-align: center;
}

.oe-empty-catalog h2,
.oe-empty-catalog h3,
.oe-empty-catalog p {
	margin-inline: auto;
}

.oe-closing-stage {
	border-top: 1px solid var(--wp--preset--color--divider);
	padding-top: clamp(64px, 8vw, 108px);
	text-align: center;
}

.oe-closing-stage h2,
.oe-closing-stage p {
	margin-inline: auto;
}

main.wp-block-group:not(.oe-home):not(.oe-modern) {
	min-height: 54vh;
	padding-block: clamp(54px, 8vw, 108px);
}

main.wp-block-group:not(.oe-home):not(.oe-modern) > :first-child {
	margin-top: 0;
}

.oe-content-page > .wp-block-post-title {
	max-width: 14ch;
}

.oe-content-page > .wp-block-post-content {
	margin-top: clamp(36px, 5vw, 64px);
}

.oe-content-page .wp-block-post-content h2,
.oe-legal-page .wp-block-post-content h2 {
	margin-top: clamp(56px, 8vw, 88px);
}

.oe-content-page .wp-block-heading[id] {
	scroll-margin-top: 88px;
}

.oe-legal-page .wp-block-post-content > h1:first-child {
	max-width: 20ch;
}

.oe-document-nav {
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--wp--preset--color--divider);
	border-radius: 16px;
	gap: 10px 26px;
	margin-block: clamp(34px, 5vw, 58px) clamp(54px, 7vw, 80px);
	padding: 18px 22px;
}

.oe-document-nav p {
	margin: 0;
}

.oe-document-nav a {
	font-weight: 600;
	text-decoration: none;
}

.oe-support-guide,
.oe-contact-action {
	margin-top: clamp(72px, 9vw, 120px);
}

.oe-support-list {
	list-style: none;
	margin: clamp(32px, 5vw, 56px) 0 0;
	padding: 0;
}

.oe-support-list li {
	border-top: 1px solid var(--wp--preset--color--divider);
	display: grid;
	gap: 4px;
	padding: 22px 0;
}

.oe-support-list li:last-child {
	border-bottom: 1px solid var(--wp--preset--color--divider);
}

.oe-support-list strong {
	font-size: var(--wp--preset--font-size--medium);
}

.oe-support-list span {
	color: var(--wp--preset--color--muted);
}

.oe-contact-action {
	border-radius: 16px;
	box-shadow: 0 24px 64px rgb(0 26 65 / 16%);
	padding: clamp(48px, 7vw, 88px);
	text-align: center;
}

.oe-contact-action h2,
.oe-contact-action p {
	margin-inline: auto;
}

.oe-contact-email {
	background: var(--wp--preset--color--accent);
	border-radius: 999px;
	color: var(--wp--preset--color--surface);
	display: inline-flex;
	font-weight: 600;
	justify-content: center;
	margin-top: 18px;
	padding: 12px 22px;
	text-decoration: none;
}

.oe-contact-email:hover {
	background: var(--wp--preset--color--surface);
	color: var(--wp--preset--color--accent-deep);
}

/*
 * The address as it appears inside a clause of the legal documents: part of
 * the sentence, not a control. Typed as a selector with an element so it beats
 * the global link colour that theme.json prints at class specificity.
 */
a.oe-contact-email-inline {
	background: none;
	border-radius: 0;
	color: inherit;
	display: inline;
	font-size: 10px;
	font-weight: inherit;
	margin: 0;
	padding: 0;
	text-decoration: underline;
	text-underline-offset: 2px;
	overflow-wrap: anywhere;
}

.oe-shop-intro {
	padding-block: clamp(34px, 5vw, 64px) clamp(30px, 4vw, 50px);
	text-align: center;
}

.oe-store-page {
	padding-top: clamp(32px, 4vw, 56px) !important;
}

.oe-shop-intro h1,
.oe-shop-intro p {
	margin-inline: auto;
}

.oe-shop-intro h1 {
	max-width: 18ch;
}

.oe-shop-intro p {
	max-width: 720px;
}

.oe-catalog-tools {
	border-block: 1px solid var(--wp--preset--color--divider);
	margin-bottom: 42px;
	padding-block: 16px;
}

/*
 * Search results.
 *
 * A result is read as a catalog tile, because most of them are products and a
 * product that looks like a blog post reads as a different site. The card is
 * the archive's: the same square media box, the same category line above the
 * title, the same price. The grid is auto-filled rather than set to a column
 * count, so the same markup is one column on a phone and four on a desk
 * without a breakpoint deciding it.
 */
.oe-search-head {
	border-bottom: 1px solid var(--wp--preset--color--divider);
	padding-bottom: clamp(16px, 2.5vw, 24px);
}

/*
 * A search term is whatever the visitor typed, and some of them are a batch
 * identifier with no spaces in it. At 44px a long one would run off the side
 * of the page if it were not allowed to break mid-word.
 */
.oe-search-page .wp-block-query-title {
	max-width: 24ch;
	overflow-wrap: anywhere;
}

/* The term is the one part of the heading the visitor wrote. */
.oe-search-page .wp-block-query-title span {
	color: var(--wp--preset--color--accent-text);
}

.oe-search-head .oe-search-count {
	color: var(--wp--preset--color--muted);
	font-size: var(--wp--preset--font-size--small);
	margin-block-start: 10px;
}

/*
 * Written out rather than left to the block's own grid layout, because this
 * is the rule that keeps the page off a horizontal scrollbar. min() caps the
 * track at the width actually available, so a 256px minimum can never insist
 * on a column wider than a 320px screen has room for; the count of columns is
 * then whatever fits, from one on a phone to four on a desk, with no
 * breakpoint deciding it.
 */
.oe-search-page .oe-search-results {
	display: grid;
	gap: clamp(22px, 3vw, 34px);
	grid-template-columns: repeat(auto-fill, minmax(min(16rem, 100%), 1fr));
}

.oe-search-results {
	list-style: none;
	margin: 0;
	padding: 0;
}

.oe-search-results > li {
	display: flex;
	flex-direction: column;
	gap: 8px;
	min-width: 0;
}

.oe-search-results > li > * {
	margin-block: 0;
}

.oe-search-results .wp-block-post-title {
	line-height: 1.2;
	overflow-wrap: anywhere;
}

/*
 * Three lines of context, and the same three whatever the excerpt holds:
 * results are compared down a column, and a ragged one is harder to scan
 * than a short one.
 */
.oe-search-results .wp-block-post-excerpt__excerpt {
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 3;
	display: -webkit-box;
	margin: 0;
	overflow: hidden;
}

/*
 * A page or a policy answer has no product image, so among the tiles it would
 * be a title floating in white space. The panel the catalog uses for its own
 * empty state gives it the same weight as the cards beside it.
 */
.oe-search-results > li:not(.type-product) {
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--wp--preset--color--divider);
	border-radius: 16px;
	padding: clamp(18px, 3vw, 26px);
}

.oe-search-page .wp-block-query-no-results {
	margin-inline: auto;
	max-width: 760px;
}

/*
 * The same box the catalog's own empty state uses, because this is the same
 * message in the same position and a bare rule with nothing inside it leaves
 * the text flush against the border on any screen under 760px.
 */
.oe-search-empty {
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--wp--preset--color--divider);
	border-radius: 16px;
	padding: clamp(28px, 5vw, 56px);
}

.oe-search-empty h2,
.oe-search-empty p {
	margin-inline: auto;
}

.oe-search-empty .wp-block-search {
	margin-inline: auto;
	max-width: 440px;
}

/* The same control as the header's, so it takes the same shape; the rest of
   it is the theme's own input. */
.oe-search-empty .wp-block-search .wp-block-search__input {
	border-radius: 999px;
	padding-inline: 18px;
}

.oe-search-page .oe-search-pagination {
	border-top: 1px solid var(--wp--preset--color--divider);
	gap: 8px;
	margin-block-start: clamp(40px, 5vw, 64px);
	padding-top: clamp(18px, 3vw, 28px);
}

.oe-search-page .oe-search-pagination .wp-block-query-pagination-numbers {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	justify-content: center;
}

/*
 * Page links are the only control on this page a thumb has to hit, and a page
 * number is one or two characters, so they are sized rather than padded. Ten
 * of them wrap rather than run off a 320px screen.
 */
.oe-search-page .oe-search-pagination .page-numbers,
.oe-search-page .oe-search-pagination .wp-block-query-pagination-previous,
.oe-search-page .oe-search-pagination .wp-block-query-pagination-next {
	align-items: center;
	border-radius: 999px;
	display: inline-flex;
	justify-content: center;
	min-height: 44px;
	min-width: 44px;
	padding-inline: 12px;
	text-decoration: none;
}

.oe-search-page .oe-search-pagination .page-numbers:hover,
.oe-search-page .oe-search-pagination .wp-block-query-pagination-previous:hover,
.oe-search-page .oe-search-pagination .wp-block-query-pagination-next:hover {
	background: var(--wp--preset--color--mist);
}

.oe-search-page .oe-search-pagination .page-numbers.current {
	background: var(--wp--preset--color--contrast);
	color: var(--wp--preset--color--surface);
}

.oe-product-layout {
	align-items: flex-start;
	gap: clamp(42px, 7vw, 96px);
}

.oe-purchase-panel {
	background: var(--wp--preset--color--surface);
	border: 1px solid rgb(29 29 31 / 7%);
	border-radius: 16px;
	box-shadow: 0 18px 48px rgb(0 26 65 / 8%);
	padding: clamp(28px, 4vw, 52px);
}

.oe-purchase-panel > :first-child,
.oe-purchase-summary > :first-child {
	margin-top: 0;
}

.oe-purchase-summary,
.oe-product-information {
	display: contents;
}

.oe-product-boundary {
	border-top: 1px solid var(--wp--preset--color--divider);
	padding-top: 20px;
}

/*
 * "Purchase Option", and the column that is never wide enough for it.
 *
 * The variations form is a two-column table: WooCommerce 11.1.0 still emits
 * table.variations > tbody > tr > th.label + td.value from its classic
 * variable.php, which is what wp:woocommerce/add-to-cart-form renders here.
 * Nothing in WooCommerce stacks that row. woocommerce-blocktheme.css is the
 * sheet that styles this table on a block theme, and it sets the table itself
 * to `display: block` but leaves the row in table layout at every width.
 *
 * Whenever the column is narrow the select wants the width more than the label
 * does, so automatic table layout takes it from the label column, and a text
 * column's minimum is its longest word: "Purchase Option" breaks after
 * "Purchase" beside a control that is not using the room it took.
 *
 * Unconditional, with no media query, because the viewport is the wrong thing
 * to ask. What squeezes the label is the width of `.oe-purchase-panel`, and
 * that does not fall with the viewport -- it drops when the layout goes to two
 * columns. `.oe-product-layout` is a core columns block, so core un-stacks it
 * at 782px, and the panel is then half the page: measured, the label wraps from
 * 390px all the way to about 1020px, and is at its worst around 900px, where
 * the panel is narrower than it is on a phone. A breakpoint would have to be
 * both a phone rule and a laptop rule and would still be a guess about a width
 * it cannot see.
 *
 * Stacked, each gets the whole row -- the label says what it is, the select
 * shows what is chosen, and they are read in that order anyway. Core marks the
 * table role="presentation", so there are no table semantics to lose, and the
 * label keeps its `for` whatever the cells display as. On a wide screen this
 * moves the label from beside the field to above it; to put that back, wrap
 * this block in `@media (max-width: 900px)` and accept the wrap from 901px up.
 *
 * Only padding is adjusted. The cells have no bottom rule to drop --
 * WooCommerce zeroes their borders from
 * `.woocommerce div.product form.cart .variations th` at a specificity the
 * shared `.woocommerce table th` rule further down does not reach -- and the
 * 32px below each cell is a `--wp--style--block-gap` from
 * woocommerce-blocktheme.css, which is right under the select and wrong
 * between a label and the field it belongs to. The table is already
 * `display: block` from that same sheet, so only the row and the cells change.
 */
.woocommerce table.variations tbody,
.woocommerce table.variations tr,
.woocommerce table.variations th.label,
.woocommerce table.variations td.value {
	display: block;
}

.woocommerce table.variations th.label {
	padding-bottom: 4px;
}

.woocommerce table.variations td.value {
	padding-top: 0;
}

@media (min-width: 901px) {
	.oe-product-layout {
		column-gap: clamp(42px, 7vw, 96px);
		flex-wrap: wrap !important;
		row-gap: clamp(42px, 5vw, 64px);
	}

	.oe-product-gallery,
	.oe-purchase-summary {
		flex: 1 1 0;
		min-width: 0;
	}

	/* ponytail: Current products have one image; reassess when multi-image galleries are added. */
	.oe-product-gallery .woocommerce-product-gallery {
		opacity: 1 !important;
	}

	.oe-purchase-panel {
		display: contents;
	}

	.oe-purchase-summary {
		background: var(--wp--preset--color--surface);
		border: 1px solid rgb(29 29 31 / 7%);
		border-radius: 16px;
		box-shadow: 0 18px 48px rgb(0 26 65 / 8%);
		display: block;
		padding: clamp(28px, 4vw, 52px);
	}

	.oe-product-information {
		display: block;
		flex: 0 0 100%;
		min-width: 0;
	}
}

.woocommerce-breadcrumb,
.wc-block-breadcrumbs {
	color: var(--wp--preset--color--muted);
	font-size: 0.86rem;
}

.wp-block-table table,
.woocommerce table {
	border-collapse: collapse;
	font-variant-numeric: tabular-nums;
	width: 100%;
}

.wp-block-table th,
.wp-block-table td,
.woocommerce table th,
.woocommerce table td {
	border-bottom: 1px solid var(--wp--preset--color--divider);
	padding: 14px 10px;
	text-align: left;
}

.wc-block-components-notice-banner,
.woocommerce-message,
.woocommerce-info,
.woocommerce-error {
	background: var(--wp--preset--color--surface);
	border: 0;
	border-radius: 12px;
	box-shadow: 0 10px 30px rgb(0 26 65 / 8%);
	color: var(--wp--preset--color--contrast);
	padding: 16px 18px;
}

/*
 * Stripe's payment form lives in an iframe and takes its colours from the
 * page: it uses the background of the first element in a fixed list that is
 * not transparent, trying the payment option, the checkout form and block,
 * then main, then the first .wp-block-group. With the checkout transparent,
 * that group is the navy research-use bar at the top, so Stripe switched to
 * its dark theme and set the payment methods as dark text on navy. Giving the
 * checkout block the page's own ground ends the search there; nothing visible
 * changes.
 */
.wc-block-checkout {
	background-color: var(--wp--preset--color--base);
}

.wp-block-woocommerce-empty-cart-block,
.wp-block-query-no-results {
	background: var(--wp--preset--color--surface);
	border-radius: 16px;
	padding: clamp(36px, 6vw, 72px);
	text-align: center;
}

.oe-site-footer {
	margin-top: 0;
	padding-block: clamp(58px, 8vw, 96px) 34px;
}

.oe-site-footer a,
.oe-site-footer .wp-block-site-title a {
	color: var(--wp--preset--color--surface);
}

.oe-site-footer .wp-block-navigation-item__content {
	text-decoration: none;
}

.oe-site-footer .wp-block-navigation-item__content:hover {
	color: #b9d6f4;
}

.oe-footer-grid {
	gap: clamp(34px, 5vw, 72px);
}

.oe-footer-grid h2 {
	letter-spacing: 0;
	margin-bottom: 18px;
}

.oe-footer-summary {
	color: #b9c9db;
	max-width: 44ch;
}

/*
 * Regulatory fine print. Set quieter than the rest of the footer, and across
 * its full width, so it reads as the notice it is rather than competing with the navigation,
 * but still at the small preset rather than something smaller invented here --
 * it has to stay legible to be worth printing.
 */
.oe-footer-fineprint {
	border-top: 1px solid rgb(255 255 255 / 18%);
	color: #9fb2c8;
	margin-top: clamp(42px, 6vw, 72px);
	padding-top: 24px;
}

.oe-footer-fineprint p {
	line-height: 1.6;
	margin: 0 0 12px;
}

.oe-footer-fineprint p:last-child {
	margin-bottom: 0;
}

/* The bar sits directly under the notice, so it does not need its own rule
   above it as well. */
.oe-footer-fineprint + .oe-footer-legal {
	border-top: 0;
	margin-top: 28px;
	padding-top: 0;
}

.oe-footer-legal {
	border-top: 1px solid rgb(255 255 255 / 18%);
	color: #b9c9db;
	margin-top: clamp(42px, 6vw, 72px);
	padding-top: 24px;
}

.oe-footer-legal p {
	margin: 0;
}

/*
 * The bar is space-between, so a third item would settle in the middle. This
 * one belongs with the links: absorbing the free space after it keeps it
 * beside Terms and still pushes the disclaimer to the far edge.
 */
/*
 * The disclaimer is a sentence now rather than a phrase, so it takes its own
 * line under the rest of the bar instead of competing with them for the row.
 * Above the widest phone it still sits right, where it was.
 */
.oe-footer-legal .oe-footer-disclaimer {
	flex-basis: 100%;
	margin-top: 14px;
	max-width: 68ch;
}

@media (min-width: 900px) {
	.oe-footer-legal .oe-footer-disclaimer {
		flex-basis: auto;
		margin-top: 0;
		text-align: right;
	}
}

/*
 * Named rather than positional. This spaced the Privacy and Terms links until
 * a copyright line was added ahead of them and quietly took :first-child with
 * it, leaving the two links touching.
 */
.oe-footer-legal .oe-footer-links {
	display: flex;
	gap: 22px;
	/* Takes the free space the dispatch line used to absorb, so the copyright
	   and the links stay together on the left and the disclaimer stays right. */
	margin-inline-end: auto;
}

@keyframes oe-stage-reveal {
	from {
		opacity: 0;
		transform: translateY(20px) scale(0.99);
	}
	to {
		opacity: 1;
		transform: translateY(0) scale(1);
	}
}

@media (max-width: 900px) {
	.oe-footer-grid {
		flex-wrap: wrap !important;
	}

	.oe-product-information > :first-child {
		margin-block-start: var(--wp--preset--spacing--40);
	}

	.oe-site-nav {
		gap: 12px;
	}

	.oe-primary-navigation {
		order: 2;
	}

	/*
	 * Below 901px the field cannot share the row with four links and three
	 * icon targets, so it moves into the panel and the button takes its
	 * place. The button is 44px square whatever else is in the row.
	 */
	.oe-search-inline {
		display: none;
	}

	.oe-search-panel {
		display: block;
		padding-block: 0 12px;
	}

	.oe-search-js .oe-search-toggle {
		display: inline-flex;
	}

	/*
	 * Armed, the panel leaves the flow and hangs off the bottom of the
	 * header, so opening and closing it can move neither the row above it nor
	 * the page below it. visibility rather than display because it is what
	 * takes the closed field out of the tab order while still allowing the
	 * open to be animated.
	 */
	.oe-search-js .oe-search-panel {
		background: var(--wp--preset--color--surface);
		border-bottom: 1px solid rgb(29 29 31 / 9%);
		box-shadow: 0 18px 38px rgb(0 26 65 / 12%);
		left: 0;
		opacity: 0;
		padding: 10px clamp(20px, 4vw, 48px) 14px;
		position: absolute;
		right: 0;
		top: 100%;
		transform: translateY(-8px);
		/*
		 * visibility is stepped, not interpolated: listing it plainly here held
		 * the panel hidden for the whole 180ms, so focus() found an unfocusable
		 * element no matter how long the script deferred. Delay it on the way
		 * out, apply it instantly on the way in (see .is-open).
		 */
		transition: opacity 180ms ease, transform 180ms ease, visibility 0s linear 180ms;
		visibility: hidden;
	}

	.oe-search-js .oe-search-panel.is-open {
		opacity: 1;
		transform: none;
		transition: opacity 180ms ease, transform 180ms ease, visibility 0s;
		visibility: visible;
	}

	/* The panel field is a touch target rather than a header ornament. */
	.oe-search-panel .oe-search-form input.oe-search-field {
		min-height: 46px;
	}

	.oe-search-panel .oe-search-submit {
		min-height: 46px;
		min-width: 48px;
	}

	/*
	 * A third icon target joins the row here, and the four links are the only
	 * slack left before the navigation wraps onto a second line and the whole
	 * header gets taller.
	 */
	.oe-nav-actions {
		gap: 8px;
	}

	/*
	 * The third 44px target arrives at this width, not at 600px, and this is
	 * the band where the four links are still on the row beside it. The badge
	 * carries the cart's state on its own, so the running total is what goes.
	 */
	.oe-nav-actions .wc-block-mini-cart__amount {
		display: none;
	}

	.oe-primary-navigation .wp-block-navigation__container {
		gap: 18px;
	}

	.oe-assurance-rail {
		align-items: flex-start;
	}

	.oe-proof-stage {
		padding: clamp(34px, 7vw, 56px);
	}

	.oe-footer-grid > .wp-block-column:first-child {
		flex-basis: 100% !important;
	}
}

@media (max-width: 600px) {
	.oe-notice {
		font-size: 0.74rem;
	}

	.oe-site-nav {
		min-height: 52px;
	}

	.oe-brand img {
		width: 118px;
	}

	.oe-brand-navigation {
		gap: 10px;
	}

	.oe-nav-actions {
		gap: 6px;
	}

	.oe-hero {
		padding-top: 56px;
	}

	.oe-hero-media {
		border-radius: 12px;
	}

	.oe-hero-media img {
		aspect-ratio: 4 / 5;
	}

	.oe-hero-data {
		background: var(--wp--preset--color--surface);
		border: 1px solid var(--wp--preset--color--divider);
		border-radius: 12px;
		box-shadow: none;
		display: grid;
		margin-top: 12px;
		padding: 18px;
		position: static;
	}

	.oe-assurance-rail {
		display: grid;
	}

	.oe-assurance-rail p {
		border-bottom: 1px solid var(--wp--preset--color--divider);
		padding-bottom: 18px;
	}

	.oe-proof-stage {
		border-radius: 12px;
		margin-top: 76px;
		padding: 34px 24px;
	}

	.oe-order-journey,
	.oe-catalog-preview,
	.oe-closing-stage {
		margin-top: 76px;
	}

	.oe-proof-media img {
		aspect-ratio: 16 / 10;
	}

	.oe-order-path li {
		grid-template-columns: 34px 1fr;
	}

	.oe-closing-stage {
		padding-top: 56px;
	}

	.oe-contact-action,
	.oe-purchase-panel {
		border-radius: 12px;
		padding: 34px 24px;
	}

	.oe-footer-legal {
		align-items: flex-start;
		display: grid;
		gap: 16px;
	}
}

/*
 * 320px is the narrowest screen the storefront is expected on, and it leaves
 * 280px between the gutters. The three icon targets in the action row will
 * not go below 44px each, and the menu button and the wordmark have to fit
 * beside them, so at this width the wordmark is what gives.
 */
@media (max-width: 359px) {
	.oe-brand img {
		width: 96px;
	}

	.oe-brand-navigation {
		gap: 8px;
	}

	.oe-nav-actions {
		gap: 4px;
	}

	/*
	 * The row's own gap counts too. With it at 12px the wordmark, the menu
	 * button and the three icon targets add up to the whole 280px the
	 * gutters leave at 320px, which is not a budget, it is the edge.
	 */
	.oe-site-nav {
		gap: 8px;
	}
}

@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}

	.oe-hero-stage {
		animation: none;
	}

	.oe-search-js .oe-search-panel {
		transition: none;
	}

	.wp-element-button,
	.wp-block-button__link,
	button,
	.oe-product-media img,
	.wp-block-woocommerce-product-image img {
		transition: none;
	}
}

/*
 * The no-results page offers the failed query back in a search field. Left to
 * its intrinsic width the submit button takes what it needs and the input
 * collapses -- 53px at 320px, narrower than the word it is holding, so the
 * customer cannot see what they searched for. Give the form the row and let
 * the field absorb whatever the button leaves.
 */
.oe-search-page .wp-block-search,
.wp-block-query-no-results .wp-block-search {
	width: 100%;
}

.oe-search-page .wp-block-search__input,
.wp-block-query-no-results .wp-block-search__input {
	flex: 1 1 auto;
	min-width: 0;
}

/*
 * The iOS zoom floor, and the opaque mobile header.
 *
 * Both are last in the file and both use !important, which is not the house
 * style and is deliberate here. A bare `select` is specificity (0,0,1) and
 * loses to every `.woocommerce ... select` rule WooCommerce ships, and the
 * header's own background already carries !important. These are not
 * preferences a later rule should be able to win: under 16px iOS zooms the
 * page and does not zoom back, and a see-through sticky header is unreadable.
 */
input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]),
select,
textarea {
	font-size: max(16px, 1rem) !important;
}

@media (max-width: 599px) {
	.oe-site-header {
		background: rgb(255 255 255) !important;
	}
}

/*
 * The no-results search form is shrink-to-fit, so on a narrow phone the button
 * takes what it needs and the field collapses to 53px -- narrower than the
 * query it is meant to be holding for the customer to edit.
 */
.wp-block-query-no-results .wp-block-search,
.oe-search-empty .wp-block-search {
	width: 100% !important;
}

.wp-block-query-no-results .wp-block-search__inside-wrapper,
.oe-search-empty .wp-block-search__inside-wrapper {
	width: 100%;
}

.wp-block-query-no-results .wp-block-search__input,
.oe-search-empty .wp-block-search__input {
	flex: 1 1 auto;
	min-width: 0;
}

/* ─────────────────────────────────────────────────────────────
 * Findings from the platform audit. Grouped here rather than scattered so the
 * next audit can tell what was answered and what was not.
 * ───────────────────────────────────────────────────────────── */

/*
 * The outline button carries a 1px border the filled one does not, so the pair
 * resolved to different heights -- 46.7 against 47.9 -- and sat on different
 * baselines. Stretching the row makes the border-box heights agree without
 * having to subtract the border from the padding by hand.
 */
.oe-hero .wp-block-buttons {
	align-items: stretch;
}

/*
 * The active suggestion was tinted rgb(234,245,255) against white: a contrast
 * of 1.11:1, which is no indication at all for anyone who cannot see a faint
 * blue wash. The brand blue as a left rule carries it instead, and the tint
 * stays as a second, redundant cue.
 */
.oe-suggest-item.is-active {
	box-shadow: inset 3px 0 0 var(--wp--preset--color--accent);
}

/*
 * Flicking past the end of the suggestion list handed the scroll to the page
 * behind it, which on a phone moves the thing being read out from under the
 * finger.
 */
.oe-suggest {
	overscroll-behavior: contain;
}

/*
 * Safari draws its own 16px grey clear disc inside a search field, unstyled and
 * sitting next to the submit button in the pill. Nothing is lost by removing
 * it: the field clears from the keyboard, and the form has its own button.
 */
.oe-search-form input.oe-search-field::-webkit-search-cancel-button {
	appearance: none;
	-webkit-appearance: none;
}

/*
 * Tap targets. Each of these sat well under 44px next to siblings that met it,
 * which is the tell that they were missed rather than deliberately small. The
 * glyphs keep their size; only the hit area grows.
 */
.wp-block-navigation__responsive-container-open,
.wp-block-navigation__responsive-container-close {
	align-items: center;
	display: inline-flex;
	justify-content: center;
	min-height: 44px;
	min-width: 44px;
}

.woocommerce-pagination a.page-numbers,
.woocommerce-pagination span.page-numbers,
.wp-block-query-pagination a {
	align-items: center;
	display: inline-flex;
	justify-content: center;
	min-height: 44px;
	min-width: 44px;
}

a.button.occ-aov-add-to-cart,
a.reset_variations {
	align-items: center;
	display: inline-flex;
	justify-content: center;
	min-height: 44px;
}

/*
 * Core switches the navigation from its overlay to an inline row at 600px, but
 * the row does not have space for brand + nav + search + account + cart until
 * 681px. Between those two widths the actions wrapped to a second line and the
 * header grew from 91px to 145px. Hold the overlay across that band; core's own
 * rules resume above it.
 */
@media (min-width: 600px) and (max-width: 680px) {
	.oe-primary-navigation .wp-block-navigation__responsive-container-open:not(.always-shown) {
		display: flex;
	}

	.oe-primary-navigation .wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open) {
		background-color: inherit;
		display: none;
		position: inherit;
		width: 100%;
		z-index: auto;
	}
}

/*
 * The no-results field was 53px wide at 320px -- narrower than the query it is
 * meant to be handing back for editing, so the customer could not see what
 * they had searched for.
 *
 * Nothing was setting that width. Three gutters were stacking: main pads 20px,
 * the no-results container adds its own global padding of 36px inside a main
 * that is already padded, and the card pads another 28px. That is 84px a side
 * out of 320, leaving 152px for a field and a button.
 *
 * Drop the middle gutter, which is the redundant one, and ease the card's own
 * padding on the narrowest screens where clamp()'s floor is still too generous.
 */
.wp-block-query-no-results {
	padding-left: 0;
	padding-right: 0;
}

@media (max-width: 480px) {
	.oe-search-empty {
		padding: 22px 18px;
	}
}
