/**
 * Shared front-end styles for the delivery-promise surfaces (M1b).
 *
 * One stylesheet, registered once by `Surface\Assets` and reused by every
 * surface: the W1 destination bar (Task 5) today, the product-page express
 * gauge (Task 6) next. Kept deliberately lean — layout, spacing and the
 * design system's signal colors only. Matteo's Oxygen theme owns
 * typography (font-family/weight/line-height are never set here).
 */

/* -------------------------------------------------------------------------
 * Design tokens (design.md §1) — signal colors, brighter than the site
 * palette on purpose (design spec's own wording), shared by W1's VAT/
 * language chrome today and Task 6's capacity gauge next.
 * ---------------------------------------------------------------------- */
:root {
	--ibdp-color-green: #4c9a52;
	--ibdp-color-yellow: #e0a800;
	--ibdp-color-red: #d4453a;
	--ibdp-color-grey: #b5b1a8;

	--ibdp-color-ink: #1f1f1f;
	--ibdp-color-ink-muted: #5c5c5c;
	--ibdp-color-border: #d8d5cf;
	--ibdp-color-surface: #fdfcfa;
	--ibdp-color-surface-muted: #f4f2ee;
	--ibdp-color-panel-shadow: rgba(0, 0, 0, 0.12);

	/* T5 — the promise card's amber countdown row (design.md §1: "amber ⏳
	 * row"). A dedicated token rather than reusing --ibdp-color-yellow
	 * (same hex today) so the countdown row's styling can diverge from the
	 * gauge's yellow SIGNAL state later without a shared-token side effect. */
	--ibdp-color-amber: #e0a800;
	--ibdp-color-amber-bg: #fdf3d9;

	/* T23 (shipping-price wave) — the amber row's TEXT colour, a THIRD
	 * token rather than a shifted one. Matteo read the promise block on a
	 * real product page (2026-08-27, thread 23) and the countdown — the
	 * most urgent line in the block — was the least readable thing on it:
	 * `--ibdp-color-amber` (#e0a800) on `--ibdp-color-amber-bg` (#fdf3d9)
	 * measures **1.94:1**, where WCAG AA for normal text is 4.5:1. This
	 * brown-amber measures **4.65:1** on the same background and stays in
	 * the same colour family (no redesign — the row still reads amber).
	 * Deliberately NOT a change to `--ibdp-color-amber` itself: that token
	 * is the SIGNAL hue — the punctuality wall's amber brick, the conflict
	 * dialog's verdict border, the account journey's pending step border —
	 * and a signal that shifts hue has lost its meaning. Rule of thumb this
	 * file now follows, pinned by `SurfaceCssTest`: the signal amber may
	 * paint backgrounds, borders and needles; TEXT reads this token. */
	--ibdp-color-amber-text: #a35c00;

	/* M3 Task 6 (W12) — the account journey's ON SCHEDULE chip (design.md
	 * §7: green). A dedicated background token, same reasoning as
	 * --ibdp-color-amber-bg immediately above (--ibdp-color-green already
	 * exists as the gauge's green SIGNAL color; this is only the chip's own
	 * pale background, not a new signal hue). */
	--ibdp-color-green-bg: #e3f2e4;

	/* TASK 36 (shipping-price wave) — the SHOP's own green, the one the
	 * price block and the lane cards already paint with. It exists twice in
	 * this file already, scoped to the two surfaces that own it
	 * (`--ibdp-bar-tertiary` on the W1 pre-header, `--ibdp-w2-tertiary` on
	 * the W2 product-page block) — deliberately independent copies, so
	 * either surface can diverge later (both blocks' own top comments state
	 * this). The icon family (`.ibdp-icon--truck`/`.ibdp-icon--shield`
	 * below) is the first thing in this stylesheet that crosses ALL the
	 * surfaces at once — product page, basket card, drawer, checkout,
	 * thank-you page, account journey — so it cannot read either scoped
	 * copy. This is the shared one, and it is a SHARED token on purpose:
	 * these thirteen icons must never drift apart from each other.
	 *
	 * NOT `--ibdp-color-green` (#4c9a52): that is the gauge's green SIGNAL
	 * hue, brighter than the brand by design (§1's own note) — the same
	 * separation `--ibdp-color-amber` vs `--ibdp-color-amber-text` keeps. */
	--ibdp-color-tertiary: hsl( 121, 30%, 30% );
}

/* -------------------------------------------------------------------------
 * TASK 36 (shipping-price wave, Matteo 2026-08-15 thread 31) — the icon
 * family: ONE truck, ONE clock, ONE shield, drawn as inline SVG by
 * `IB_Delivery_Promise\Surface\Icons` (and mirrored byte-for-byte in
 * `assets/js/lane-selector.js` / `assets/js/basket-card.js`, pinned by
 * `tests/Unit/IconsTest.php`). They replace the `🚚`/`🛡️` emoji on the
 * delivery line, the countdown and the guarantee, everywhere those three
 * blocks appear.
 *
 * Every icon's stroke is `currentColor`, so an icon takes the colour of the
 * line it sits in — which is exactly what the CLOCK wants: inside the amber
 * countdown box it reads `--ibdp-color-amber-text` with the words beside
 * it, with no rule of its own. The truck and the shield are the shop's
 * green instead, stated ONCE here rather than at thirteen call sites.
 *
 * `flex: none` because the delivery line's own `.ibdp-day-echo__day` is a
 * flex row: without it the icon is a flex item free to shrink, and a
 * squashed truck on a narrow phone is worse than no truck. `vertical-align`
 * only matters in the INLINE contexts (the countdown row, the promise
 * card's day line, the guarantee heading) — a flex item ignores it.
 *
 * NOT `.ibdp-destination-bar`: the shop's pre-header keeps its own 🚚
 * emoji, ruled out of scope twice (area decision log 2026-08-28 (1),
 * thread 29).
 * ---------------------------------------------------------------------- */

.ibdp-icon {
	flex: none;
	vertical-align: -0.15em;
}

.ibdp-icon--truck,
.ibdp-icon--shield {
	color: var( --ibdp-color-tertiary );
}

/* -------------------------------------------------------------------------
 * W1 — destination bar (visual-fidelity wave Task 1, 2026-08-24)
 *
 * Restyled/restructured to `artifact-w1.html` (the approved claude.ai
 * artifact, pixel authority per the wave's own decision log — colors below
 * are its literal `:root`/rule values, not this file's shared signal-color
 * tokens, which stay untouched for the OTHER surfaces that use them).
 * Scoped to `.ibdp-destination-bar` rather than added to the file's shared
 * `:root` block: these are this bar's own palette, not meant to leak into
 * F1's gauge or W2's lane cards.
 *
 * Two deliberate unit choices, both explained once here rather than per
 * rule: (a) the panel's own literal pixel values the task brief calls out
 * by name — 380px width, the `0 14px 40px rgba(40,35,28,.22)` shadow, the
 * 18px padding, the 8px radius, the 12px `::before` caret — are kept as
 * LITERAL px, matching the artifact exactly; (b) everything else (the
 * pre-header's own padding/gaps/font-sizes) stays `em`-based, this file's
 * pre-existing convention (top-of-file comment: "Matteo's Oxygen theme owns
 * typography… never set here") — `em` spacing scales with whatever
 * font-size the Oxygen element carries, where a literal px would look
 * wrong the moment the theme's own base size differs from the artifact's
 * assumed 16px.
 *
 * OXYGEN CONTAINER NOTE (task brief): `.ibdp-destination-bar` is
 * `width: 100%` and fills whatever element the `[ibdp_destination_bar]`
 * shortcode sits in (TODO #12 resolved: Matteo placed it in the Oxygen
 * header). If that Oxygen element itself is narrower than the header row
 * (a centered/max-width container) the bar will only fill THAT box, not a
 * true edge-to-edge strip like the artifact — set the Oxygen element
 * holding the shortcode to full width / remove its own inner padding for
 * an edge-to-edge match (see task-1-report.md's own caveat).
 * ---------------------------------------------------------------------- */

.ibdp-destination-bar {
	--ibdp-bar-bg: #e7e4df;
	--ibdp-bar-text: #5d594f;
	--ibdp-bar-hover: #dbd7d0;
	--ibdp-bar-sep: #b5b0a6;
	--ibdp-bar-field-text: #4a463d;
	--ibdp-bar-panel-border: #e3e1dd;
	--ibdp-bar-panel-shadow: rgba( 40, 35, 28, 0.22 );
	--ibdp-bar-tertiary: hsl( 121, 30%, 30% );
	--ibdp-bar-tertiary-soft: hsl( 121, 30%, 96% );
	--ibdp-bar-grey: #8a8a8a;

	position: relative;
	display: flex;
	align-items: center;
	width: 100%;
	gap: 1em;
	/* Background and spacing belong to the Oxygen element hosting the
	 * shortcode (Matteo, 2026-08-25): the bar paints NO background of its
	 * own and adds NO padding, so the host div's color shows through and
	 * the content spans the full div edge to edge. `--ibdp-bar-bg` stays
	 * defined for the hover/panel palette derived from it. */
	padding: 0;
	background: transparent;
	color: var( --ibdp-bar-text );
	font-size: 0.85rem;
	line-height: 1.4;
	box-sizing: border-box;
}

.ibdp-destination-bar__claim {
	flex: 0 1 auto;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	letter-spacing: 0.02em;
}

/* `.destgroup` — pushed right via its OWN margin, not `justify-content` on
 * the row (artifact's own DOM shape, this class's docblock in DestinationBar.php). */
.ibdp-destination-bar__group {
	margin-left: auto;
	display: flex;
	align-items: center;
}

.ibdp-destination-bar__toggle,
.ibdp-destination-bar__strip {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	background: none;
	border: none;
	margin: 0;
	padding: 3px 10px;
	border-radius: 3px;
	color: var( --ibdp-bar-field-text );
	font: inherit;
	cursor: pointer;
	white-space: nowrap;
}

.ibdp-destination-bar__toggle:hover,
.ibdp-destination-bar__toggle:focus-visible {
	background: var( --ibdp-bar-hover );
}

.ibdp-destination-bar__toggle b,
.ibdp-destination-bar__strip b {
	font-weight: 600;
}

.ibdp-destination-bar__sep {
	color: var( --ibdp-bar-sep );
	padding: 0 0.3em;
}

.ibdp-destination-bar__caret {
	display: inline-block;
	color: var( --ibdp-bar-grey );
	transition: transform 0.15s ease;
}

.ibdp-destination-bar__toggle[ aria-expanded="true" ] .ibdp-destination-bar__caret,
.ibdp-destination-bar__strip[ aria-expanded="true" ] .ibdp-destination-bar__caret {
	transform: rotate( 180deg );
}

/* Mobile strip + veil: built desktop-hidden, the >782px block flips them
 * on (this file's mobile section, below). */
.ibdp-destination-bar__strip,
.ibdp-destination-bar__veil,
.ibdp-destination-bar__grab {
	display: none;
}

/* Desktop: the panel is an anchored dropdown under the toggle, its `right`
 * matched to the bar's own horizontal padding so the panel's right edge
 * lines up with the destination group above it (the artifact's own
 * `right: 24px` is relative to a DIFFERENT ancestor — its full demo frame,
 * not applicable here 1:1; DestinationBar.php's own docblock on why the
 * anchor point is adapted, not the panel's own visual proportions).
 *
 * Z-INDEX: 1000, not the artifact's own z:20 demo value — proven against
 * the REAL Oxygen sticky header on staging (`#_header-109-82{z-index:100}`,
 * fetched live via `?wpcs_bypass=true`; today's z:100 panel LOSES that tie
 * on DOM order, the plan's own documented bug). 1000 is not an invented
 * number — it's the same "elevated fixed overlay" value the theme's own
 * `oxygen/css/universal.css` already uses; full citation in the wave's
 * decision log, 2026-08-24 Task 1 entry.
 *
 * TASK 15 requirement 4 (Matteo: "the header's magnifier icon covers the
 * dropdown panel") — 1000 was never big enough. Diagnosed read-only against
 * the LIVE production header (`https://italianabandiere.com/?wpcs_bypass=true`,
 * curled `82.css`, the per-template Oxygen stylesheet): the destination bar
 * and the header search icon are BOTH descendants of the SAME stacking
 * context, `#_header-109-82` (`position: relative` from `oxygen.css`'s own
 * `.oxy-header-wrapper` rule, `z-index: 100` from `82.css`'s own
 * `#_header-109-82{z-index:100}`) — so their z-index values are compared
 * DIRECTLY against each other at that one level, exactly like this panel's
 * own 1000 vs the header's 100 above. The real culprit, found in that same
 * `82.css`: `#-header-search-898-82{z-index:10000000}` — the search icon's
 * OWN wrapper div (`class="oxy-header-search"`, a flex item of
 * `.oxy-header-center`, which is enough for z-index to apply with no
 * `position` of its own) carries a flat, UNCONDITIONAL z-index of ten
 * million, apparently hand-added (a stray `#-header-search-972-82{z-index:
 * 10000000;display:none;.test{color:red}}` fragment two rules later, with a
 * dangling debug `.test` selector, confirms this was a manual CSS edit, not
 * generated by Oxygen) to make the search overlay always cover the page
 * when open — it also outranks EVERY other in-header element all the time,
 * open or not, this panel included. 100000000 (100 million) here: two
 * orders of magnitude above that 10,000,000, so this panel always wins
 * regardless of that value, with headroom for any other icon that might
 * copy the same pattern — deliberately still well BELOW Oxygen's own true
 * "escape everything" convention, `oxygen.css`'s `.oxy-nav-menu.oxy-nav-menu-open{z-index:
 * 2147483642 !important}` (the full-screen mobile nav overlay), so that
 * genuinely full-page takeover still wins over this small anchored dropdown
 * in the unlikely case both are open at once — the site's own established
 * layering intent, not overridden here.
 */
