/*
 * Save Point Shop — theme stylesheet.
 *
 * Only what theme.json cannot express. Five things live here:
 *   1. The pixel label and display type details.
 *   2. Bays — the section grid, ruled rather than boxed.
 *   3. Cards — platform tiles, feedback quotes, the eBay rail.
 *   4. Editable placeholder slots — visible gaps for artwork that does
 *      not exist yet, which disappear the moment it does.
 *   5. The navigation breakpoint.
 *
 * Loaded on the front end and inside the editor, so the canvas matches.
 */

/* WordPress does NOT ship a global box-sizing reset — core sets it on some
   blocks and leaves the rest as content-box. Every width in this theme is
   written as a border-box width (a 1320px measure means 1320px on screen,
   padding included), so the theme has to own the reset. Without it, any
   element with both a max-width and padding renders wider than its measure
   and drifts out of alignment with its neighbours. */
*,
*::before,
*::after { box-sizing: border-box; }

:root {
	--sps-gutter: clamp(1rem, 4.5vw, 4rem);
	--sps-measure: 1320px;
	--sps-radius: 6px;
}

/* ---------------------------------------------------------------
   1. Type
   --------------------------------------------------------------- */

/* The pixel eyebrow. Press Start 2P is a display face at one size and
   one job: the small caps line above a heading. It is never body copy —
   at 10px it is already at its legibility floor. */
.sps-label {
	font-family: var(--wp--preset--font-family--pixel);
	font-size: var(--wp--preset--font-size--label);
	font-weight: 400;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--wp--preset--color--amber);
	line-height: 1.8;
}
/* Small text needs a lighter red than the buttons do: #E02B2B at 10px is
   3.44:1 on a panel, well under AA. #FF6B6B reads as the same accent and
   clears 5:1 everywhere it is used. */
.sps-label--red { color: var(--wp--preset--color--red-text); }
.sps-label--muted { color: var(--wp--preset--color--cream-2); }

/* A deck is the sentence under a heading. It keeps a reading measure
   regardless of the column it sits in. */
.sps-deck {
	font-size: var(--wp--preset--font-size--large);
	line-height: 1.5;
	color: var(--wp--preset--color--cream-2);
	max-width: 46ch;
}

.sps-accent { color: var(--wp--preset--color--red-2); }
.sps-amber  { color: var(--wp--preset--color--amber); }

/* Figures in the trust row. Tabular so the columns do not jitter. */
.sps-figure {
	font-family: var(--wp--preset--font-family--display);
	font-weight: 700;
	font-size: var(--wp--preset--font-size--xx-large);
	line-height: 0.9;
	font-variant-numeric: tabular-nums;
	color: var(--wp--preset--color--cream);
}

/* ---------------------------------------------------------------
   2. Bays
   Every top-level section is a full-width group with a 1320px inner
   measure. Ruled top, never boxed.
   --------------------------------------------------------------- */

.sps-bay {
	padding-inline: var(--sps-gutter);
	border-top: 1px solid var(--wp--preset--color--rule);
}
.sps-bay--flush { border-top: 0; }
/* The inset is the distance from the bay's padding edge to the measure's left
   edge once the viewport outgrows the measure. Below that it is zero. */
.sps-bay { --sps-inset: max(0px, (100% - var(--sps-measure)) / 2); }

/* Children start at the measure's left edge and are capped at its width.
 *
 * The obvious rule here is `margin-inline: auto`, and it was that for a long
 * time. It is wrong, and wrong in a way that only shows above ~1450px, which
 * is why it survived three separate alignment passes. `auto` CENTRES a child
 * within the bay: correct for a full-measure child, where centred and
 * measure-aligned are the same place, and quietly wrong for any child that is
 * narrower — a pull quote, a map — which then floats in the middle of the
 * column instead of lining up with everything above it.
 *
 * Starting every child at the inset instead makes the two cases identical:
 * full-measure children land exactly where centring put them, and narrower
 * children line up with them instead of drifting. One rule, no per-element
 * exceptions, and nothing new to remember when a narrow element is added.
 *
 * The remaining trap, which this rule cannot defend against: a child that
 * resets its own margins with the `margin` shorthand cancels the inline half
 * of this and pins itself to the padding edge. Use `margin-block` when you
 * mean "kill the UA's vertical margin" — `margin: 0` has caused this exact
 * bug four times in this theme's history. */
.sps-bay > * {
	max-width: var(--sps-measure);
	margin-inline: var(--sps-inset) auto;
}

/* Section header: label, heading, deck, stacked with tight leading. */
.sps-bay__head { margin-bottom: clamp(2rem, 4vw, 3.5rem); }

/* Asymmetric columns grow from a zero basis. Taking basis percentages
   overflows the row once the gap is added, and it wraps at desktop
   widths — learned the hard way on the classic theme. */
.sps-split { display: flex; flex-wrap: wrap; gap: clamp(1.5rem, 4vw, 4rem); }
.sps-split > * { flex-basis: 0; min-width: min(18rem, 100%); }
.sps-split--58 > :first-child { flex-grow: 58; }
.sps-split--58 > :last-child  { flex-grow: 42; }
/* Inverted: the narrow side leads. Used where the right-hand column is a
   form, which needs more room than the sentence introducing it. */
