/*
 * PouchPick Design System — PouchPick-owned foundation (--pp-* / .pp-*).
 *
 * v1 (S0–S8): colours, typography, spacing, radii, container, the .pp-btn /
 * .pp-input primitives and the focus ring — values taken 1:1 from DESIGN.md.
 *
 * S9D-A (Global Commerce Polish — foundations, 2026-09-03): the storefront-
 * wide FOUNDATION locked by design-locks/GLOBAL-COMMERCE-POLISH-LOCK.md
 * (S9C v1.0 FINAL) and measured from the promoted lab
 * design-lab/final/global-polish/ (Hybrid V2): colour-depth / motion /
 * control-size / type-scale / spacing tokens (§7, §10, §11, §17), the
 * two-scope control reset (§12), the button system + Press signature
 * (§3, §4), compact-control and icon-button primitives, the field system
 * (§13) with scoped WooCommerce / SelectWoo normalization (§12, §14), one
 * focus language (§16 / §50), the ≥44px hit-area and safe-area utilities
 * (§15, §16), the inline-SVG icon class (§18), the modal scroll-lock
 * primitive (§8) and the settle keyframe (§6) for later gates.
 *
 * Surface-level application of these primitives (header, cards, tiers,
 * drawer, PLP filters, PDP, checkout, account, footer) belongs to the
 * S9D-B+ gates — this file deliberately creates the foundation and does not
 * restyle those surfaces. Zero WoodMart variables/classes. No Market
 * literal: every value here is a design token or a technical constant
 * (MARKET-ARCHITECTURE.md §14 "Not covered by this rule").
 */

/* =========================================================================
 * 1. TOKENS
 * ====================================================================== */
:root {
	/* Colours — DESIGN.md */
	--pp-ink: #111111;
	--pp-page-bg: #FFFFFF;
	--pp-soft-surface: #F6F6F5;
	--pp-secondary-surface: #EEEFEF;
	--pp-card-bg: #FFFFFF;
	--pp-secondary-text: #676767;
	--pp-border: #DADDDC;
	--pp-header-bg: #FFFFFF;
	--pp-navy: #142F51;
	--pp-navy-tint: rgba(20, 47, 81, 0.06);
	--pp-green: #47D758;
	--pp-red: #F00000;
	--pp-lime: #D7FF00;
	--pp-success-text: #1A7A3D;

	/* Colour depth — GLOBAL-COMMERCE-POLISH-LOCK.md §10 (Hybrid V2 values).
	   Navy gains ONE hover and ONE pressed step; semantic tints, the overlay
	   scrim and the popover / drawer / sticky shadows become tokens. Roles
	   are unchanged: Red = error / genuine sale, Green = success, Amber =
	   warning / on hold, Lime stays scarce (never a CTA). */
	--pp-navy-hover: #0E2440;
	--pp-navy-pressed: #0A1B31;
	--pp-navy-chrome: #0B1D38;         /* HEADER-COMMERCE-LOCK.md two-Navy system: the campaign/utility rail's darker chrome layer — never a CTA, never a third hue family */
	--pp-navy-tint-strong: rgba(20, 47, 81, 0.12);
	--pp-border-hover: #B9BDBC;
	--pp-error-bg: #FFF2F2;
	--pp-error-border: #F5B8B8;
	--pp-error-text: #8A1414;
	--pp-success-bg: #F2FBF3;
	--pp-success-border: #B8E6BD;
	--pp-amber-text: #8A6D1F;
	--pp-amber-bg: #FDF8EA;
	--pp-amber-border: #F0E2B8;
	--pp-info-bg: var(--pp-soft-surface);
	--pp-overlay: rgba(17, 17, 17, 0.32);
	--pp-shadow-popover: 0 16px 40px rgba(17, 17, 17, 0.14);
	--pp-shadow-drawer: -12px 0 30px rgba(0, 0, 0, 0.14);
	--pp-shadow-sticky: 0 -6px 16px rgba(17, 17, 17, 0.07);

	/* Typography — DESIGN.md */
	--pp-font-display: 'Barlow', sans-serif;
	--pp-font-body: 'Inter', sans-serif;

	/* Type scale — lock §11 (roles, not raw sizes). Declared for the S9D
	   surface gates; body copy keeps its current computed size until the
	   page-title / body roles are migrated surface by surface. */
	--pp-text-display: clamp(2.25rem, 4vw, 3rem);
	--pp-text-page-title: clamp(1.625rem, 2.4vw, 1.75rem);   /* 26–28: PLP / Cart / Checkout / Account / Order Received */
	--pp-text-section-title: 1.875rem;                        /* 30: Homepage sections */
	--pp-text-sub-title: 1.1875rem;                           /* 19 */
	--pp-text-card-title: 0.9375rem;                          /* 15 */
	--pp-text-price-primary: 1.25rem;                         /* 20 */
	--pp-text-price-total: 1.875rem;                          /* 30: PDP total (PDP lock) */
	--pp-text-body: 0.9375rem;                                /* 15 */
	--pp-text-label: 0.8125rem;                               /* 13 */
	--pp-text-meta: 0.75rem;                                  /* 12 — metadata floor 11 */
	--pp-text-meta-min: 0.6875rem;                            /* 11 */
	--pp-text-btn-l: 1rem;
	--pp-text-btn-m: 0.875rem;
	--pp-text-btn-s: 0.8125rem;

	/* Spacing scale */
	--pp-space-1: 4px;
	--pp-space-2: 8px;
	--pp-space-3: 12px;
	--pp-space-4: 16px;
	--pp-space-5: 24px;
	--pp-space-6: 32px;
	--pp-space-7: 40px;

	/* Spacing rhythm — lock §17 (container ≈1320, desktop gutter 32, primary
	   mobile commerce gutter 16; Account keeps its own locked 18px token in
	   account.css). */
	--pp-gutter: 32px;
	--pp-gutter-mobile: 16px;
	--pp-section-gap-l: 48px;
	--pp-section-gap-m: 40px;
	--pp-section-gap-s: 32px;
	--pp-component-gap: 24px;
	--pp-component-gap-s: 16px;
	/* Homepage vertical rhythm — HOMEPAGE-VERTICAL-RHYTHM-LOCK.md (B — Balanced
	   Commerce): fluid 390→1440, frozen outside; consumed only by the homepage
	   section roles in home-page.css. The --pp-section-gap-* tokens above stay
	   the PDP / footer / non-home authority. */
	--pp-home-vr-1: clamp(12px, calc(12px + (100vw - 390px) * 0.007619), 20px);
	--pp-home-vr-2: clamp(18px, calc(18px + (100vw - 390px) * 0.009524), 28px);
	--pp-home-vr-3: clamp(22px, calc(22px + (100vw - 390px) * 0.011429), 34px);
	--pp-home-vr-4: clamp(26px, calc(26px + (100vw - 390px) * 0.013333), 40px);
	--pp-home-vr-5: clamp(30px, calc(30px + (100vw - 390px) * 0.015238), 46px);
	--pp-home-vr-6: clamp(32px, calc(32px + (100vw - 390px) * 0.019048), 52px);
	--pp-card-pad: 16px;
	--pp-card-pad-compact: 12px;
	--pp-control-gap: 8px;

	/* Radii */
	--pp-radius-sm: 6px;
	--pp-radius-md: 9px;
	--pp-radius-lg: 12px;
	--pp-radius-btn: var(--pp-radius-md);        /* normal rectangular commerce control — lock §3 (circular icon controls are a preserved exception) */
	--pp-radius-control: var(--pp-radius-sm);    /* compact commerce controls: tier cells, steppers, chips, icon buttons */
	--pp-radius-card: var(--pp-radius-lg);
	--pp-radius-edge: 1px;
	/* Edge — lock §5: the Level-1 proportion (≈73/27 Navy/Lime, hard boundary)
	   reused as the ONE selection mark; consumed only by selected tier cells
	   and active facet triggers (product-card.css / plp.css). */
	--pp-edge-gradient: linear-gradient(90deg, var(--pp-navy) 0 73.3%, var(--pp-lime) 73.3% 100%);

	/* Control sizes — lock §3 (L 52 / M 44 / S 36), §15 (≥44px effective
	   true-mobile hit area), §18 (20 / 24px icon glyphs). */
	--pp-btn-h-l: 52px;
	--pp-btn-h-m: 44px;
	--pp-btn-h-s: 36px;
	--pp-hit-min: 44px;
	--pp-icon: 20px;
	--pp-icon-lg: 24px;

	/* Layout */
	--pp-container-max: 1320px;

	/* Focus — one language site-wide (lock §13 / §16 / §50): 1px Ink ring on
	   light controls; Navy fills get a 2px white gap + Ink ring so the ring is
	   visible on the CTA itself (S9A gap: 1px Ink on Navy is near-invisible). */
	--pp-focus-ring: 0 0 0 1px var(--pp-ink);
	--pp-focus-ring-on-dark: 0 0 0 2px #fff, 0 0 0 4px var(--pp-ink);

	/* Motion — lock §7 (categories, curves and the reduced-motion equivalents
	   below are locked; values sit inside the ±20ms tuning latitude). CSS
	   transitions + small vanilla JS only — no animation framework. */
	--pp-motion-micro: 120ms;
	--pp-motion-component: 200ms;
	--pp-motion-component-exit: 140ms;
	--pp-motion-overlay: 260ms;
	--pp-motion-overlay-exit: 200ms;
	--pp-motion-feedback: 220ms;
	--pp-motion-press-in: 100ms;
	--pp-motion-press-out: 180ms;
	--pp-motion-stagger: 60ms;
	--pp-motion-ticker: 360ms;
	--pp-motion-entrance: 240ms;
	--pp-motion-popover: 210ms;                    /* FULL popover-surface arrival (INT.5) */
	--pp-motion-popover-fast: 165ms;               /* COMPACT popover-surface arrival (INT.5 / INT.6) */
	--pp-ease-out: cubic-bezier(0.2, 0, 0, 1);     /* enter — decelerate */
	--pp-ease-in: cubic-bezier(0.4, 0, 1, 1);      /* exit — accelerate */
	--pp-ease-standard: cubic-bezier(0.2, 0, 0.2, 1);
	--pp-ease-enter: cubic-bezier(0.16, 1, 0.3, 1); /* E3 — popover arrival (INT.3 lock) */
	--pp-press-scale: 0.985;                       /* Press — lock §4: shade first, scale second */
	--pp-press-scale-compact: 0.97;
	--pp-lift: 2px;                                /* Lifted Can — lock §9 (desktop hover only, applied by the card gates); PI.1 raises it to 4px in the standard-card context only */
	--pp-tilt: 1.6deg;                             /* PI.1 pick-up tilt (H4) — one consistent direction; consumed only by the standard-card hover, zeroed under reduced motion like --pp-lift */
	--pp-settle-rise: 3px;                         /* Settle — lock §6 (applied by the commerce-feedback gates) */

	/* UI.1 interaction system (Human Lock, PouchPick-Labs design/ui-session-lock/UI-HUMAN-LOCK.md
	   §5 H2 · §7 directional · §9 C2). Hover-capable input only — every consumer sits inside
	   @media (hover: hover), so a tap never leaves a lift, a shadow or a travelled arrow behind.
	   Only transform / box-shadow / colour move: zero layout shift by construction. */
	--pp-hover-rise: 2px;                          /* H2: a button/pill control lifts ~2px as ONE object */
	--pp-card-rise: 1px;                           /* C2: a single-link card lifts ~1px */
	--pp-dir-travel: 2px;                          /* a directional arrow travels 2px in its direction */
	--pp-shadow-hover: 0 6px 14px -10px rgba(11, 29, 56, .35);      /* H2 separation, light controls (HIL R1 H2) */
	--pp-shadow-hover-navy: 0 6px 14px -8px rgba(11, 29, 56, .5);   /* H2 separation, Navy-filled controls (HIL R1 H2 Cart pill) */
	--pp-shadow-hover-on-dark: 0 8px 18px -10px rgba(0, 0, 0, .45); /* H2 separation, inverse controls on Navy surfaces (IC.2 H2) */

	/* Safe areas — lock §16. Inert (0px) until the viewport meta opts into
	   `viewport-fit=cover`; that activation belongs to the gate that owns the
	   sticky surfaces, together with the left/right insets it then requires. */
	--pp-safe-top: env(safe-area-inset-top, 0px);
	--pp-safe-right: env(safe-area-inset-right, 0px);
	--pp-safe-bottom: env(safe-area-inset-bottom, 0px);
	--pp-safe-left: env(safe-area-inset-left, 0px);

	/* Scroll-lock scrollbar compensation — written by assets/js/pp-overlay.js
	   while a modal overlay is open (0 on overlay-scrollbar platforms). */
	--pp-scrollbar-comp: 0px;
}

