/*
 * PouchPick PDP — PDP-VISUAL-SYSTEM-LOCK.md architecture (Concept C + Concept
 * B sticky column, TITLE A, SPEC A, FV1, ST2, T3, S3, SD2, Navy CTA, trust,
 * gallery rule) rendered in the S9C global system, with the PDP.2B Final
 * Hybrid purchase area (strength indicator C, per-can-first price summary —
 * superseding P2 — and the delivery + payment group;
 * design-locks/PDP-2B-FINAL-HYBRID-LOCK.md).
 *
 * S9D-C: values measured from the promoted final lab
 * design-lab/final/global-polish/ (Hybrid V2 — `.pp-pdp--v2`, global-polish.css
 * §PDP), against GLOBAL-COMMERCE-POLISH-LOCK.md §16 (safe areas), §17 (16px
 * mobile commerce gutter), §26/§27 (price + tier grammar), §30 (purchase block
 * and mobile order), §50 (accessibility). The tier CELL grammar itself is the
 * shared one in product-card.css (`.pp-tiers`) — this file only adds the PDP's
 * own compact-grid density, so there is one tier component, not three.
 *
 * Presentation only: every price, saving, stock and dispatch value is
 * server-formatted WooCommerce / resolved-profile data.
 */

/* Gutter (lock §17): 32px desktop, the 16px primary commerce gutter on true
   mobile — the purchase flow never sits in a 32px gutter. */
.pp-pdp { max-width: var(--pp-container-max); margin: 0 auto; padding: 26px var(--pp-gutter) 40px; }
@media (max-width: 767px) {
	.pp-pdp { padding-inline: var(--pp-gutter-mobile); }
}

.pp-pdp-crumb { font-size: var(--pp-text-meta-min); color: var(--pp-secondary-text); margin-bottom: var(--pp-space-3); }
.pp-pdp-crumb a { color: var(--pp-secondary-text); }
.pp-pdp-crumb a:hover { color: var(--pp-ink); }
.pp-pdp-crumb span[aria-hidden] { margin: 0 4px; }

/*
 * DOCUMENT ORDER = VISUAL ORDER (lock §30). The template writes the three
 * areas in the MOBILE order (gallery → purchase → lower); the desktop
 * two-column composition is produced by grid-template-areas alone, so nothing
 * is visually reordered against the DOM at any width and keyboard, screen
 * reader and reading order all match what is seen.
 */
.pp-pdp-split {
	display: grid;
	grid-template-columns: 58% minmax(0, 1fr);
	gap: 36px;
	grid-template-areas: "gallery purchase" "lower purchase";
	align-items: start;
}
.pp-pdp-gallery-area { grid-area: gallery; }
.pp-pdp-purchase { grid-area: purchase; }
.pp-pdp-lower-area { grid-area: lower; margin-top: 28px; min-width: 0; }

@media (max-width: 1024px) {
	.pp-pdp-split {
		grid-template-columns: minmax(0, 1fr);
		grid-template-areas: "gallery" "purchase" "lower";
		gap: 24px;
	}
	.pp-pdp-lower-area { margin-top: 0; }
}

/* ---------- Gallery (PDP lock Section T) ----------
   The shared `.pp-packshot` component (lock §24) with the PDP's own approved
   hero sizing: the one-image state is capped at the validated ~460px
   reference, centred, never stretched. No fake thumbnail/dot controls unless
   real additional images exist. */
.pp-pdp-gallery { position: relative; }
/* S9E-A2-R1: with more than one real image the hero also accepts a horizontal
   touch swipe (pdp.js initGallery() — one gallery state shared with the dots).
   The class is set by the script, so this touch-action restriction exists only
   where the handler does: vertical panning and pinch stay native (a vertical
   gesture on the image scrolls the page exactly as before); only horizontal
   panning is handed to the script. Mouse / desktop is unaffected. */