.sps-split--42 > :first-child { flex-grow: 42; }
.sps-split--42 > :last-child  { flex-grow: 58; }

/* ---------------------------------------------------------------
   3. Cards
   --------------------------------------------------------------- */

.sps-card {
	background: var(--wp--preset--color--panel);
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: var(--sps-radius);
	padding: clamp(1.25rem, 2.5vw, 2rem);
}
.sps-card--raised { background: var(--wp--preset--color--panel-2); }

/* Platform tiles: the grid of what we stock. Auto-fit so it reflows
   without a media query at every count. */
.sps-tiles {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr));
	gap: 1rem;
}
.sps-tile {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
	background: var(--wp--preset--color--panel);
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: var(--sps-radius);
	padding: 1.25rem;
	transition: border-color 140ms ease, transform 140ms ease;
}
.sps-tile:hover,
.sps-tile:focus-within {
	border-color: var(--wp--preset--color--red-2);
	transform: translateY(-2px);
}
@media (prefers-reduced-motion: reduce) {
	.sps-tile { transition: none; }
	.sps-tile:hover, .sps-tile:focus-within { transform: none; }
}

/* A feedback quote. Real eBay feedback only — if there is no quote for
   a slot, the slot stays empty rather than carrying an invented one. */
.sps-quote {
	background: var(--wp--preset--color--panel);
	border: 1px solid var(--wp--preset--color--rule);
	border-left: 3px solid var(--wp--preset--color--amber);
	border-radius: var(--sps-radius);
	padding: 1.25rem 1.4rem;
}
.sps-quote__meta {
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--cream-2);
}

/* ---------------------------------------------------------------
   4. Placeholder slots
   Anything that does not exist yet renders as a labelled box on a
   drafting grid — never blank space, never a fake value. Replace the
   group with a real image block and the slot is gone.
   --------------------------------------------------------------- */

.sps-slot {
	display: grid;
	place-items: center;
	min-height: 14rem;
	border: 1px dashed var(--wp--preset--color--rule);
	border-radius: var(--sps-radius);
	background-color: var(--wp--preset--color--night-deep);
	background-image:
		linear-gradient(var(--wp--preset--color--rule) 1px, transparent 1px),
		linear-gradient(90deg, var(--wp--preset--color--rule) 1px, transparent 1px);
	background-size: 24px 24px, 24px 24px;
	color: var(--wp--preset--color--cream-2);
	font-family: var(--wp--preset--font-family--pixel);
	font-size: var(--wp--preset--font-size--label);
	text-align: center;
	padding: 1rem;
	line-height: 1.9;
}
.sps-slot--inline { min-height: 4.5rem; }
.sps-slot--tall { min-height: 22rem; }

/* ---------------------------------------------------------------
   5. Navigation
   Core flips the overlay at 600px, which is far too late for a menu
   this wide. Flip it where it actually stops fitting.
   --------------------------------------------------------------- */

@media (max-width: 1080px) {
	.wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open) {
		display: none;
	}
	.wp-block-navigation__responsive-container-open:not(.always-shown) {
		display: flex;
	}
}

/* The mobile overlay.
 *
 * Core's overlay defaults are written as
 * `.is-menu-open:not(.disable-default-overlay)` and
 * `.is-menu-open:where(...) .…-content .…-item__content`, which outrank a
 * plain two- or three-class rule. A theme that styles the overlay without
 * matching those selectors gets core's white panel with black text and no
 * padding at all — core's padding clamps against `--wp--style--root--padding-*`,
 * which this theme does not set, so the declaration is invalid and computes 0.
 * Every selector below is shaped to match core's and win on source order.
 */
.wp-block-navigation:not(.has-background) .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay) {
	background-color: var(--wp--preset--color--night);
}
.wp-block-navigation:not(.has-text-color) .wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay) {
	color: var(--wp--preset--color--cream);
}
.wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay) {
	padding: clamp(4.5rem, 16vw, 6rem) var(--sps-gutter) 2.5rem;
	align-items: stretch;
	justify-content: flex-start;
}

