/**
 * AstraSolara Product Page v2.
 *
 * Every selector is namespaced under .aspdp-page or .aspdp* so nothing here can reach
 * another product page, the cart, or Basel's own product styles. The only places this
 * deliberately reaches into WooCommerce markup are inside .aspdp-page, where the buy
 * column has to hold the standard summary hooks' output.
 *
 * Tokens come from basel-child/style.css. Fallbacks are spelled out so the page still
 * reads correctly if it is ever rendered without them.
 */

/* Layout — the Mirror ------------------------------------------------------ */

.aspdp {
	display: grid;
	grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
	gap: 40px;
	align-items: start;
}

.aspdp__visual {
	min-width: 0;
}

.aspdp__buy {
	min-width: 0;
	float: none !important;
	width: auto !important;
}

/*
 * Basel's summary column carries a scroll wrapper for its "compact" product design. v2
 * never uses that design, and the wrapper's overflow would clip the express checkout
 * element's own popovers.
 */
.aspdp__buy .summary-inner,
.aspdp__buy .basel-scroll-content {
	overflow: visible;
	max-height: none;
	height: auto;
}

/*
 * The title and price are NOT styled here.
 *
 * They render above the stage in `.astrasolara-single-title`, the band every product on
 * the shop shares, sized by basel-child/style.css at 22px. Nothing in this file should
 * reach them: the moment v2 sizes its own heading, a metal print stops introducing itself
 * the way a mug does, which is the thing the shared band exists to prevent.
 */

/* The stage — the hero ------------------------------------------------------ */