.pp-pdp-gallery--swipe .pp-pdp-main-img { touch-action: pan-y pinch-zoom; }
.pp-pdp-gallery .pp-pdp-main-img {
	max-width: 460px;
	margin-inline: auto;
	border-radius: var(--pp-radius-lg);
	/* PI.1: the PDP main stage is the approved 82% optical target (82/66 on
	   the reference) — delivered as a surface factor, so the PHP scale clamp
	   needs no change. The image stays STATIC: this stage is outside the
	   .pp-card hover context, so no lift, no tilt, no hover motion. */
	--pp-stage-fit: 1.2424;

	/* PI.1 PDP shadow correction (human visual review of the live 82% PDP):
	   the shared can-relative SF1 geometry, scaled to this can, read as a
	   broad fog — ambient ≈377×51px at α.18 under a 377px can. PDP-specific
	   SF1 GEOMETRY refinement, same two-layer family and character:
	   STRONGER/TIGHTER CONTACT (α .50→.56, width 44→42% of the can) over a
	   SMALLER RESTRAINED AMBIENT floor (width 100→68%, height 13.5→9%,
	   α .18→.14, blur 2.8→1.6cqw, dy 2→1.4%) — the can rests just above a
	   studio floor instead of hovering on a blurred ellipse. Cards and
	   compact picks keep the global SF1 values (design-system.css §10b-GS). */
	--pp-shadow-contact-w: 42%;
	--pp-shadow-contact-h: 5.5%;
	--pp-shadow-contact-a: 0.56;
	--pp-shadow-contact-blur: 0.45cqw;
	--pp-shadow-ambient-w: 68%;
	--pp-shadow-ambient-h: 9%;
	--pp-shadow-ambient-a: 0.14;
	--pp-shadow-ambient-blur: 1.6cqw;
	--pp-shadow-ambient-dy: 1.4%;
	/* Its narrower ambient needs a wider gradient spread for the same mass
	   as the former blur (browser-calibrated, mass 0.995–1.007). */
	--pp-shadow-ambient-spread-x: 9;
	--pp-shadow-ambient-spread-y: 3.5;
}
/* S9D-C-R (MINOR 1): the CONTROL BOX itself is ≥44×44 and the 8px visual dot
   sits centred inside it. The previous 8px button with an overlapping 44px
   `::after` gave each dot only ~14px of EXCLUSIVE tappable width (8px dot +
   6px gap pitch), because neighbouring pseudo-targets covered each other —
   the review measured this on the two real multi-image products (XQS, VELO).
   Real, non-overlapping flex boxes fix it without a 44px visual circle and
   without any absolute-positioned hit area. The row grows; that is accepted.
   Every rule is scoped to `.pp-pdp-dots` so the stock/dispatch separator can
   never inherit the dot's fill again. */
/* ---------- Gallery Previous / Next (S9F-B, >=768px only) ----------
   Restrained secondary controls INSIDE the gallery area, vertically centred
   on the PRODUCT IMAGE (the stage is exactly 460px tall at every width the
   arrows show - measured 768-1440 - so 230px is the stage centre; never the
   whole column), ~28px inside each gallery edge. Even at the tightest
   two-column width (~1025px, stage inset ~48px) the 44px button clears the
   can by ~18px. The foundation `.pp-icon-btn --bordered` owns the box
   (44x44, white, 1px border, radius token, hover Soft, press scale,
   disabled); here: position, Navy glyph, the shared focus ring, the locked
   ~0.3 disabled opacity, and transform overrides so press / disabled keep
   the vertical centring (the base rules' `transform: scale()` / `none`
   would otherwise drop the translateY). z-index 3 sits above the grounded
   packshot stack (shadow 0/1, image 2) inside the gallery's own stacking
   context - the S9F-A shadow itself is untouched. Hierarchy: PRODUCT first,
   arrows secondary, dots position/status. */