.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content {
	padding-top: 0;
	width: 100%;
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content .wp-block-navigation__container {
	width: 100%;
	gap: 0;
	align-items: stretch;
}

/* One rule per row, a tap target well past the 44px floor, and the display
   face the rest of the site uses. */
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content .wp-block-navigation-item {
	width: 100%;
	border-bottom: 1px solid var(--wp--preset--color--rule);
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content .wp-block-navigation-item__content {
	display: block;
	width: 100%;
	padding: 1.15rem 0;
	color: var(--wp--preset--color--cream);
	font-family: var(--wp--preset--font-family--display);
	text-transform: uppercase;
	font-size: 1.8rem;
	letter-spacing: 0.02em;
	line-height: 1.1;
	transition: color 160ms var(--sps-ease, ease);
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content .wp-block-navigation-item__content:hover,
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content .wp-block-navigation-item__content:focus-visible {
	color: var(--wp--preset--color--amber);
}

.wp-block-navigation__responsive-container-close {
	color: var(--wp--preset--color--cream);
	top: 1.35rem;
	right: var(--sps-gutter);
}
.wp-block-navigation__responsive-container-close svg { width: 30px; height: 30px; }

/* The eBay call to action, as a menu item so it lives inside the overlay —
   the header button it mirrors is behind the overlay while the menu is open,
   and the eBay store is the whole point of the site. Hidden wherever the
   desktop bar is showing, where the real button is already on screen. */
@media (min-width: 1081px) {
	.sps-nav-cta { display: none; }
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content .sps-nav-cta {
	border-bottom: 0;
	margin-top: 2.25rem;
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content .sps-nav-cta .wp-block-navigation-item__content {
	background: var(--wp--preset--color--red);
	background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.11), rgba(0, 0, 0, 0.07));
	color: var(--wp--preset--color--white, #fff);
	text-align: center;
	padding: 1rem 1.25rem;
	border-radius: var(--sps-radius);
	font-size: 1.5rem;
	/* Same moulded base as every other primary button. */
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, 0.20),
		0 4px 0 var(--sps-btn-edge, #7F1313),
		0 7px 14px rgba(0, 0, 0, 0.38);
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content .sps-nav-cta .wp-block-navigation-item__content:active {
	transform: translateY(4px);
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, 0.10),
		0 0 0 var(--sps-btn-edge, #7F1313),
		0 1px 3px rgba(0, 0, 0, 0.40);
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content .sps-nav-cta .wp-block-navigation-item__content:hover,
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content .sps-nav-cta .wp-block-navigation-item__content:focus-visible {
	background: var(--wp--preset--color--red-2);
	color: var(--wp--preset--color--white, #fff);
}

/* The logo is a wordmark: it already says the shop's name, so the site title
   beside it was saying it twice. The title stays in the markup as
   screen-reader-text — machines and assistive tech still get the site name,
   which an image alt alone does not reliably give them. */
.sps-header .wp-block-site-logo img { display: block; height: auto; }

/* Sticky header. The one piece of chrome that follows the visitor,
   because the eBay button lives in it. */
/* Sticky has to go on the template-part wrapper, not on .sps-header.
   A sticky element can only travel inside its own containing block, and
   WordPress wraps every template part in a <header> that is exactly as tall
   as its contents — so sticky applied to the inner group had zero travel and
   the header scrolled away like any static element. Sticking the wrapper,
   whose containing block is .wp-site-blocks, gives it the whole page to
   travel. (position: sticky does not create a containing block for fixed
   descendants, so this does not re-break the mobile overlay.) */
.wp-site-blocks > header.wp-block-template-part {
	position: sticky;
	top: 0;
	z-index: 40;
}

/* ---------------------------------------------------------------
   Taking the header out of the flow, but only once JS is running
   ---------------------------------------------------------------
   Sticky keeps the header in the flow, so when it condenses past the
   hero it gets shorter and the document above the viewport shrinks
   with it. The browser's scroll anchoring then moves the scroll
   position to compensate, and the page nudges under the cursor.
   Measured before this block: 0.106 CLS at 900px wide from that one
   event, which fails the 0.1 budget on its own.

   Fixed instead, with the flow space held open by a constant that the
   condense cannot change: shrinking the header now moves nothing.

   Gated on .sps-js because the padding depends on --sps-header-h,
   which only JavaScript can measure. Without JS the header stays
   sticky and never condenses, so there is nothing to shift and
   nothing to reserve — the no-JS page is correct by doing less. */
.sps-js .wp-site-blocks > header.wp-block-template-part {
	position: fixed;
	inset-inline: 0;
}
.sps-js .wp-site-blocks { padding-top: var(--sps-header-h, 0px); }

/* Anchor targets have to clear the fixed header. The old 5.5rem was a
   guess that fitted the condensed header and hid ~40px of an anchor
   target under the expanded one. */
html.sps-js { scroll-padding-top: var(--sps-header-h, 5.5rem); }
.sps-header {
	position: relative;
	border-bottom: 1px solid var(--wp--preset--color--rule);
}

/* The glass lives on a pseudo-element, not on .sps-header itself.
   A non-none backdrop-filter makes an element the containing block for every
   position:fixed descendant — which meant core's full-screen mobile overlay
   was resolving its top/bottom against the 128px header instead of the
   viewport, rendering as a letterbox with four of the five links cut off
   below the fold. Painting the same effect one level down keeps the look and
   gives the overlay the viewport back. */
.sps-header::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: color-mix(in srgb, var(--wp--preset--color--night) 92%, transparent);
	backdrop-filter: blur(8px);
}
@supports not (backdrop-filter: blur(8px)) {
	.sps-header::before { background: var(--wp--preset--color--night); }
}

/* Secondary button: outlined, for the CTA that is not the primary one
   in its bay. Applied with the "is-style-outline" core style plus this. */
.wp-block-button.is-style-outline .wp-block-button__link {
	/* 3:1 minimum: this border is the control's only boundary. */
	border-color: #6E74AE;
	color: var(--wp--preset--color--cream);
	background: transparent;
}
.wp-block-button.is-style-outline .wp-block-button__link:hover {
	border-color: var(--wp--preset--color--amber);
	color: var(--wp--preset--color--amber);
	background: transparent;
}

/* Skip link visibility on a dark ground. */
.skip-link:focus {
	background: var(--wp--preset--color--amber);
	color: var(--wp--preset--color--night);
}

/* ---------------------------------------------------------------
   6. List forms used inside HTML blocks
   These three shapes appear often enough to be styled once rather
   than rebuilt with nested columns every time.
   --------------------------------------------------------------- */

/* Tile internals. The whole tile is the link, so kill the underline
   and let the heading carry the colour change on hover. */
.sps-tile { text-decoration: none; color: inherit; }
.sps-tile h3 {
	font-family: var(--wp--preset--font-family--display);
	font-weight: 700;
	text-transform: uppercase;
	font-size: 1.5rem;
	line-height: 1.05;
	margin: 0;
	color: var(--wp--preset--color--cream);
}
.sps-tile:hover h3 { color: var(--wp--preset--color--amber); }
.sps-tile p {
	margin: 0;
	font-size: 1rem;
	line-height: 1.5;
	color: var(--wp--preset--color--cream-2);
}
.sps-tile .sps-label { margin-top: auto; padding-top: 0.5rem; }

/* Ruled rows: a term and its answer, separated by a hairline. The
   shape the "why buy" and FAQ sections use. */
.sps-rows { margin-block: 0; }   /* margin-block, never the shorthand — see the bay rule */
.sps-rows > div {
	display: grid;
	gap: 0.35rem;
	padding: 1.15rem 0;
	border-top: 1px solid var(--wp--preset--color--rule);
}
.sps-rows > div:last-child { border-bottom: 1px solid var(--wp--preset--color--rule); }
.sps-rows dt {
	font-family: var(--wp--preset--font-family--display);
	font-weight: 700;
	text-transform: uppercase;
	font-size: 1.375rem;
	line-height: 1.1;
	color: var(--wp--preset--color--cream);
}
.sps-rows dd {
	margin: 0;
	font-size: 1rem;
	line-height: 1.55;
	color: var(--wp--preset--color--cream-2);
	max-width: 52ch;
}

/* Check list: the short reassurance list beside a CTA. The marker is
   drawn in CSS so it needs no icon font and no image request. */
.sps-checks { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.7rem; }
.sps-checks li {
	position: relative;
	padding-left: 1.85rem;
	font-size: 1.0625rem;
	line-height: 1.45;
}
.sps-checks li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.34em;
	width: 0.65rem;
	height: 0.34rem;
	border-left: 2px solid var(--wp--preset--color--amber);
	border-bottom: 2px solid var(--wp--preset--color--amber);
	transform: rotate(-45deg);
}

/* The trust figures. A grid rather than a columns block so a phone gets
   two-by-two instead of four full-width rows of dead space. */
.sps-figures {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
	gap: 2rem 1.5rem;
}
.sps-figures > div { display: grid; gap: 0.25rem; align-content: start; }

/* Tile number. Carried over from the Shopify shop-by-category section,
   where the 01–05 sequence is doing the ordering the eye follows. */
.sps-tile__num {
	font-family: var(--wp--preset--font-family--pixel);
	font-size: var(--wp--preset--font-size--label);
	color: var(--wp--preset--color--cream-2);
	line-height: 1;
}
.sps-tile:hover .sps-tile__num { color: var(--wp--preset--color--red-text); }

/* The feedback wall. Three verified reviews, equal height, quote marks
   left off on purpose — the star row already says what this is. */
/* The review wall is a carousel: a native scroll-snap track, not a widget.
 *
 * Six reviews will not fit across a page without shrinking to unreadable, and
 * stacking them costs a screen and a half of vertical space for content most
 * visitors skim. A horizontal track solves both, and doing it with overflow
 * and scroll-snap rather than a slider library means it works before any
 * JavaScript runs: touch swipe, trackpad, keyboard arrows and a real
 * scrollbar all come free from the browser. The buttons the script adds are
 * a convenience on top of a thing that already works, not the mechanism.
 *
 * `scroll-padding-inline` matters: without it a snapped card sits flush to
 * the edge with its shadow clipped. */
.sps-quotes {
	/* position: relative is load-bearing, not tidiness.
	 *
	 * Every card carries a .screen-reader-text span, which WordPress styles
	 * as `position: absolute` with a 1px box. `overflow` does not clip an
	 * absolutely positioned descendant whose containing block is an ancestor
	 * OUTSIDE the scroller — so the spans belonging to cards 4, 5 and 6 sat
	 * at x≈2600 and dragged the whole PAGE into horizontal scroll, ~950px of
	 * it. Making the track the containing block clips them with everything
	 * else.
	 *
	 * It only showed up under prefers-reduced-motion: with motion allowed the
	 * track carries the reveal's transform, and a transform already makes an
	 * element a containing block, which was hiding the bug. */
	position: relative;
	display: flex;
	gap: 1rem;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scroll-padding-inline: 0;
	/* Room for the cards' shadow and the hover lift, which would otherwise be
	   clipped by the scroll container. */
	padding-block: 0.5rem 1.25rem;
	overscroll-behavior-x: contain;
	scrollbar-width: thin;
	scrollbar-color: var(--wp--preset--color--rule) transparent;
}
.sps-quotes > * {
	flex: 0 0 auto;
	scroll-snap-align: start;
	/* Three across at the full measure, two on a tablet, one on a phone —
	   expressed as a width rather than a media query so it responds to the
	   container it is actually in. */
	width: calc((100% - 2rem) / 3);
	min-width: 17rem;
}
@media (max-width: 62rem) {
	.sps-quotes > * { width: calc((100% - 1rem) / 2); }
}
@media (max-width: 40rem) {
	.sps-quotes > * { width: 100%; min-width: 0; }
}

/* WebKit still needs its own scrollbar pseudo-elements. */
.sps-quotes::-webkit-scrollbar { height: 8px; }
.sps-quotes::-webkit-scrollbar-track { background: transparent; }
.sps-quotes::-webkit-scrollbar-thumb {
	background: var(--wp--preset--color--rule);
	border-radius: 999px;
}
.sps-quotes::-webkit-scrollbar-thumb:hover { background: var(--wp--preset--color--cream-2); }

/* The scroll container is focusable so it can be reached and driven from the
   keyboard; give that focus a visible ring like everything else. */
.sps-quotes:focus-visible {
	outline: 2px solid var(--wp--preset--color--amber);
	outline-offset: 4px;
}
.sps-quote { display: grid; gap: 0.75rem; align-content: start; margin: 0; }
.sps-quote__stars { color: var(--wp--preset--color--amber); letter-spacing: 0.15em; font-size: 1rem; }
.sps-quote blockquote {
	margin: 0;
	font-size: 1.0625rem;
	line-height: 1.55;
	color: var(--wp--preset--color--cream);
}
.sps-quote__meta {
	font-family: var(--wp--preset--font-family--display);
	text-transform: uppercase;
	font-size: 1rem;
	letter-spacing: 0.04em;
	color: var(--wp--preset--color--amber);
	line-height: 1.45;
}
.sps-quote__meta span {
	color: var(--wp--preset--color--cream-2);
	text-transform: none;
	font-family: var(--wp--preset--font-family--sans);
	font-size: 0.875rem;
	letter-spacing: 0;
}

/* ---------------------------------------------------------------
   7. The sell page
   --------------------------------------------------------------- */

/* Numbered steps. The number is set in the pixel face because it is the
   one place a retro cue reads as structure rather than decoration. */
.sps-steps {
	list-style: none;
	/* margin-block, not the margin shorthand: the bay gives every direct child
	   'margin-inline: auto' so it centres once the viewport outgrows the
	   measure. A shorthand reset here would cancel that and pin this list to
	   the padding edge, left of every other section, above ~1450px. */
	margin-block: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
	gap: 1rem;
}
.sps-steps li {
	display: grid;
	gap: 0.6rem;
	align-content: start;
	background: var(--wp--preset--color--panel);
	border: 1px solid var(--wp--preset--color--rule);
	border-top: 3px solid var(--wp--preset--color--red);
	border-radius: var(--sps-radius);
	padding: 1.5rem 1.35rem;
}
.sps-steps__num {
	font-family: var(--wp--preset--font-family--pixel);
	font-size: var(--wp--preset--font-size--label);
	color: var(--wp--preset--color--amber);
}
.sps-steps h3, .sps-buylists h2, .sps-buylists h3, .sps-compare h3 {
	font-family: var(--wp--preset--font-family--display);
	font-weight: 700;
	text-transform: uppercase;
	font-size: 1.5rem;
	line-height: 1.05;
	margin: 0;
	color: var(--wp--preset--color--cream);
}
.sps-steps p, .sps-buylists p, .sps-compare p {
	margin: 0;
	font-size: 1rem;
	line-height: 1.55;
	color: var(--wp--preset--color--cream-2);
}

/* Two (or four) equal cards side by side. */
.sps-buylists {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
	gap: 1rem;
}
.sps-buylists--four { grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
/* min-width: 0 is the grid guard. A grid item's default min-width is
   `auto`, which means it refuses to shrink below its content's min-content
   width — and one card here holds info@savepointshop.ca, an unbreakable
   23-character string. The track was capped at 1fr while the content kept
   its intrinsic width, so every child of that one card hung 68px outside the
   card's own border at 1300px wide. `overflow-wrap: anywhere` then lets the
   address itself break rather than just stop overflowing. */
.sps-buylists .sps-card {
	display: grid;
	gap: 0.9rem;
	align-content: start;
	min-width: 0;
}
.sps-buylists .sps-card h2,
.sps-buylists .sps-card h3 { overflow-wrap: anywhere; }

/* The contact cards put the label in the heading and the value in the
   paragraph — "Email" as the h2, the address as the text — because a
   crawler reads a page's h2s as its section topics, and four headings
   reading "info@savepointshop.ca", "thesavepointshop", "Norfolk County"
   and "Within 24 hours" told it nothing. Swapping them means the heading
   now has to look like a label and the paragraph like a heading, which
   is what these two rules do. Class hooks rather than inline styles, so
   the markup stays readable and this stays editable in one place. */
.sps-buylists .sps-card h2.sps-label {
	font-family: var(--wp--preset--font-family--pixel);
	font-size: var(--wp--preset--font-size--label);
	font-weight: 400;
	letter-spacing: 0.06em;
	line-height: 1.8;
	color: var(--wp--preset--color--cream-2);
}
.sps-buylists .sps-card .sps-card__value {
	font-family: var(--wp--preset--font-family--display);
	font-weight: 700;
	text-transform: uppercase;
	font-size: 1.5rem;
	letter-spacing: -0.01em;
	line-height: 1.05;
	color: var(--wp--preset--color--cream);
	overflow-wrap: anywhere;
}

/* overflow-wrap: anywhere above stops the address hanging outside the card,
   but it pays for that by breaking mid-word when the track is a few pixels
   short: between roughly 1120px and 1296px wide the four-up grid gives each
   value 213px, info@savepointshop.ca wants 219px at this size, and the card
   renders INFO@SAVEPOINTSHOP.C with a lone A under it. A container query
   rather than a viewport one, because what is actually too narrow is the
   card — the same four-up grid turns up at different viewport widths on
   pages with different gutters. */
.sps-buylists--four .sps-card { container-type: inline-size; }
@container (max-width: 15.6rem) {
	.sps-buylists .sps-card .sps-card__value { font-size: 1.25rem; }
}

/* Tag list: what we buy, as chips rather than bullets, so a seller can
   scan it for their own shelf in one pass. */
.sps-tags { list-style: none; margin-block: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.5rem; }
.sps-tags li {
	font-family: var(--wp--preset--font-family--display);
	text-transform: uppercase;
	font-size: 1.0625rem;
	letter-spacing: 0.02em;
	line-height: 1;
	padding: 0.5rem 0.75rem;
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: var(--sps-radius);
	color: var(--wp--preset--color--cream);
	background: var(--wp--preset--color--night);
}

/* Outright vs consignment, side by side and equal height. */
.sps-compare {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(21rem, 100%), 1fr));
	gap: 1rem;
}
.sps-compare .sps-card { display: grid; gap: 1rem; align-content: start; }
.sps-compare__best { margin-top: auto; padding-top: 0.5rem; }

/* The three consignment terms. These are real commitments — 20%, $75,
   three business days — so they get the figure treatment. */
.sps-terms {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
	gap: 1.5rem;
	margin-top: 2rem;
	padding-top: 2rem;
	border-top: 1px solid var(--wp--preset--color--rule);
}
.sps-terms > div { display: grid; gap: 0.4rem; align-content: start; }
.sps-terms__text {
	font-family: var(--wp--preset--font-family--display);
	text-transform: uppercase;
	font-size: 1.375rem;
	line-height: 1.1;
	color: var(--wp--preset--color--cream);
	margin: 0;
}

/* FAQ. Core details blocks, ruled rather than boxed. */
.sps-faq .wp-block-details {
	border-top: 1px solid var(--wp--preset--color--rule);
	padding: 1.15rem 0;
}
.sps-faq .wp-block-details:last-child { border-bottom: 1px solid var(--wp--preset--color--rule); }
.sps-faq summary {
	cursor: pointer;
	font-family: var(--wp--preset--font-family--display);
	font-weight: 700;
	text-transform: uppercase;
	font-size: 1.375rem;
	line-height: 1.15;
	color: var(--wp--preset--color--cream);
	list-style: none;
}
.sps-faq summary::-webkit-details-marker { display: none; }
.sps-faq summary::after {
	content: "+";
	float: right;
	color: var(--wp--preset--color--red-2);
	font-weight: 600;
	margin-left: 1rem;
}
.sps-faq details[open] summary::after { content: "–"; }
.sps-faq details p {
	margin-top: 0.75rem;
	color: var(--wp--preset--color--cream-2);
	max-width: 62ch;
}

/* ---------------------------------------------------------------
   8. The quote form
   Inputs are 16px and ~48px tall on purpose: below 16px, iOS zooms the
   page the moment a field is tapped, and most of this traffic is a
   phone in someone's basement looking at a box of carts.
   --------------------------------------------------------------- */

.sps-form { display: grid; gap: 1.1rem; }
.sps-form__row { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 1.1rem; }
.sps-field { display: grid; gap: 0.4rem; }
.sps-field > label {
	font-family: var(--wp--preset--font-family--display);
	text-transform: uppercase;
	font-size: 1.0625rem;
	letter-spacing: 0.03em;
	color: var(--wp--preset--color--cream);
}
.sps-field .req { color: var(--wp--preset--color--red-text); } /* red-2 measured 3.38:1 on the card; body text needs 4.5:1 */
.sps-field input,
.sps-field select,
.sps-field textarea {
	font-family: var(--wp--preset--font-family--sans);
	font-size: 16px;
	line-height: 1.5;
	color: var(--wp--preset--color--cream);
	background: var(--wp--preset--color--night);
	/* A control has to be identifiable as a control: the rule colour gives a
	   1.36:1 edge, which is not a boundary, it is a rumour. */
	border: 1px solid #6E74AE; /* 3.88:1 on night, 3.61:1 on panel — 1.4.11 wants 3:1; #5A5F8C measured 2.80:1 */
	border-radius: var(--sps-radius);
	padding: 0.75rem 0.85rem;
	min-height: 48px;
	width: 100%;
}
.sps-field textarea { min-height: 9rem; resize: vertical; }
/* No opacity: cream-2 at 70% is 3.56:1. Plain cream-2 is 5.9:1. */
.sps-field input::placeholder,
.sps-field textarea::placeholder { color: var(--wp--preset--color--cream-2); opacity: 1; }
.sps-field input:focus,
.sps-field select:focus,
.sps-field textarea:focus {
	/* An outline, not a box-shadow: a shadow ring disappears entirely in
	   forced-colors mode, and the old one computed to 1.15:1 anyway. Amber
	   matches the focus ring theme.json already sets for links and buttons. */
	outline: 2px solid var(--wp--preset--color--amber);
	outline-offset: 2px;
	border-color: var(--wp--preset--color--amber);
}
.sps-field__hint { font-size: 0.875rem; color: var(--wp--preset--color--cream-2); }

/* Said next to the photo picker, before the upload is attempted, when the
   batch is one the server would throw away without a word. */
.sps-field__error {
	font-size: 0.9375rem;
	line-height: 1.5;
	margin: 0.6rem 0 0;
	padding: 0.6rem 0.8rem;
	border-left: 3px solid var(--wp--preset--color--red-2);
	background: rgba(224, 43, 43, 0.10);
	color: var(--wp--preset--color--cream);
	border-radius: 0 4px 4px 0;
	/* The message quotes the file's own name back, and a phone's name for a
	   photo is one unbreakable 40-character token. Without this it pushes
	   the whole page sideways. */
	overflow-wrap: anywhere;
}
.sps-field__error[hidden] { display: none; }

/* Two paragraphs in the "sent, but we lost a photo" banner need the gap the
   single-paragraph banners do not. */
.sps-result p + p { margin-top: 0.75rem; }

/* The upload field styled properly — the one thing the Shopify form app
   could not do on its free plan, where the dropzone rendered white. */
.sps-field input[type="file"] { padding: 0.65rem; background: var(--wp--preset--color--night-deep); }
.sps-field input[type="file"]::file-selector-button {
	font-family: var(--wp--preset--font-family--display);
	text-transform: uppercase;
	font-size: 1rem;
	color: var(--wp--preset--color--cream);
	background: var(--wp--preset--color--panel);
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: 4px;
	padding: 0.45rem 0.8rem;
	margin-right: 0.75rem;
	cursor: pointer;
}
.sps-form__submit { width: 100%; }
.sps-form__note { font-size: 0.875rem; color: var(--wp--preset--color--cream-2); }

/* Honest banner for a section that is built but not yet connected.
   Delete this rule the day the form is wired. */
.sps-unwired {
	border: 1px dashed var(--wp--preset--color--amber);
	border-radius: var(--sps-radius);
	background: rgba(245, 166, 35, 0.08);
	color: var(--wp--preset--color--amber);
	font-family: var(--wp--preset--font-family--pixel);
	font-size: var(--wp--preset--font-size--label);
	line-height: 1.9;
	padding: 0.9rem 1rem;
	margin-bottom: 1.5rem;
}

/* The honeypot. Hidden from sight and from screen readers, but not with
   display:none — some bots skip fields they can tell are hidden that way. */
.sps-hp {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* Result banners, shown in place of (or above) the form after a submission. */
.sps-result {
	border-radius: var(--sps-radius);
	padding: 1.25rem 1.4rem;
	font-size: 1.0625rem;
	line-height: 1.55;
	margin-bottom: 1.25rem;
}
.sps-result p { margin: 0; }
.sps-result--sent {
	border: 1px solid var(--wp--preset--color--amber);
	background: rgba(245, 166, 35, 0.10);
	color: var(--wp--preset--color--cream);
}
.sps-result--error {
	border: 1px solid var(--wp--preset--color--red-2);
	background: rgba(224, 43, 43, 0.10);
	color: var(--wp--preset--color--cream);
}

/* Links inside a card heading keep the heading's weight and pick up the
   amber on hover, rather than inheriting the body link colour. */
.sps-buylists h2 a, .sps-buylists h3 a, .sps-compare h3 a { text-decoration: none; color: inherit; }
.sps-buylists h2 a:hover, .sps-buylists h3 a:hover, .sps-compare h3 a:hover { color: var(--wp--preset--color--amber); }
.sps-buylists .sps-checks { font-size: 1rem; }

/* The dateline under the trust figures. Saying when a number was checked is
   what makes the number worth printing. */
.sps-figures__asof {
	margin-top: 1.75rem;
	padding-top: 1.25rem;
	border-top: 1px solid var(--wp--preset--color--rule);
}

/* ---------------------------------------------------------------
   9. Brand artwork
   The illustrations came off the Shopify build and carry their own
   palette — teal Saveo, orange-and-blue wordmark. They sit on the navy
   without a plate behind them; boxing them in a card would fight the
   fact that they are cut-outs on transparency.
   --------------------------------------------------------------- */

.sps-hero__art { align-self: center; margin: 0; }
.sps-hero__art img { width: 100%; height: auto; display: block; }

/* Category tile icon. Sized so the illustration leads and the heading
   still reads as the thing you click. */
.sps-tile__icon {
	width: 100%;
	max-width: 7.5rem;
	height: auto;
	margin-bottom: 0.35rem;
	filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.35));
}

/* Saveo beside a section heading. Floats right of the head on a wide
   screen, drops above it on a phone rather than shrinking to nothing. */
.sps-bay__head--withart { position: relative; }
.sps-head__art {
	width: 11rem;
	height: auto;
	float: right;
	margin: 0 0 1rem 1.5rem;
	filter: drop-shadow(0 6px 16px rgba(0, 0, 0, 0.4));
}
@media (max-width: 600px) {
	.sps-head__art { float: none; display: block; margin: 0 0 1rem; width: 6.5rem; }
}

/* Three real photographs, equal and square. */
.sps-gallery {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
	gap: 1rem;
	margin-top: 2.5rem;
}
.sps-gallery img {
	width: 100%;
	height: 100%;
	aspect-ratio: 1;
	object-fit: cover;
	border-radius: var(--sps-radius);
	border: 1px solid var(--wp--preset--color--rule);
	display: block;
}

/* The Top Rated badge, sized as a mark rather than a picture. */
.sps-card__badge { width: 4.5rem; height: auto; }

/* The storefront band: Saveo holding the eBay mark, next to the one button
   that leaves the site. Stacks on a phone with the art first. */
.sps-storefront {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: clamp(1.25rem, 3vw, 2.5rem);
	margin-top: 2.5rem;
	padding: clamp(1.25rem, 3vw, 2rem);
	background: var(--wp--preset--color--panel);
	border: 1px solid var(--wp--preset--color--rule);
	border-radius: var(--sps-radius);
}
.sps-storefront img { width: clamp(6rem, 12vw, 9rem); height: auto; flex: none; }
.sps-storefront > div { flex: 1 1 18rem; display: grid; gap: 0.75rem; }
.sps-storefront p { margin: 0; color: var(--wp--preset--color--cream-2); max-width: 54ch; }
.sps-storefront .sps-label { color: var(--wp--preset--color--amber); }


/* ---------------------------------------------------------------
   Utilities
   --------------------------------------------------------------- */

/* Visually hidden, still announced. Used for star ratings, "opens in a new
   tab", and anywhere an icon carries the meaning. */
.screen-reader-text {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* A sentence-length note. The pixel face is a 10px display type — fine for a
   two-word eyebrow, punishing for a whole line of prose, which is what
   .sps-label was quietly being used for in five places. */
.sps-note {
	font-size: 0.875rem;
	line-height: 1.55;
	color: var(--wp--preset--color--cream-2);
	letter-spacing: 0.01em;
}

/* The sticky header is ~60px, so anchor targets and freshly-focused elements
   have to be pushed clear of it or they land underneath. */
html { scroll-padding-top: 5.5rem; } /* no-JS fallback; the JS path overrides with the measured height */
[id] { scroll-margin-top: 5.5rem; }

/* The submission result banner takes focus, and should not draw a ring for
   a mouse user who never asked for one. */
.sps-result:focus { outline: none; }
.sps-result:focus-visible { outline: 2px solid var(--wp--preset--color--amber); outline-offset: 3px; }

/* ---------------------------------------------------------------
   Reflow at the 320px floor (WCAG 1.4.10)
   ---------------------------------------------------------------
   Two things pushed the page sideways at a 320px viewport — which is
   where a 1280px screen lands at the 400% zoom a low-vision visitor
   actually uses, so it is not a hypothetical width.

   1. The display headings are set in a clamp() whose floor is still
      large enough that one long word ("collecting") is wider than the
      column. Nothing was wrong with the box; the word simply could not
      fit on a line and refused to break.
   2. A core image block is a <figure>, and the UA stylesheet gives
      figure a 40px inline margin. Core's block styles normally reset
      it; this does not depend on them arriving. */
h1, h2, h3, .sps-accent { overflow-wrap: break-word; }
.wp-block-image, .wp-block-image figure { margin-inline: 0; }