.ibdp-destination-bar__panel {
	position: absolute;
	top: 100%;
	right: 2em;
	z-index: 100000000;
	width: 380px;
	max-width: calc( 100vw - 2em );
	margin-top: 0.5em;
	padding: 18px;
	background: #fff;
	border: 1px solid var( --ibdp-bar-panel-border );
	border-radius: 8px;
	box-shadow: 0 14px 40px var( --ibdp-bar-panel-shadow );
	color: var( --ibdp-color-ink );
	text-align: left;
}

.ibdp-destination-bar__panel::before {
	content: "";
	position: absolute;
	top: -7px;
	right: 60px;
	width: 12px;
	height: 12px;
	background: #fff;
	border-left: 1px solid var( --ibdp-bar-panel-border );
	border-top: 1px solid var( --ibdp-bar-panel-border );
	transform: rotate( 45deg );
}

.ibdp-destination-bar__panel[ hidden ] {
	display: none;
}

.ibdp-destination-bar__heading {
	font-size: 0.95rem;
	font-weight: 600;
	color: #222;
	margin: 0;
}

/* Section labels ("Delivery destination" / "Language" / "Prices",
 * `artifact-w1.html`'s `.plabel`) — the ONLY consumer of this class now:
 * per-field `<label>`s moved to `.ibdp-destination-bar__visually-hidden`
 * (`DestinationBar::render_destination_fields()`'s own docblock), freeing
 * this class name to match the artifact's section-heading look exactly. */
.ibdp-destination-bar__label {
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var( --ibdp-bar-grey );
	margin: 14px 0 6px;
}

.ibdp-destination-bar__visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect( 0, 0, 0, 0 );
	white-space: nowrap;
	border: 0;
}

/* TASK 15 FIX ROUND 1, styling pass (Matteo's ruling: the confirmed mockup
 * IS the pixel authority, so the unstyled mode-switch buttons flagged as a
 * concern in the original fix-round-1 report are a contract gap, not a
 * deferrable nice-to-have). Restyled to `artifact-bar-v2.html`'s own
 * `.modeswitch`/`.modebtn`/`.modebtn.on` rules verbatim in SHAPE (joined
 * pill group: one shared 1px border + 4px radius + `overflow: hidden` on
 * the wrapper, `gap: 0` between the two segments so no visible seam shows
 * between them; the selected tab gets the tertiary-soft fill, tertiary
 * text, 600 weight, and the inset 2px bottom bar) — adapted to this
 * plugin's BEM naming (`.ibdp-destination-bar__mode-switch`/
 * `-mode-button`, `.is-selected` for the artifact's bare `.on`, this bar's
 * own state-class convention already used by `.ibdp-destination-bar__vat-button.is-selected`/
 * `.ibdp-destination-bar__language.is-current`) and this bar's OWN CSS
 * custom properties in place of the mockup's literal hexes, wherever an
 * equivalent token already exists on `.ibdp-destination-bar` itself (this
 * section's own `:root`-equivalent block, above): `--border` ->
 * `--ibdp-bar-panel-border`, `--site-grey` -> `--ibdp-bar-grey`,
 * `--tertiary`/`--tertiary-soft` -> `--ibdp-bar-tertiary`/`-tertiary-soft`.
 * The one literal left as-is, `#fafaf8` (the UNSELECTED segment's own
 * background): no token for this exact off-white exists on this bar, and
 * the artifact's own value already matches — byte-for-byte — the SAME
 * literal `.ibdp-destination-bar__vat-button` (below) already uses for its
 * own unselected state, so keeping it literal here is consistency with an
 * existing sibling rule, not a new exception. Units: this section's own
 * PANEL content (not the pre-header) already establishes rem for
 * font-size and literal px for padding/gap/radius throughout — see the
 * VAT toggle immediately below, the closest structural sibling (also a
 * two-state button pair with a `.is-selected` fill) — followed here
 * rather than the top-of-section note's em convention, which that note's
 * own text scopes to "the pre-header's own padding/gaps/font-sizes"
 * specifically, not the panel. Hover: no dedicated state exists on the VAT
 * buttons to mirror, so this reuses `.ibdp-destination-bar__toggle`'s own
 * `:hover`/`:focus-visible` treatment instead (`background: var(
 * --ibdp-bar-hover)`) — the closest "plain flat button" precedent in this
 * bar — deliberately scoped to `:not(.is-selected)` only: hover-tinting
 * the already-active tab would fight its own selected fill for no benefit,
 * and no segmented-control convention does that. No custom `outline`: like
 * every other button in this bar, the native focus ring is left alone.
 */
.ibdp-destination-bar__mode-switch {
	display: flex;
	gap: 0;
	border: 1px solid var( --ibdp-bar-panel-border );
	border-radius: 4px;
	overflow: hidden;
	margin-bottom: 8px;
}

.ibdp-destination-bar__mode-button {
	flex: 1;
	background: #fafaf8;
	border: none;
	margin: 0;
	padding: 7px 8px;
	color: var( --ibdp-bar-grey );
	font: inherit;
	font-size: 0.76rem;
	cursor: pointer;
}

.ibdp-destination-bar__mode-button:not( .is-selected ):hover,
.ibdp-destination-bar__mode-button:not( .is-selected ):focus-visible {
	background: var( --ibdp-bar-hover );
}

.ibdp-destination-bar__mode-button.is-selected {
	background: var( --ibdp-bar-tertiary-soft );
	color: var( --ibdp-bar-tertiary );
	font-weight: 600;
	box-shadow: inset 0 -2px 0 var( --ibdp-bar-tertiary );
}

.ibdp-destination-bar__field-row {
	display: flex;
	gap: 10px;
}

/* TASK 15 FIX ROUND 1 (Matteo, live screenshot, production 0.4.20): with
 * book mode active, the manual country+postcode fields were ALSO visible
 * right below the saved-address select — both `.ibdp-destination-bar__field-row`
 * blocks on screen at once, against the confirmed mockup (book mode shows
 * ONLY the select). ROOT CAUSE: `DestinationBar::render_manual_fields()`
 * (PHP) already emits the `hidden` attribute correctly, on the very first
 * render — the bug was never server-side. Author CSS always overrides the
 * User-Agent stylesheet's own `[hidden] { display: none }` regardless of
 * specificity (UA rules are the lowest-priority cascade origin, full
 * stop), so the UNCONDITIONAL `display: flex` rule immediately above
 * silently defeated `hidden` on whichever field-row block currently
 * carried it — on first open AND after clicking the book/manual switch.
 * FIX: this override selector is the SAME class token plus `[hidden]` — a
 * compound selector that is structurally MORE specific than the bare
 * class alone (class and attribute selectors count identically toward
 * specificity, one point each), so it wins regardless of source order,
 * not merely because it appears later in this file. NOT an invented
 * pattern: this file already carries the identical idiom for every other
 * element whose own class sets `display` and is ALSO toggled via the
 * `hidden` attribute — `.ibdp-destination-bar__panel[ hidden ]`,
 * `.ibdp-destination-bar__error[ hidden ]`,
 * `.ibdp-lane-selector__lanes[ hidden ]`, `.ibdp-gauge-explainer[ hidden ]`,
 * `.ibdp-day-echo__shipline[ hidden ]` (all elsewhere in this file) — this
 * rule is simply the missing member of that family for the field-row
 * markup Task 15 introduced. `SurfaceCssTest.php` pins this exact
 * selector.
 */
.ibdp-destination-bar__field-row[ hidden ] {
	display: none;
}

.ibdp-destination-bar__field {
	flex: 1;
	width: 100%;
	background: #fff;
	border: 1px solid var( --ibdp-bar-panel-border );
	border-radius: 4px;
	padding: 9px 11px;
	color: var( --ibdp-color-ink );
	font: inherit;
	font-size: 0.85rem;
	text-align: left;
}

.ibdp-destination-bar__field--country {
	flex: 1.4;
}

.ibdp-destination-bar__field--postcode {
	flex: 1;
}

.ibdp-destination-bar__note {
	font-size: 0.72rem;
	color: var( --ibdp-bar-grey );
	line-height: 1.45;
	margin: 6px 0 0;
}

.ibdp-destination-bar__languages {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
}

.ibdp-destination-bar__language {
	border: 1px solid var( --ibdp-bar-panel-border );
	border-radius: 4px;
	padding: 6px 11px;
	font-size: 0.8rem;
	background: #fafaf8;
	color: var( --ibdp-color-ink );
	text-decoration: none;
}

.ibdp-destination-bar__language.is-current {
	border: 2px solid var( --ibdp-bar-tertiary );
	background: var( --ibdp-bar-tertiary-soft );
	font-weight: 600;
	padding: 5px 10px;
}

.ibdp-destination-bar__vat {
	display: flex;
	gap: 6px;
}

.ibdp-destination-bar__vat-button {
	flex: 1;
	border: 1px solid var( --ibdp-bar-panel-border );
	border-radius: 4px;
	padding: 8px;
	font-size: 0.8rem;
	background: #fafaf8;
	color: var( --ibdp-color-ink );
	text-align: center;
}

.ibdp-destination-bar__vat-button.is-selected {
	border: 2px solid var( --ibdp-bar-tertiary );
	background: var( --ibdp-bar-tertiary-soft );
	font-weight: 600;
	padding: 7px;
}

.ibdp-destination-bar__error {
	margin: 8px 0 0;
	color: var( --ibdp-color-red );
	font-size: 0.8em;
}

.ibdp-destination-bar__error[ hidden ] {
	display: none;
}

.ibdp-destination-bar__save {
	display: block;
	width: 100%;
	margin-top: 16px;
	background: var( --ibdp-bar-tertiary );
	color: #fff;
	border: none;
	border-radius: 4px;
	font-weight: 700;
	font-size: 0.82rem;
	letter-spacing: 0.03em;
	padding: 10px;
	text-align: center;
	cursor: pointer;
}

.ibdp-destination-bar__save:hover,
.ibdp-destination-bar__save:focus-visible {
	opacity: 0.92;
}

.ibdp-destination-bar__save[ disabled ] {
	opacity: 0.6;
	cursor: default;
}

.ibdp-destination-bar__footer {
	font-size: 0.72rem;
	color: var( --ibdp-bar-grey );
	margin: 8px 0 0;
	text-align: center;
}

/* -------------------------------------------------------------------------
 * Mobile: the desktop pre-header collapses to one slim strip
 * (`artifact-w1.html`'s `.m-strip`) that opens the SAME panel, now a
 * bottom sheet with a veil backdrop and a grab handle — same three
 * sections + SAVE, no separate markup (`DestinationBar::render_panel()`'s
 * own docblock).
 * ---------------------------------------------------------------------- */
@media ( max-width: 782px ) {
	.ibdp-destination-bar {
		flex-wrap: wrap;
		/* Same rule as the base: spacing is the host div's job. */
		padding: 0;
	}

	.ibdp-destination-bar__claim,
	.ibdp-destination-bar__group {
		display: none;
	}

	.ibdp-destination-bar__strip {
		display: flex;
		width: 100%;
		padding: 0;
		font-size: 0.74rem;
	}

	/* `artifact-w1.html`'s `.m-strip .chev { margin-left: auto; }` — pins the
	 * chevron to the strip's right edge (fix round 1, F2/M1). Scoped to the
	 * strip on purpose: the desktop `.ibdp-destination-bar__toggle` shares
	 * the SAME `.ibdp-destination-bar__caret` class but must NOT get this
	 * push — that button is `inline-flex`/width:auto and already sits
	 * right-aligned via its `.ibdp-destination-bar__group` wrapper
	 * (`margin-left: auto` there); an auto margin on the caret ITSELF would
	 * additionally split it away from the sentence text inside the button,
	 * which the artifact's own `.destbtn` never does. */
	.ibdp-destination-bar__strip .ibdp-destination-bar__caret {
		margin-left: auto;
	}

	.ibdp-destination-bar__grab {
		display: block;
		width: 38px;
		height: 4px;
		border-radius: 2px;
		background: #d8d4cd;
		margin: 0 auto 12px;
	}

	.ibdp-destination-bar__veil:not( [ hidden ] ) {
		display: block;
		position: fixed;
		inset: 0;
		z-index: 999;
		background: rgba( 30, 26, 20, 0.35 );
	}

	.ibdp-destination-bar__panel {
		position: fixed;
		inset: auto 0 0 0;
		top: auto;
		right: auto;
		/* TASK 15 requirement 4: same fix, same reasoning, as the desktop
		 * rule above — the mobile bottom sheet sits in the SAME
		 * `#_header-109-82` stacking context as the header search icon. */
		z-index: 100000000;
		width: auto;
		max-width: none;
		margin-top: 0;
		padding: 16px 16px 20px;
		border: none;
		/* Square at the bottom on phones. The sheet stops just above Safari's
		 * own address bar, which is semi-transparent: with 30px of rounding
		 * the page behind showed through the two bottom corners (Matteo, an
		 * iPhone, 2026-09-05). The top corners keep their curve — that edge
		 * has the page above it and is meant to look like a sheet sliding up. */
		border-radius: 18px 18px 0 0;
		box-shadow: 0 -10px 30px rgba( 0, 0, 0, 0.2 );
		max-height: 80vh;
		overflow-y: auto;
	}

	.ibdp-destination-bar__panel::before {
		display: none;
	}
}