.aspdp__stage {
	position: relative;
	width: 100%;
	aspect-ratio: 1 / 1;
	max-width: 100%;
	border-radius: 14px;
	overflow: hidden;
	background:
		radial-gradient(circle at 50% 45%, rgba(122, 142, 255, 0.10), transparent 62%),
		var(--astrasolara-color-surface, #10131b);
	border: 1px solid var(--astrasolara-color-border, rgba(255, 255, 255, 0.08));
	cursor: zoom-in;
}

@media (min-width: 992px) {
	.aspdp__stage {
		min-height: 560px;
	}
}

.aspdp__sample,
.aspdp__render {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: contain;
}

.aspdp__sample[hidden],
.aspdp__render[hidden],
.aspdp__overlay[hidden],
.aspdp__shimmer[hidden],
.aspdp__zoom[hidden],
.aspdp__stage-note[hidden],
.aspdp__reveal[hidden],
.aspdp__elements[hidden],
.aspdp__chip[hidden],
.aspdp__error[hidden],
.aspdp__dominant[hidden] {
	display: none !important;
}

.aspdp__render {
	transition: opacity 220ms ease;
}

/*
 * The text block, drawn in the browser. Pointer-events off so the whole stage stays one
 * click target for the lightbox.
 */
.aspdp__overlay {
	position: absolute;
	/* top/left are set in JS from the image's actual letterboxed square, so the block
	   tracks the artwork rather than the box that contains it. */
	top: 0;
	left: 0;
	pointer-events: none;
}

/*
 * Shimmer over the WHEEL, not the whole square — the metadata block below it is being
 * drawn live and should not flicker every time a render lands. The previous image stays
 * fully visible underneath; a blank stage would read as the chart having been lost.
 */
.aspdp__shimmer {
	position: absolute;
	left: 50%;
	top: 46%;
	width: 78%;
	aspect-ratio: 1 / 1;
	transform: translate(-50%, -50%);
	border-radius: 50%;
	pointer-events: none;
	background: linear-gradient(
		105deg,
		rgba(255, 255, 255, 0) 38%,
		rgba(255, 255, 255, 0.16) 50%,
		rgba(255, 255, 255, 0) 62%
	);
	background-size: 280% 100%;
	animation: aspdp-shimmer 1.15s linear infinite;
}

@keyframes aspdp-shimmer {
	from { background-position: 180% 0; }
	to   { background-position: -80% 0; }
}

@media (prefers-reduced-motion: reduce) {
	.aspdp__shimmer { animation: none; background: rgba(255, 255, 255, 0.08); }
}

/* A settled edit is about to fire: a whisper, not the full shimmer. */
.aspdp__stage--pending .aspdp__render { opacity: 0.88; }

.aspdp__zoom {
	position: absolute;
	right: 12px;
	bottom: 12px;
	width: 38px;
	height: 38px;
	padding: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	border: 1px solid var(--astrasolara-color-border-strong, rgba(255, 255, 255, 0.16));
	border-radius: 50%;
	background: rgba(5, 6, 10, 0.62);
	color: var(--astrasolara-color-text, #f2f5f8);
	cursor: zoom-in;
	backdrop-filter: blur(6px);
}

.aspdp__zoom svg {
	width: 16px;
	height: 16px;
	fill: none;
	stroke: currentColor;
	stroke-width: 2;
	stroke-linecap: round;
}

.aspdp__stage-note {
	position: absolute;
	left: 12px;
	bottom: 12px;
	padding: 5px 11px;
	border-radius: 999px;
	font-size: 11px;
	letter-spacing: 0.03em;
	text-transform: uppercase;
	background: rgba(5, 6, 10, 0.62);
	color: var(--astrasolara-color-text-muted, rgba(242, 245, 248, 0.72));
	backdrop-filter: blur(6px);
}

/* Thumbnail strip ----------------------------------------------------------- */

.aspdp__thumbs {
	display: flex;
	gap: 10px;
	margin-top: 14px;
	overflow-x: auto;
	padding-bottom: 4px;
	scrollbar-width: thin;
}

.aspdp__thumb {
	flex: 0 0 auto;
	width: 72px;
	height: 72px;
	padding: 0;
	border-radius: 9px;
	overflow: hidden;
	border: 1px solid var(--astrasolara-color-border, rgba(255, 255, 255, 0.08));
	background: var(--astrasolara-color-surface-alt, #161a24);
	cursor: zoom-in;
	transition: border-color 160ms ease;
}

.aspdp__thumb:hover,
.aspdp__thumb:focus-visible {
	border-color: var(--astrasolara-color-border-strong, rgba(255, 255, 255, 0.16));
}

.aspdp__thumb img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Reveal strip -------------------------------------------------------------- */

.aspdp__reveal {
	margin-top: 18px;
	padding: 16px 18px;
	border-radius: 12px;
	border: 1px solid var(--astrasolara-color-border, rgba(255, 255, 255, 0.08));
	background: var(--astrasolara-color-surface-alt, #161a24);
}

.aspdp__chips {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
}

.aspdp__chip {
	display: inline-flex;
	align-items: baseline;
	gap: 7px;
	padding: 7px 13px;
	border-radius: 999px;
	font-size: 13px;
	line-height: 1.2;
	background: var(--astrasolara-color-surface-soft, #1d2230);
	border: 1px solid var(--astrasolara-color-border, rgba(255, 255, 255, 0.08));
	color: var(--astrasolara-color-text, #f2f5f8);
}

.aspdp__chip-glyph { font-size: 14px; opacity: 0.9; }

.aspdp__chip-label {
	font-size: 11px;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	opacity: 0.62;
}

.aspdp__chip-value { font-weight: 600; }

/* Said out loud, because a cusp date can genuinely land either side of it. */
.aspdp__chip--provisional .aspdp__chip-value {
	font-weight: 500;
	opacity: 0.72;
	font-style: italic;
}

.aspdp__elements { margin-top: 14px; }

.aspdp__bar {
	display: flex;
	height: 8px;
	border-radius: 999px;
	overflow: hidden;
	background: var(--astrasolara-color-surface-soft, #1d2230);
}

.aspdp__seg { display: block; flex: 0 1 auto; min-width: 0; transition: flex-grow 320ms ease; }
.aspdp__seg--empty { flex-grow: 0 !important; }
.aspdp__seg--fire  { background: #ff7a59; }
.aspdp__seg--earth { background: #8fbf6f; }
.aspdp__seg--air   { background: #7fb8e6; }
.aspdp__seg--water { background: #7d8ff0; }

.aspdp__dominant {
	margin: 9px 0 0;
	font-size: 12px;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--astrasolara-color-text-muted, rgba(242, 245, 248, 0.72));
}

/* Messages ------------------------------------------------------------------ */

.aspdp__error {
	margin: 12px 0 0;
	padding: 10px 13px;
	border-radius: 9px;
	font-size: 13px;
	background: rgba(255, 107, 107, 0.10);
	border: 1px solid rgba(255, 107, 107, 0.32);
	color: var(--astrasolara-color-coral, #ff6b6b);
}

.aspdp__disclaimer {
	margin: 14px 0 0;
	font-size: 12px;
	opacity: 0.6;
}

/* The form ------------------------------------------------------------------ */

.aspdp-form { margin: 0 0 20px; }

/*
 * "Enter your details below" — the buy panel's call to action.
 *
 * It shipped at 14px/400 in body white, a point and a half off the muted note beneath
 * it, so the line telling the shopper what to do and the line qualifying it read as the
 * same kind of small print.
 *
 * The whole line takes the gold the "Free US shipping" pill already uses. Both accents
 * on this page were tried against this panel and the gold is simply the brighter one:
 * against the panel's near-black it carries roughly 12:1, where the teal of the price
 * manages about 7:1. On a surface this dark the teal reads as a muted label; the gold
 * reads as an instruction, which is what this line is.
 *
 * It does not fight the pill. The pill is a small FILLED lozenge up in the title band,
 * beside the price and above the image; this is unfilled text in the buy column. One
 * hue used twice in two different registers reads as a palette; it would only have gone
 * busy if this were filled too, which is why it is not.
 */
.aspdp-form__intro {
	margin: 0 0 14px;
	font-size: 18px;
	font-weight: 600;
	line-height: 1.4;
	color: #f6d66e;
}

/* Light theme, same pattern as the shipping pill: the pale gold that carries a dark
   backdrop is barely there on a white one, so it steps down to a readable bronze.
   The media query is load-bearing — `astrasolara-dark` is set nowhere, so an unwrapped
   body:not(.astrasolara-dark) would repaint the dark page too. */
@media (prefers-color-scheme: light) {
	body:not(.astrasolara-dark) .aspdp-form__intro {
		color: #8a6a12;
	}
}

@media (max-width: 480px) {
	.aspdp-form__intro {
		font-size: 17px;
		margin: 0 0 12px;
	}
}

/* Stays small and stays muted: it qualifies the line above, and the whole point of the
   change above is that the two should no longer look like the same kind of remark. */
.aspdp-form__note {
	margin: -4px 0 14px;
	font-size: 12.5px;
	opacity: 0.68;
}

.aspdp-form__field { margin: 0 0 14px; }

.aspdp-form__field label {
	display: block;
	margin: 0 0 5px;
	font-size: 12px;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--astrasolara-color-text-muted, rgba(242, 245, 248, 0.72));
}

.aspdp-form__field input {
	width: 100%;
	max-width: 100%;
	box-sizing: border-box;
	padding: 11px 13px;
	border-radius: 9px;
	background: var(--astrasolara-color-surface, #10131b);
	border: 1px solid var(--astrasolara-color-border, rgba(255, 255, 255, 0.08));
	color: var(--astrasolara-color-text, #f2f5f8);

	/*
	 * The native widgets, told what colour the page actually is.
	 *
	 * `type="date"` and `type="time"` are not text boxes: the browser draws a picker
	 * indicator inside them and opens its own calendar or clock panel below. Both are
	 * painted for a LIGHT page by default, so on this one the indicator was a dark glyph
	 * on a near-black field — effectively invisible — and the panel that opened over it
	 * was a white rectangle.
	 *
	 * `color-scheme: dark` fixes both at once, and it fixes them properly: the glyph comes
	 * back light, the popup comes back dark, and the spin buttons and selection highlight
	 * inside it follow. It is the declaration the rule below is a fallback FOR, not a
	 * partner to it — see the @supports block.
	 *
	 * Unconditional, and deliberately so. This page has no light mode: the surface token
	 * it sits on is defined once, dark, in basel-child/style.css with no
	 * `prefers-color-scheme` branch anywhere, and style-light.css is not enqueued. The two
	 * `prefers-color-scheme: light` rules in this file adjust accent COLOURS on a page
	 * that stays dark; matching that pattern here — flipping the icons dark when the OS is
	 * in light mode — would put a dark glyph back on a dark field, which is the exact bug
	 * being fixed. If the page ever gains a real light surface, this is one of the
	 * declarations that has to move with it.
	 */
	color-scheme: dark;
}

/*
 * The picker indicator: a bigger target, and something to hover.
 *
 * Chrome ships it at about 13px square with no padding, which is under half the 44px a
 * finger needs. Padding on the pseudo-element is inside the input's own 11px, so this
 * costs no layout — it just makes the hit area roughly 26px and, with the field's height,
 * comfortably tappable.
 *
 * No `filter` here. `color-scheme: dark` above has already made the glyph light, and
 * inverting an already-light glyph would hand back the dark one this exists to remove.
 */
.aspdp-form__field input::-webkit-calendar-picker-indicator {
	/* Measured: the indicator's own padding does not change the input's height in Chrome
	   (date stays 44px, time stays its intrinsic 60px either way), so this buys hit area
	   and costs no layout. */
	padding: 7px;
	margin-right: -3px;
	opacity: 0.8;
	cursor: pointer;
	transition: opacity 140ms ease;
}

.aspdp-form__field input::-webkit-calendar-picker-indicator:hover,
.aspdp-form__field input:focus::-webkit-calendar-picker-indicator {
	opacity: 1;
}

/*
 * Belt and braces, and mutually exclusive with the braces by construction.
 *
 * An engine that does not understand `color-scheme` drops that declaration silently and
 * paints the indicator dark again. Only THAT engine gets the inversion, so there is no
 * arrangement in which both apply and the glyph ends up dark twice over.
 */
@supports not (color-scheme: dark) {
	.aspdp-form__field input::-webkit-calendar-picker-indicator {
		filter: invert(1);
	}
}

.aspdp-form__field input:focus {
	outline: none;
	border-color: var(--astrasolara-color-primary, #0073aa);
}

.aspdp-form__row {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: 12px;
}

.aspdp-form .field-error {
	display: block;
	margin-top: 4px;
	font-size: 12px;
	color: var(--astrasolara-color-coral, #ff6b6b);
}

.aspdp-page .single_add_to_cart_button[disabled],
.aspdp-page .single_add_to_cart_button.aspdp-disabled {
	opacity: 0.45;
	cursor: not-allowed;
}

/* Lightbox ------------------------------------------------------------------ */

.aspdp-lightbox {
	position: fixed;
	inset: 0;
	/*
	 * Above Pinterest's pinit.js overlay, which plants itself near the top of the signed
	 * 32-bit range. The nopin attributes on our images should mean it never appears over
	 * the chart at all; this is the belt to that pair of braces.
	 */
	z-index: 2147483000;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 4vmin;
	background: rgba(3, 4, 8, 0.92);
	overflow: hidden;
	touch-action: none;
}

.aspdp-lightbox[hidden] { display: none !important; }

body.aspdp-lightbox-open { overflow: hidden; }

/*
 * pinit.js appends its hover button to <body>, not inside the image's container, so no
 * amount of stacking context on the lightbox can cover it. Suppress it outright, and only
 * while the lightbox is open — every other image on the shop keeps its Save button.
 */
body.aspdp-lightbox-open span[class*="PIN_"],
body.aspdp-lightbox-open [data-pin-log],
body.aspdp-lightbox-open [id^="PIN_"] {
	display: none !important;
}

/*
 * Vestigial, kept deliberately.
 *
 * These never worked for the stage: pinit.js hangs its button off <body>, so nothing
 * scoped under .aspdp__stage is an ancestor of it. The real fix is in
 * class-astrasolara-product-page-v2.php, which dequeues pinit.js on v2 pages outright.
 * This stays only so that a stale cached page still carrying the script degrades to the
 * old half-measure rather than to nothing.
 */
.aspdp__stage span[class*="PIN_"],
.aspdp__stage [data-pin-log] {
	display: none !important;
}

.aspdp-lightbox__inner {
	position: relative;
	width: min(92vw, 92vh);
	aspect-ratio: 1 / 1;
}

.aspdp-lightbox__img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: contain;
	transform-origin: center center;
	transition: transform 120ms ease-out;
}

.aspdp-lightbox__overlay {
	position: absolute;
	top: 0;
	left: 0;
	transform-origin: center center;
	pointer-events: none;
	transition: transform 120ms ease-out;
}

.aspdp-lightbox__overlay[hidden] { display: none !important; }

.aspdp-lightbox__close {
	position: absolute;
	top: 16px;
	right: 18px;
	width: 42px;
	height: 42px;
	padding: 0;
	font-size: 26px;
	line-height: 1;
	border: 1px solid var(--astrasolara-color-border-strong, rgba(255, 255, 255, 0.16));
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.06);
	color: #fff;
	cursor: pointer;
}

/* Narrow ------------------------------------------------------------------- */

/*
 * Everything below 992px is the phone/tablet layout, and it is a different page from the
 * desktop one — not a narrower one.
 *
 * Measured on a 723px-tall viewport before this: a 495px stage, then 268px of reveal
 * strip and thumbnails, then the form starting some 760px below the top of the stage.
 * There was no scroll position at which a shopper could see both the chart and the field
 * they were editing, so every single edit was a scroll round trip — on the one page whose
 * whole premise is that you watch the chart change as you type.
 *
 * Three things fix it, and all three are confined to this file's mobile blocks so the
 * desktop layout above 991px is untouched:
 *
 *   1. The stage pins to the top of the viewport and the form scrolls underneath it.
 *   2. The reveal strip and the thumbnails move BELOW the form. They are the reward for
 *      filling it in, not an obstacle on the way to it.
 *   3. The form loses the fine print it can afford to lose, and tightens up.
 */

@media (max-width: 991px) {
	/*
	 * The one rule in this file that reaches outside .aspdp, and the reason the sticky
	 * stage works at all.
	 *
	 * Basel wraps the site in `.website-wrapper { overflow: hidden }`. That makes the
	 * wrapper a scroll CONTAINER, and `position: sticky` sticks to its nearest scroll
	 * container rather than to the viewport — so a sticky descendant of a wrapper that is
	 * exactly as tall as the page, and therefore never scrolls, never moves. Measured at
	 * 375×723: the stage sat at -343px, straight off the top, while `top: 0` computed
	 * correctly. (The mobile Add to Cart button below has carried `position: sticky` since
	 * v2 shipped and has never pinned either, for the same reason. It does now.)
	 *
	 * `overflow: clip` clips exactly as `hidden` does — Basel wants it for the horizontal
	 * overflow of its full-width sections — but does not create a scroll container. The
	 * body class comes from AstraSolara_Product_Page_V2::body_class(), so this cannot
	 * reach another page, and it is inside the mobile block, so the desktop layout is not
	 * touched by it at all. A browser without `clip` (Safari before 16) drops the
	 * declaration and gets precisely today's non-sticky behaviour.
	 */
	body.aspdp-v2-page .website-wrapper { overflow: clip; }

	/*
	 * Flex, not the stacked grid, and `.aspdp__visual` dissolves into it.
	 *
	 * The reveal strip and the thumbnails are children of the visual column while the
	 * form lives in the buy column, so no amount of ordering INSIDE the visual column can
	 * put them after the form. `display: contents` promotes the visual column's children
	 * to be siblings of the buy column, and then one `order` per item is enough — one DOM
	 * for both layouts, no markup moved, nothing for the desktop path to skip.
	 */
	.aspdp {
		display: flex;
		flex-direction: column;
		gap: 18px;
	}

	.aspdp__visual { display: contents; }

	.aspdp__stage      { order: 1; }
	.aspdp__error      { order: 2; }
	.aspdp__disclaimer { order: 3; }
	.aspdp__buy        { order: 4; }
	.aspdp__thumbs     { order: 5; }
	.aspdp__reveal     { order: 6; }

	/* The flex gap owns the vertical rhythm now; the authored margins would double it. */
	.aspdp__thumbs,
	.aspdp__reveal,
	.aspdp__error,
	.aspdp__disclaimer { margin-top: 0; }

	/*
	 * The pinned stage.
	 *
	 * `--aspdp-stage-h` is the height budget: about 45vh at rest, dropping to about 32vh
	 * while a field has focus so the field and the keyboard both fit under it. JS keeps it
	 * in PIXELS off `window.visualViewport`, because iOS Safari's `vh` is a fiction the
	 * moment a keyboard or the dynamic toolbar is on screen — it keeps reporting the tall
	 * viewport that is no longer visible. The vh values here are the no-JS fallback and
	 * the pre-first-frame value, nothing more.
	 *
	 * The box is the full width of the column and the budget is its HEIGHT, so the artwork
	 * — which is square and `object-fit: contain` — letterboxes inside it rather than
	 * distorting. `containedSquare()` in product-page-v2.js already computes exactly that
	 * inner square for the name overlay, so the caption keeps tracking the art as the box
	 * resizes.
	 *
	 * It is deliberately NOT a square box that shrinks. That was the first version of this
	 * and it is wrong in a way a screenshot makes obvious: a 180px square centred in a
	 * 303px column leaves 60px of transparent gutter down each side, and the form scrolls
	 * up through it. A pinned preview has to be opaque across the whole column or it reads
	 * as a sticker stuck over the page.
	 *
	 * `--aspdp-sticky-top` is any fixed site header's height (Basel's sticky header is
	 * switched off on this site — body carries `disable-sticky-header` — so it is 0 here,
	 * but the page should not break if that is ever turned back on) plus the visual
	 * viewport's own offset, which is how iOS reports a keyboard having pushed the visible
	 * area down inside the layout viewport.
	 */
	.aspdp__stage {
		position: sticky;
		top: var(--aspdp-sticky-top, 0px);
		/*
		 * Above the sticky Add to Cart's 5. The two are pinned to opposite edges and never
		 * meet while the keyboard is up, but as the shopper scrolls past the end of the
		 * form the button reaches its natural position — which by then is up under the
		 * pinned stage — and at a higher z-index it punched a grey ADD TO CART bar clean
		 * through the middle of the chart. Everything scrolls UNDER the preview.
		 */
		z-index: 6;
		aspect-ratio: auto;
		height: var(--aspdp-stage-h, 45vh);
		transition: height 220ms ease;
	}

	/*
	 * The shimmer is sized off the WHEEL, and in a letterboxed box the wheel is as wide as
	 * the box is tall, not as wide as the box. Driving it from height keeps the sweep over
	 * the artwork instead of running out into the side bands.
	 */
	.aspdp__shimmer {
		width: auto;
		height: 78%;
	}

	/*
	 * The seam. Without it the top line of whatever is scrolling underneath meets the
	 * stage's own dark background with no edge at all, and the page looks like it has
	 * simply stopped repainting.
	 */
	.aspdp__stage::after {
		content: '';
		position: absolute;
		left: 0;
		right: 0;
		bottom: 0;
		height: 1px;
		background: var(--astrasolara-color-border-strong, rgba(255, 255, 255, 0.16));
		pointer-events: none;
	}

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

	/*
	 * Form compaction — targeted, not a squeeze.
	 *
	 * Deliberately NOT collapsing the four fields into one or two horizontal rows: at
	 * 375px that puts the native date and time pickers below the width at which iOS will
	 * render their segments, and the tap targets under 44px. What comes out instead is
	 * text that is not load-bearing on a phone, and vertical air.
	 */

	/*
	 * "Filled in from your profile. Changes here apply to this order only…"
	 *
	 * True, and worth a line on a desktop panel with room for it. On a phone it is two
	 * lines of grey between the call to action and the first input, explaining a state
	 * the shopper can see for themselves — the fields are already full.
	 */
	.aspdp-form__note { display: none; }

	.aspdp-form__field { margin: 0 0 10px; }

	.aspdp-form__field label { margin: 0 0 3px; }

	/* 11px of padding plus the line box already clears 44px; stated so it cannot drift. */
	.aspdp-form__field input { min-height: 44px; }
}

@media (max-width: 575px) {
	.aspdp__stage { border-radius: 10px; }

	.aspdp__reveal { padding: 13px 14px; }

	/* Two date/time fields side by side stop fitting well before 375px. */
	.aspdp-form__row { grid-template-columns: minmax(0, 1fr); }

	.aspdp__thumb { width: 62px; height: 62px; }

	/*
	 * Keeps Add to Cart reachable while the shopper scrolls the buy column, without
	 * taking it out of flow — a fixed bar would sit on top of the express checkout
	 * buttons that follow the form.
	 *
	 * 5 sits it above the form's own content and below the pinned stage's 6; see the
	 * z-index note there for what the other order looked like.
	 */
	.aspdp-page form.cart .single_add_to_cart_button {
		position: sticky;
		bottom: 10px;
		z-index: 5;
		width: 100%;
	}

	/*
	 * Opaque even while disabled — which, now that the button actually pins, it has to be.
	 *
	 * A bottom-sticky button floats over the fields above it; that is what it is for. At
	 * the 45% opacity the disabled state uses everywhere else, the BIRTH LOCATION label
	 * showed straight through ADD TO CART and the two sets of letters interleaved. The
	 * disabled state says the same thing here with colour instead of alpha.
	 *
	 * Mobile only, and only for the sticky instance: the desktop button is in flow with
	 * nothing behind it, and keeps the fade.
	 */
	.aspdp-page form.cart .single_add_to_cart_button[disabled],
	.aspdp-page form.cart .single_add_to_cart_button.aspdp-disabled {
		opacity: 1;
		background-color: var(--astrasolara-color-surface-soft, #1d2230);
		color: var(--astrasolara-color-text-muted, rgba(242, 245, 248, 0.72));
	}
}