.pp-pdp-gallery-nav {
	position: absolute;
	top: 230px;
	transform: translateY(-50%);
	z-index: 3;
	color: var(--pp-navy);
}
.pp-pdp-gallery-prev { left: 28px; }
.pp-pdp-gallery-next { right: 28px; }
@media (hover: hover) { .pp-pdp-gallery-nav:hover { border-color: var(--pp-border-hover); } } /* UI.1 P2 (Human Lock §8): hover-capable input only — a tap never leaves this shade behind. */
.pp-pdp-gallery-nav:active, .pp-pdp-gallery-nav.is-pressed { transform: translateY(-50%) scale(var(--pp-press-scale-compact)); }
.pp-pdp-gallery-nav:focus-visible { outline: none; box-shadow: var(--pp-focus-ring); }
.pp-pdp-gallery-nav:disabled {
	opacity: .3;
	cursor: default;
	transform: translateY(-50%);
	background: #fff;             /* no hover treatment while disabled */
	border-color: var(--pp-border);
}
@media (max-width: 767px) {
	/* True mobile keeps exactly the approved swipe + dots - no extra UI. */
	.pp-pdp-gallery-nav { display: none; }
}

.pp-pdp-dots { display: flex; gap: 2px; justify-content: center; margin-top: 0; }
.pp-pdp-dots .pp-dot {
	width: var(--pp-hit-min); height: var(--pp-hit-min);
	flex: none; padding: 0; border: none; background: none;
	border-radius: 50%; cursor: pointer;
	display: inline-flex; align-items: center; justify-content: center;
	-webkit-tap-highlight-color: transparent; touch-action: manipulation;
}
.pp-pdp-dots .pp-dot::before {
	content: "";
	width: 8px; height: 8px; border-radius: 50%;
	background: var(--pp-border);
	transition: background-color var(--pp-motion-micro) var(--pp-ease-out);
}
.pp-pdp-dots .pp-dot.pp-active::before { background: var(--pp-navy); }
@media (hover: hover) {
	.pp-pdp-dots .pp-dot:hover::before { background: var(--pp-border-hover); }
	.pp-pdp-dots .pp-dot.pp-active:hover::before { background: var(--pp-navy); }
}
.pp-pdp-dots .pp-dot:focus-visible { outline: none; box-shadow: var(--pp-focus-ring); }

/* ---------- Purchase column (PDP lock Section A / R) ----------
   Sticky on true desktop only; the mobile sticky CTA is the persistence
   mechanism below 1025px (PDP lock Section S). */
.pp-pdp-purchase { align-self: start; min-width: 0; }
@media (min-width: 1025px) {
	/* PI.1 sticky correction: the previous `top: 16px` measured from the
	   VIEWPORT, so once the fixed header (HC.2/HC.8) was in play the summary
	   stuck 87px BEHIND the compact header. The header's own geometry
	   contract is the authority: --pp-header-compact-h (defined once in
	   header.css, HC.2 GC-4 — the same value the site's scroll-padding-top
	   already trusts). Summary top = compact header bottom + a small
	   intentional gap; no magic copy of a header height lives here. */
	/* UI.1 (Human Lock §11): the compact-header line is now the ONE sticky-
	   offset authority, header.css --pp-sticky-top — identical on desktop
	   (102px), and on the 1025–1179 tablet tier it is the S1 header's real,
	   measured line (compact, or compact under T2) instead of a phantom
	   102px gap. The admin-bar offset (logged-in staff, fixed from 783px) is
	   part of the same formula. */
	.pp-pdp-purchase { position: sticky; top: calc(var(--pp-sticky-top, 0px) + 16px + var(--pp-admin-bar-h, 0px)); }
}

.pp-product-identity-brand { font: 700 11.5px/1.2 var(--pp-font-body); color: var(--pp-navy); letter-spacing: .02em; text-transform: uppercase; margin-bottom: 2px; }
.pp-product-identity-title { font-family: var(--pp-font-display); font-weight: 600; font-size: 24px; line-height: 1.15; margin-bottom: var(--pp-space-2); letter-spacing: -0.015em; }
.pp-spec-line { font: 400 13.5px/1.4 var(--pp-font-body); color: var(--pp-ink); margin-bottom: var(--pp-space-2); }
.pp-spec-line .pp-sep { margin: 0 6px; color: var(--pp-border); }