/* -------------------------------------------------------------------------
 * TASK 24 (cosmetic pass, Matteo 2026-08-27) — requirement (c): EVERY
 * shortcode root fills the container it is dropped into.
 *
 * Matteo places these roots by hand as Oxygen elements. A `<div>` is
 * block-level, so it usually fills its parent already — but a root dropped
 * inside a flex/grid/inline-block container (an Oxygen column set to
 * "fit content", a theme wrapper with its own `width: auto`) shrink-wraps
 * its content instead and the widget floats in a column it does not fill.
 * `width: 100%` states the intent once for all of them; `box-sizing:
 * border-box` rides along so a container that adds padding can never push
 * the root past its own box.
 *
 * The eighth root, `[ibdp_destination_bar]`, already carries both in its
 * own W1 rule at the top of this file (pinned by `SurfaceCssTest`) and is
 * not repeated here.
 * ---------------------------------------------------------------------- */

.ibdp-lane-selector,
.ibdp-day-echo,
.ibdp-guarantee,
.ibdp-shipping-cost,
.ibdp-cutoff-countdown,
.ibdp-product-promise,
.ibdp-cart-promise {
	width: 100%;
	box-sizing: border-box;
}

/* -------------------------------------------------------------------------
 * TASK 32 (shipping-price wave, Matteo 2026-08-27 requirement (c) — "gli
 * shortcode dovrebbero sempre prendere la larghezza del div") — the rule
 * above only HALF works, and the measurement on the live page shows why.
 *
 * A root's own `width: 100%` resolves against whatever box the page
 * builder handed it — and Oxygen does not always hand it a box that fills
 * the column. Measured live on `https://stg.italianabandiere.com/italy-flag/`
 * (administrator, ibdp 0.4.55, desktop viewport, DOM boxes read directly):
 * the product column `#div_block-102-101318` is `display: flex;
 * flex-direction: column; align-items: flex-start`, content box 610px
 * wide. `align-items: flex-start` makes EACH CHILD WRAPPER shrink-wrap its
 * own content instead of stretching to the column's cross axis — so
 * `.ibdp-lane-selector`'s `width: 100%` above measured 610px of NOTHING,
 * because its own wrapper had already shrunk to the width of the card
 * inside it: **393px**, inside that same 610px column. `.ibdp-day-echo`
 * only reached the full 610px because ITS wrapper
 * (`#div_block-209-101318`) happens to carry its own `width: 100%` in the
 * page template — a per-page accident of how that one element was built,
 * not something this stylesheet can rely on for every root on every page.
 * Visible result: the lane selector sat visibly narrower than the delivery
 * line directly under it.
 *
 * `:has()` reaches the wrapper a descendant-only rule cannot: it selects
 * an ancestor BY the descendant it contains. Proved by injection on the
 * live page before this rule was written (`CSS.supports('selector(:has(*))')`
 * is `true` there): widening `.ct-shortcode:has( > .ibdp-lane-selector )`
 * took `.ibdp-lane-selector` from the measured **393px to 610px**, flush
 * with the delivery line and with the cxvf price block that shares this
 * same column (widened to 610px by the sibling task in the OTHER plugin,
 * `codexyl-variable-flag`'s own `assets/css/variable-flag.css` — a
 * different repo and a different file, using the same `:has()` technique
 * independently; this is not the only place it is used). Nothing else on
 * the page moved.
 *
 * Two ancestor levels per root because Oxygen nests a `.ct-shortcode` span
 * around the shortcode's own output INSIDE a `.ct-div-block` column cell —
 * either level can be the one the page template left shrink-wrapped, so
 * both are widened. Every selector is scoped through the child combinator
 * (`>`) AND one of the SEVEN named `ibdp-` roots below: never a bare
 * `.ct-div-block { width: 100% }`, which would widen every Oxygen div on
 * the site.
 *
 * NOT `.ibdp-destination-bar` (TASK 33, shipping-price wave) — Task 32
 * added it here too, on the assumption that it had the same ancestor
 * problem as the other seven roots. That assumption was never measured
 * before it shipped. Measured on `https://stg.italianabandiere.com/italy-flag/`
 * at ibdp 0.4.56: the bar's Oxygen wrapper `#shortcode-1343-82` is a FLEX
 * ITEM of `#div_block-1341-82` (`display: flex`) — not a shrink-wrapped box
 * sitting in a stacked column like the other seven roots. BEFORE Task 32
 * the wrapper was shrink-wrapped, so the whole pre-header row sat packed to
 * the left: the slogan «Sewn to measure. On time. Every time.» followed
 * immediately by «🚚 Deliver to Ljubljana · EN · excl. VAT ⌄», both inside
 * the left half of the screen. AFTER Task 32 the wrapper measured 1512px
 * (the full viewport) and the bar's OWN flex layout spread across that: the
 * slogan stayed hard left and the delivery/language/VAT controls jumped to
 * the far right edge of the pre-header — a visible change to the shop's top
 * bar Matteo did not ask for and had not seen. This block widens roots
 * dropped into a COLUMN of stacked shortcodes; the destination bar is
 * itself a flex ROW, so widening its wrapper re-lays-out the whole row
 * instead of just the root inside it. The bar's own `width: 100%` in the W1
 * rule at the top of this file is untouched — it still fills whatever box
 * it is handed, exactly as before Task 32. Whether the controls SHOULD move
 * to the right of the pre-header is a separate question, for Matteo.
 *
 * FALLBACK: a browser without `:has()` support (pre-Chrome 105, pre-Safari
 * 15.4, pre-Firefox 121) simply never matches these selectors — the root
 * keeps its own `width: 100%` above, on whatever wrapper the page builder
 * left it in, exactly today's behaviour. No regression there, just no fix.
 *
 * MOBILE (checked): this block carries no `@media` query, so it applies at
 * every viewport, including under 768px, where the roots already stack one
 * per row. Nothing in this file gives a `.ct-shortcode`/`.ct-div-block`
 * ancestor a `flex-direction: row` or a multi-column grid at any
 * breakpoint (the `@media ( max-width: 782px )` blocks above and below
 * this one only ever restyle a shortcode's OWN inner markup —
 * `.ibdp-destination-bar__strip`, `.ibdp-lane`, `.ibdp-conflict-dialog`);
 * the stacking is the column's own `flex-direction: column`, measured
 * above, which a WIDTH change on a child cannot turn into a row.
 * ---------------------------------------------------------------------- */

.ct-shortcode:has( > .ibdp-lane-selector ),
.ct-div-block:has( > .ct-shortcode > .ibdp-lane-selector ),
.ct-shortcode:has( > .ibdp-day-echo ),
.ct-div-block:has( > .ct-shortcode > .ibdp-day-echo ),
.ct-shortcode:has( > .ibdp-guarantee ),
.ct-div-block:has( > .ct-shortcode > .ibdp-guarantee ),
.ct-shortcode:has( > .ibdp-shipping-cost ),
.ct-div-block:has( > .ct-shortcode > .ibdp-shipping-cost ),
.ct-shortcode:has( > .ibdp-cutoff-countdown ),
.ct-div-block:has( > .ct-shortcode > .ibdp-cutoff-countdown ),
.ct-shortcode:has( > .ibdp-product-promise ),
.ct-div-block:has( > .ct-shortcode > .ibdp-product-promise ),
.ct-shortcode:has( > .ibdp-cart-promise ),
.ct-div-block:has( > .ct-shortcode > .ibdp-cart-promise ) {
	width: 100%;
}

/* -------------------------------------------------------------------------
 * W2 + F1 — product-page lane selector and its express capacity gauge.
 *
 * Restyled/restructured to `artifact-w2.html` (the approved claude.ai
 * artifact, pixel authority per the wave's own decision log 2026-08-24,
 * visual-fidelity wave Task 6 — `LaneSelector`'s own class docblock has the
 * full anatomy citation) — the custom properties below are its literal
 * `.lane`/`.radio`/`.lname`/`.day`/`.sub` rule values, NOT this file's
 * shared design tokens (§1 above), scoped to `.ibdp-lane-selector`/
 * `.ibdp-day-echo`/`.ibdp-guarantee` rather than the shared `:root` block —
 * same reasoning the W1 block's own top comment states for its own
 * `--ibdp-bar-*` tokens: this is W2's own palette (identical hsl() green to
 * W1's by coincidence of one shared brand color, kept as an independent copy
 * so either surface can diverge later without a shared-token side effect).
 *
 * Cards carry DAYS ONLY (task brief: "lanes carry days only, all money in
 * its single home") — the per-card money line
 * (`.ibdp-lane__shipping-effect`) that used to live here is GONE
 * (`assets/js/lane-selector.js`'s own `buildLaneCard()` no longer builds
 * it); the SAME `ShippingEffect`-rendered text now lives exactly once, in
 * the `.ibdp-day-echo__shipline` block below.
 * ---------------------------------------------------------------------- */

.ibdp-lane-selector,
.ibdp-day-echo,
.ibdp-guarantee,
.ibdp-shipping-cost {
	--ibdp-w2-tertiary: hsl( 121, 30%, 30% );
	--ibdp-w2-tertiary-soft: hsl( 121, 30%, 96% );
	--ibdp-w2-border: #e3e1dd;

	/* T23 — the muted text grey, darkened from #8a8a8a (**3.45:1** on
	 * white, under the 4.5:1 AA floor: the shipline, the standalone
	 * shipping-cost line, the guarantee, the day echo's «which» qualifier
	 * and the lane cards' sub-line were all painted with it) to #5c5c5c,
	 * measured **6.69:1**. Shifted rather than split because EVERY consumer
	 * of this token paints TEXT — borders and dividers read
	 * `--ibdp-w2-border` immediately above, which is untouched; a
	 * `SurfaceCssTest` pin fails the day a non-text consumer is added
	 * instead of being split off. Same value as `--ibdp-color-ink-muted`
	 * by arithmetic, kept as its own token for the reason the whole W2
	 * block states above: this is W2's own palette, free to diverge. */
	--ibdp-w2-grey: #5c5c5c;
}

.ibdp-lane-selector__skeleton {
	margin: 0;
	padding: 0.75em 1em;
	color: var( --ibdp-color-ink-muted );
	font-size: 0.85rem;
	border: 1px dashed var( --ibdp-color-border );
	border-radius: 0.5em;
}

.ibdp-lane-selector__lanes {
	display: grid;
	grid-template-columns: repeat( 3, 1fr );
	gap: 10px;
}

.ibdp-lane-selector__lanes[ hidden ] {
	display: none;
}

/* TASK 23 (instantaneity wave) — the DECLARED updating state a
 * destination-changing SAVE paints on every date-bearing surface
 * (`destination-bar.js`'s `markDatesUpdating()`; `lane-selector.js`'s own
 * landings clear it): the dated content dims — visibly "these values are
 * being updated", never silently stale — and the widget carries an explicit
 * English note underneath. */
[data-ibdp-dates-updating] [data-ibdp-lanes],
[data-ibdp-dates-updating][data-ibdp-product-promise],
[data-ibdp-dates-updating][data-ibdp-cutoff-countdown],
[data-ibdp-dates-updating][data-ibdp-day-echo],
[data-ibdp-dates-updating][data-ibdp-shipping-cost] {
	opacity: 0.45;
	transition: opacity 0.15s ease;
}

.ibdp-dates-updating-note {
	margin: 0.4em 0 0;
	color: var( --ibdp-color-ink-muted );
	font-size: 0.85rem;
}

.ibdp-dates-updating-note[ hidden ] {
	display: none;
}

/* GAP NEUTRALIZED (fix round 1, review M1): this pre-existing
 * `display:flex; flex-direction:column` layout used to carry `gap:0.35em`
 * as its ONLY inter-line spacing — harmless before T6, when no child here
 * had its own margin. T6 added the artifact's own literal `margin-top`
 * values to `.ibdp-lane__day`/`.ibdp-lane__sub` (6px/2px, verbatim from
 * `artifact-w2.html`, which lays its `.lane` out in plain block flow, no
 * flex/gap at all) — a flex `gap` and a flex ITEM's own margin are
 * ADDITIVE, not collapsed, so the un-neutralized gap silently stacked on
 * top of both artifact values (computed: 0.35em ≈ 4.6px at this card's own
 * 0.82rem font-size, so name→day was rendering ≈10.6px instead of the
 * artifact's 6px, and day→sub ≈6.6px instead of 2px). `gap: 0` here makes
 * `.ibdp-lane__day`'s/`.ibdp-lane__sub`'s own `margin-top` the ONLY spacing
 * again — COMPUTED RESULT: name→day now renders EXACTLY 6px, day→sub
 * EXACTLY 2px, matching the artifact value-for-value. The two dynamic lines
 * the artifact's own static card never shows at all (`.ibdp-lane__reason`,
 * the unavailable-state line; `.ibdp-lane__urgency`, F1's yellow/red gauge
 * line) get their OWN explicit `margin-top` right below, reusing this same
 * 6px/2px rhythm, so removing the gap doesn't leave THEM flush against
 * their own preceding line. */
.ibdp-lane {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 0;
	padding: 12px 12px 13px;
	background: #fff;
	border: 1px solid var( --ibdp-w2-border );
	border-radius: 4px;
	color: var( --ibdp-color-ink );
	text-align: left;
	font-size: 0.82rem;
	cursor: pointer;
	transition: border-color 0.15s;
}

.ibdp-lane:hover {
	border-color: var( --ibdp-w2-tertiary );
}