/* =========================================================================
 * 2. REDUCED MOTION — every motion category declares its own equivalent
 *    (lock §7). Only the tokens change here; transitions that exist for
 *    state readability keep working at the reduced values, and nothing is
 *    globally stripped.
 * ====================================================================== */
@media (prefers-reduced-motion: reduce) {
	:root {
		--pp-motion-micro: 80ms;            /* colour / border only — transforms are removed below */
		--pp-motion-component: 0ms;
		--pp-motion-component-exit: 0ms;
		--pp-motion-overlay: 120ms;         /* fade only */
		--pp-motion-overlay-exit: 100ms;
		--pp-motion-feedback: 0ms;
		--pp-motion-press-in: 0ms;
		--pp-motion-press-out: 0ms;
		--pp-motion-stagger: 0ms;
		--pp-motion-ticker: 0ms;
		--pp-motion-entrance: 0ms;
		--pp-motion-popover: 80ms;          /* G0 — FULL/COMPACT surfaces fade only; travel removed per component */
		--pp-motion-popover-fast: 80ms;
		--pp-press-scale: 1;
		--pp-press-scale-compact: 1;
		--pp-lift: 0px;
		--pp-tilt: 0deg;
		--pp-settle-rise: 0px;
		--pp-hover-rise: 0px;               /* UI.1: no lift, no card rise, no arrow travel — colour/shadow state only */
		--pp-card-rise: 0px;
		--pp-dir-travel: 0px;
	}
	/* Component-level equivalents (transform: none, spinner slowdown) live in
	   section 12b, after the primitives they override, so they win at equal
	   specificity by source order. */
}

/* =========================================================================
 * 3. BASE
 * ====================================================================== */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
	margin: 0;
	background: var(--pp-page-bg);
	color: var(--pp-ink);
	font-family: var(--pp-font-body);
	font-size: 16px;
	line-height: 1.5;
	-webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }

a { color: inherit; text-decoration: none; }

h1, h2, h3, h4 {
	font-family: var(--pp-font-display);
	font-weight: 600;
	letter-spacing: -0.02em;
	margin: 0;
}

/* Typography roles — DESIGN.md Hierarchy */
.pp-display  { font: 600 clamp(2.5rem, 4vw, 3rem)/1.08 var(--pp-font-display); letter-spacing: -0.02em; }
.pp-headline { font: 600 2rem/1.12 var(--pp-font-display); letter-spacing: -0.02em; }
.pp-title    { font: 600 1.5rem/1.15 var(--pp-font-display); letter-spacing: -0.015em; }
.pp-body     { font: 400 1rem/1.5 var(--pp-font-body); }
.pp-label    { font: 500 0.8125rem/1.3 var(--pp-font-body); }

.pp-container {
	max-width: var(--pp-container-max);
	margin: 0 auto;
	padding-inline: var(--pp-gutter);
}
@media (max-width: 480px) {
	.pp-container { padding-inline: var(--pp-gutter-mobile); }
}

/* =========================================================================
 * 4. CONTROL RESET — two scopes, never one blanket rule (lock §12)
 * ====================================================================== */

/* Scope 1 — EVERY control inherits the PouchPick type and colour. This is
   the only rule that touches unknown WooCommerce / extension / gateway
   controls: it removes the browser default (Arial / system-ui / iOS accent-
   blue button text — S9A F4, S8F V2) and nothing else. Element-level
   specificity, so any class-based presentation such a control carries
   still wins; an unrecognised control keeps its own shape and stays
   usable. Longhands on purpose, not the `font` shorthand: the shorthand
   would also inherit the body line-height (1.5) into every control and
   grow tier cells, nav items, steppers and Place Order by 3–6px (measured);
   line-height stays with the component (or the browser default) so this
   gate changes type, never geometry. */
button, input, select, textarea {
	font-family: inherit;
	font-size: inherit;
	font-weight: inherit;
	font-style: inherit;
	color: inherit;
	letter-spacing: inherit;
	margin: 0;
}
textarea { resize: vertical; }
input[type="search"] { -webkit-appearance: none; appearance: none; }
input[type="checkbox"], input[type="radio"] {
	accent-color: var(--pp-navy);   /* native checkbox / radio semantics kept — never appearance:none on these two */
	width: 18px; height: 18px;
	flex: none;
	cursor: pointer;
}
a, button, input, select, textarea, summary, [tabindex] { touch-action: manipulation; }

/* Scope 2 — PouchPick-OWNED buttons (any `pp-*` class, or the header's two
   attribute-addressed icon toggles) get the full reset before their
   component styles apply. `:where()` keeps this at zero specificity, so
   every component rule — including the ones that exist today — wins
   wherever it declares a value, and this only fills in what a component
   left to the browser. Deliberately NOT applied to `.button` / `.input-text`
   / gateway-injected controls: those are normalized only through the scoped
   rules in section 8. */
:where(button, input[type="button"], input[type="submit"], input[type="reset"]):where([class^="pp-"], [class*=" pp-"], [data-pp-menu-toggle], [data-pp-search-toggle]) {
	-webkit-appearance: none;
	appearance: none;
	background: none;
	border: 0;
	border-radius: 0;
	padding: 0;
	cursor: pointer;
}
:where(button, input[type="button"], input[type="submit"], input[type="reset"]):where([class^="pp-"], [class*=" pp-"]):disabled { cursor: not-allowed; }

/* =========================================================================
 * 5. BUTTON SYSTEM — lock §3 + Press signature §4
 *    PRIMARY / SECONDARY / TERTIARY-TEXT / (COMPACT COMMERCE in section 6).
 *    Sizes L ≈52 / M ≈44 (default) / S ≈36; ≥44px on true mobile for every
 *    tier. One radius (9px), Inter 600 16/14/13, one hover shade, one
 *    pressed shade, one disabled treatment, one loading affordance, one
 *    success affordance (never Lime).
 * ====================================================================== */