/* ---------- PDP.2B strength indicator C (PDP-2B-FINAL-HYBRID-LOCK.md §S) ----------
   One compact row under the spec line (which then no longer repeats the mg):
   spec line → 2px → row → 6px → rating, ~16px added. Meter = the approved
   Strength component grammar on its own Navy pill (DESIGN.md Strength-Signal
   Rule: Lime ONLY on the "on" segments); C dimensions are the measured
   midpoints of the R2 A/B variants — 92×16 pill, 12×6 segments, gap 4 (mobile
   92×14). mg 13.5/600 Ink; the PouchPick band word muted. */
.pp-pdp-idline { margin-bottom: 6px; }
.pp-pdp-idline .pp-spec-line { margin-bottom: 2px; }
.pp-pdp-strength { display: flex; align-items: center; gap: 8px; font: 400 13.5px/1.15 var(--pp-font-body); color: var(--pp-secondary-text); }
.pp-pdp-strength-mg { font-weight: 600; color: var(--pp-ink); }
.pp-pdp-strength-sep { color: var(--pp-border); }

/* The meter's base component moved to design-system.css §10d (SHOP.SEO V4.2,
   pure move: the listing's strength row and guide use it); the PDP's size
   variant stays here. */
.pp-strength-meter--c { padding: 5px 8px; gap: 4px; }
.pp-strength-meter--c i { width: 12px; height: 6px; border-radius: 2px; }
@media (max-width: 767px) {
	.pp-strength-meter--c { padding: 4px 8px; }
	.pp-pdp-strength { gap: 7px; line-height: 1.1; }
}

.pp-rating { font: 400 12.5px/1.3 var(--pp-font-body); color: var(--pp-secondary-text); margin-bottom: 14px; }
.pp-rating a { color: var(--pp-navy); text-decoration: underline; text-underline-offset: 2px; }

/* ---------- Flavour discovery FV1 (PDP lock Section D) ----------
   Presentation polish only — these remain links to real separate products;
   no Edge (lock §5: the Edge is a tier/facet selection mark, never a generic
   selected-state decoration). */
.pp-flavour-discovery { margin-bottom: 14px; }
.pp-fd-label { font: 700 var(--pp-text-meta-min)/1.2 var(--pp-font-body); color: var(--pp-secondary-text); text-transform: uppercase; letter-spacing: .05em; margin-bottom: var(--pp-space-2); }
.pp-fd-row { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 2px; scrollbar-width: none; }
.pp-fd-row::-webkit-scrollbar { display: none; }
.pp-fd-item { flex: none; display: flex; flex-direction: column; align-items: center; gap: 6px; width: 76px; text-decoration: none; }
.pp-fd-circle {
	width: 52px; height: 52px; border-radius: 50%; overflow: hidden; display: block;
	border: 2px solid var(--pp-border); background: #fff;
	transition: border-color var(--pp-motion-micro) var(--pp-ease-out), transform var(--pp-motion-press-out) var(--pp-ease-out);
}
.pp-fd-circle img { width: 100%; height: 100%; object-fit: cover; }
@media (hover: hover) {
	.pp-fd-item:hover .pp-fd-circle { border-color: var(--pp-navy); }
	.pp-fd-item:hover .pp-fd-name { color: var(--pp-ink); }
}
.pp-fd-item:active .pp-fd-circle { transform: scale(var(--pp-press-scale-compact)); }
.pp-fd-item.pp-active .pp-fd-circle { border-color: var(--pp-navy); box-shadow: 0 0 0 2px var(--pp-navy-tint-strong); }
.pp-fd-name { font: 500 var(--pp-text-meta-min)/1.25 var(--pp-font-body); text-align: center; color: var(--pp-secondary-text); }
.pp-fd-item.pp-active .pp-fd-name { color: var(--pp-ink); font-weight: 700; }