.ibdp-lane:focus-visible {
	outline: 2px solid var( --ibdp-w2-tertiary );
	outline-offset: 2px;
}

/* Padding drops by the same 1px the border grows (12/12/13 -> 11/11/12) so
 * the card's own outer box size never shifts on selection (artifact's own
 * `.lane.sel` rule, verbatim). */
.ibdp-lane--selected {
	padding: 11px 11px 12px;
	border: 2px solid var( --ibdp-w2-tertiary );
	background: var( --ibdp-w2-tertiary-soft );
}

.ibdp-lane--unavailable {
	cursor: default;
	color: var( --ibdp-color-ink-muted );
	background: var( --ibdp-color-surface-muted );
}

/* The radio dot — CSS-only, no JS state of its own: purely a function of
 * `.ibdp-lane--selected` already sitting on the card (`LaneSelector`'s own
 * class docblock). */
.ibdp-lane__radio {
	position: absolute;
	top: 10px;
	right: 10px;
	width: 14px;
	height: 14px;
	border: 1.5px solid #bbb;
	border-radius: 50%;
}

.ibdp-lane--selected .ibdp-lane__radio {
	border-color: var( --ibdp-w2-tertiary );
	background: radial-gradient( circle, var( --ibdp-w2-tertiary ) 45%, transparent 50% );
}

/* The name row — label + (express only) the gauge pill, on ONE line
 * (artifact's own `.lname`: was two stacked flex items before T6). */
.ibdp-lane__name {
	display: flex;
	align-items: center;
	gap: 6px;
	font-weight: 600;
}

.ibdp-lane__day {
	margin-top: 6px;
	color: #222;
	font-size: 0.95rem;
	font-weight: 700;
	/* TASK 50 — the slot is one line tall whether it holds a date or the
	 * words that are holding its place, so the card is the size it will keep
	 * from the first paint and does not resize when the date lands. */
	min-height: 1.45em;
}

/* TASK 50 (2026-08-31) — the words standing in for an answer not known yet:
 * the same size and the same line as the real value, so nothing moves when it
 * arrives, but quiet rather than shouting — a date you can act on is bold and
 * dark, a message about waiting is neither.
 *
 * FIX ROUND 2 (re-review) — it WRAPS. The first cut forbade the wrap
 * (`white-space: nowrap`) to stop a placeholder making a card taller than the
 * date will. That was the wrong lever: nothing in the lane grid or the two
 * promise containers sets `overflow`, and a grid item's default `min-width:
 * auto` means unwrappable text WIDENS its own column instead of being cut —
 * so on a narrow phone «calculating…» in a card a third of a row wide could
 * push the whole block wider than the page and make it scroll sideways. The
 * slot's own `min-height` (`.ibdp-lane__day` above) is what actually holds
 * the height; letting the words wrap costs nothing and cannot move the page
 * horizontally. */
.ibdp-waiting {
	color: var( --ibdp-color-ink-muted );
	font-weight: 400;
}

/* TASK 51 FIX ROUND 1 (review N3) — the date row's SETTLED bad news, as
 * opposed to a placeholder. «We can't work out a delivery date for Germany ·
 * 10115» is an answer: the shop asked, the courier replied, and this is the
 * reply. The first cut painted it with `.ibdp-waiting`, the style reserved for
 * a row still working something out — a small lie told in CSS, and the only
 * thing keeping it safe from `silenceWaitingWords()` was that function's own
 * selector scoping rather than its being a different thing. It is a different
 * thing now, and it reads like one: the same size and line as the date it
 * replaces, in the ordinary ink rather than the placeholder grey. */
.ibdp-unreachable {
	color: var( --ibdp-color-ink );
	font-weight: 400;
}

/* The unavailable-state line occupies the SAME "second line" slot
 * `.ibdp-lane__day` fills when available (the two are mutually exclusive,
 * `render_lane_card()`'s own docblock) — same 6px margin-top for a
 * consistent rhythm, now that the flex `gap` above is neutralized (fix
 * round 1, review M1). No artifact equivalent to match (the pixel authority
 * never shows an unavailable card), so this reuses the day line's own
 * value rather than inventing a new one. */
.ibdp-lane__reason {
	margin-top: 6px;
	/* FIX ROUND 2 (re-review) — the LAST height difference between the two
	 * card states. This slot replaces `.ibdp-lane__day` on a card that cannot
	 * deliver, so the two have to measure the same: it was two steps smaller
	 * (0.85em against 0.95rem) and clamped at nothing, while its copy is a
	 * whole sentence («Gone for today — order by 11:00 tomorrow») in a card a
	 * third of a row wide, so it wraps where a date does not. Same size and
	 * the same floor as the day line now; a sentence that needs two lines
	 * still gets them, but the card can no longer be SHORTER than the one
	 * standing there a moment earlier. */
	font-size: 0.95rem;
	min-height: 1.45em;
	color: var( --ibdp-color-ink-muted );
}

/* The available-state sub-line — EVERY lane carries one now (artifact's own
 * `.sub`, T6: was express-only under the old `.ibdp-lane__cutoff` name). */
.ibdp-lane__sub {
	margin-top: 2px;
	color: var( --ibdp-w2-grey );
	font-size: 0.72rem;
	/* TASK 50 FIX ROUND 1 (review M3) — the slot is on every card now, empty
	 * where there is nothing to say under it, and it keeps its one line
	 * either way: a lane that comes back unavailable must not make the card
	 * shorter than the card that was standing there a moment earlier. */
	min-height: 1.3em;
}

/* F1's own dynamic addition — no artifact equivalent (the pixel authority's
 * static card never shows a gauge-urgency line at all). Always follows
 * `.ibdp-lane__sub` directly when present (both only ever render together,
 * express + available); reuses the sub-line's own 2px rhythm rather than
 * sitting flush against it now that the flex `gap` above is neutralized
 * (fix round 1, review M1). */
.ibdp-lane__urgency {
	margin-top: 2px;
	font-size: 0.8em;
	font-weight: bold;
	/* TASK 50 FIX ROUND 1 (review M2) — same reason as `.ibdp-lane__sub`
	 * above: the express card carries this slot in every state, empty unless
	 * today's queue is filling up or full, so the block cannot grow a line
	 * the moment the answer lands on a busy queue. */
	min-height: 1.3em;
}

/* TASK 51 (2026-08-31) — the ONE card that stands where the three speed
 * cards stand when nothing can be delivered to the destination the bar is
 * showing («Set a delivery country and postcode we can reach, up in the bar,
 * to see the three speeds and their dates.»).
 *
 * IT SPANS THE WHOLE ROW. One card left in a `repeat( 3, 1fr )` grid would be
 * a third of a card with two thirds of empty grid beside it; `1 / -1` gives it
 * the row the three cards had. On the mobile breakpoint the grid is a single
 * column already, so this changes nothing there.
 *
 * ITS HEIGHT IS THE CARDS' OWN HEIGHT, and deliberately not a number written
 * here: the markup carries the SAME slot stack an express card carries — a
 * name row, `.ibdp-lane__reason` where the date line would be,
 * `.ibdp-lane__sub`, `.ibdp-lane__urgency` — so the floors already declared
 * above are what measure it. Nothing to keep in sync, nothing to rot when a
 * slot changes. The empty name row is the one slot with no text of its own to
 * give it a line, so it gets the card font's own line here.
 *
 * NOT A CHOICE: no pointer, no hover border, no selection dot — there is
 * nothing to select, which is the whole state. */
.ibdp-lane--invitation {
	grid-column: 1 / -1;
	/* FIX ROUND 1 (review, visual note): the sentence sits in the middle of
	 * the card rather than at the top of it. The empty slots below are what
	 * make the card measure like a lane card, and left unbalanced they read
	 * as a card somebody forgot to finish. Costs no height. */
	justify-content: center;
	cursor: default;
	background: var( --ibdp-color-surface-muted );
}

.ibdp-lane--invitation:hover {
	border-color: var( --ibdp-w2-border );
}

.ibdp-lane--invitation .ibdp-lane__name {
	min-height: 1.2em;
}

.ibdp-lane__urgency--yellow {
	color: var( --ibdp-color-yellow );
}

.ibdp-lane__urgency--red {
	color: var( --ibdp-color-red );
}

/* -- F1 capacity gauge --------------------------------------------------- */

.ibdp-gauge-pill {
	display: inline-flex;
	align-items: center;
	gap: 0.25em;
	width: fit-content;
	padding: 0.15em 0.5em;
	background: #fff;
	border: 1px solid var( --ibdp-color-border );
	border-radius: 999px;
	color: inherit;
	font: inherit;
	cursor: pointer;
}

.ibdp-gauge-pill__needle {
	width: 1.4em;
	height: 0.85em;
}

.ibdp-gauge-pill__arc {
	fill: none;
	stroke: var( --ibdp-color-border );
	stroke-width: 2;
}

.ibdp-gauge-pill__needle-line {
	stroke: var( --ibdp-color-ink );
	stroke-width: 1.5;
	stroke-linecap: round;
	transform-origin: 12px 12px;
}

.ibdp-gauge--green .ibdp-gauge-pill__needle-line {
	stroke: var( --ibdp-color-green );
	transform: rotate( -45deg );
}

.ibdp-gauge--yellow .ibdp-gauge-pill__needle-line {
	stroke: var( --ibdp-color-yellow );
	transform: rotate( 0deg );
}

.ibdp-gauge--red .ibdp-gauge-pill__needle-line {
	stroke: var( --ibdp-color-red );
	transform: rotate( 45deg );
}

.ibdp-gauge--grey .ibdp-gauge-pill__needle-line {
	stroke: var( --ibdp-color-grey );
	transform: rotate( 0deg );
}

/* TASK 24 (change b) — the product page's own gauge TRIGGER, in Matteo's
 * mock-up shape: the arc drawn as three coloured segments (the same three
 * states `.ibdp-gauge-explainer` lists — since TASK 25 green left, amber
 * middle, red right), a needle rotated onto the segment of the current
 * state, then the word «info» with a dotted underline. No pill: no border, no background,
 * no caret. The bordered `.ibdp-gauge-pill` block ABOVE stays exactly as it
 * is — it is the drawer/checkout cards' own gauge
 * (`PromiseCard::render_gauge_pill()`), which this task does not touch.
 *
 * The SIGNAL tokens are the pre-existing ones (`--ibdp-color-green|yellow|
 * red|grey`): the needle is stroked with its OWN state's colour and points
 * at the segment painted in that same colour — a needle whose colour and
 * direction disagreed would be a lie about today's capacity. Geometry: the
 * dial is a half circle of radius 10 centred on (12,12) in a 24×14 viewBox,
 * cut into three 60° segments at (7, 3.34) and (17, 3.34); the needle is
 * shorter than the radius (y2="5") so its tip stops before the coloured
 * band instead of disappearing into it.
 *
 * TASK 25 (change b, Matteo 2026-08-27: «gira l'arco, rosso va a destra») —
 * the arc is FLIPPED: GREEN on the left, amber in the middle, RED on the
 * right, the direction of travel a fuel or capacity dial reads in. Only the
 * order flipped: the same three segments, the same three tokens, the same
 * dial. The needle follows its own segment, so the two side rotations swap
 * with it — green now -45deg (left), red +45deg (right); yellow keeps
 * pointing up at the middle segment, which did not move, and grey keeps
 * standing centred. Which colour sits on which arc is decided in the SVG
 * (`LaneSelector::render_gauge_trigger()` and its byte-identical JS mirror),
 * not here: this file only paints the classes. */
.ibdp-gauge-trigger {
	display: inline-flex;
	align-items: center;
	gap: 0.3em;
	width: fit-content;
	padding: 0;
	background: none;
	border: 0;
	color: inherit;
	font: inherit;
	cursor: pointer;
}

.ibdp-gauge-trigger__dial {
	width: 1.7em;
	height: 1em;
}

.ibdp-gauge-trigger__arc {
	fill: none;
	stroke-width: 3;
}

.ibdp-gauge-trigger__arc--red {
	stroke: var( --ibdp-color-red );
}

.ibdp-gauge-trigger__arc--yellow {
	stroke: var( --ibdp-color-yellow );
}

.ibdp-gauge-trigger__arc--green {
	stroke: var( --ibdp-color-green );
}

.ibdp-gauge-trigger__needle {
	stroke: var( --ibdp-color-ink );
	stroke-width: 1.6;
	stroke-linecap: round;
	transform-origin: 12px 12px;
}

.ibdp-gauge--red .ibdp-gauge-trigger__needle {
	stroke: var( --ibdp-color-red );
	transform: rotate( 45deg );
}

.ibdp-gauge--yellow .ibdp-gauge-trigger__needle {
	stroke: var( --ibdp-color-yellow );
	transform: rotate( 0deg );
}

.ibdp-gauge--green .ibdp-gauge-trigger__needle {
	stroke: var( --ibdp-color-green );
	transform: rotate( -45deg );
}

/* State unknown — centred and grey, never a colour it has not earned. */
.ibdp-gauge--grey .ibdp-gauge-trigger__needle {
	stroke: var( --ibdp-color-grey );
	transform: rotate( 0deg );
}

/* The dotted underline is the affordance the caret used to carry: it says
 * "this word opens something" without borrowing a link's solid underline. */
.ibdp-gauge-trigger__word {
	color: var( --ibdp-color-ink-muted );
	font-size: 0.8em;
	font-weight: 400;
	text-decoration: underline dotted;
	text-underline-offset: 0.2em;
}