.pp-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--pp-control-gap);
	min-height: var(--pp-btn-h-m);
	padding: 10px 20px;                          /* vertical padding only matters once a label wraps (i18n) — the min-height owns the single-line height */
	font-family: var(--pp-font-body);
	font-weight: 600;
	font-size: var(--pp-text-btn-m);
	line-height: 1.2;
	color: inherit;
	background: none;
	border: 1px solid transparent;
	border-radius: var(--pp-radius-btn);
	cursor: pointer;
	position: relative;
	text-align: center;
	text-decoration: none;
	-webkit-tap-highlight-color: transparent;
	transition:
		background-color var(--pp-motion-micro) var(--pp-ease-out),
		border-color var(--pp-motion-micro) var(--pp-ease-out),
		color var(--pp-motion-micro) var(--pp-ease-out),
		box-shadow var(--pp-motion-micro) var(--pp-ease-out),
		transform var(--pp-motion-press-out) var(--pp-ease-out);
}
.pp-btn-l { min-height: var(--pp-btn-h-l); padding-inline: 26px; font-size: var(--pp-text-btn-l); }
.pp-btn-m { min-height: var(--pp-btn-h-m); padding-inline: 20px; font-size: var(--pp-text-btn-m); }
/* `.pp-btn-sm` is the pre-existing Account modifier (S8F) — it now maps
   onto the foundation's S tier instead of carrying its own geometry. */
.pp-btn-s, .pp-btn-sm { min-height: var(--pp-btn-h-s); padding: 8px 14px; font-size: var(--pp-text-btn-s); }
.pp-btn-block { display: flex; width: 100%; }

/* UI.1 P2 (Human Lock §8): every hover shade below is gated to hover-capable
   input, so a tap never leaves a desktop hover shade on the tapped control;
   pressed states stay ungated. */