/* ---------- Strength discovery ST2 (PDP lock Section E) ----------
   Text-first and deliberately distinct from the quantity tier selector. */
.pp-strength-discovery { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; font: 400 var(--pp-text-meta)/1.3 var(--pp-font-body); color: var(--pp-secondary-text); margin-bottom: 16px; }
.pp-sd-label { font-weight: 600; }
.pp-sd-val { color: var(--pp-secondary-text); display: inline-flex; align-items: center; }
a.pp-sd-val:hover { color: var(--pp-navy); }
.pp-sd-val.pp-active { color: var(--pp-ink); font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }
.pp-sd-dot { color: var(--pp-border); }
@media (max-width: 767px) {
	/* ≥44px effective target for the real links (lock §15) — the visual text
	   is unchanged; only the tappable box grows. */
	a.pp-sd-val { min-height: var(--pp-hit-min); padding-inline: 2px; }
}

/* ---------- Price summary — PDP.2B per-can first (PDP-2B-FINAL-HYBRID-LOCK.md §P) ----------
   SUPERSEDES the P2 hierarchy (PDP lock Section G, total as the dominant
   number). The product-card hierarchy (lock §26) at PDP scale: selected
   quantity + Best value context → the per-can price as the largest figure
   (800, the PDP's dominant size) with its /can unit → the struck original
   per-can on discount tiers → TOTAL with the total saving on the same line —
   never beside the per-can figures, so "Save $7.00" at 10 cans can't read as
   a per-can saving next to "$7.00/can". Every amount is a server string. */
.pp-price-block { margin-bottom: 4px; }
.pp-ctxline { font: 400 var(--pp-text-meta)/1.3 var(--pp-font-body); color: var(--pp-secondary-text); display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-bottom: 2px; }
.pp-ctx-bv { background: var(--pp-navy-tint); color: var(--pp-navy); font: 800 9.5px/1 var(--pp-font-body); padding: 3px 6px; border-radius: 4px; letter-spacing: .02em; }
.pp-ctx-bv[hidden] { display: none; }
/* Single-price states (out of stock, a non-tier product) keep the one amount. */
.pp-price-amt { font: 800 var(--pp-text-price-total)/1.1 var(--pp-font-body); color: var(--pp-ink); }
.pp-pdp-price-row { display: flex; align-items: baseline; flex-wrap: wrap; gap: 2px 10px; margin-top: 1px; }
.pp-pdp-price-unit { font: 800 var(--pp-text-price-total)/1.1 var(--pp-font-body); color: var(--pp-ink); letter-spacing: -0.01em; }
.pp-pdp-price-unit .unit { font: 500 var(--pp-text-body)/1 var(--pp-font-body); color: var(--pp-secondary-text); letter-spacing: 0; margin-left: 2px; }
.pp-pdp-price-ref { font: 400 var(--pp-text-label)/1.3 var(--pp-font-body); color: var(--pp-secondary-text); }
.pp-pdp-price-ref s { text-decoration-thickness: 1px; }
.pp-pdp-price-total { margin-top: 3px; display: flex; align-items: baseline; gap: 6px; color: var(--pp-secondary-text); }
.pp-pdp-price-total-k { font: 600 var(--pp-text-meta-min)/1 var(--pp-font-body); letter-spacing: .06em; text-transform: uppercase; }
.pp-pdp-price-total b { font: 700 var(--pp-text-body)/1.3 var(--pp-font-body); color: var(--pp-ink); }
.pp-pdp-price-save { font: 700 var(--pp-text-label)/1.3 var(--pp-font-body); color: var(--pp-navy); }
/* Decorative separator — empty alternative text keeps it out of the AT tree. */
.pp-pdp-price-save::before { content: "·"; content: "·" / ""; margin-right: 6px; color: var(--pp-border); font-weight: 400; }
.pp-pdp-price-ref[hidden], .pp-pdp-price-save[hidden] { display: none; }