/* `.ibdp-guarantee__caret`/`.ibdp-guarantee-explainer` (Task 10,
 * surface-shortcodes wave) ride these three rules as SIBLING selectors —
 * `[ibdp_guarantee]`'s toggle caret and explainer panel are the gauge's own
 * caret and panel by design (task brief: same visual style, no copy of this
 * block); only what differs lives in the W2 guarantee block below. */
.ibdp-gauge-pill__caret,
.ibdp-guarantee__caret {
	font-size: 0.8em;
	color: var( --ibdp-color-ink-muted );
}

.ibdp-gauge-explainer,
.ibdp-guarantee-explainer {
	position: absolute;
	top: 100%;
	left: 0;
	z-index: 50;
	width: 16em;
	max-width: calc( 100vw - 2em );
	margin-top: 0.4em;
	padding: 0.75em;
	background: var( --ibdp-color-surface );
	border: 1px solid var( --ibdp-color-border );
	border-radius: 0.5em;
	box-shadow: 0 0.4em 1.2em var( --ibdp-color-panel-shadow );
}

.ibdp-gauge-explainer[ hidden ],
.ibdp-guarantee-explainer[ hidden ] {
	display: none;
}

.ibdp-gauge-explainer__row {
	position: relative;
	padding: 0.3em 0 0.3em 1.1em;
	font-size: 0.8em;
}

.ibdp-gauge-explainer__row::before {
	content: "";
	position: absolute;
	top: 0.5em;
	left: 0;
	width: 0.6em;
	height: 0.6em;
	border-radius: 999px;
}

.ibdp-gauge-explainer__row--green::before {
	background: var( --ibdp-color-green );
}

.ibdp-gauge-explainer__row--yellow::before {
	background: var( --ibdp-color-yellow );
}

.ibdp-gauge-explainer__row--red::before {
	background: var( --ibdp-color-red );
}

.ibdp-gauge-explainer__row.is-current {
	font-weight: bold;
}

.ibdp-gauge-explainer__note {
	margin: 0.5em 0 0;
	color: var( --ibdp-color-ink-muted );
	font-size: 0.75em;
}

/* -------------------------------------------------------------------------
 * W2 — day echo + shipline + guarantee (visual-fidelity wave Task 6):
 * `[ibdp_day_echo]`'s own three-part assembly, "near the add-to-basket"
 * (task brief's own words — the artifact's own grouping,
 * `artifact-w2.html`'s `.dayline`/`.shipline`/`.guarantee`).
 * `.ibdp-day-echo__day`/`.ibdp-day-echo__shipline` are painted live by
 * `lane-selector.js`'s own `updateDayEcho()`; `.ibdp-guarantee` is fully
 * server-rendered, static copy (`LaneSelector::render_guarantee_line()`).
 * ---------------------------------------------------------------------- */

.ibdp-day-echo {
	margin-top: 12px;
}

/* The dayline itself — artifact's own `.dayline`: a flex row so the leading
 * icon and the day text sit on one baseline-aligned row. `:empty` collapses
 * the box entirely before the first payload lands (no bare colored strip
 * while the skeleton is still showing).
 *
 * TASK 36 (shipping-price wave) — that icon used to be the `🚚` emoji, an
 * ANONYMOUS flex item (a bare text run between the container and the span);
 * it is now a real `<svg>` element, so it is a NAMED flex item and free to
 * shrink — which is why `.ibdp-icon` carries `flex: none` at the top of
 * this file. The single space between the two items is whitespace-only and
 * creates no anonymous item of its own, so the 8px `gap` still owns the
 * separation here exactly as before. */
.ibdp-day-echo__day {
	display: flex;
	gap: 8px;
	align-items: baseline;
	margin: 0;
	padding: 10px 12px;
	background: var( --ibdp-w2-tertiary-soft );
	border-radius: 4px;
	/* TASK 36 FIX ROUND 1 (review F2) — the block states its own text
	 * colour. «At your door» used to sit INSIDE the `<b>` below, which
	 * paints it ink; Task 36 moved the prefix out of the `<b>` (the DATE is
	 * the bold half now), and nothing else in this block set a colour, so
	 * the prefix silently started inheriting whatever the Oxygen theme
	 * passes down — onto a tinted #f2f8f2 strip, with no pinned contrast.
	 * Ink on that strip measures 15.29:1. The lane name after the em dash
	 * is unaffected: `.ibdp-day-echo__which` sets its own muted colour
	 * directly on the element, and a colour set on an element always beats
	 * one inherited from its ancestor. */
	color: var( --ibdp-color-ink );
	font-size: 0.85rem;
}

.ibdp-day-echo__day:empty {
	display: none;
}

/* TASK 36 FIX ROUND 1 (review F1) — `white-space: nowrap`, the SAME
 * protection `.ibdp-promise-card__line1 b` has carried since T23 and for
 * the same reason, quoted from that rule: the bold day is the WHOLE date,
 * and on a narrow product page the sentence used to wrap wherever it ran
 * out of room — "including between the day number and the month, which
 * reads as two different dates for a beat".
 *
 * It was not needed here while this line wrote «Wed 9 Sep»; Task 36 is what
 * made this date long («Wednesday 9 September»), so this task owns the
 * defect it created. `.ibdp-day-echo__day` is a flex row and its `<span>`
 * item wraps normally, so the break simply moves to a space BEFORE the
 * date and the date always lands whole. Done in CSS rather than with a
 * non-breaking space in the markup, for T23's own reason: neither producer
 * moves, and `lane-selector.js`'s painted line stays byte-for-byte what its
 * pin holds it to. */
.ibdp-day-echo__day b {
	color: var( --ibdp-color-ink );
	white-space: nowrap;
}

/* The word naming the lane after the date — on the day echo and, since
 * 0.21.0, on the promise card («— Express», thread 8): ONE rule, so the two
 * cannot drift. The token is the root's `--ibdp-color-ink-muted` (the same
 * #5c5c5c as `--ibdp-w2-grey`), because the promise card's roots
 * (`.ibdp-product-promise`, `.ibdp-cart-promise`) sit outside the block
 * that declares the W2 tokens — a `var(--ibdp-w2-grey)` there would
 * resolve to nothing and the word would print in full ink. */
.ibdp-day-echo__which,
.ibdp-promise-card__lane {
	color: var( --ibdp-color-ink-muted );
	font-size: 0.78rem;
}

/* The shipline — money's single home (this block's own top comment): the
 * per-card line the lanes used to carry is gone, this is the ONLY place
 * this widget ever shows a price. `hidden` (JS-toggled) whenever the
 * destination's zone carries no enabled `ibdp_lane` instance yet
 * (refuse-to-show, never a guessed line).
 *
 * Task 11 (surface-shortcodes wave): `.ibdp-shipping-cost` — the STANDALONE
 * `[ibdp_shipping_cost]` line's root (`LaneSelector::render_shipping_cost()`,
 * painted by `lane-selector.js`'s `updateShippingCost()` from the same
 * landing as the shipline) — rides these two rules as a sibling selector,
 * never a copied block; `[ibdp_day_echo]`'s own shipline is untouched
 * (Matteo's ruling). It also joins the W2 token block above (the colour is
 * `var(--ibdp-w2-grey)`) and the T23 updating-state dim. */
.ibdp-day-echo__shipline,
.ibdp-shipping-cost {
	margin: 8px 0 0;
	color: var( --ibdp-w2-grey );
	/* T23: 0.8125rem = 13px, up from 0.78rem (12.5px) — this line carries
	 * MONEY, the one number in the block a customer must not have to lean
	 * in for. The day echo's «which» qualifier above stays at 0.78rem: it
	 * is the sub-line of a line, and the type scale stays stepped. */
	font-size: 0.8125rem;
}

/* TASK 24 FIX ROUND 1 — on the twin render (the second `[ibdp_shipping_cost]`
 * root of one Oxygen template, the controller's field walk on staging
 * 0.4.49) the standalone line inherited a RIGHT alignment from its
 * container. Same reasoning as `.ibdp-product-promise`/`.ibdp-guarantee`
 * (Task 24 (f)/(g)): the block's OWN `text-align` beats any inherited value,
 * no `!important`. Its OWN rule on purpose — the shared rule above is not
 * widened, because `[ibdp_day_echo]`'s shipline is untouched (Matteo's
 * ruling, Task 11) and keeps inheriting its own block's alignment. */
.ibdp-shipping-cost {
	text-align: left;
}

/* TASK 25 (change a, Matteo 2026-08-27: «prezzo: aumenta il grassetto al
 * massimo») — the money at MAXIMUM boldness. `lane-selector.js`'s own
 * `boldMoney()` wraps every money figure of the line (and the word «free»)
 * in a bare `<b>`, which a browser paints at its default `bold` = 700; 900
 * is the boldest weight CSS can ask for. If the theme's font family has no
 * 900 face the browser falls back to the boldest face it does have, so this
 * can never render LIGHTER than the 700 it replaces.
 *
 * BOTH roots, because both are painted from the same `boldMoney()` output:
 * `[ibdp_day_echo]`'s own shipline and the standalone `[ibdp_shipping_cost]`
 * line. Its own `b`-scoped rule and NOT a widening of the shared rule
 * above — that rule styles the LINE (colour, size), this one the money
 * inside it (same separation the `text-align` rule above keeps, and
 * `SurfaceCssTest` pins both). */
.ibdp-day-echo__shipline b,
.ibdp-shipping-cost b {
	font-weight: 900;
}

.ibdp-product-promise[ hidden ],
.ibdp-cutoff-countdown[ hidden ],
.ibdp-day-echo__shipline[ hidden ],
.ibdp-shipping-cost[ hidden ] {
	display: none;
}

/* Task 9 (surface-shortcodes wave): `.ibdp-cutoff-countdown` — the STANDALONE
 * `[ibdp_cutoff_countdown]` root (`LaneSelector::render_cutoff_countdown()`,
 * filled by `lane-selector.js`'s `updateCutoffCountdown()` with one
 * `.ibdp-cutoff-countdown__row`, which rides the promise card's own amber
 * countdown rule below as a sibling selector — the ticker it reuses, the
 * look it reuses). The root itself only spaces the row like the shipline
 * (the row's own rule zeroes its margin); `hidden` (JS-toggled, the
 * override above, listed FIRST so Task 11's own adjacency pin still holds)
 * whenever there is nothing honest to count down to; it joins the T23
 * updating-state dim above the same way.
 *
 * Task 22 (shipping-price wave): `.ibdp-product-promise` — the STANDALONE
 * `[ibdp_product_promise]` root (`LaneSelector::render_product_promise()`,
 * filled by `lane-selector.js`'s `updateProductPromise()` with the promise
 * card's own MINI markup) — rides this spacing rule, the `[hidden]`
 * override and the T23 dim as a sibling selector. It has NO rule of its
 * own beyond that, and needs none: the card inside it is
 * `.ibdp-promise-card--mini`, the very block the drawer's own mini card
 * uses (further down this file) — the look is reused, never copied. */
.ibdp-cutoff-countdown,
.ibdp-product-promise {
	margin: 8px 0 0;
}

/* TASK 24 — requirement (g): `[ibdp_product_promise]` is dropped into an
 * Oxygen container that may centre or justify its text; the block imposes
 * its own left alignment. An element's OWN `text-align` beats any value
 * INHERITED from an ancestor, whatever that ancestor's specificity — no
 * `!important` needed. */
.ibdp-product-promise {
	text-align: left;
}

/* TASK 36 (shipping-price wave, Matteo thread 31) — the guarantee is a BOX
 * now: 1px border, 4px radius (the SAME radius as the amber countdown box
 * above — one family), a soft neutral fill, and the shield + heading +
 * two arrow lines `LaneSelector::guarantee_text_html()` builds inside it.
 *
 * The fill is `--ibdp-color-surface-muted` (#f4f2ee), NOT the delivery
 * line's soft green (`--ibdp-w2-tertiary-soft`): those two blocks sit one
 * under the other on the product page, and two identical green strips read
 * as one block that lost its divider. Measured on this fill: the body text
 * `--ibdp-w2-grey` (#5c5c5c) at **5.98:1**, the green heading and arrows
 * (hsl(121,30%,30%) = #366336) at **6.27:1** — both well over the 4.5:1 AA
 * floor for normal text. Its own border, `--ibdp-w2-border` (#e3e1dd),
 * measures **1.17:1** on that fill: a hairline edge, deliberately quiet,
 * carrying no information the words do not.
 *
 * BOTH blocks that render this markup get the box, and that is the point:
 * the standalone `[ibdp_guarantee]` shortcode AND the guarantee line inside
 * `[ibdp_day_echo]`, which contains it (task brief: "that is intended, not
 * a side effect"). `box-sizing: border-box` already rides the Task 24
 * full-width rule at the top of this file, so the new padding cannot push
 * the block past its column. */
.ibdp-guarantee {
	margin-top: 12px;
	padding: 10px 12px;
	background: var( --ibdp-color-surface-muted );
	border: 1px solid var( --ibdp-w2-border );
	border-radius: 4px;
	/* TASK 24 — requirement (f): same reasoning as `.ibdp-product-promise`
	 * above; this block must read left-aligned whatever the hosting Oxygen
	 * container inherits down to it. */
	text-align: left;
	color: var( --ibdp-w2-grey );
	/* T23: 0.78rem = 12.5px, up from 0.75rem (12px) — the block's smallest
	 * type, kept one step below the money line above rather than levelled
	 * with it. */
	font-size: 0.78rem;
	line-height: 1.5;
}

.ibdp-guarantee b {
	color: var( --ibdp-color-ink );
}

.ibdp-guarantee a {
	color: var( --ibdp-w2-tertiary );
}