.pp-btn-primary { background: var(--pp-navy); color: #fff; border-color: var(--pp-navy); }
@media (hover: hover) { .pp-btn-primary:hover { background: var(--pp-navy-hover); border-color: var(--pp-navy-hover); } }
.pp-btn-primary:active, .pp-btn-primary.is-pressed { background: var(--pp-navy-pressed); border-color: var(--pp-navy-pressed); }

.pp-btn-secondary { background: #fff; color: var(--pp-ink); border-color: var(--pp-border); }
@media (hover: hover) { .pp-btn-secondary:hover { border-color: var(--pp-ink); } }
.pp-btn-secondary:active, .pp-btn-secondary.is-pressed { border-color: var(--pp-navy); background: var(--pp-navy-tint); color: var(--pp-navy); }

/* Inverse Primary — the approved variant for Navy surfaces (lock §46). */
.pp-btn-inverse { background: #fff; color: var(--pp-navy); border-color: #fff; }
@media (hover: hover) { .pp-btn-inverse:hover { background: var(--pp-soft-surface); border-color: var(--pp-soft-surface); } }
.pp-btn-inverse:active, .pp-btn-inverse.is-pressed { background: var(--pp-secondary-surface); border-color: var(--pp-secondary-surface); }

/* Tertiary / text — Edit, Remove, Clear all, Sign in, promo toggles. */
.pp-btn-text {
	background: none; border-color: transparent; color: var(--pp-navy);
	padding-inline: 6px; min-height: var(--pp-btn-h-s);
	text-decoration: underline; text-decoration-color: transparent; text-underline-offset: 3px;
	transition: color var(--pp-motion-micro) var(--pp-ease-out), text-decoration-color var(--pp-motion-micro) var(--pp-ease-out);
}
@media (hover: hover) { .pp-btn-text:hover { text-decoration-color: currentColor; } }
.pp-btn-text:active, .pp-btn-text.is-pressed { color: var(--pp-navy-pressed); transform: none; }
.pp-btn-text--muted { color: var(--pp-secondary-text); }

/* Outline Navy — Checkout's always-visible Apply stays intentional (lock §3). */
.pp-btn-outline-navy { background: none; color: var(--pp-navy); border-color: var(--pp-navy); }
@media (hover: hover) { .pp-btn-outline-navy:hover { background: var(--pp-navy); color: #fff; } }
.pp-btn-outline-navy:active, .pp-btn-outline-navy.is-pressed { background: var(--pp-navy-pressed); border-color: var(--pp-navy-pressed); color: #fff; }

/* UI.1 H2 (Human Lock §5): on hover-capable input a boxed CTA lifts ~2px as
   ONE object with a subtle existing-system Navy separation, on top of the
   unchanged colour/keyline response above; no glyph moves on its own (only a
   directional arrow travels, §11 below). Text buttons have no box and keep
   their underline. Scope:
   - storefront surfaces only: Checkout (incl. Order Received / Pay for Order)
     and Account keep their locked quiet / calm grammar
     (GLOBAL-COMMERCE-POLISH-LOCK §2, §41);
   - never the Spotlight stretched link (.pp-spot-link): a transform on it
     collapses its card-wide hit area (home-spotlight.css), and that card's
     locked hover has no transform.
   Press always wins over the lift (lock §4: shade first, scale second), and
   the separation never replaces a keyboard focus ring (lock §16 / §50: the
   ring is a box-shadow too, so the separation steps aside under
   :focus-visible; the ring rides the lift). */
@media (hover: hover) {
	body:not(.woocommerce-checkout):not(.woocommerce-account) :is(.pp-btn-primary, .pp-btn-outline-navy, .pp-btn-secondary, .pp-btn-inverse):not(.pp-spot-link):hover {
		transform: translateY(calc(var(--pp-hover-rise) * -1));
		transition-duration: var(--pp-motion-micro);
	}
	body:not(.woocommerce-checkout):not(.woocommerce-account) .pp-btn-secondary:not(.pp-spot-link):hover:not(:focus-visible) { box-shadow: var(--pp-shadow-hover); }
	body:not(.woocommerce-checkout):not(.woocommerce-account) :is(.pp-btn-primary, .pp-btn-outline-navy):not(.pp-spot-link):hover:not(:focus-visible) { box-shadow: var(--pp-shadow-hover-navy); }
	body:not(.woocommerce-checkout):not(.woocommerce-account) .pp-btn-inverse:not(.pp-spot-link):hover:not(:focus-visible) { box-shadow: var(--pp-shadow-hover-on-dark); }
	body:not(.woocommerce-checkout):not(.woocommerce-account) :is(.pp-btn-primary, .pp-btn-outline-navy, .pp-btn-secondary, .pp-btn-inverse):not(.pp-spot-link):is(:active, .is-pressed) {
		transform: scale(var(--pp-press-scale));
		transition-duration: var(--pp-motion-press-in);
	}
	body:not(.woocommerce-checkout):not(.woocommerce-account) :is(.pp-btn-primary, .pp-btn-outline-navy, .pp-btn-secondary, .pp-btn-inverse):not(.pp-spot-link):is(:active, .is-pressed):not(:focus-visible) { box-shadow: none; }
}

/* Press signature — pressed shade is primary (above), a small scale is
   secondary; ≈100ms in / 180ms out on the decelerate curve. `.is-pressed`
   is set on pointerdown by assets/js/pp-foundation.js to back `:active` on
   touch. Never spring, bounce, shadow pulse or opacity-only. */
.pp-btn:active, .pp-btn.is-pressed { transform: scale(var(--pp-press-scale)); transition-duration: var(--pp-motion-press-in); }
.pp-btn:disabled, .pp-btn.is-disabled, .pp-btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; transform: none; pointer-events: none; }

/* Loading — inline spinner in the icon slot, label kept, width stable. */
.pp-btn.is-loading { pointer-events: none; }
.pp-btn.is-loading .pp-btn-spinner { display: inline-block; }
.pp-btn-spinner {
	display: none; width: 16px; height: 16px; flex: none; border-radius: 50%;
	border: 2px solid currentColor; border-inline-end-color: transparent;
	animation: pp-spin 700ms linear infinite;
}
@keyframes pp-spin { to { transform: rotate(360deg); } }

/* Success — label swap + check on soft surface / success text (never Lime). */
.pp-btn.is-success, .pp-btn.is-confirmed { background: var(--pp-soft-surface); color: var(--pp-success-text); border-color: var(--pp-success-border); }

/* True mobile: ≥44px effective hit area for every tier (lock §3, §15) —
   the S tier only grows to the floor; no size modifier may set a competing
   mobile min-height (Account lock AK-3). Block CTAs may wrap under long
   translations (lock §51).

   S9D-D-R (MINOR 3): `.pp-btn` and `.pp-btn-l` have identical specificity
   (0,1,0), so this later rule silently OUT-RANKED the L tier and collapsed
   every 52px L button — Checkout's Place Order, the Cart Page and Cart
   Drawer Checkout, Pay for Order — to 44px on ≤767px. That contradicted
   both the locked tier system and this rule's own stated intent ("the S
   tier only grows to the floor"). The floor now applies to every tier
   EXCEPT L, which already exceeds it: `:not(.pp-btn-l)` stops the rule
   matching L buttons at all, so `.pp-btn-l`'s own 52px stands unopposed.
   M (44), S (36 → 44) and the text tier are unchanged.

   Permanent rule: L = 52px at every width · M = 44px · S = 36px desktop and
   ≥44px on true mobile. */
@media (max-width: 767px) {
	.pp-btn:not(.pp-btn-l), .pp-btn-s, .pp-btn-sm, .pp-btn-text { min-height: var(--pp-hit-min); }
}

/* =========================================================================
 * 6. COMPACT COMMERCE PRIMITIVES — lock §3 (COMPACT COMMERCE tier)
 *    Consumed by the later gates for tier cells, steppers, chips, facet
 *    triggers and icon buttons; nothing in production carries these classes
 *    yet.
 * ====================================================================== */
.pp-control {
	position: relative; display: inline-flex; align-items: center; justify-content: center;
	font: 600 var(--pp-text-btn-s)/1.2 var(--pp-font-body); color: var(--pp-ink);
	background: #fff; border: 1px solid var(--pp-border); border-radius: var(--pp-radius-control);
	cursor: pointer; -webkit-tap-highlight-color: transparent;
	transition:
		background-color var(--pp-motion-micro) var(--pp-ease-out),
		border-color var(--pp-motion-micro) var(--pp-ease-out),
		color var(--pp-motion-micro) var(--pp-ease-out),
		transform var(--pp-motion-press-out) var(--pp-ease-out);
}
.pp-control:hover { background: var(--pp-soft-surface); }
.pp-control:active, .pp-control.is-pressed { background: var(--pp-navy-tint); border-color: var(--pp-navy); transform: scale(var(--pp-press-scale-compact)); transition-duration: var(--pp-motion-press-in); }
.pp-control:disabled, .pp-control.is-disabled { opacity: .5; cursor: not-allowed; transform: none; background: #fff; }

/* Icon button: 20–24px glyph inside a 44px hit area; the visual box may be
   smaller. `--round` is the preserved circular exception (rail arrows,
   icon-only circular controls — lock §3). */
.pp-icon-btn {
	display: inline-flex; align-items: center; justify-content: center;
	width: var(--pp-hit-min); height: var(--pp-hit-min);
	border-radius: var(--pp-radius-control); color: var(--pp-ink); cursor: pointer;
	-webkit-tap-highlight-color: transparent;
	transition: background-color var(--pp-motion-micro) var(--pp-ease-out), transform var(--pp-motion-press-out) var(--pp-ease-out);
}
/* UI.1 P2 (Human Lock §8): the hover shade is hover-capable input only, so a
   tap never leaves it behind. The header's own icon controls press with the
   P2 shade + scale(.985) (header.css); elsewhere the compact press stands. */
@media (hover: hover) { .pp-icon-btn:hover { background: var(--pp-soft-surface); } }
.pp-icon-btn:active, .pp-icon-btn.is-pressed { background: var(--pp-navy-tint); transform: scale(var(--pp-press-scale-compact)); transition-duration: var(--pp-motion-press-in); }
.pp-icon-btn--bordered { border: 1px solid var(--pp-border); background: #fff; }
.pp-icon-btn--round { border-radius: 50%; }
.pp-icon-btn:disabled { opacity: .5; cursor: not-allowed; transform: none; }

/* Chip — active filters and search trending (lock §3 COMPACT COMMERCE, §29):
   32px rest / 40px true mobile, Inter 600 12, secondary surface; the outline
   variant is the trending link chip. Consumed by plp.css / header-commerce.css
   (S9D-B); the close glyph inside is a 14px inline SVG. */
.pp-chip {
	display: inline-flex; align-items: center; gap: 6px; min-height: 32px;
	padding: 0 10px 0 12px; font: 600 var(--pp-text-meta)/1 var(--pp-font-body); color: var(--pp-ink);
	background: var(--pp-secondary-surface); border: 1px solid transparent; border-radius: var(--pp-radius-control);
	position: relative; cursor: pointer; -webkit-tap-highlight-color: transparent;
	transition: background-color var(--pp-motion-micro) var(--pp-ease-out), border-color var(--pp-motion-micro) var(--pp-ease-out), transform var(--pp-motion-press-out) var(--pp-ease-out);
}
.pp-chip .pp-i { width: 14px; height: 14px; }
.pp-chip:hover { background: #E4E6E5; }
.pp-chip:active, .pp-chip.is-pressed { transform: scale(var(--pp-press-scale-compact)); transition-duration: var(--pp-motion-press-in); }
.pp-chip--outline { background: #fff; border-color: var(--pp-border); border-radius: var(--pp-radius-btn); min-height: 36px; padding-inline: 14px; }
.pp-chip--outline:hover { border-color: var(--pp-ink); background: #fff; }
.pp-chip.is-focus { background: var(--pp-navy-tint); border-color: var(--pp-navy); }
@media (max-width: 767px) { .pp-chip { min-height: 40px; } }

/* Edge reveal — lock §5: ≤120ms scaleX; reduced motion = instant (section 12b). */
@keyframes pp-edge-in { from { transform: translateX(-50%) scaleX(.6); opacity: 0; } to { transform: translateX(-50%) scaleX(1); opacity: 1; } }

/* =========================================================================
 * 7. FIELD SYSTEM — lock §13: 1.5px border, 9px radius, ≈46px, Inter 15
 *    (16px on true mobile — iOS Safari auto-zoom safe), label Inter 13/600;
 *    states normal / hover / focus / valid / invalid / disabled; one focus
 *    language (Ink border + 1px Ink ring).
 * ====================================================================== */
.pp-field { display: flex; flex-direction: column; gap: 6px; }
.pp-field > label, .pp-field-label { font: 600 var(--pp-text-label)/1.3 var(--pp-font-body); color: var(--pp-ink); }
.pp-field .req { color: var(--pp-red); }
.pp-field .opt { font-weight: 400; color: var(--pp-secondary-text); }
.pp-field-wrap { position: relative; }

.pp-input, .pp-select, .pp-textarea {
	width: 100%;
	min-height: 46px;
	padding: 11px 14px;
	font: 400 var(--pp-text-body)/1.4 var(--pp-font-body);
	color: var(--pp-ink);
	background: #fff;
	border: 1.5px solid var(--pp-border);
	border-radius: var(--pp-radius-md);
	transition:
		border-color var(--pp-motion-micro) var(--pp-ease-out),
		box-shadow var(--pp-motion-micro) var(--pp-ease-out),
		background-color var(--pp-motion-micro) var(--pp-ease-out);
}
.pp-input::placeholder, .pp-textarea::placeholder { color: var(--pp-secondary-text); opacity: 1; }
.pp-input:hover, .pp-select:hover, .pp-textarea:hover { border-color: var(--pp-border-hover); }
.pp-input:focus-visible, .pp-select:focus-visible, .pp-textarea:focus-visible { outline: none; border-color: var(--pp-ink); box-shadow: var(--pp-focus-ring); }
.pp-field.is-valid .pp-input { padding-inline-end: 42px; }
.pp-field.is-valid .pp-field-wrap::after {
	content: ""; position: absolute; inset-inline-end: 14px; top: 50%; width: 16px; height: 16px; transform: translateY(-50%);
	background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231A7A3D' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E") center/contain no-repeat;
	pointer-events: none;
}
.pp-field.is-invalid .pp-input, .pp-field.is-invalid .pp-select, .pp-field.is-invalid .pp-textarea,
.pp-input[aria-invalid="true"], .pp-select[aria-invalid="true"], .pp-textarea[aria-invalid="true"] { border-color: var(--pp-red); background: #FFF6F6; }
.pp-field.is-invalid .pp-input:focus-visible, .pp-input[aria-invalid="true"]:focus-visible { box-shadow: 0 0 0 1px var(--pp-red); }
.pp-field-msg { font: 600 var(--pp-text-meta)/1.4 var(--pp-font-body); color: var(--pp-red); display: flex; align-items: flex-start; gap: 6px; }   /* never faded in — readable instantly */
.pp-field-msg .pp-i { width: 14px; height: 14px; margin-top: 2px; }
.pp-field-hint { font: 400 var(--pp-text-meta)/1.4 var(--pp-font-body); color: var(--pp-secondary-text); }
.pp-input:disabled, .pp-select:disabled, .pp-textarea:disabled, .pp-field.is-disabled .pp-input { background: var(--pp-soft-surface); color: var(--pp-secondary-text); border-color: var(--pp-border); cursor: not-allowed; }

/* PouchPick selects (native, where an enhanced control is not required):
   explicit SVG chevron, same box as the input. */
.pp-select, select.pp-input {
	-webkit-appearance: none; appearance: none;
	padding-inline-end: 40px; cursor: pointer;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23676767' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
	background-repeat: no-repeat; background-position: right 14px center; background-size: 18px;
}
[dir="rtl"] .pp-select, [dir="rtl"] select.pp-input { background-position: left 14px center; }
.pp-textarea, textarea.pp-input { min-height: 96px; }
.pp-check { display: flex; align-items: flex-start; gap: 10px; font: 400 var(--pp-text-label)/1.4 var(--pp-font-body); cursor: pointer; min-height: 24px; }
.pp-check input { margin-top: 1px; }
.pp-field-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--pp-space-4); }
.pp-field-grid .full { grid-column: 1 / -1; }
@media (max-width: 767px) {
	.pp-input, .pp-select, .pp-textarea { font-size: 16px; min-height: 48px; }
	.pp-field-grid { grid-template-columns: 1fr; }
}

/* =========================================================================
 * 8. SCOPED WOOCOMMERCE / SELECTWOO NORMALIZATION — lock §12, §14
 *    Known WooCommerce control classes adopt the PouchPick focus language
 *    and, for the enhanced (SelectWoo) selects that Country / State and
 *    extensions functionally require, the PouchPick field appearance.
 *    Behaviour is untouched — these are the enhanced controls WooCommerce
 *    renders, never replaced with native selects. Field shape on the
 *    surfaces themselves (Checkout, Account) stays owned by their own
 *    stylesheets until their S9D gates.
 * ====================================================================== */
.input-text:focus-visible, .woocommerce-Input:focus-visible,
select.country_select:focus-visible, select.state_select:focus-visible { outline: none; border-color: var(--pp-ink); box-shadow: var(--pp-focus-ring); }

.select2-container--default .select2-selection--single,
.select2-container--default .select2-selection--multiple {
	height: auto; min-height: 46px;
	display: flex; align-items: center;
	background: #fff;
	border: 1.5px solid var(--pp-border);
	border-radius: var(--pp-radius-md);
	transition: border-color var(--pp-motion-micro) var(--pp-ease-out), box-shadow var(--pp-motion-micro) var(--pp-ease-out);
}
.select2-container--default .select2-selection--single:hover { border-color: var(--pp-border-hover); }
.select2-container--default .select2-selection--single .select2-selection__rendered {
	flex: 1; min-width: 0;
	padding: 11px 40px 11px 14px;
	line-height: 1.4;
	font: 400 var(--pp-text-body)/1.4 var(--pp-font-body);
	color: var(--pp-ink);
}
.select2-container--default .select2-selection--single .select2-selection__placeholder { color: var(--pp-secondary-text); }
.select2-container--default .select2-selection--single .select2-selection__arrow {
	position: absolute; top: 0; right: 0; width: 40px; height: 100%;
	background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23676767' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") center / 18px no-repeat;
}
.select2-container--default .select2-selection--single .select2-selection__arrow b { display: none; }
.select2-container--default.select2-container--focus .select2-selection--single,
.select2-container--default.select2-container--open .select2-selection--single,
.select2-container--default .select2-selection--single:focus-visible { outline: none; border-color: var(--pp-ink); box-shadow: var(--pp-focus-ring); }
.select2-container--default .select2-selection--single .select2-selection__clear { margin-right: 6px; font-family: var(--pp-font-body); }
.select2-dropdown {
	border: 1.5px solid var(--pp-border);
	border-radius: var(--pp-radius-md);
	box-shadow: var(--pp-shadow-popover);
	overflow: hidden;
	font: 400 var(--pp-text-body)/1.4 var(--pp-font-body);
	color: var(--pp-ink);
}
.select2-container--default .select2-search--dropdown .select2-search__field {
	border: 1.5px solid var(--pp-border); border-radius: var(--pp-radius-sm); padding: 8px 10px; font: inherit;
}
.select2-container--default .select2-search--dropdown .select2-search__field:focus-visible { outline: none; border-color: var(--pp-ink); box-shadow: var(--pp-focus-ring); }
.select2-container--default .select2-results__option { padding: 10px 14px; }
.select2-container--default .select2-results__option--highlighted[aria-selected],
.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable { background: var(--pp-navy); color: #fff; }
.select2-container--default .select2-results__option[aria-selected="true"]:not(.select2-results__option--highlighted),
.select2-container--default .select2-results__option--selected:not(.select2-results__option--highlighted) { background: var(--pp-navy-tint); color: var(--pp-ink); }
.form-row.woocommerce-invalid .select2-container--default .select2-selection--single { border-color: var(--pp-red); background: #FFF6F6; }
@media (max-width: 767px) {
	.select2-container--default .select2-selection--single .select2-selection__rendered,
	.select2-container--default .select2-search--dropdown .select2-search__field,
	.select2-dropdown { font-size: 16px; }
	.select2-container--default .select2-selection--single { min-height: 48px; }
}

/* =========================================================================
 * 9. FOCUS — one language (lock §16 / §50). Ink ring on light controls; the
 *    Navy-filled PouchPick controls get the white-gap ring so focus stays
 *    visible on the CTA itself. Never removed for mouse users at keyboard
 *    users' expense (:focus-visible); never colour-only (the ring is a shape).
 * ====================================================================== */
.pp-focusable:focus-visible,
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible,
[role="button"]:focus-visible {
	outline: none;
	box-shadow: var(--pp-focus-ring);
}
.pp-btn-primary:focus-visible,
.pp-btn-outline-navy:hover:focus-visible,
.pp-cart:focus-visible,
.pp-mobile-cart:focus-visible,
.pp-tile:focus-visible,
.pp-checkout-place-order-btn:focus-visible,
.pp-checkout-sticky-btn:focus-visible,
.pp-acct-nav a.is-active:focus-visible,
.pp-home-quicklink.pp-active:focus-visible,
.pp-skip-link:focus-visible,
.pp-navy-surface :focus-visible,
.pp-navy-surface:focus-visible {
	box-shadow: var(--pp-focus-ring-on-dark);
}
/* Windows High Contrast / forced colours drop box-shadows — keep a real outline there. */
@media (forced-colors: active) {
	a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible, summary:focus-visible, [tabindex]:focus-visible { outline: 2px solid; outline-offset: 2px; }
}

/* =========================================================================
 * 10. HIT-AREA + SAFE-AREA UTILITIES — lock §15, §16
 *     `.pp-hit` extends the effective hit area of a small visual control to
 *     ≥44×44 (centred, invisible, clicks land on the element) without
 *     enlarging the glyph; `.pp-hit-mobile` does the same on true mobile
 *     only. Desktop controls are never globally enlarged.
 * ====================================================================== */
.pp-hit, .pp-hit-mobile { position: relative; }
.pp-hit::after {
	content: ""; position: absolute; top: 50%; left: 50%;
	width: max(100%, var(--pp-hit-min)); height: max(100%, var(--pp-hit-min));
	transform: translate(-50%, -50%);
}
@media (max-width: 767px) {
	.pp-hit-mobile::after {
		content: ""; position: absolute; top: 50%; left: 50%;
		width: max(100%, var(--pp-hit-min)); height: max(100%, var(--pp-hit-min));
		transform: translate(-50%, -50%);
	}
	.pp-hit-min-mobile { min-width: var(--pp-hit-min); min-height: var(--pp-hit-min); }
}
/* Safe area: `padding-bottom: calc(<pad> + env(safe-area-inset-bottom))` —
   the consuming surface sets its own base padding in --pp-safe-pad-bottom
   (default 12px). Intended for the PDP sticky CTA, the Checkout sticky
   Place Order bar, the Cart Drawer foot, the filter sheet foot and the
   Footer bottom band (lock §16). */
.pp-safe-bottom { padding-bottom: calc(var(--pp-safe-pad-bottom, var(--pp-space-3)) + var(--pp-safe-bottom)); }

/* =========================================================================
 * 10b. PACKSHOT — lock §24: ONE shared product-image component.
 *      Fixed 1:1 box, `contain`, white ground, per-product display scale
 *      consumed from the single interim adapter pp_get_packshot_scale()
 *      (inc/product-data.php) as --pp-packshot-scale. Source images are
 *      never modified. S9D-D moved this block here from product-card.css
 *      (a pure move — identical declarations, no visual change) so every
 *      surface that renders a product image gets the same component,
 *      including those that do not load the card stylesheet: Checkout's
 *      order review, Pay for Order and Order Received. Per-context BOX
 *      SIZES stay with each surface's own stylesheet.
 * ====================================================================== */
.pp-packshot {
	position: relative;
	aspect-ratio: 1 / 1;
	background: #fff;
	border-radius: var(--pp-radius-sm);
	overflow: hidden;
	display: flex;
	align-items: center;
	justify-content: center;
	/* PI.1: ONE display scale, two factors kept apart on purpose.
	   --pp-packshot-scale (inline, from pp_get_packshot_scale()) EQUALISES the
	   products: with the corrected _np_thumb_scale values every contract master
	   renders its visible can at the 66% REFERENCE of the stage. --pp-stage-fit
	   is the surface's PRESENTATION factor on top of that reference (approved
	   PI.1 targets: standard cards 1.2121 → 80%, compact picks 1.0909 → 72%,
	   PDP 1.2424 → 82%; surfaces that declare no fit stay at the reference).
	   Every consumer of the packshot scale below reads the product of the two. */
	--pp-packshot-display: calc(var(--pp-packshot-scale, 1) * var(--pp-stage-fit, 1));
}
.pp-packshot img {
	width: 100%;
	height: 100%;
	object-fit: contain;
	transform: scale(var(--pp-packshot-display, 1));
	transition: transform var(--pp-motion-component) var(--pp-ease-out);
}
.pp-packshot--soft { background: var(--pp-soft-surface); }

/* -------------------------------------------------------------------------
 * 10b-GS. PACKSHOT GROUND SHADOW — PI.1 human selection: SF1 "STUDIO
 * GROUND+" (final-calibration lab, board 26/27/34), superseding the S9F-A
 * E+ "Strong Contact" values by explicit human decision. PDP 100% ·
 * Home/PLP/related cards 95% · compact picks 90% (home-page.css).
 *
 * Two stage-anchored layers under the product: ::before = broad restrained
 * AMBIENT ground; ::after = strong-but-soft PROFILED CONTACT CORE whose
 * radial profile concentrates darkness beneath the can centre and rolls
 * off toward the sides. The intent (PI.1 shadow contract): a clearly
 * visible product floor — placed, grounded, photographed — never a halo,
 * glow, sticker edge or black blob.
 *
 * PI.1 geometry is expressed relative to the VISIBLE CAN, not the stage:
 * --pp-packshot-can = display scale × the asset contract's fill constant
 * (visible product ≈ 81% of the source canvas — measured across all six
 * 2026-09 masters, 80.5–81.5%). The shadow therefore tracks the can at
 * every optical size (80% cards / 72% picks / 82% PDP) without retuning.
 * Blur stays in cqw (1cqw = 1% of stage width) so it scales per surface.
 *
 * OPT-IN POLARITY (unchanged from S9F-A): layers exist ONLY for
 * `.pp-packshot--grounded`, emitted when a PRESENTATION call site passes
 * `shadow => true` AND the asset passes pp_packshot_shadow_eligible()
 * (inc/product-data.php — PI.1: `_pp_packshot` attachment meta, set for
 * contract-compliant transparent packshots). Commerce thumbnails never
 * opt in; campaign art / editorial imagery never carries the meta.
 *
 * HOVER (PI.1 H4, fine pointer only): the product lifts 4px and tilts
 * 1.6°; the floor shadow RESPONDS — it stays on the floor but slips a
 * little opposite the tilt while the contact narrows and eases, so the
 * weight visibly shifts. Under prefers-reduced-motion the product motion
 * tokens are zeroed and the response rules below do not apply at all.
 * Decorative only: pointer-events none, no DOM node, no AT surface.
 * `@supports (width: 1cqw)`: a browser without container-query units gets
 * NO shadow (clean degrade) instead of an unblurred hard ellipse.
 * ---------------------------------------------------------------------- */

:root {
	/* ONE catalogue constant: silhouette bottom / canvas height. PI.1:
	   measured 0.903–0.907 across all six 2026-09 contract masters; the
	   centre 0.905 replaces the VELO-only 0.907 (sub-2px at every stage). */
	--pp-packshot-baseline: 0.905;

	/* Asset-contract fill: visible product width / canvas width (≈81%). */
	--pp-packshot-fill: 0.81;

	/* SF1 "Studio Ground+" geometry (PI.1). Contact/ambient lengths are
	   fractions of the VISIBLE CAN (see --pp-packshot-can below); dy too. */
	--pp-shadow-contact-w: 44%;
	--pp-shadow-contact-h: 6%;
	--pp-shadow-contact-blur: 0.5cqw;
	--pp-shadow-contact-a: 0.50;

	--pp-shadow-ambient-w: 100%;
	--pp-shadow-ambient-h: 13.5%;
	--pp-shadow-ambient-blur: 2.8cqw;
	--pp-shadow-ambient-a: 0.18;
	--pp-shadow-ambient-dy: 2%;
	/* The ambient's softness is drawn as a gradient, not a CSS filter (post-
	   launch iPhone review: iOS Safari drew the blurred layer at ~20% on some
	   cards and the PDP while the gradient contact always drew fully). Its box
	   grows by these multiples of the blur token so the gradient carries the
	   same falloff; fitted to the former blur within ~1 grey level RMS. */
	--pp-shadow-ambient-spread-x: 7;
	--pp-shadow-ambient-spread-y: 2.5;

	/* Surface strength. PDP inherits 1; card surfaces step down below. */
	--pp-shadow-strength: 1;
}

@supports (width: 1cqw) {
	/* container-type so blur can be expressed in cqw; `inline-size`
	   containment only — the 1:1 box and centring are unchanged.

	   The derived contact line MUST be declared HERE, not on :root: custom
	   properties substitute where they are DECLARED, and the theme sets
	   --pp-packshot-scale per element (inline style, from
	   pp_get_packshot_scale()). On :root it would resolve against :root's
	   (undefined) scale and silently fall back to 1, putting the shadow at
	   90.7% of the stage instead of the derived contact line. */
	.pp-packshot--grounded {
		container-type: inline-size;
		/* Both derived values MUST be declared HERE, not on :root: custom
		   properties substitute where they are DECLARED, and the display
		   scale is composed per element (inline --pp-packshot-scale × the
		   surface's --pp-stage-fit). */
		--pp-packshot-can: calc(var(--pp-packshot-display, 1) * var(--pp-packshot-fill));
		--pp-packshot-shadow-y: calc(50% + (var(--pp-packshot-display, 1) * (var(--pp-packshot-baseline) - 0.5)) * 100%);
	}

	/* Lift the product above both shadow layers. Width / height /
	   object-fit / transform / transition are the shared rules above. */
	.pp-packshot--grounded img { position: relative; z-index: 2; }

	/* LAYER 2 — AMBIENT: broad, restrained, sits slightly lower. A radial
	   gradient fitted to the approved blurred ellipse (no filter): the same
	   floor, drawn by the construction every engine paints reliably. */
	.pp-packshot--grounded::before {
		content: "";
		position: absolute;
		left: 50%;
		top: calc(var(--pp-packshot-shadow-y) + var(--pp-packshot-can) * var(--pp-shadow-ambient-dy));
		width: calc(var(--pp-packshot-can) * var(--pp-shadow-ambient-w) + var(--pp-shadow-ambient-spread-x) * var(--pp-shadow-ambient-blur));
		height: calc(var(--pp-packshot-can) * var(--pp-shadow-ambient-h) + var(--pp-shadow-ambient-spread-y) * var(--pp-shadow-ambient-blur));
		transform: translate(-50%, -50%);
		background: radial-gradient(closest-side,
			rgba(17, 17, 17, calc(var(--pp-shadow-ambient-a) * 0.951)) 0%,
			rgba(17, 17, 17, calc(var(--pp-shadow-ambient-a) * 0.940)) 12.5%,
			rgba(17, 17, 17, calc(var(--pp-shadow-ambient-a) * 0.903)) 25%,
			rgba(17, 17, 17, calc(var(--pp-shadow-ambient-a) * 0.836)) 37.5%,
			rgba(17, 17, 17, calc(var(--pp-shadow-ambient-a) * 0.736)) 50%,
			rgba(17, 17, 17, calc(var(--pp-shadow-ambient-a) * 0.607)) 62.5%,
			rgba(17, 17, 17, calc(var(--pp-shadow-ambient-a) * 0.404)) 75%,
			rgba(17, 17, 17, calc(var(--pp-shadow-ambient-a) * 0.186)) 87.5%,
			rgba(17, 17, 17, 0) 100%);
		opacity: var(--pp-shadow-strength);
		z-index: 0;
		pointer-events: none;
		transition:
			opacity var(--pp-motion-component) var(--pp-ease-out),
			transform var(--pp-motion-component) var(--pp-ease-out),
			left var(--pp-motion-component) var(--pp-ease-out);
	}

	/* LAYER 1 — PROFILED CONTACT CORE: strong-but-soft centre, gradual
	   rolloff, centred ON the contact line so its upper half tucks behind
	   the product and no white gap can open between product and shadow. */
	.pp-packshot--grounded::after {
		content: "";
		position: absolute;
		left: 50%;
		top: var(--pp-packshot-shadow-y);
		width: calc(var(--pp-packshot-can) * var(--pp-shadow-contact-w));
		height: calc(var(--pp-packshot-can) * var(--pp-shadow-contact-h));
		transform: translate(-50%, -50%);
		border-radius: 50%;
		background: radial-gradient(ellipse closest-side,
			rgba(17, 17, 17, var(--pp-shadow-contact-a)) 0%,
			rgba(17, 17, 17, var(--pp-shadow-contact-a)) 32%,
			rgba(17, 17, 17, calc(var(--pp-shadow-contact-a) * 0.58)) 60%,
			rgba(17, 17, 17, calc(var(--pp-shadow-contact-a) * 0.22)) 82%,
			rgba(17, 17, 17, 0) 100%);
		filter: blur(var(--pp-shadow-contact-blur));
		opacity: var(--pp-shadow-strength);
		z-index: 1;
		pointer-events: none;
		transition:
			opacity var(--pp-motion-component) var(--pp-ease-out),
			transform var(--pp-motion-component) var(--pp-ease-out),
			left var(--pp-motion-component) var(--pp-ease-out);
	}

	/* Card surfaces (Home / PLP / related): 95% of PDP strength (S9F-A-R1
	   finding kept by PI.1). Compact picks step to 90% in home-page.css. */
	.pp-card .pp-packshot--grounded { --pp-shadow-strength: .95; }

	/* PI.1 H4 — RESPONSIVE FLOOR SHADOW on the standard-card hover only.
	   The product (product-card.css) lifts 4px and tilts 1.6° to the left;
	   the floor shadow slips a touch to the RIGHT (opposite the tilt), the
	   contact narrows and eases, the ambient spreads slightly. The shadow
	   itself never leaves the floor. Gated exactly like the product motion:
	   fine pointer, and not under reduced motion (where the product does
	   not move, the shadow must not react either). */
	@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
		.pp-card:hover .pp-packshot--grounded::after {
			left: calc(50% + var(--pp-packshot-can) * 1.8%);
			transform: translate(-50%, -50%) scaleX(0.96);
			opacity: calc(var(--pp-shadow-strength) * 0.78);
		}
		.pp-card:hover .pp-packshot--grounded::before {
			left: calc(50% + var(--pp-packshot-can) * 2.5%);
			transform: translate(-50%, -50%) scaleX(1.1);
			opacity: calc(var(--pp-shadow-strength) * 0.9);
		}
	}
}

/* =========================================================================
 * 10c. COMMERCE NOTICE — S9D-D-R4, cascade corrected S9D-D-R5
 *
 * The one PouchPick presentation for real WooCommerce notices, rendered by
 * the three template overrides in woocommerce/notices/. It lives in the
 * shared foundation because notices surface on every commerce surface
 * (PDP, PLP, Cart, Checkout, Account, Order Received, Pay for Order) and
 * design-system.css is the only stylesheet all of them already load — no
 * new stylesheet, no new request.
 *
 * Premium INLINE commerce feedback, not a default WooCommerce alert, a
 * toast, a SaaS notification or a promotional banner: white ground, one
 * hairline border, 9px radius, compact padding, a small semantic icon and a
 * restrained Navy text action. Green is used ONLY as the success icon,
 * because the event genuinely succeeded. No Lime, no shadow, no gradient,
 * no pill, no entrance motion (settle is for changed commerce VALUES, not
 * whole cards — lock §6).
 *
 * ---------------------------------------------------------------------------
 * SPECIFICITY CONTRACT (S9D-D-R5, MATERIAL 1)
 *
 * The base needs `.woocommerce .pp-commerce-notice` (0,2,0) to out-rank
 * WooCommerce's own default band. A single-class variant such as
 * `.pp-commerce-notice--error` (0,1,0) therefore LOST to its own base and
 * the error notice rendered with the neutral success surface — a real
 * semantic defect, measured on the Cart coupon rejection.
 *
 * The permanent order is now explicit, and every step is one deliberate
 * specificity level above the previous one — no !important anywhere:
 *
 *   BASE                .pp-commerce-notice            + .woocommerce .pp-commerce-notice            (0,1,0 / 0,2,0)
 *   SEMANTIC VARIANT    .pp-commerce-notice.--variant  + .woocommerce .pp-commerce-notice.--variant  (0,2,0 / 0,3,0)
 *   RESPONSIVE          same double-class pattern as the layer it overrides
 *
 * Any future variant MUST repeat the double-class pattern, or it will lose
 * to the base exactly as the error variant did.
 * ---------------------------------------------------------------------------
 */

/* ---- Stack ---- */
.pp-notice-stack { display: flex; flex-direction: column; gap: var(--pp-space-2); margin: 0 0 var(--pp-space-4); }
/* An AJAX checkout failure removes `.woocommerce-message` from inside the
   stack (WooCommerce's own submit_error()); a stack left holding no notice
   must not keep reserving its margin. Pure presentation — no JS, no timer,
   no notice semantics. Browsers without :has() simply keep today's
   behaviour. */
.pp-notice-stack:not(:has(.pp-commerce-notice)) { display: none; }

/* ---- BASE ---- */
.pp-commerce-notice,
.woocommerce .pp-commerce-notice {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	margin: 0;
	padding: 14px var(--pp-space-4);   /* one-line notice lands in the 52-64px target band */
	background: var(--pp-page-bg);
	border: 1px solid var(--pp-border);
	border-top: 1px solid var(--pp-border);   /* overrides WooCommerce's own coloured top rule */
	border-radius: var(--pp-radius-btn);
	box-shadow: none;
	font: 400 var(--pp-text-body)/1.45 var(--pp-font-body);
	color: var(--pp-ink);
	list-style: none;
}
/* WooCommerce's default band paints a large ::before glyph and a coloured
   top border on these same elements — both retired here in favour of the
   real inline-SVG icon the templates render. */
.pp-commerce-notice::before,
.pp-commerce-notice::after,
.woocommerce .pp-commerce-notice::before,
.woocommerce .pp-commerce-notice::after { content: none; display: none; }

.pp-commerce-notice-icon { flex: none; margin-top: 2px; }
.pp-commerce-notice-body { flex: 1; min-width: 0; }
/* The Add-to-Cart marker (inc/notices.php) is a classification hook, not a
   layout box — it must not become the single child that traps the message
   text and its action in one inline run. */
.pp-commerce-notice .pp-atc-notice { display: contents; }

/* The action WooCommerce puts inside the message ("View cart", "Continue
   shopping") — a restrained Navy text action, never the default grey block
   button. It sits inline on one row where space allows and wraps beneath
   the copy when it does not. */
.pp-commerce-notice a.button,
.pp-commerce-notice a.wc-forward,
.woocommerce .pp-commerce-notice a.button,
.woocommerce .pp-commerce-notice a.wc-forward {
	display: inline-flex;
	align-items: center;
	float: none;                       /* WooCommerce's default floats this action right */
	margin: 0 0 0 10px;
	padding: 0;
	min-height: 0;
	background: none;
	border: 0;
	border-radius: 0;
	color: var(--pp-navy);
	font: 600 var(--pp-text-label)/1.3 var(--pp-font-body);
	text-transform: none;
	letter-spacing: 0;
	text-decoration: underline;
	text-underline-offset: 3px;
	white-space: nowrap;
}
.pp-commerce-notice a.button:hover,
.pp-commerce-notice a.wc-forward:hover,
.woocommerce .pp-commerce-notice a.button:hover,
.woocommerce .pp-commerce-notice a.wc-forward:hover { color: var(--pp-navy-hover); background: none; }
.pp-commerce-notice a.button::after,
.pp-commerce-notice a.wc-forward::after { content: none; }
/* WooCommerce's own `.woocommerce a.button { box-shadow: … }` out-ranks the
   theme's `a:focus-visible` ring on this element, so the one shared focus
   language is restated here at matching specificity (lock §16 / §50). */
.pp-commerce-notice a.button:focus-visible,
.pp-commerce-notice a.wc-forward:focus-visible,
.woocommerce .pp-commerce-notice a.button:focus-visible,
.woocommerce .pp-commerce-notice a.wc-forward:focus-visible {
	outline: none;
	box-shadow: var(--pp-focus-ring);
	border-radius: 3px;
}

/* ---- SEMANTIC VARIANTS — one specificity step above the base ----
   Surfaces stay restrained; only genuine error feedback changes ground and
   border, using the EXISTING semantic error tokens. No new colour token, no
   saturated red block. Red remains reserved for real error semantics. */
.pp-commerce-notice.pp-commerce-notice--success .pp-commerce-notice-icon,
.woocommerce .pp-commerce-notice.pp-commerce-notice--success .pp-commerce-notice-icon { color: var(--pp-success-text); }

.pp-commerce-notice.pp-commerce-notice--info .pp-commerce-notice-icon,
.woocommerce .pp-commerce-notice.pp-commerce-notice--info .pp-commerce-notice-icon { color: var(--pp-navy); }

.pp-commerce-notice.pp-commerce-notice--error,
.woocommerce .pp-commerce-notice.pp-commerce-notice--error {
	flex-direction: column;
	gap: var(--pp-space-2);
	background: var(--pp-error-bg);
	border-color: var(--pp-error-border);
	color: var(--pp-error-text);
}
.pp-commerce-notice.pp-commerce-notice--error li,
.woocommerce .pp-commerce-notice.pp-commerce-notice--error li { display: flex; align-items: flex-start; gap: 10px; }
.pp-commerce-notice.pp-commerce-notice--error .pp-commerce-notice-icon,
.woocommerce .pp-commerce-notice.pp-commerce-notice--error .pp-commerce-notice-icon { color: var(--pp-red); }
.pp-commerce-notice.pp-commerce-notice--error a.button,
.pp-commerce-notice.pp-commerce-notice--error a.wc-forward,
.woocommerce .pp-commerce-notice.pp-commerce-notice--error a.button,
.woocommerce .pp-commerce-notice.pp-commerce-notice--error a.wc-forward { color: var(--pp-error-text); }

/* ---- SURFACE ALIGNMENT — commerce feedback belongs to the surface, never
   to the viewport (S9D-D-R5, MATERIAL 2 + MINOR C).
   WooCommerce's own `.woocommerce-notices-wrapper` is the print root on PDP,
   Account and Sign in, where nothing else constrains it; the Cart prints
   through this theme's own template, where the stack and the error root are
   the roots. PLP already prints INSIDE `.pp-container`, which owns the
   gutter, so it is reset below rather than double-guttered. ---- */
/* MARGIN, not padding: the error root IS the notice, so padding would move
   its text while leaving the border box edge-to-edge. Constraining the box
   itself makes a Cart error land on exactly the same 1256px measure as a
   Cart success.
   S9D-D-R6 (MATERIAL): this rule previously also declared `padding-inline: 0`,
   which is an INNER property. On `.woocommerce-error` — the one root here that
   IS the notice rather than a container around it — that declaration (0,2,1)
   out-ranked the component's own `padding: 14px var(--pp-space-4)` (0,2,0) and
   stripped the card's internal breathing room to zero, welding the icon to the
   border. It is removed rather than compensated for: this block governs the
   OUTER box only, and the shared component stays the single owner of the
   14/16 internal geometry. Nothing else declares padding on these roots. */
/* The measure is expressed exactly the way `.pp-container` expresses its
   own: capped at the container measure, and otherwise the viewport minus
   the same gutter on both sides. `max-width` alone only produces a gutter
   once the viewport is wider than the container, which left the notice
   flush at x=0 between 768px and 1180px while the surface's own content
   sat at x=32. */
.woocommerce-notices-wrapper,
body.woocommerce-cart .pp-notice-stack,
body.woocommerce-cart .woocommerce-error {
	width: calc(100% - 2 * var(--pp-gutter));
	max-width: calc(var(--pp-container-max) - 2 * var(--pp-gutter));
	margin-inline: auto;
}
/* A stack inside an already-aligned print root inherits that root's measure;
   only the outermost notice root aligns, so the gutter is never applied twice. */
.woocommerce-notices-wrapper .pp-notice-stack,
.woocommerce-notices-wrapper .woocommerce-error,
.pp-container .woocommerce-notices-wrapper,
.pp-acct-container .woocommerce-notices-wrapper {
	width: auto;
	max-width: none;
	margin-inline: 0;
}
@media (max-width: 767px) {
	.woocommerce-notices-wrapper,
	body.woocommerce-cart .pp-notice-stack,
	body.woocommerce-cart .woocommerce-error {
		width: calc(100% - 2 * var(--pp-gutter-mobile));
		max-width: none;
		margin-inline: auto;
	}
	.woocommerce-notices-wrapper .pp-notice-stack,
	.woocommerce-notices-wrapper .woocommerce-error,
	.pp-container .woocommerce-notices-wrapper,
	.pp-acct-container .woocommerce-notices-wrapper { width: auto; margin-inline: 0; }
}

/* ---- RESPONSIVE — same double-class pattern as the layer it overrides ----
   The base padding (14/16) is the human-approved geometry at every width;
   only the action's behaviour changes on true mobile. */
@media (max-width: 767px) {
	/* The action drops under the copy rather than squeezing it. Its ≥44px
	   governed target (lock §15) comes from the shared invisible hit
	   expander, not from a 44px box — a tall box would push a two-line
	   notice past 120px and recreate the system-looking band this component
	   replaces. The expander is confined to the link's own width and the
	   notice contains no other control, so it can overlap nothing. */
	.pp-commerce-notice a.button,
	.pp-commerce-notice a.wc-forward,
	.woocommerce .pp-commerce-notice a.button,
	.woocommerce .pp-commerce-notice a.wc-forward {
		position: relative;
		margin: 0;
	}
	.pp-commerce-notice a.button::after,
	.pp-commerce-notice a.wc-forward::after {
		content: "";
		position: absolute;
		top: 50%;
		left: 50%;
		width: max(100%, var(--pp-hit-min));
		height: max(100%, var(--pp-hit-min));
		transform: translate(-50%, -50%);
	}
	.pp-commerce-notice-body { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
}

/* =========================================================================
 * 10d. STRENGTH METER — the approved strength component (DESIGN.md
 *      Strength-Signal Rule: a Navy pill, Lime ONLY on the "on" segments).
 *      SHOP.SEO V4.2: moved here from pdp.css unchanged (pure move) so the
 *      listing's strength row and the shop guide use the same component;
 *      surface sizes stay with their surface (pdp.css --c, plp.css,
 *      shop-guide.css). Markup: pp_pdp_strength_meter_html().
 * ====================================================================== */
.pp-strength-meter {
	/* The approved R2 off-segment value for the PDP meter (the homepage band
	   uses its own .26 on a larger meter — home-strength.css). */
	--pp-strength-meter-off: rgba(164, 184, 209, 0.32);
	display: inline-flex; flex: none; align-items: center; gap: 3px;
	background: var(--pp-navy); border-radius: 999px; padding: 4px 7px; vertical-align: middle;
}
.pp-strength-meter i { display: block; width: 10px; height: 5px; border-radius: 1.5px; background: var(--pp-strength-meter-off); }
.pp-strength-meter i.on { background: var(--pp-lime); }

/* =========================================================================
 * 11. ICONS — lock §18: geometric inline SVG, 24-unit grid, 1.75 stroke,
 *     round caps, currentColor; rendered by pp_icon() (inc/icons.php).
 *     No icon font, no external framework.
 * ====================================================================== */
.pp-i {
	width: var(--pp-icon); height: var(--pp-icon); flex: none;
	fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round;
	display: inline-block; vertical-align: middle;
}
.pp-i--lg { width: var(--pp-icon-lg); height: var(--pp-icon-lg); }
.pp-i--sm { width: 16px; height: 16px; }
.pp-i--fill { fill: currentColor; stroke: none; }
[dir="rtl"] .pp-i--mirror { transform: scaleX(-1); }

/* UI.1 directional arrows (Human Lock §7): an arrow whose direction carries
   meaning travels 2px in that direction while its link or enabled button is
   hovered — forward / drill-in glyphs (`.pp-i--fwd`) forward, back / previous
   glyphs (`.pp-i--back`) back, both set by pp_icon() — 120ms on the locked
   enter curve, monotonic: no bounce, spring or loop. Carets (chevron) are
   state indicators and never travel; they keep rotating on their open state.
   Components whose locked interaction already owns its arrow motion keep it
   untouched: homepage flavour art (R4), strength band, How to choose, Picks
   and Spotlight; Checkout (incl. Order Received / Pay for Order) and Account
   keep their locked quiet / calm grammar (GLOBAL-COMMERCE-POLISH-LOCK §2). */
:is(.pp-i--fwd, .pp-i--back):not(:is(.pp-home-flavour, .pp-home-strength, .pp-home-understand, .pp-home-picks, .pp-home-spotlight, .woocommerce-checkout, .woocommerce-account) *) { transition: transform var(--pp-motion-micro) var(--pp-ease-out); }
@media (hover: hover) {
	:is(a, button:not(:disabled)):hover .pp-i--fwd:not(:is(.pp-home-flavour, .pp-home-strength, .pp-home-understand, .pp-home-picks, .pp-home-spotlight, .woocommerce-checkout, .woocommerce-account) *) { transform: translateX(var(--pp-dir-travel)); }
	:is(a, button:not(:disabled)):hover .pp-i--back:not(:is(.pp-home-flavour, .pp-home-strength, .pp-home-understand, .pp-home-picks, .pp-home-spotlight, .woocommerce-checkout, .woocommerce-account) *) { transform: translateX(calc(var(--pp-dir-travel) * -1)); }
	[dir="rtl"] :is(a, button:not(:disabled)):hover .pp-i--fwd.pp-i--mirror:not(:is(.pp-home-flavour, .pp-home-strength, .pp-home-understand, .pp-home-picks, .pp-home-spotlight, .woocommerce-checkout, .woocommerce-account) *) { transform: scaleX(-1) translateX(var(--pp-dir-travel)); }
	[dir="rtl"] :is(a, button:not(:disabled)):hover .pp-i--back.pp-i--mirror:not(:is(.pp-home-flavour, .pp-home-strength, .pp-home-understand, .pp-home-picks, .pp-home-spotlight, .woocommerce-checkout, .woocommerce-account) *) { transform: scaleX(-1) translateX(calc(var(--pp-dir-travel) * -1)); }
}

/* =========================================================================
 * 12. OVERLAY + FEEDBACK PRIMITIVES — lock §8 (scroll lock), §6 (settle)
 * ====================================================================== */
/* Body scroll is locked while a modal overlay is open (set / cleared by
   assets/js/pp-overlay.js, reference-counted); the measured scrollbar width
   is compensated so the page never shifts on platforms with classic
   scrollbars. */
body.pp-scroll-locked { overflow: hidden; padding-inline-end: var(--pp-scrollbar-comp); }
/* S9E-A2-R1: the history-restoration frame (pp-overlay.js, `pageshow` from the
   back/forward cache). Transient UI restored open is closed through its owners
   in that same frame; this class holds every closed state INSTANT for the frame
   instead of playing exit transitions (drawer slide, overlay fade, delayed
   visibility) on a page the customer is returning to. Removed on the next
   frame; nothing else changes. */
.pp-history-restore *, .pp-history-restore *::before, .pp-history-restore *::after { transition: none !important; }

/* Settle: a changed commerce value acknowledges itself — the value swaps
   instantly, only the container settles (opacity ≈.4→1, ≈3px rise, ≈220ms).
   Applied by the feedback gates via window.ppFoundation.settle(); never in
   Checkout, on historical values, legal text or titles. */
@keyframes pp-settle { from { opacity: .4; transform: translateY(var(--pp-settle-rise)); } to { opacity: 1; transform: none; } }
.pp-settle { animation: pp-settle var(--pp-motion-feedback) var(--pp-ease-out); }

/* =========================================================================
 * 12b. REDUCED MOTION — component equivalents (lock §7). Placed after every
 *      primitive above so these win at equal specificity: Press becomes
 *      colour/state only (no transform), settle is instant, the loading
 *      spinner slows. The token equivalents are in section 2.
 * ====================================================================== */
@media (prefers-reduced-motion: reduce) {
	.pp-btn:active, .pp-btn.is-pressed,
	.pp-control:active, .pp-control.is-pressed,
	.pp-icon-btn:active, .pp-icon-btn.is-pressed,
	.pp-chip:active, .pp-chip.is-pressed { transform: none; }
	.pp-settle { animation: none; }
	.pp-btn-spinner { animation-duration: 1400ms; }
}

/* =========================================================================
 * 13. UTILITIES
 * ====================================================================== */
.pp-visually-hidden {
	position: absolute !important;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

.pp-skip-link {
	position: absolute;
	inset-inline-start: 0;
	top: 0;
	transform: translateY(-200%);   /* off-canvas above the page — direction-neutral, never creates RTL scroll width (the old left:-9999px did — S9D-B) */
	background: var(--pp-navy);
	color: #fff;
	padding: 10px 16px;
	z-index: 1000;
	border-radius: 0 0 8px 0;
}
.pp-skip-link:focus { transform: none; }

/* =========================================================================
 * 14. TRUE-MOBILE TEXT-ENTRY FLOOR — lock §13 / §29 ("16px on true mobile —
 *     Safari auto-zoom safe"). A deliberate foundation floor for EVERY
 *     control that opens a keyboard or picker on iOS: the `!important` is
 *     intentional so a surface's own smaller font-size (checkout 15px,
 *     account 14.5px, coupon / quantity / sort 13px, review form 13.5px)
 *     can never reintroduce focus zoom; nothing else about those controls
 *     changes. Last in the file on purpose.
 * ====================================================================== */
@media (max-width: 767px) {
	input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="color"]):not([type="button"]):not([type="submit"]):not([type="reset"]):not([type="image"]):not([type="hidden"]),
	textarea,
	select { font-size: 16px !important; }
}