/* ---------- Tier selector — PDP density (lock §27, PDP lock T3/S3) ----------
   Cell grammar, states, Edge, Navy percentage and the selected-cell rule all
   come from the shared `.pp-tiers` component (product-card.css). The PDP adds
   only its own compact-grid density: a taller cell for the T3 three-line
   content (quantity + −X% + muted per-can) and the ladder's own rhythm. The
   2×2 + full-width final tier layout is the shared `--grid` layout, which is
   what removes the ragged orphan row. */
.pp-pdp .pp-tiers { margin: 14px 0; gap: var(--pp-space-2); }
.pp-tiers--pdp .pp-tier { min-height: 58px; }
.pp-tiers--pdp .pp-tier-percan { display: block; font: 500 var(--pp-text-meta-min)/1.2 var(--pp-font-body); color: var(--pp-secondary-text); }
/* S3 (PDP lock Section H): the selected cell repeats neither the saving nor
   the per-can figure the price block above already states. */
.pp-tiers--pdp .pp-tier.is-selected .pp-tier-percan { display: none; }

/* ---------- Stock / dispatch SD2 — BEFORE the CTA (lock §30) ---------- */
/* S9D-C-R (MINOR 2): Ink, from the token — the promoted lab sets no colour on
   the stock line, so it renders as primary informational text. The previous
   unmanaged `#3a3833` literal is removed rather than promoted to a new
   near-black token. */
.pp-stock-dispatch { font: 400 var(--pp-text-meta)/1.4 var(--pp-font-body); color: var(--pp-ink); margin-bottom: var(--pp-space-3); display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: center; }
.pp-in-stock { color: var(--pp-success-text); font-weight: 700; display: inline-flex; align-items: center; gap: 4px; }
.pp-in-stock .pp-i { width: 14px; height: 14px; }
.pp-stock-dispatch .stock { margin: 0; }
/* The stock/dispatch separator uses this template's existing `.pp-sep`
   separator pattern (spec line, related card). It previously reused `.pp-dot`,
   which the gallery-dot block above then styled as an 8px grey FILLED circle
   with the glyph invisible against it — a real, pre-existing rendering defect
   found while measuring MINOR 1. */
.pp-stock-dispatch .pp-sep { color: var(--pp-border); }

/* ---------- CTA + post-CTA trust ---------- */
.pp-purchase-form { margin-bottom: 10px; }
/* S9E-A1-R1 / R2: a WooCommerce add-to-cart REJECTION, rendered through the
   ONE shared Commerce Notice error variant (design-system.css §10c) inside the
   purchase context after a direct add. Success renders nothing here (CTA state
   + badge + Drawer are the confirmation), so the slot is normally empty:
   empty = no box, no gap. */
.pp-purchase-feedback { margin: 0 0 10px; }
.pp-purchase-feedback:empty { display: none; }
/* Primary L (lock §3) — the purchase CTA keeps the 52px L height at every
   width; the global ≥44px mobile floor is a minimum, not a cap. */
.pp-cta { min-height: var(--pp-btn-h-l); font-size: var(--pp-text-btn-l); }
.pp-trust { display: flex; gap: 14px; flex-wrap: wrap; font: 500 var(--pp-text-meta)/1.3 var(--pp-font-body); color: var(--pp-secondary-text); margin-top: 10px; }
.pp-trust span { display: inline-flex; align-items: center; gap: 5px; }
.pp-trust .pp-i { width: 14px; height: 14px; }