/* TASK 36 — «On time, or we pay», the box's own heading line: green and
 * bold, one step up in size from the remedy lines under it. The `b`-scoped
 * colour is a compound selector (class + class + type), so it out-specifies
 * the `.ibdp-guarantee b` ink rule above without `!important`. */
.ibdp-guarantee__lead {
	margin: 0;
	font-size: 0.85rem;
}

.ibdp-guarantee__lead b {
	color: var( --ibdp-w2-tertiary );
}

/* TASK 36 — the two remedy lines. `margin-top` only: they stack under the
 * heading and wrap freely on a narrow screen, which is what the brief asks
 * for («the boxes stay full width and the arrow lines wrap»). */
.ibdp-guarantee__remedy {
	margin: 4px 0 0;
}

.ibdp-guarantee__arrow {
	color: var( --ibdp-w2-tertiary );
}

/* TASK 36 — «How the guarantee works» is its own row now, under the
 * remedies, in both blocks: a real `<button>` in `[ibdp_guarantee]` (it
 * opens the explainer panel in place) and a real `<a>` in `[ibdp_day_echo]`
 * (it navigates to the punctuality page). Same spacing for both, so the
 * two blocks end the same way. */
.ibdp-guarantee__link {
	display: inline-block;
	margin-top: 6px;
}

/* Task 10 (surface-shortcodes wave) — `[ibdp_guarantee]`, the STANDALONE
 * guarantee line with its «How the guarantee works» panel
 * (`LaneSelector::render_guarantee()`). `[ibdp_day_echo]`'s own line above
 * is untouched (Matteo's thread-10 ruling). The panel and the caret ride
 * the F1 gauge block's rules as sibling selectors (`.ibdp-guarantee-explainer`
 * next to `.ibdp-gauge-explainer`, `.ibdp-guarantee__caret` next to
 * `.ibdp-gauge-pill__caret`) — only what differs lives here: the line is
 * the panel's positioning anchor, the toggle reads like the link it
 * replaces (same tertiary green as `.ibdp-guarantee a`), and the panel
 * resets the line's own 0.75rem/grey so the explainer stays legible. Later
 * in the file than the shared rule at equal specificity, so `width`/`color`/
 * `font-size` here win over the gauge panel's own 16em values. */
.ibdp-guarantee--explainable {
	position: relative;
}

.ibdp-guarantee__toggle {
	display: inline-flex;
	align-items: center;
	gap: 0.25em;
	padding: 0;
	background: none;
	border: 0;
	color: var( --ibdp-w2-tertiary );
	font: inherit;
	/* TASK 24 — requirement (e): AFTER `font: inherit` (which resets
	 * font-weight along with everything else in the shorthand), or the
	 * shorthand would silently undo it. «How the guarantee works ⌄» is the
	 * one thing in this block a customer is meant to click; in bold it
	 * reads as a control instead of as more small print. */
	font-weight: 700;
	cursor: pointer;
	/* TASK 36 — its own row under the remedy lines, matching
	 * `.ibdp-guarantee__link`'s spacing in the other block. */
	margin-top: 6px;
}

.ibdp-guarantee-explainer {
	width: 22em;
	color: var( --ibdp-color-ink );
	font-size: 0.8rem;
	line-height: 1.5;
}

.ibdp-guarantee-explainer__text {
	margin: 0 0 0.5em;
}

.ibdp-guarantee-explainer__text:last-child {
	margin-bottom: 0;
}

/* Mobile: stack the three cards (design.md §3 — the sticky bottom bar itself
 * is Oxygen template layout, not this shortcode's own markup). */
@media ( max-width: 782px ) {
	.ibdp-lane-selector__lanes {
		grid-template-columns: 1fr;
	}

	/* TASK 24 — requirement (d): "below 768px the three cards stack, each
	 * full width". The stacking query was already here, at 782px — a
	 * SUPERSET of 768 (every screen below 768 is inside it), deliberately
	 * NOT narrowed to 768: moving the breakpoint down would UN-stack the
	 * 769–782px band that stacks today. What was missing is this: the card
	 * itself stated as full width, so a card whose own content is narrow
	 * (an unavailable lane's short reason line) cannot end up narrower than
	 * the row it now owns. */
	.ibdp-lane {
		width: 100%;
		box-sizing: border-box;
	}
}

/* -------------------------------------------------------------------------
 * M2 Task 5 — the promise card (design.md §1): ONE card anatomy every
 * surface mounts (checkout = full, drawer = compact, mini-cart = mini).
 * Minimal — layout + the amber/signal tokens only; the theme owns
 * typography (font-family/weight/line-height untouched here), same
 * convention as every other block in this file. `.ibdp-gauge-*` classes are
 * shared verbatim with the F1 product-page gauge above — no duplicate gauge
 * CSS needed here (`PromiseCard::render_gauge_pill()`/`render_gauge_explainer()`'s
 * own "MUST match LaneSelector" docblock note).
 * ---------------------------------------------------------------------- */

.ibdp-promise-card {
	display: flex;
	flex-direction: column;
	gap: 0.5em;
	padding: 0.85em 1em;
	background: var( --ibdp-color-surface );
	border: 1px solid var( --ibdp-color-border );
	border-radius: 0.6em;
	color: var( --ibdp-color-ink );
}

.ibdp-promise-card--mini {
	flex-direction: row;
	align-items: center;
	padding: 0.4em 0.7em;
	border-style: dashed;
}

.ibdp-promise-card__line1 {
	margin: 0;
	font-size: 1em;
}

/* T23 — the bold day is the WHOLE date («giovedì 4 settembre»), and on a
 * narrow product page the sentence «🚚 At your door giovedì 4 settembre»
 * used to wrap wherever it ran out of room — including between the day
 * number and the month, which reads as two different dates for a beat.
 * `nowrap` moves the break to a space BEFORE the date instead, so the date
 * always lands whole on its own line; the paragraph itself still wraps
 * normally. Done here, in CSS, rather than with a non-breaking space in
 * the markup, precisely so NEITHER producer moves: `PromiseCard`'s PHP and
 * `lane-selector.js`'s hand-kept mirror stay byte-for-byte what their
 * parity pins hold them to (`PromiseCardTest` /
 * `lane-selector-product-promise.test.js`). It applies to every card
 * variant because the sentence is the same sentence everywhere. */
.ibdp-promise-card__line1 b {
	white-space: nowrap;
}

/* The lane after the date is one unbreakable unit on the card — the dash
 * never stays behind on the line above. Tone and size: the shared rule
 * beside `.ibdp-day-echo__which`. */
.ibdp-promise-card__lane {
	white-space: nowrap;
}

/* T23 — under 480px the sentence above almost always takes two lines (the
 * date can no longer be split, by design), so the mini card — the product
 * page's own `[ibdp_product_promise]` card, the tightest variant, dashed
 * border and 0.4em of vertical padding — gets room for the second line
 * instead of squeezing it against its own border. Only the mini variant:
 * the full/compact cards are multi-line by construction and already
 * spaced. */
@media ( max-width: 480px ) {
	.ibdp-promise-card--mini {
		padding: 0.6em 0.7em;
		line-height: 1.45;
	}
}

/* TASK 36 (shipping-price wave, Matteo thread 31) — the countdown is a
 * BOX now, not a tinted strip: the 1px amber border and the 4px radius the
 * guarantee box below carries too, so the three blocks of the product-page
 * promise read as one family instead of three visual languages.
 *
 * The HUE is untouched: fill `--ibdp-color-amber-bg` (#fdf3d9), text
 * `--ibdp-color-amber-text` (#a35c00), measured **4.65:1** — the ratio
 * Task 23 fixed from 1.94:1 and which this task must not regress. The
 * border draws with the SIGNAL amber `--ibdp-color-amber` (#e0a800),
 * measured **1.94:1** against the fill: that is a BORDER, not text, and
 * WCAG's 3:1 floor applies to a UI component a user must find and operate
 * — this line is neither, it is a tint edge around a box whose own words
 * carry the message at 4.65:1. Stated, not hidden.
 *
 * 4px, a literal pixel value, where this rule used to say `0.4em`: `em`
 * here resolves against the row's own `font-size: 0.85em`, so the corner
 * radius silently changed with the theme's base size and could never match
 * the guarantee box beside it. One radius, one number, all three blocks.
 *
 * `.ibdp-cutoff-countdown__row` (the STANDALONE `[ibdp_cutoff_countdown]`
 * shortcode, Task 9) rides this rule as a sibling selector, as it always
 * has — the box is defined once. */
.ibdp-promise-card__countdown,
.ibdp-cutoff-countdown__row {
	margin: 0;
	padding: 0.4em 0.6em;
	background: var( --ibdp-color-amber-bg );
	border: 1px solid var( --ibdp-color-amber );
	border-radius: 4px;
	color: var( --ibdp-color-amber-text );
	font-size: 0.85em;
	font-weight: bold;
}

.ibdp-promise-card__guarantee,
.ibdp-promise-card__clock-start {
	margin: 0;
	color: var( --ibdp-color-ink-muted );
	font-size: 0.8em;
}

/* TASK 45 (v0.7.0, Matteo's decision 2026-08-30 (2)) — the DRAWER card's
 * shipping line and estimated total (`PromiseCard::render_shipping_lines()`),
 * between the day line and the countdown. The same recipe as the product
 * page's own `[ibdp_shipping_cost]` line, which prints the same sentence:
 * the readable muted grey (`--ibdp-color-ink-muted`, #5c5c5c — the card's
 * own token, the same value as W2's `--ibdp-w2-grey`, measured 6.69:1 on
 * white by Task 23; the W2 token itself is scoped to the W2 blocks and
 * does not reach this card) at the 13px money floor (0.8125rem — Task 23:
 * a line that carries money is never below 13px), and the figure — or the
 * word «free» — at maximum boldness (900, Task 25) so the customer reads
 * the amount before the sentence. The estimated total keeps the card's own
 * ink colour: it is the one number the drawer's Subtotal above it
 * under-states, and it must not read as a footnote. The unavailable words
 * are neither bolded nor darkened — a refusal is not money
 * (`PromiseCard::SHIPPING_UNAVAILABLE_CLASS` carries no rule of its own on
 * purpose: nothing to add, and nothing to forget). Only the drawer mount
 * hands the card these lines; the checkout card never carries either class
 * (`PromiseCardTest`'s v0.6.3 fixtures). */
.ibdp-promise-card__shipping,
.ibdp-promise-card__total {
	margin: 0;
	font-size: 0.8125rem;
}

.ibdp-promise-card__shipping {
	color: var( --ibdp-color-ink-muted );
}

.ibdp-promise-card__shipping b,
.ibdp-promise-card__total b {
	font-weight: 900;
}

.ibdp-promise-card__gauge {
	position: relative;
	display: flex;
}

.ibdp-promise-card__change-speed {
	margin-top: 0.2em;
}

.ibdp-promise-card__change-speed > summary {
	cursor: pointer;
	color: var( --ibdp-color-ink-muted );
	font-size: 0.85em;
	list-style: none;
}

.ibdp-promise-card__change-speed > summary::-webkit-details-marker {
	display: none;
}

.ibdp-promise-card__lanes {
	display: flex;
	flex-direction: column;
	gap: 0.4em;
	margin-top: 0.5em;
}

.ibdp-promise-card__lane-row {
	display: flex;
	align-items: center;
	gap: 0.5em;
	cursor: pointer;
	font-size: 0.9em;
}

/* fix round 1, M: the `compact` variant's folded rows are <button>s, not
 * <label>s (PromiseCard::render_change_speed_button_row()) — strip the
 * browser's own button chrome so they read identically to the `full`
 * variant's radio rows. */
button.ibdp-promise-card__lane-row {
	width: 100%;
	background: none;
	border: none;
	margin: 0;
	padding: 0;
	color: inherit;
	font: inherit;
	text-align: left;
}

.ibdp-promise-card__lane-row--unavailable {
	color: var( --ibdp-color-ink-muted );
	cursor: default;
}

/* fix round 1, M: the compact variant's current-lane indicator
 * (aria-pressed="true" companion class). */
.ibdp-promise-card__lane-row.is-current {
	color: var( --ibdp-color-green );
	font-weight: bold;
}

/* -------------------------------------------------------------------------
 * 2026-09-03 (area decision log (2)) — THE DRAWER'S THREE SPEED BUTTONS.
 *
 * The customer changes the QUANTITY in the slide-in basket, and the quantity
 * decides which speed can carry it, so the speed is chosen in the same place.
 * Three plain buttons side by side, always visible, names only: no dates (the
 * line above says the date) and no prices (that card shows no money at all).
 *
 * A speed that cannot carry this basket is GREYED AND STILL THERE. Hiding it
 * was refused on the prototype, and rightly: a customer who cannot see
 * Express has no way of understanding why their basket moved off it.
 *
 * The greying hangs on the `--unavailable` class, never on `[disabled]`:
 * `promise-card.js` disables every button for the length of one click
 * (`holdLaneButtons()`), and painting all three grey for that beat would say
 * «none of these can carry your basket», which is the opposite of true.
 * ---------------------------------------------------------------------- */

.ibdp-promise-card__lane-buttons {
	display: flex;
	gap: 0.35em;
	margin-top: 0.45em;
}

.ibdp-promise-card__lane-button {
	flex: 1 1 0;
	min-width: 0;
	margin: 0;
	padding: 0.35em 0.2em;
	border: 1px solid var( --ibdp-color-border );
	border-radius: 4px;
	background: none;
	color: inherit;
	font: inherit;
	font-size: 0.85em;
	line-height: 1.2;
	text-align: center;
	cursor: pointer;
}