/* ---------- PDP.2B delivery + payment group (PDP-2B-FINAL-HYBRID-LOCK.md §T) ----------
   The approved R2 grammar: hairline above, 20px glyph, 600 label, 22px mark
   tiles (official artwork, ratios intact). Which marks exist is resolved in
   inc/pdp-information.php; this only lays them out.
   - Delivery (final Human ruling: DHL, PostNord, UPS on ONE row): label and
     the three carrier marks always share the first line (≥360px). From 480px
     "View delivery options" ends that line, right-aligned (the whole row needs
     ~473px: the desktop column from ~1290px, tablet). Below 480px, with marks,
     the row is a small grid: the link takes the second line on its own, from
     the row's left edge — the approved R2 mobile arrangement — at every width
     and for any number of marks. Without marks the link keeps the end of the
     label's line. No overflow at any width.
   - Payment: one line where the six marks fit (≥460px, a container query on
     the group's own width); below that the marks take their own indented
     line (the approved R2 mobile arrangement).
   The 4px top margin sits on the group itself: container-type stops a child's
   margin from collapsing through it, and the lab's collapsed with the form's. */
.pp-pdp-assurance { container-type: inline-size; margin-top: 4px; }
.pp-pdp-delivery,
.pp-pdp-payment { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 10px; font: 500 var(--pp-text-label)/1.3 var(--pp-font-body); color: var(--pp-ink); }
.pp-pdp-delivery { padding-top: 12px; border-top: 1px solid var(--pp-border); }
.pp-pdp-delivery + .pp-pdp-payment { margin-top: 10px; }
.pp-pdp-payment:first-child { padding-top: 12px; border-top: 1px solid var(--pp-border); }
.pp-pdp-delivery > .pp-i,
.pp-pdp-payment > .pp-i { width: 20px; height: 20px; flex: none; }
.pp-pdp-assurance-k { font-weight: 600; }
.pp-pdp-assurance-link { margin-left: auto; display: inline-flex; align-items: center; gap: 2px; color: var(--pp-navy); font-weight: 600; text-decoration: none; white-space: nowrap; }
.pp-pdp-assurance-link .pp-i { width: 16px; height: 16px; }
.pp-pdp-assurance-link:hover { text-decoration: underline; text-underline-offset: 3px; }
.pp-pdp-assurance-link:focus-visible { outline: none; box-shadow: var(--pp-focus-ring); border-radius: var(--pp-radius-sm); }

.pp-carrier-marks,
.pp-pay-marks { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0; padding: 0; list-style: none; }
.pp-carrier-marks { flex: 0 1 auto; min-width: 0; } /* stays one row for the approved three; would wrap, never overflow, if Core ever confirms more */
.pp-pay-marks { flex: 1 0 100%; padding-left: 30px; }
@container (min-width: 460px) {
	.pp-pay-marks { flex: 0 1 auto; padding-left: 0; }
}
@container (max-width: 479px) {
	.pp-pdp-delivery:has(> .pp-carrier-marks) { display: grid; grid-template-columns: auto auto minmax(0, 1fr); }
	.pp-pdp-delivery:has(> .pp-carrier-marks) > .pp-pdp-assurance-link { grid-column: 1 / -1; justify-self: start; margin-left: 0; }
}

/* Carrier tiles: optical sizes judged by rendered ink against the approved
   R2 pair (DHL 9px on its own yellow, PostNord 10px) — UPS's shield 15px.
   The yellow is the DHL artwork's own (#FECC00), so the tile and the logo
   meet without a seam. */
.pp-carrier-mark { display: inline-grid; place-items: center; height: 22px; padding: 0 7px; border-radius: 4px; border: 1px solid var(--pp-border); background: #fff; }
.pp-carrier-mark img { display: block; width: auto; height: 10px; }
.pp-carrier-mark--dhl { background: #FECC00; border-color: #FECC00; }
.pp-carrier-mark--dhl img { height: 9px; }
.pp-carrier-mark--ups img { height: 15px; }

/* Payment tiles: the footer PM.1 marks at 0.73x, same optical ratios. */
.pp-pay-mark { display: inline-flex; align-items: center; justify-content: center; height: 22px; min-width: 34px; padding: 0 6px; border-radius: 4px; border: 1px solid var(--pp-border); background: #fff; overflow: hidden; }
.pp-pay-mark img { display: block; width: auto; height: 10px; }
.pp-pay-mark-text { font: 600 var(--pp-text-meta-min)/1 var(--pp-font-body); color: var(--pp-ink); white-space: nowrap; }
.pp-pay-mark--visa img { height: 8px; }
.pp-pay-mark--mastercard img { height: 13px; }
.pp-pay-mark--amex { padding: 0; border-color: transparent; }
.pp-pay-mark--amex img { height: 100%; }
.pp-pay-mark--klarna { background: #FFA8CD; border-color: #FFA8CD; }
.pp-pay-mark--klarna img { height: 7px; }

/* ---------- Mobile sticky CTA (PDP lock Section S, lock §16/§30) ----------
   Supplemental only: shown once the in-page CTA leaves the viewport, hidden
   again when it returns — the two are never both visible. Safe-area inset per
   lock §16 (the bottom pad is the base pad + env(safe-area-inset-bottom)). */
.pp-sticky-buy {
	position: fixed; inset-inline: 0; bottom: 0; z-index: 50;
	background: #fff; border-top: 1px solid var(--pp-border);
	box-shadow: var(--pp-shadow-sticky);
	padding: 10px var(--pp-gutter-mobile);
	padding-bottom: calc(10px + var(--pp-safe-bottom));
	display: flex; align-items: center; gap: 10px;
	flex-wrap: wrap;   /* S9E-A1-R3: lets the rejection row above take its own full-width line; empty = no wrap, layout unchanged */
	/* Hidden state is `visibility: hidden`, not just an off-screen transform,
	   so the supplemental CTA is never a hidden tabbable while the real
	   in-page CTA is on screen (lock §50 "no hidden focusables"). Visibility
	   flips only after the slide-out finishes, so the exit is still animated. */
	visibility: hidden;
	transform: translateY(110%);
	transition:
		transform var(--pp-motion-component) var(--pp-ease-out),
		visibility 0s linear var(--pp-motion-component);
}
.pp-sticky-buy.pp-io-visible {
	visibility: visible;
	transform: none;
	transition: transform var(--pp-motion-component) var(--pp-ease-out), visibility 0s;
}
/* S9E-A1-R3: the sticky bar's rejection slot — a WooCommerce rejection of an
   add started from the sticky CTA is rendered HERE, beside the tapped control
   (the in-page slot would be off screen). Full-width row above the info + CTA
   row; the shared error component owns its own geometry and wraps real
   WooCommerce copy (no truncation, no fixed height); empty = no row, no gap. */
.pp-sticky-feedback { flex: 1 1 100%; min-width: 0; }
.pp-sticky-feedback:empty { display: none; }
.pp-sticky-info { flex: 1; min-width: 0; }
.pp-sticky-qty { font: 500 var(--pp-text-meta-min)/1.2 var(--pp-font-body); color: var(--pp-secondary-text); }
.pp-sticky-total { font: 800 16px/1.2 var(--pp-font-body); color: var(--pp-ink); }
.pp-sticky-cta { flex: 0 1 auto; min-width: 0; padding-inline: 18px; font-size: var(--pp-text-btn-m); }

@media (min-width: 1025px) {
	.pp-sticky-buy { display: none; }
}

/* ---------- Reduced motion (lock §7) ---------- */
@media (prefers-reduced-motion: reduce) {
	.pp-fd-item:active .pp-fd-circle { transform: none; }
	/* The sticky bar still resolves to its shown/hidden end state — it is
	   never left mid-transition, only instant. */
	.pp-sticky-buy { transition-duration: 0ms; }
}

/* ---------- MK.8B-P1: fail-closed "not available" purchase area ----------
   Replaces price block + tiers + form when no valid storefront price
   exists. Quiet statement, no money, no control. */
.pp-price-block--unavailable { margin-bottom: 8px; }
.pp-unavailable-note { font: 600 var(--pp-text-body)/1.4 var(--pp-font-body); color: var(--pp-ink); }
.pp-unavailable-sub { font: 400 var(--pp-text-meta)/1.5 var(--pp-font-body); color: var(--pp-secondary-text); margin: 4px 0 0; }