.ibdp-promise-card__lane-button.is-current {
	border-color: var( --ibdp-color-green );
	color: var( --ibdp-color-green );
	font-weight: bold;
}

.ibdp-promise-card__lane-button--unavailable {
	border-style: dashed;
	color: var( --ibdp-color-ink-muted );
	cursor: default;
	opacity: 0.65;
}

/* «Express isn't available for 84 pieces — switched to Standard.» Muted and
 * small: it explains a change, it does not compete with the date above it. */
.ibdp-promise-card__lane-switch {
	margin: 0.4em 0 0;
	color: var( --ibdp-color-ink-muted );
	font-size: 0.85em;
	line-height: 1.35;
}

/* -------------------------------------------------------------------------
 * M2 Task 9 (W7) — the conflict dialog (design.md §6): fact-first message,
 * three doors, bottom sheet under 782px (fix round 1, F1 — moved here from a
 * JS-injected <style> block, same shared-stylesheet convention every other
 * Surface widget in this file already follows; same 782px breakpoint every
 * other mobile rule in this file uses).
 * ---------------------------------------------------------------------- */

.ibdp-conflict-dialog__backdrop {
	position: fixed;
	inset: 0;
	z-index: 100000;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 1em;
	background: rgba( 0, 0, 0, 0.5 );
}

.ibdp-conflict-dialog__sheet {
	position: relative;
	width: 100%;
	max-width: 26em;
	padding: 1.5em;
	background: var( --ibdp-color-surface );
	border: 1px solid var( --ibdp-color-border );
	border-radius: 0.75em;
	box-shadow: 0 0.5em 1.9em var( --ibdp-color-panel-shadow );
	color: var( --ibdp-color-ink );
}

.ibdp-conflict-dialog__close {
	position: absolute;
	top: 0.75em;
	right: 0.75em;
	padding: 0.35em;
	background: none;
	border: none;
	color: inherit;
	font-size: 1.1em;
	line-height: 1;
	cursor: pointer;
}

.ibdp-conflict-dialog__facts {
	margin: 0 0 0.75em;
}

.ibdp-conflict-dialog__fact {
	display: flex;
	justify-content: space-between;
	gap: 0.75em;
	padding: 0.25em 0;
	color: var( --ibdp-color-ink-muted );
	font-size: 0.8em;
	text-transform: uppercase;
	letter-spacing: 0.02em;
}

.ibdp-conflict-dialog__verdict {
	margin: 0 0 1em;
	padding: 0.6em 0.75em;
	background: var( --ibdp-color-amber-bg );
	border: 1px solid var( --ibdp-color-amber );
	border-radius: 0.5em;
	font-weight: bold;
}

.ibdp-conflict-dialog__doors {
	display: flex;
	flex-direction: column;
	gap: 0.5em;
}

.ibdp-conflict-dialog__door {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 0.1em;
	padding: 0.75em 0.85em;
	background: var( --ibdp-color-surface-muted );
	border: 1px solid var( --ibdp-color-border );
	border-radius: 0.5em;
	color: inherit;
	text-align: left;
	font: inherit;
	cursor: pointer;
}

.ibdp-conflict-dialog__door--add_slipped,
.ibdp-conflict-dialog__door--add_switched {
	background: var( --ibdp-color-ink );
	border-color: var( --ibdp-color-ink );
	color: #fff;
}

.ibdp-conflict-dialog__door-date {
	color: inherit;
	opacity: 0.75;
	font-size: 0.75em;
}

/* Bottom sheet on mobile (design.md §6). */
@media ( max-width: 782px ) {
	.ibdp-conflict-dialog__backdrop {
		align-items: flex-end;
		padding: 0;
	}

	.ibdp-conflict-dialog__sheet {
		max-width: none;
		border-radius: 0.75em 0.75em 0 0;
	}
}

/* -------------------------------------------------------------------------
 * M2 Task 11 (R4) — `/basket/` Cart BLOCK mini-card
 * (`assets/js/basket-card.js`'s own `ExperimentalOrderMeta` Fill). Same
 * `--ibdp-color-*` design tokens as `.ibdp-promise-card`/`.ibdp-promise-card__countdown`
 * above — a deliberately smaller/dashed variant, mirroring
 * `.ibdp-promise-card--mini`'s own row layout, since this card renders
 * inside the Cart block's own OrderSummary sidebar (narrower column than the
 * drawer/checkout surfaces).
 * ---------------------------------------------------------------------- */

.ibdp-basket-card {
	display: flex;
	flex-direction: column;
	gap: 0.4em;
	padding: 0.6em 0.75em;
	margin: 0 0 1em;
	background: var( --ibdp-color-surface );
	border: 1px dashed var( --ibdp-color-border );
	border-radius: 0.6em;
	color: var( --ibdp-color-ink );
}

.ibdp-basket-card__line1 {
	margin: 0;
	font-size: 1em;
}

/* TASK 36 — the `/basket/` Cart block's own countdown row is the same amber
 * box as `.ibdp-promise-card__countdown` above, on the one surface that
 * cannot reuse that class (the WooCommerce Cart BLOCK paints its own markup
 * through `assets/js/basket-card.js`, `BasketBlockData`'s own SEAM note), so
 * the border and the radius are added here too — the customer meets the SAME
 * box on the product page, in the drawer, at checkout and in the basket. */
.ibdp-basket-card__countdown {
	margin: 0;
	padding: 0.4em 0.6em;
	background: var( --ibdp-color-amber-bg );
	border: 1px solid var( --ibdp-color-amber );
	border-radius: 4px;
	color: var( --ibdp-color-amber-text );
	font-size: 0.85em;
	font-weight: bold;
}

/* -------------------------------------------------------------------------
 * M3 Task 5 (W11), rebuilt fix round 1 to design.md §7 — the thank-you
 * promise package. The day/countdown block itself REUSES the
 * `.ibdp-promise-card*` classes above verbatim
 * (`PromiseCard::render_day_line_markup()`/`render_countdown_markup()`,
 * shared not mirrored — that class's own review F5/H1 promotion, and
 * `ThankYouPackage`'s own class docblock). Only the wrapper and the rows
 * unique to this surface — thanks, pending, the «things start your clock»
 * checklist (heading, done/action-needed items, bank-details box, upload
 * button), the closing line and the account pointer — get new rules here.
 * ---------------------------------------------------------------------- */

.ibdp-thankyou-package {
	display: flex;
	flex-direction: column;
	gap: 0.75em;
	margin: 0 0 1.5em;
}

.ibdp-thankyou-package__thanks {
	margin: 0;
	font-size: 1.1em;
	font-weight: bold;
}

.ibdp-thankyou-package__pending {
	margin: 0;
	padding: 0.6em 0.75em;
	background: var( --ibdp-color-surface-muted );
	border: 1px solid var( --ibdp-color-border );
	border-radius: 0.5em;
	color: var( --ibdp-color-ink-muted );
}

.ibdp-thankyou-package__checklist {
	display: flex;
	flex-direction: column;
	gap: 0.5em;
}

.ibdp-thankyou-package__checklist-heading {
	margin: 0;
	color: var( --ibdp-color-ink-muted );
	font-size: 0.85em;
	font-weight: bold;
	text-transform: uppercase;
	letter-spacing: 0.02em;
}

.ibdp-thankyou-package__item--done {
	margin: 0;
	color: var( --ibdp-color-green );
	font-weight: bold;
}

.ibdp-thankyou-package__item--action {
	display: flex;
	flex-direction: column;
	gap: 0.35em;
	padding: 0.6em 0.75em;
	background: var( --ibdp-color-amber-bg );
	border-radius: 0.5em;
}

.ibdp-thankyou-package__item-urgent {
	margin: 0;
	color: var( --ibdp-color-amber-text );
	font-weight: bold;
}

.ibdp-thankyou-package__item-advice {
	margin: 0;
	color: var( --ibdp-color-ink-muted );
	font-size: 0.85em;
}

.ibdp-thankyou-package__bank-details {
	display: flex;
	flex-direction: column;
	gap: 0.15em;
	margin: 0.25em 0 0;
	padding: 0;
	list-style: none;
	font-size: 0.9em;
}

.ibdp-thankyou-package__upload-button {
	align-self: flex-start;
	padding: 0.5em 1em;
	background: var( --ibdp-color-ink );
	border-radius: 0.4em;
	color: #fff;
	text-decoration: none;
	font-weight: bold;
}

.ibdp-thankyou-package__closing {
	margin: 0;
	color: var( --ibdp-color-ink-muted );
	font-size: 0.85em;
}

.ibdp-thankyou-package__account-pointer {
	margin: 0;
}

/* -------------------------------------------------------------------------
 * M3 Task 6 (W12) — the account order page's journey timeline
 * (`Surface\AccountJourney`). The day/countdown block itself REUSES the
 * `.ibdp-promise-card*` classes above verbatim (same REUSE-not-mirror
 * reasoning as `.ibdp-thankyou-package` immediately above — that class's
 * own comment). Only the wrapper, header (order number + chip) and the six
 * timeline steps (done/pending, bank details, upload button, the
 * destination day + struck contract + guarantee) get new rules here.
 * ---------------------------------------------------------------------- */

.ibdp-account-journey {
	display: flex;
	flex-direction: column;
	gap: 1em;
	margin: 0 0 1.5em;
}

.ibdp-account-journey__header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.75em;
	margin: 0;
}

.ibdp-account-journey__order-number {
	font-weight: bold;
	color: var( --ibdp-color-ink );
}

.ibdp-account-journey__chip {
	padding: 0.25em 0.75em;
	border-radius: 999px;
	font-size: 0.8em;
	font-weight: bold;
	text-transform: uppercase;
	letter-spacing: 0.02em;
}

.ibdp-account-journey__chip--waiting {
	background: var( --ibdp-color-amber-bg );
	color: var( --ibdp-color-amber-text );
}

.ibdp-account-journey__chip--on_schedule {
	background: var( --ibdp-color-green-bg );
	color: var( --ibdp-color-green );
}

.ibdp-account-journey__steps {
	display: flex;
	flex-direction: column;
	gap: 0.5em;
}

.ibdp-account-journey__step {
	padding: 0.6em 0.75em;
	border-left: 3px solid var( --ibdp-color-border );
	background: var( --ibdp-color-surface );
}

.ibdp-account-journey__step--done {
	border-left-color: var( --ibdp-color-green );
}

.ibdp-account-journey__step--pending {
	border-left-color: var( --ibdp-color-amber );
	background: var( --ibdp-color-surface-muted );
}

.ibdp-account-journey__step-label {
	margin: 0;
	font-weight: bold;
	color: var( --ibdp-color-ink );
}

.ibdp-account-journey__step--done .ibdp-account-journey__step-label {
	color: var( --ibdp-color-green );
}

.ibdp-account-journey__step-urgent {
	margin: 0.25em 0 0;
	color: var( --ibdp-color-amber-text );
	font-weight: bold;
}

.ibdp-account-journey__step-advice,
.ibdp-account-journey__step-explainer {
	margin: 0.25em 0 0;
	color: var( --ibdp-color-ink-muted );
	font-size: 0.85em;
}

.ibdp-account-journey__bank-details {
	display: flex;
	flex-direction: column;
	gap: 0.15em;
	margin: 0.5em 0 0;
	padding: 0;
	list-style: none;
	font-size: 0.9em;
}

.ibdp-account-journey__upload-button {
	display: inline-block;
	align-self: flex-start;
	margin-top: 0.5em;
	padding: 0.5em 1em;
	background: var( --ibdp-color-ink );
	border-radius: 0.4em;
	color: #fff;
	text-decoration: none;
	font-weight: bold;
}

.ibdp-account-journey__step--destination {
	border-left-color: var( --ibdp-color-ink );
}

.ibdp-account-journey__destination-day {
	margin: 0;
	font-size: 1em;
}

.ibdp-account-journey__destination-day del {
	margin-left: 0.5em;
	color: var( --ibdp-color-ink-muted );
}

.ibdp-account-journey__destination-explainer {
	margin: 0.25em 0 0;
	color: var( --ibdp-color-ink-muted );
	font-size: 0.85em;
}

/* -------------------------------------------------------------------------
 * 2026-08-31 (threads register 43) — THE THREE BLOCKS OF THE PRODUCT-PAGE
 * PROMISE SHARE ONE ICON COLUMN AND ONE TEXT COLUMN.
 *
 * Matteo, on the day/countdown/guarantee blocks: «vorrei che lo spazio
 * icona sia sempre uguale nei 3 casi e che il testo a capo sia rientrato,
 * in modo che tutti e 3 condividano lo stesso rientro».
 *
 * WHAT WAS WRONG. Each block drew its icon at `1em` of ITS OWN font size —
 * the day line at 1em, the countdown at 0.85em, the guarantee lead at
 * 0.85rem and the remedy arrows at 0.78rem — so the three icons were three
 * different sizes and started three different text columns. And every icon
 * was an inline node followed by a space, so a line that wrapped came back
 * to the box's own edge, under the icon, instead of under the text.
 *
 * HOW. One gutter, one drawn size, both fixed in rem so they do not move
 * with each block's type size; the icon is taken out of the flow and parked
 * in that gutter, and the text keeps a padding of exactly the gutter, so
 * the first line and every wrapped line start on the same column. Taking
 * the icon out of the flow also disposes of the literal space that follows
 * it in the markup: at the start of a line box, collapsible white space is
 * removed, so nothing pushes the first line a few pixels right of the ones
 * under it. No markup moves — both producers of these blocks (PHP and
 * `lane-selector.js`'s mirror) stay byte-for-byte what their parity tests
 * pin them to.
 *
 * The `left` on each rule is that block's OWN padding, so the icon sits
 * where the text used to start, not against the border.
 * ---------------------------------------------------------------------- */

.ibdp-product-promise,
.ibdp-cutoff-countdown,
.ibdp-guarantee {
	--ibdp-promise-gutter: 1.6rem;
	--ibdp-promise-icon: 1.05rem;
}

.ibdp-product-promise .ibdp-promise-card__line1,
.ibdp-cutoff-countdown__row,
.ibdp-guarantee__lead,
.ibdp-guarantee__remedy {
	position: relative;
}

.ibdp-product-promise .ibdp-promise-card__line1 > .ibdp-icon,
.ibdp-cutoff-countdown__row > span > .ibdp-icon,
.ibdp-guarantee__lead > .ibdp-icon,
.ibdp-guarantee__remedy > .ibdp-guarantee__arrow {
	position: absolute;
	top: 0.1em;
	width: var( --ibdp-promise-icon );
	height: var( --ibdp-promise-icon );
	margin: 0;
	line-height: 1;
}

/* The clock is wrapped in a `<span>` of its own (`LaneSelector`'s countdown
 * markup), so the span is what has to leave the flow — an absolutely
 * positioned SVG inside a still-inline span would leave the span's own
 * width behind. */
.ibdp-cutoff-countdown__row > span:first-child {
	position: absolute;
	/* 2026-09-01 (threads register 43, Matteo: «il countdown della chiusura
	 * della finestra ha l'icona allineata male»). An absolutely positioned
	 * child is placed against the PADDING box, so `top` here starts at the
	 * border — above this row's own 0.4em of padding, where its first line of
	 * text starts. Measured on the live page before this: the clock's centre
	 * sat at y=480,8 against the text's 485,8, five pixels high, while the
	 * day and guarantee icons (in boxes with no padding of their own) were
	 * within half a pixel. The row's padding is added back here, exactly as
	 * `left` already adds back the horizontal one. */
	top: calc( 0.4em + 0.05em );
	left: 0.6em;
	width: var( --ibdp-promise-icon );
	height: var( --ibdp-promise-icon );
	line-height: 1;
}

.ibdp-cutoff-countdown__row > span:first-child > .ibdp-icon {
	position: static;
	top: auto;
}

.ibdp-product-promise .ibdp-promise-card__line1 > .ibdp-icon {
	left: 0;
}

.ibdp-guarantee__lead > .ibdp-icon,
.ibdp-guarantee__remedy > .ibdp-guarantee__arrow {
	left: 0;
}

.ibdp-product-promise .ibdp-promise-card__line1 {
	padding-left: var( --ibdp-promise-gutter );
}

.ibdp-cutoff-countdown__row {
	padding-left: calc( 0.6em + var( --ibdp-promise-gutter ) );
}

.ibdp-guarantee__lead,
.ibdp-guarantee__remedy {
	padding-left: var( --ibdp-promise-gutter );
}

/* The arrow is a text glyph, not an SVG, and that is exactly why it needed
 * its own rule (2026-09-01, Matteo: «le frecce non sono centrate nè rispetto
 * alla riga su cui sono nè rispetto alla colonna in cui idealmente è centrata
 * l'icona dello scudo»). Measured on the live page before this: the shield's
 * centre at x=1184,5 and on its line at y=563,8, both exact; the arrow's ink
 * at x=1181,0 and y=584,2 against a line centred at 587,7 — 3,5 px left and
 * 3,5 px high, twice.
 *
 * Both misses come from the glyph being smaller than the slot it sits in:
 * 9,9 px of ink in a 16,8 px column, left-aligned, and a box one line-height
 * shorter than the line it belongs to. The slot now IS a box the height of
 * the block's own line (`line-height: 1.5` on `.ibdp-guarantee`), with the
 * glyph centred in it both ways — so any arrow, in any font, lands on the
 * same column as the shield and on the middle of its own line. */
.ibdp-guarantee__remedy > .ibdp-guarantee__arrow {
	top: 0;
	height: 1.5em;
	display: flex;
	align-items: center;
	justify-content: center;
}

/* «How the guarantee works» sits under the remedy lines and is not part of
 * the icon column: it keeps the block's own left edge. */
.ibdp-guarantee__link {
	padding-left: 0;
}

/* -------------------------------------------------------------------------
 * 2026-08-31 (threads register 44) — THE COUNTRY AND POSTCODE FIELDS ARE
 * ONE PAIR, NOT TWO CONTROLS.
 *
 * Matteo: «verifica i campi paese e cap nel dropdown nell'header, la
 * dimensione e gli allineamenti nella pagina sono diversi, uniformati».
 *
 * MEASURED ON THE LIVE PAGE (2026-08-31, panel open): the country
 * `<select>` was **38,5 px** tall with its top at y=136, the postcode
 * `<input>` **58,5 px** with its top at y=126 — 20 px of height and 10 px of
 * baseline apart, in a pair that reads as one field.
 *
 * WHY, read in the stylesheets that actually won: the theme's
 * `universal.css` gives every bare `select` `margin: 10px`, which nothing
 * here had reset, and the field row is a flex row whose default
 * `align-items: stretch` then grew the input to the select's 38,5 px + its
 * 20 px of margin. The same file's `.woocommerce input[type="text"]` branch
 * (specificity 0,2,1) also out-ranked this file's own single-class
 * `.ibdp-destination-bar__field` padding — which is why the rules below are
 * written with the panel ancestor, three classes, 0,3,0: enough to win, and
 * no `!important` anywhere.
 *
 * WHAT IS FIXED: one height, one padding, no inherited margin, and the row
 * centring instead of stretching. `appearance: none` on the pair drops the
 * platform's own select chrome (which is what made the two boxes look like
 * different species), so the select draws its own chevron below.
 * ---------------------------------------------------------------------- */

.ibdp-destination-bar__panel .ibdp-destination-bar__field-row {
	align-items: center;
}

.ibdp-destination-bar__panel .ibdp-destination-bar__field-row .ibdp-destination-bar__field {
	box-sizing: border-box;
	height: 38px;
	margin: 0;
	padding: 0 11px;
	line-height: normal;
	appearance: none;
	-webkit-appearance: none;
	background-color: #fff;
	border: 1px solid var( --ibdp-bar-panel-border );
	border-radius: 4px;
	color: var( --ibdp-color-ink );
	font: inherit;
	font-size: 0.85rem;
	text-align: left;
}

/* The chevron the platform used to draw. Inline SVG, so it needs no file
 * and no request; `right 10px center` keeps it clear of the longest country
 * name, and the right padding keeps the text clear of it. */
.ibdp-destination-bar__panel .ibdp-destination-bar__field-row .ibdp-destination-bar__field--country,
.ibdp-destination-bar__panel .ibdp-destination-bar__field-row .ibdp-destination-bar__field--wide {
	padding-right: 30px;
	background-image: url( "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%235c5c5c' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E" );
	background-repeat: no-repeat;
	background-position: right 10px center;
	background-size: 10px 7px;
}

/* -------------------------------------------------------------------------
 * 2026-09-01 (threads register 47) — the sentence that explains a speed the
 * visitor did not change themselves: «Speed set back to Standard — Express
 * isn't available for this destination.»
 *
 * It sits under the cards, in the block's own quiet grey and one step below
 * the card type, because it is an explanation and not an offer. Same family
 * as the «Updating delivery dates…» note beside it.
 * ---------------------------------------------------------------------- */

.ibdp-lane-reset-notice {
	margin: 8px 0 0;
	color: var( --ibdp-color-ink-muted );
	font-size: 0.8rem;
	line-height: 1.45;
}

/* -------------------------------------------------------------------------
 * 2026-09-02 (area decision log (3)(a)) — the country menu shows a flag
 * IMAGE per country, so it can no longer be a native `<select>`.
 *
 * WHY THE CONTROL CHANGED SHAPE: an `<option>` can only hold text, and the
 * flag used to be an emoji inside that text. Text is what TranslatePress
 * translates, and the stored Italian translation of «🇮🇹 Italy» is the bare
 * word «Italia» — so the Italian shop's menu had no flags at all while the
 * German one did. An `<img>` is a node and survives every translation pass.
 *
 * The button keeps `.ibdp-destination-bar__field--country`, so it inherits
 * the panel's own 38px box AND the inline-SVG chevron the block above draws
 * for that class — the custom control looks like the field it replaced, and
 * beside the postcode input it still looks like its twin.
 * ---------------------------------------------------------------------- */

.ibdp-destination-bar__country {
	position: relative;
	flex: 1.4;
	min-width: 0;
}

.ibdp-destination-bar__country .ibdp-destination-bar__field--country {
	display: flex;
	align-items: center;
	gap: 8px;
	cursor: pointer;
	overflow: hidden;
}

.ibdp-destination-bar__flag {
	flex: 0 0 auto;
	width: 22px;
	height: 15px;
	border-radius: 2px;
	/* A white flag on a white field would otherwise have no edge at all. */
	box-shadow: 0 0 0 1px rgba( 0, 0, 0, 0.08 );
	object-fit: cover;
}

.ibdp-destination-bar__country-name {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.ibdp-destination-bar__country-list {
	position: absolute;
	z-index: 20;
	top: calc( 100% + 4px );
	left: 0;
	right: 0;
	max-height: 260px;
	overflow-y: auto;
	margin: 0;
	padding: 4px;
	list-style: none;
	background: #fff;
	border: 1px solid var( --ibdp-bar-panel-border );
	border-radius: 4px;
	box-shadow: 0 8px 24px rgba( 0, 0, 0, 0.12 );
}

.ibdp-destination-bar__country-list[ hidden ] {
	display: none;
}

/* WRITTEN WITH THE PANEL ANCESTOR, THREE CLASSES (0,3,0) — and it has to be
 * (2026-09-03, Matteo: «la lista dei paesi ha le bandiere attaccate al nome»).
 *
 * Oxygen's own stylesheet carries
 * `:is(li, div._important) { display: list-item }`, and `:is()` takes the
 * specificity of its most specific argument — `div._important`, 0,1,1 — so it
 * outranked this rule's single class and every row stayed a `list-item`.
 * `gap` means nothing outside a flex or grid container, so the 8px below was
 * inert and each flag sat glued to the country's name. Measured on staging:
 * `display: list-item`, `gap: 8px`, real distance between the image and the
 * text 0px. The button above the list was never affected — it is a `<button>`,
 * not an `<li>`.
 *
 * Same remedy the panel's own field rules already use further down this file:
 * enough specificity to win, and no `!important` anywhere. */
.ibdp-destination-bar__panel .ibdp-destination-bar__country-list .ibdp-destination-bar__country-option {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 7px 8px;
	border-radius: 3px;
	font-size: 0.85rem;
	color: var( --ibdp-color-ink );
	cursor: pointer;
}

.ibdp-destination-bar__country-option.is-active,
.ibdp-destination-bar__country-option:hover {
	background: #f2f2ef;
}

.ibdp-destination-bar__country-option.is-selected {
	font-weight: 600;
}

/* The bar sentence's own flag, before «Italy · 00187». Slightly smaller
 * than the menu's: it sits inside a line of running text, not a row. */
.ibdp-destination-bar__toggle .ibdp-destination-bar__flag,
.ibdp-destination-bar__strip .ibdp-destination-bar__flag {
	width: 18px;
	height: 12px;
	vertical-align: -1px;
	margin-right: 5px;
}

/* -------------------------------------------------------------------------
 * 2026-09-02 (area decision log (3)(d)) — the summary's rows in the order the
 * customer reads them.
 *
 * 2026-09-03: the VAT row this block was written for is GONE — the VAT is
 * named inside the Subtotal and Shipping labels instead (Matteo, area decision
 * log 2026-09-03: a row splitting only the subtotal's VAT told half the story,
 * because the shipping amount is VAT-inclusive too). The ordering stays: the
 * hook anything of ours can mount on still fires after every row FunnelKit
 * prints, so our promise card would otherwise land above the shipping row.
 *
 * WHY THE ORDER IS CSS'S JOB. FunnelKit prints its summary rows in a fixed
 * sequence — Subtotal, coupons, shipping, taxes, the calculation note — and
 * only THEN fires `fkcart_after_order_summary`, the hook anything of ours can
 * mount on. So a row rendered by us always arrives last in the markup. The
 * two other ways to move it are both worse: overriding the vendor template
 * (never — vendor code is not edited here) and reordering with JavaScript
 * (the whole drawer is re-rendered as one fragment on every cart change,
 * which wipes it). Making the container a flex column and giving each row an
 * `order` costs nothing and survives every re-render.
 *
 * The shipping row carries BOTH `fkcart-coupon-applied` and
 * `fkcart-shipping-wrap`, so its rule is written with both classes to outrank
 * the coupon one.
 * ---------------------------------------------------------------------- */

.fkcart-order-summary-container {
	display: flex;
	flex-direction: column;
}

.fkcart-order-summary-container .fkcart-subtotal-wrap {
	order: 0;
}

.fkcart-order-summary-container .fkcart-coupon-applied {
	order: 1;
}

.fkcart-order-summary-container .fkcart-coupon-applied.fkcart-shipping-wrap {
	order: 3;
}

.fkcart-order-summary-container .fk-tax-rate {
	order: 4;
}

.fkcart-order-summary-container .ibdp-cart-promise,
.fkcart-order-summary-container .ibdp-promise-card {
	order: 6;
}
