/* ==========================================================================
   Standalone public pages — /location-voiture/, /transfert-aeroport/,
   /commande/{token}.

   Full-document pages (own <html>/<body>, no Elementor/theme template) —
   same pattern as quote-public.css. Local --sa-* tokens map to the REAL
   theme tokens defined in evd/assets/css/lightweight.css (loaded via
   wp_head()); the theme's light-mode JS remap (evd/functions.php) then
   drives both light/dark automatically — no separate dark/light branch
   needed here beyond the RTL block.

   Spacing scale: --sa-gap (20px) is the minimum gap between any two
   adjacent blocks — never two sections touching directly.
   ========================================================================== */

.mphb-gs-standalone-page {
	--sa-gap: 20px;
	--sa-gap-lg: 32px;
	--sa-radius: 10px;
	--sa-radius-sm: 6px;

	/* Color tokens — mapped to real --lw-* vars (evd/assets/css/lightweight.css). */
	--sa-bg: var(--lw-navy-dark);
	--sa-bg-alt: var(--lw-navy);
	/* Solid, opaque surface for floating/elevated UI (dropdown panels) —
	   deliberately NOT aliased through --lw-navy or --lw-bg-warm. Both are
	   in evd/functions.php's early theme-toggle script's inline var-remap
	   table (`r.style.setProperty(...)` on :root, applied unconditionally
	   regardless of this page's own body class) and get overwritten to
	   translucent values there: --lw-bg-warm becomes rgba(30,55,80,0.04) in
	   LIGHT mode specifically (measured directly — this is the actual root
	   cause of the "menu langue buggé" prod bug, Ahmed 28/07: the panel
	   used --sa-bg-alt → --lw-bg-warm and inherited that same near-
	   transparency, just previously undiscovered because it only reproduces
	   once you inspect the LIGHT theme, which nobody had yet for this
	   specific panel). Literal hex here means the theme's remap script,
	   which only touches property names it explicitly lists, can never
	   touch this one — it doesn't know the name exists. Same value as
	   --lw-navy's own true, unremapped constant (#1e3750) / --sa-card-bg's
	   light value (#ffffff, already independently confirmed opaque). */
	--sa-elevated-bg: #1e3750;
	--sa-text: var(--lw-section-text);
	--sa-heading: var(--lw-section-heading);
	--sa-muted: var(--lw-section-muted);
	--sa-border: var(--lw-section-border);
	--sa-card-bg: var(--lw-card-bg);
	--sa-card-border: var(--lw-card-border);
	--sa-accent: var(--lw-gold-a11y-dark);
	--sa-accent-contrast: var(--lw-btn-on-gold);
	--sa-input-bg: var(--lw-white-08);
	--sa-input-border: var(--lw-white-20);
	--sa-control-border: #7f93b0;
	--sa-control-disabled-text: rgba(255, 255, 255, 0.45);
	--sa-control-disabled-border: rgba(255, 255, 255, 0.45);
	--sa-verified-bg: #22c55e;
	--sa-verified-text: #152840;
	--sa-input-text: #ffffff;
	--sa-success: var(--lw-success);
	/* --lw-error (#f87171) is 4.42:1 on the elevated card; this lighter red clears 4.5:1. */
	--sa-error: #f08a8a;
	--sa-warning: var(--lw-warning);
	--sa-info: var(--lw-info);

	background: var(--sa-bg);
	color: var(--sa-text);
	font-family: var(--lw-font-body);
	line-height: 1.55;
	margin: 0;
	min-height: 100vh;
}

/* Light theme remap (body[data-pp-theme="light"] is stamped by the theme's
   early light-mode JS, evd/functions.php — see lightweight.css's own
   light-theme block for the same pattern). */
body[data-pp-theme="light"].mphb-gs-standalone-page {
	--sa-bg: #ffffff;
	--sa-bg-alt: var(--lw-bg-warm);
	--sa-elevated-bg: #ffffff;
	--sa-text: var(--lw-body-text);
	--sa-heading: var(--lw-text-heading);
	--sa-muted: var(--lw-text-secondary);
	--sa-border: var(--lw-border-medium);
	--sa-card-bg: #ffffff;
	--sa-card-border: var(--lw-border-medium);
	--sa-accent: var(--lw-gold-wcag);
	--sa-accent-contrast: #ffffff;
	--sa-input-bg: #ffffff;
	--sa-input-border: var(--lw-input-border);
	--sa-control-border: #8a8a8a;
	--sa-control-disabled-text: #8a94a3;
	--sa-control-disabled-border: #8a94a3;
	--sa-error: #b42318;
	--sa-warning: #92400e;
	--sa-success: #1b7a3d;
	--sa-verified-bg: #1b7a3d;
	--sa-verified-text: #ffffff;
	--sa-input-text: var(--lw-text-dark);
}

.mphb-gs-sa-shell {
	max-width: var(--lw-container-max);
	margin: 0 auto;
	padding: 0 var(--lw-container-pad) 64px;
}

/* -- RTL: dir + is-rtl class both live on <body> (the styled root) so any
   selector using either hook actually matches — see standalone-car.php /
   standalone-transfer.php / standalone-order.php for how both are set
   together. -------------------------------------------------------------- */
.mphb-gs-standalone-page.is-rtl {
	direction: rtl;
	text-align: right;
}
.mphb-gs-standalone-page.is-rtl .mphb-gs-sa-field-row,
.mphb-gs-standalone-page.is-rtl .mphb-gs-sa-radio-row {
	flex-direction: row-reverse;
}
.mphb-gs-standalone-page.is-rtl .mphb-gs-sa-reassure__item,
.mphb-gs-standalone-page.is-rtl .mphb-gs-sa-reassure__link {
	flex-direction: row-reverse;
	text-align: right;
}

/* -- Header ---------------------------------------------------------------
   28/07 third pass (Ahmed: "title transfert aéroport, please center it and
   use a professional font"). Two independent fixes, both scoped to
   `.mphb-gs-sa-header__title` / its column, neither touching the brand or
   controls groups' own content:

   1. Font: measured the shipped H1 at `--lw-font-heading` (Cinzel, the
      charter's Roman-inscription serif) 20px/700 — right for an editorial
      display heading, ornamental in a checkout tunnel's header bar, which is
      exactly what read as "not professional". Switched to
      `--lw-font-body` (Josefin Sans, the charter's OTHER family — no third,
      external font brought in) at 600 weight: still a real heading-weight
      break from the plain-400 subtitle/body copy around it, but neutral
      enough for a transactional bar. Letter-spacing reset to 0 (the 0.01em
      tracking was tuned for Cinzel's serif; Josefin Sans's own default
      spacing already reads open, an extra positive tracking on top made it
      feel sparse).
   2. True centering: a 2-group flex row (`justify-content: space-between`)
      can only center a middle element if both outer groups happen to be the
      same width — here the logo (~90px) and the language+theme controls
      (~250px) never are, so the title always sat off-center, closer to the
      wider group's side. Grid with `1fr auto 1fr` fixes this exactly: the
      title's own column is sized to its content and centered between two
      EQUAL flexible columns, so it sits on the page's true center line
      regardless of how wide the logo or the controls are. Explicit
      `grid-column` on all three children (not auto-placement) is load-
      bearing: standalone-order.php never sets `$sa_h1` (see
      standalone-header.php's docblock), so on that page the title column
      simply has no content — without explicit placement, grid auto-flow
      would pack brand into column 1 and controls into column 2 (the
      formerly-empty middle track), pulling controls away from the right
      edge. Pinning brand/controls to columns 1/3 always keeps them at the
      opposite edges, title-present or not — the same "space-between" result
      the old flex rule gave when the title didn't exist. */
.mphb-gs-sa-header {
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	gap: var(--sa-gap);
	padding: 24px 0;
	border-bottom: 1px solid var(--sa-border);
	margin-bottom: var(--sa-gap-lg);
}
.mphb-gs-sa-header__brand { grid-column: 1; justify-self: start; }
.mphb-gs-sa-header__title {
	grid-column: 2;
	justify-self: center;
	min-width: 0;
	margin: 0;
	color: var(--sa-heading);
	font-family: var(--lw-font-body);
	font-weight: 600;
	font-size: 1.25rem;
	letter-spacing: 0;
	text-align: center;
}
.mphb-gs-sa-header__controls { grid-column: 3; justify-self: end; }
/* 28/07 mobile-fold fix (Ahmed also flagged the header itself: logo + title
   + language switcher + theme toggle stacked on three separate lines, ~200px
   before the subtitle even starts — measured on live prod at 414px, part of
   the same "guest sees no field without scrolling" complaint). The FIRST
   version of this rework forced the title onto its own full-width line
   (three rows: brand, title, controls) reasoning the three groups could
   never share one row. Re-measured: the brand (logo only, ~70px at the
   32px mobile logo height) and the short page titles ("Car rental"/"Airport
   transfer", never more than ~20 characters translated) fit together on one
   row with room to spare at 414px — it was the CONTROLS group (language
   trigger + theme toggle, ~150-180px combined) that couldn't also join that
   same row.

   28/07 third pass: the ≥641px rule above switched to CSS Grid for true
   centering, but that centering is exactly what this narrow breakpoint must
   NOT keep — a 2-row 145px header (brand+title on row 1, controls on row 2)
   has no "page width" left to meaningfully center the title against once
   the logo sits right next to it, and grid's 3-column track would fight the
   wrap this breakpoint depends on. Reverting to `display: flex` here (same
   as before the third pass) restores the exact 2-row result byte-for-byte:
   brand+title share row 1 (title `text-align: start`, back to sitting next
   to the logo rather than centered), controls forced to their own full row
   2 via `flex-basis: 100%`. */
@media (max-width: 640px) {
	.mphb-gs-sa-header {
		display: flex;
		flex-wrap: wrap;
	}
	.mphb-gs-sa-header__title {
		flex: 1 1 auto;
		font-size: 1.125rem;
		text-align: start;
	}
	.mphb-gs-sa-header__controls {
		flex: 1 1 100%;
		justify-content: flex-end;
	}
}
.mphb-gs-sa-header__brand {
	display: flex;
	align-items: center;
	color: var(--sa-heading);
	font-family: var(--lw-font-heading);
	font-size: 1.25rem;
	letter-spacing: 0.02em;
	text-decoration: none;
}
.mphb-gs-sa-header__logo {
	display: block;
	height: 40px;
	width: auto;
	max-width: 100%;
}
/* Two color variants of the same logo (dark-bg = white lettering, light-bg =
   navy lettering — see standalone-header.php's docblock for why a single
   color can't work in both themes). Default theme is dark, so the dark-bg
   picture shows by default; body[data-pp-theme="light"] flips which one is
   visible. display:none removes the hidden <picture> from the a11y tree, so
   its <img alt> is never double-announced. */
.mphb-gs-sa-header__logo-pic--light {
	display: none;
}
body[data-pp-theme="light"] .mphb-gs-sa-header__logo-pic--dark {
	display: none;
}
body[data-pp-theme="light"] .mphb-gs-sa-header__logo-pic--light {
	display: block;
}

.mphb-gs-sa-header__controls {
	display: flex;
	align-items: center;
	gap: 16px;
	flex-wrap: wrap;
}

/* -- Language switcher — disclosure dropdown -------------------------------
   Before JS runs: .__trigger is `hidden` (in the markup) and .__panel is a
   plain, fully visible flex row of flag+name links — same information as
   the flat row it replaces, just styled. standalone-header-controls.js
   reveals the trigger and manages open/close via the `hidden` attribute +
   `.is-sa-open`; the panel is always positioned as a small dropdown card
   (see below) so there's nothing to re-layout once JS takes over. */
.mphb-gs-sa-lang-switcher {
	position: relative;
}
.mphb-gs-sa-lang-switcher__trigger {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	background: var(--sa-input-bg);
	border: 1px solid var(--sa-input-border);
	border-radius: var(--sa-radius-sm);
	color: var(--sa-heading);
	font-family: inherit;
	font-size: 0.8125rem;
	padding: 8px 12px;
	cursor: pointer;
}
.mphb-gs-sa-lang-switcher__trigger:hover,
.mphb-gs-sa-lang-switcher__trigger:focus-visible {
	border-color: var(--sa-accent);
	outline: none;
}
.mphb-gs-sa-lang-switcher__chevron {
	width: 14px;
	height: 14px;
	flex: 0 0 auto;
	transition: transform 0.15s ease;
}
.mphb-gs-sa-lang-switcher.is-sa-open .mphb-gs-sa-lang-switcher__chevron {
	transform: rotate(180deg);
}
/* A bare `display: flex` on the panel class silently beats the UA's
   `[hidden] { display: none }` (attribute selectors in the UA sheet carry
   almost no weight), which left the menu permanently open on load — this
   companion rule is what keeps it closed. Same pairing as
   .mphb-gs-sa-pay-btn__spinner[hidden]. */
.mphb-gs-sa-lang-switcher__panel[hidden] {
	display: none;
}
/* No JS: the trigger is dead weight, so the panel's [hidden] state (which the
   markup still carries) is overridden into a flat list of links. */
.no-js .mphb-gs-sa-lang-switcher__trigger {
	display: none;
}
.no-js .mphb-gs-sa-lang-switcher__panel[hidden] {
	display: flex;
	position: static;
	box-shadow: none;
	border: 0;
	padding: 0;
	background: transparent;
}

.mphb-gs-sa-lang-switcher__panel {
	position: absolute;
	top: calc(100% + 8px);
	inset-inline-start: 0;
	z-index: 40;
	display: flex;
	flex-wrap: wrap;
	gap: 4px;
	margin: 0;
	padding: 8px;
	min-width: 180px;
	list-style: none;
	/* NOT --sa-card-bg (rgba(255,255,255,0.06) in dark — --lw-card-bg, a
	   translucent surface meant to sit flush against the page background,
	   e.g. .mphb-gs-sa-block) — a floating panel using it let the page
	   content underneath show through almost unchanged (Ahmed, 28/07:
	   "menu langue buggé ouvert" — confirmed via computed background-color,
	   not a stacking/z-index issue: elementFromPoint already showed the
	   panel correctly on top). Also NOT --sa-bg-alt, my first fix attempt:
	   that resolves to --lw-bg-warm in light theme, which turned out to
	   have the SAME kind of near-transparency bug from a different source —
	   evd/functions.php's theme-toggle script inline-remaps --lw-bg-warm to
	   rgba(30,55,80,0.04) specifically when switching TO light (verified:
	   `getComputedStyle` showed alpha 0.04 in light theme after that first
	   fix). --sa-elevated-bg is a literal, un-aliased hex value the theme's
	   remap script can't touch (it only rewrites property names it lists
	   explicitly) — see its definition at the top of this file. */
	background: var(--sa-elevated-bg);
	border: 1px solid var(--sa-card-border);
	border-radius: var(--sa-radius);
	box-shadow: 0 8px 24px rgba(0, 0, 0, 0.24);
}
.mphb-gs-sa-lang-switcher__option {
	display: flex;
	align-items: center;
	gap: 8px;
	width: 100%;
	color: var(--sa-text);
	text-decoration: none;
	font-size: 0.875rem;
	padding: 8px 10px;
	border-radius: var(--sa-radius-sm);
	border: 1px solid transparent;
	box-sizing: border-box;
}
.mphb-gs-sa-lang-switcher__option:hover,
.mphb-gs-sa-lang-switcher__option:focus-visible {
	background: var(--sa-input-bg);
	border-color: var(--sa-border);
	outline: none;
}
.mphb-gs-sa-lang-switcher__option.is-current {
	color: var(--sa-heading);
	border-color: var(--sa-accent);
	font-weight: 600;
}
.mphb-gs-sa-lang-switcher__flag {
	display: block;
	flex: 0 0 auto;
	width: 20px;
	height: 14px;
	object-fit: cover;
	border-radius: 2px;
}

/* -- Theme toggle ----------------------------------------------------------
   Sun/moon dual icon, CSS-toggled by the same body[data-pp-theme="light"]
   marker as the logo variants above — no JS-computed initial icon state,
   same reasoning as the logo pair. Icon shown = the THEME YOU'D SWITCH TO
   (matches the evd theme's own convention: sun visible while dark, moon
   visible while light — the icon names the action, not the current state).
   A visible text label ("Light"/"Dark") rides along on desktop next to the
   icon — Ahmed, 28/07: an icon alone, isolated from the rest of the site's
   header (where it has nav/context around it), didn't communicate what it
   did even once sized correctly. The label names the same destination the
   icon does, toggled by the exact same selectors — kept icon-only at
   mobile (≤640px) purely for width, aria-label already carries the full
   meaning for assistive tech regardless of what's visually shown. */
.mphb-gs-sa-theme-toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	padding: 8px 12px;
	background: var(--sa-input-bg);
	border: 1px solid var(--sa-input-border);
	border-radius: var(--sa-radius-sm);
	color: var(--sa-heading);
	font-family: inherit;
	font-size: 0.8125rem;
	cursor: pointer;
}
.mphb-gs-sa-theme-toggle:hover,
.mphb-gs-sa-theme-toggle:focus-visible {
	border-color: var(--sa-accent);
	outline: none;
}
/* flex: 0 0 auto is load-bearing, not decorative: without it the SVG (no
   intrinsic size of its own — width/height are set here, not as HTML
   attributes) was free to flex-shrink along the row's main axis while its
   cross-axis (height) stayed fixed, rendering as a 4px-wide sliver in prod
   (Ahmed, 28/07 — measured computed width, not assumed). Height was never
   the affected dimension, which is exactly why it looked "right" in a
   glance at the CSS rule alone and only showed up in a real render. */
.mphb-gs-sa-theme-toggle__icon {
	flex: 0 0 auto;
	width: 18px;
	height: 18px;
}
/* Optical centring. The label's line box IS centred (measured: 0px off), but
   "Clair"/"Sombre" carry no descender, so their ink sits ~2px above the
   button's centre — 14.5px of air above, 18.5px below. Sibling controls do
   not show this because their labels do have descenders ("Français" ç,
   "Payer" y/p), which is why only this button reads as off-centre.
   Nudging the whole label would break its baseline alignment with the
   language trigger sitting right next to it (measured: +2px skew), so the
   correction is applied to the flex row instead: the icon and the text keep
   their shared baseline, and the pair as a whole is optically centred. */
.mphb-gs-sa-theme-toggle {
	padding-top: 10px;
	padding-bottom: 6px;
}

.mphb-gs-sa-theme-toggle__icon--moon,
.mphb-gs-sa-theme-toggle__label--moon {
	display: none;
}
body[data-pp-theme="light"] .mphb-gs-sa-theme-toggle__icon--sun,
body[data-pp-theme="light"] .mphb-gs-sa-theme-toggle__label--sun {
	display: none;
}
body[data-pp-theme="light"] .mphb-gs-sa-theme-toggle__icon--moon {
	display: block;
}
body[data-pp-theme="light"] .mphb-gs-sa-theme-toggle__label--moon {
	display: inline;
}

/* -- Main / titles ---------------------------------------------------------*/
.mphb-gs-sa-main {
	display: block;
}
.mphb-gs-sa-title {
	color: var(--sa-heading);
	font-family: var(--lw-font-heading);
	font-size: 1.75rem;
	/* >= --sa-gap so the title never sits glued to the subtitle line right
	   under it (CLAUDE.md spacing rule — was a hardcoded 8px, measured < 16px
	   on a Task 12 screenshot). */
	margin: 0 0 var(--sa-gap);
}
.mphb-gs-sa-subtitle {
	color: var(--sa-muted);
	margin: 0 0 var(--sa-gap-lg);
}

/* -- Reassurance strip -------------------------------------------------------
   28/07 layout rework (Ahmed: "plus compacte et au dessus du recap à
   droite") — was a full-width strip above the H1, pillars side by side.
   Moved into the wizard's right-hand column (standalone-wizard.php).

   28/07 density fix (third pass, Ahmed: "la barre de réassurance prend trop
   de place, soit on la compacte, soit on la déplace sous le récap" — both,
   his own call, see standalone-reassurance.php's docblock for the full
   rationale and standalone-public.css's `@media (min-width: 900px)` block
   below for the grid-area swap that puts the summary first). Rewrote every
   rule from here to the end of this section: pillars go from a vertical
   stack of 3 full-width, 2-line rows to a wrapping row of one-line chips —
   same card shell (background/border/padding), same `.mphb-gs-sa-wizard__layout`
   gap spacing it from its siblings (no `margin-bottom` of its own, as
   before). */
.mphb-gs-sa-reassure {
	background: var(--sa-card-bg);
	border: 1px solid var(--sa-card-border);
	border-radius: var(--sa-radius);
	padding: var(--sa-gap);
}
/* `row` + `wrap` instead of the old `column` stack — chips flow side by
   side and wrap only when the 320px column actually runs out of width,
   instead of every pillar forcibly claiming its own full-width line. */
.mphb-gs-sa-reassure__pillars {
	list-style: none;
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px 16px;
	margin: 0;
	padding: 0;
}
.mphb-gs-sa-reassure__item {
	display: flex;
	align-items: center;
	gap: 6px;
}
.mphb-gs-sa-reassure__link {
	display: flex;
	align-items: center;
	gap: 6px;
	color: inherit;
	text-decoration: none;
}
/* 18px -> 14px: a one-line chip has no room for the previous icon size
   (measured — 18px against a single 0.75rem line reads oversized, the
   two-line block it used to sit beside is gone). No `margin-top` optical
   nudge needed anymore either, now that label+detail sit on the SAME line
   as the icon (`align-items: center` above), not stacked beside it. */
.mphb-gs-sa-reassure__icon {
	flex: 0 0 auto;
	width: 14px;
	height: 14px;
	color: var(--sa-accent);
}
/* `row`, not `column`: label and detail (day count / brand marks) now sit
   on one visual line, `flex-wrap` so a long translation still wraps inside
   its OWN chip rather than forcing the whole strip back to one-per-line. */
.mphb-gs-sa-reassure__text {
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 4px 6px;
	min-width: 0;
}
.mphb-gs-sa-reassure__label {
	color: var(--sa-heading);
	font-weight: 600;
	font-size: 0.75rem;
	white-space: nowrap;
}
.mphb-gs-sa-reassure__sub {
	color: var(--sa-muted);
	font-size: 0.6875rem;
	line-height: 1.3;
}
/* Stripe/PayPal marks, inlined right after the "Secure payment" label
   (density fix — merges what used to be a separate bordered
   `.mphb-gs-sa-pay-brands` block, with its own margin-top/padding-top/
   border-top, i.e. a whole extra card-width strip, into this one chip).
   `align-items: center` keeps both wordmarks vertically centred against
   the label's baseline at this small size. */
.mphb-gs-sa-reassure__brands {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	color: var(--sa-muted);
}
.mphb-gs-sa-reassure__brands svg {
	display: block;
	height: 12px;
	width: auto;
	color: inherit;
}

.mphb-gs-sa-alert {
	background: var(--sa-card-bg);
	border: 1px solid var(--sa-border);
	border-radius: var(--sa-radius);
	padding: 16px 20px;
	margin-bottom: var(--sa-gap-lg);
}
.mphb-gs-sa-alert--info { border-color: var(--sa-info); }
.mphb-gs-sa-alert--warning { border-color: var(--sa-warning); }

/* -- Form blocks ------------------------------------------------------------
   Every block gets margin-bottom >= --sa-gap so no two sections ever touch
   (CLAUDE.md spacing rule — measured on screenshots in Task 12). */
.mphb-gs-sa-block {
	background: var(--sa-card-bg);
	border: 1px solid var(--sa-card-border);
	border-radius: var(--sa-radius);
	padding: var(--sa-gap);
	margin-bottom: var(--sa-gap-lg);
}
.mphb-gs-sa-block__title {
	color: var(--sa-heading);
	font-family: var(--lw-font-body);
	font-size: 1.125rem;
	font-weight: 600;
	font-variant: normal;
	letter-spacing: normal;
	text-transform: none;
	margin: 0 0 var(--sa-gap);
}
/* Modifier for a SECOND heading inside one wizard pane (Task 8:
   standalone-step-dates.php packs dates+price and delivery/pickup into one
   `[data-sa-pane]`, which has no card padding/border of its own — see the
   "Panes" section below). Without this top margin the delivery radio-row
   would sit directly against the price-preview note above it, zero gap
   (CLAUDE.md spacing rule: no two blocks ever glued together). */
.mphb-gs-sa-block__title--sub { margin-top: var(--sa-gap-lg); }

.mphb-gs-sa-field-row {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sa-gap);
	margin-bottom: var(--sa-gap);
}
.mphb-gs-sa-field-row:last-child { margin-bottom: 0; }
.mphb-gs-sa-field-group {
	display: flex;
	flex-direction: column;
	gap: 6px;
	flex: 1 1 200px;
	margin-bottom: var(--sa-gap);
}
/* 28/07 third pass, incidental fix (found while restyling the delivery-choice
   cards right above this field, standalone-step-dates.php): the same
   [hidden]-beaten-by-a-class-rule bug this file already documents for the
   lang switcher panel and the pay-button spinner — confirmed live on prod,
   not assumed: `[data-sa-delivery-address-field]` (this class +
   `hidden`) computed `display: flex`, not `none`, so the delivery-address
   field was visible even while the guest had "Pick up at our office"
   selected. Missing pairing rule, unrelated to anything touched this pass
   until now — added here, same convention as every other disclosure on
   this page. */
.mphb-gs-sa-field-group[hidden] {
	display: none;
}
.mphb-gs-sa-field-group--phone {
	min-width: 0;
	max-width: 100%;
}
.mphb-gs-sa-block > .mphb-gs-sa-field-group:last-child,
.mphb-gs-sa-field-row .mphb-gs-sa-field-group {
	margin-bottom: 0;
}

/* Places suggestions under the accommodation field. Absolutely positioned,
   so an open list never pushes the blocks below it. z-index sits above the
   fixed summary bar (40), which would otherwise cover the list's bottom. */
.mphb-gs-sa-field-group--suggest {
	position: relative;
}
.mphb-gs-standalone-page .mphb-gs-sa-pickup-suggestions {
	position: absolute;
	inset-block-start: calc(100% + 4px);
	inset-inline: 0;
	z-index: 60;
	margin: 0;
	padding: 4px;
	max-height: min(320px, calc(100vh - var(--sa-summary-bar-h) - 16px));
	overflow-y: auto;
	overscroll-behavior: contain;
	list-style: none;
	background: var(--sa-elevated-bg);
	border: 1px solid var(--sa-card-border);
	border-radius: var(--sa-radius);
	box-shadow: 0 8px 24px rgba(0, 0, 0, 0.24);
	text-align: start;
}
.mphb-gs-standalone-page .mphb-gs-sa-pickup-suggestions__option {
	display: flex;
	flex-direction: column;
	justify-content: center;
	min-height: 44px;
	padding: 6px 12px;
	border-radius: var(--sa-radius-sm);
	color: var(--sa-text);
	cursor: pointer;
}
.mphb-gs-standalone-page .mphb-gs-sa-pickup-suggestions__option--active {
	background: var(--sa-input-bg);
}
.mphb-gs-standalone-page .mphb-gs-sa-pickup-suggestions__main {
	font-size: 0.9375rem;
}
.mphb-gs-standalone-page .mphb-gs-sa-pickup-suggestions__secondary {
	font-size: 0.8125rem;
	color: var(--sa-muted);
}
.mphb-gs-standalone-page .mphb-gs-sa-pickup-suggestions__attribution {
	padding: 6px 12px;
	font-size: 0.75rem;
	color: var(--sa-muted);
	text-align: end;
}

.mphb-gs-sa-label {
	color: var(--sa-text);
	font-size: 0.875rem;
	font-weight: 600;
	text-transform: none;
	letter-spacing: 0;
}

/* Scoped under .mphb-gs-standalone-page (not just the bare class) so this
   deterministically beats the theme's generic
   `input[type="date"], input[type="text"], ... { background: var(--lw-white); }`
   rule from lightweight.css — same specificity (0,1,0) as a bare class
   selector otherwise, so the winner would depend on stylesheet source
   order. --lw-white is remapped by the theme's light-mode override script
   to a dark navy (it means "white text on dark bg", not "input surface" —
   the --lw-* var remap trap), which without this scope left every native
   date/text input on these pages showing a dark navy box in light theme. */
.mphb-gs-standalone-page .mphb-gs-sa-field,
.mphb-gs-standalone-page .mphb-gs-sa-textarea,
.mphb-gs-standalone-page .mphb-gs-sa-stepper-input {
	background: var(--sa-input-bg);
	border: 1px solid var(--sa-input-border);
	border-radius: var(--sa-radius-sm);
	color: var(--sa-input-text);
	font-family: inherit;
	font-size: 1rem;
	padding: 12px 14px;
	width: 100%;
	box-sizing: border-box;
}
.mphb-gs-sa-textarea { resize: vertical; min-height: 72px; }
.mphb-gs-sa-field:focus-visible,
.mphb-gs-sa-textarea:focus-visible {
	outline: 2px solid var(--sa-accent);
	outline-offset: 1px;
}

/* -- Native <select> dropdown panel ---------------------------------------
   The open option list is painted by the UA on its OWN surface: it does NOT
   inherit the <select>'s `background`, only its `color`. The phone
   country-code select below is deliberately `background: transparent` (it
   borrows the merged pill's surface), so the panel fell back to the UA's
   white Canvas while every <option> still inherited --sa-input-text
   (#ffffff in the default dark theme) => white text on a white panel, the
   whole list invisible except the single row under the OS hover highlight
   (reported by Ahmed with capture). Setting BOTH `background-color` and
   `color` on `option` itself is the only reliable fix.

   Scoped to `.mphb-gs-standalone-page select option` — every select on
   these pages, not just the phone one — so any <select> added later is
   covered by construction. This exact bug has been patched one-off
   elsewhere (lightweight.css `.datepick select option`,
   partner-availability.css `.pp-lang-select option`) and kept coming back
   precisely because those patches were per-widget AND light-theme-only.

   Both tokens used here are OPAQUE in both themes, which is the point:
   --sa-input-bg / --sa-card-bg are translucent white overlays in the dark
   theme (--lw-white-08 / --lw-card-bg) and would composite against the
   UA's white panel — i.e. white again. Measured contrast:
     dark  #ffffff on --lw-navy   #1e3750 = 12.1:1
     light --lw-text-dark #222 on --lw-bg-warm #faf7f3 = 14.9:1
   Both flip automatically: the light block above remaps --sa-bg-alt and
   --sa-input-text, so there is no second light-theme rule to keep in sync. */
.mphb-gs-standalone-page select option {
	background-color: var(--sa-bg-alt);
	color: var(--sa-input-text);
}
/* Selected row: only the surface shifts (opaque in both themes, 14.8:1 dark
   / 15.9:1 light), never the text color — Firefox propagates the checked
   option's `color` to the CLOSED control, and the merged phone pill must
   keep matching the <input> sitting next to it. `option:hover` is left to
   the UA: Chromium draws the hover highlight itself and ignores the
   declaration anyway. */
.mphb-gs-standalone-page select option:checked {
	background-color: var(--sa-bg);
}

/* -- Merged phone field: country-code <select> + <input type=tel> inside one
   bordered container, so "email + phone on one row" (Ahmed, 27/07) doesn't
   waste a whole row on a 3-digit calling-code dropdown. The container alone
   owns the field-like background/border; the select and input themselves
   are transparent/borderless so the pair reads as a single input, matching
   the classic international-phone-field pattern. The select keeps posting
   `name="phone_country"` unchanged — StandalonePublicController::
   build_order_request_from_post() reads that exact key for Phone::to_e164();
   only the visual wrapper and its label changed, not the field name. */
.mphb-gs-standalone-page .mphb-gs-sa-phone-group {
	display: flex;
	min-width: 0;
	align-items: stretch;
	background: var(--sa-input-bg);
	border: 1px solid var(--sa-input-border);
	border-radius: var(--sa-radius-sm);
}
.mphb-gs-standalone-page .mphb-gs-sa-phone-group:focus-within {
	outline: 2px solid var(--sa-accent);
	outline-offset: 1px;
}
/* The select and input both force `dir="ltr"` in the markup (dial codes and
   phone numbers are LTR content even on the Arabic page — see
   standalone-phone-country-select.php's docblock for the bidi bug that
   caused: "+216" rendering as "216+"). Because each element's own content
   direction is therefore always ltr, its divider border is addressed with
   a plain physical `border-right` (not the `border-inline-end` logical
   property, which would resolve against that fixed ltr and never move) —
   the RTL rule below explicitly relocates it to the left instead, since
   what flips in RTL is only which side of the merged pill the select sits
   on (via .mphb-gs-sa-phone-group's own row-reverse), not the select's
   internal text direction. */
/* .mphb-gs-sa-phone-select is the wrapper standalone-phone-country-select.php
   renders (native select + custom trigger + custom listbox panel); IT is
   the actual flex child of .mphb-gs-sa-phone-group now (not the select
   directly, since the select sits one level deeper inside this wrapper). */
.mphb-gs-standalone-page .mphb-gs-sa-phone-select {
	position: relative;
	flex: 0 0 auto;
	width: 108px;
	max-width: 40%;
}
.mphb-gs-standalone-page .mphb-gs-sa-phone-group__select {
	width: 100%;
	height: 100%;
	background: transparent;
	border: none;
	border-right: 1px solid var(--sa-input-border);
	border-radius: var(--sa-radius-sm) 0 0 var(--sa-radius-sm);
	color: var(--sa-input-text);
	font-family: inherit;
	font-size: 0.9375rem;
	padding: 12px 8px 12px 14px;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	box-sizing: border-box;
}
.mphb-gs-standalone-page.is-rtl .mphb-gs-sa-phone-group__select {
	border-right: none;
	border-left: 1px solid var(--sa-input-border);
	border-radius: 0 var(--sa-radius-sm) var(--sa-radius-sm) 0;
	padding: 12px 14px 12px 8px;
}
/* Applied by standalone-header-controls.js once the custom trigger/listbox
   take over — a class, not an inline style, per the project's no-inline-CSS
   rule (the existing portal time-selector.js precedent hides its own
   native <select> via `style.cssText`; this avoids that). */
.mphb-gs-standalone-page .mphb-gs-sa-phone-group__select.is-sa-visually-hidden {
	position: absolute;
	inset-inline-start: 0;
	top: 0;
	width: 1px;
	height: 1px;
	padding: 0;
	border: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	opacity: 0;
	pointer-events: none;
}
/* Trigger: flag + 2-letter ISO code, filling the exact same slot the select
   occupied (same border/radius/divider treatment) so the merged pill looks
   identical whether enhanced or not. */
.mphb-gs-standalone-page .mphb-gs-sa-phone-select__trigger {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
	width: 100%;
	height: 100%;
	background: transparent;
	border: none;
	border-right: 1px solid var(--sa-input-border);
	border-radius: var(--sa-radius-sm) 0 0 var(--sa-radius-sm);
	color: var(--sa-input-text);
	font-family: inherit;
	font-size: 0.9375rem;
	font-weight: 600;
	padding: 12px 8px;
	cursor: pointer;
	box-sizing: border-box;
}
.mphb-gs-standalone-page.is-rtl .mphb-gs-sa-phone-select__trigger {
	border-right: none;
	border-left: 1px solid var(--sa-input-border);
	border-radius: 0 var(--sa-radius-sm) var(--sa-radius-sm) 0;
}
.mphb-gs-standalone-page .mphb-gs-sa-phone-select__flag {
	font-size: 1.125rem;
	line-height: 1;
}
.mphb-gs-standalone-page .mphb-gs-sa-phone-select__code {
	letter-spacing: 0.02em;
}
.mphb-gs-standalone-page .mphb-gs-sa-phone-select__panel {
	position: absolute;
	top: calc(100% + 8px);
	inset-inline-start: 0;
	z-index: 40;
	margin: 0;
	padding: 4px;
	min-width: 220px;
	max-height: 280px;
	overflow-y: auto;
	list-style: none;
	/* Same fix and same token as .mphb-gs-sa-lang-switcher__panel above —
	   see that rule's comment for both bugs this avoids (the dark-theme
	   translucent-card-token bug Ahmed flagged, and the light-theme
	   JS-var-remap bug my first fix attempt still had). */
	background: var(--sa-elevated-bg);
	border: 1px solid var(--sa-card-border);
	border-radius: var(--sa-radius);
	box-shadow: 0 8px 24px rgba(0, 0, 0, 0.24);
	direction: ltr;
	text-align: left;
}
.mphb-gs-standalone-page .mphb-gs-sa-phone-select__option {
	padding: 8px 10px;
	font-size: 0.875rem;
	color: var(--sa-text);
	border-radius: var(--sa-radius-sm);
	cursor: pointer;
	white-space: nowrap;
}
.mphb-gs-standalone-page .mphb-gs-sa-phone-select__option:hover,
.mphb-gs-standalone-page .mphb-gs-sa-phone-select__option:focus-visible {
	background: var(--sa-input-bg);
	outline: none;
}
.mphb-gs-standalone-page .mphb-gs-sa-phone-select__option.is-selected {
	background: var(--sa-accent);
	color: var(--sa-accent-contrast);
	font-weight: 600;
}
/* The container's own :focus-within ring (below) already fires whenever the
   trigger or a listbox option has focus, so no separate focus ring is
   needed on the trigger itself. */
.mphb-gs-standalone-page .mphb-gs-sa-phone-select__trigger:focus-visible {
	outline: none;
}
.mphb-gs-standalone-page .mphb-gs-sa-phone-group__input {
	flex: 1 1 auto;
	min-width: 0;
	background: transparent;
	border: none;
	color: var(--sa-input-text);
	font-family: inherit;
	font-size: 1rem;
	padding: 12px 14px;
	box-sizing: border-box;
}
.mphb-gs-standalone-page .mphb-gs-sa-phone-group__select:focus-visible,
.mphb-gs-standalone-page .mphb-gs-sa-phone-group__input:focus-visible {
	outline: none; /* the container's :focus-within ring is the only ring shown. */
}
/* No .is-rtl row-reverse rule here, unlike .mphb-gs-sa-field-row/-radio-row/
   -pax-row above: those deliberately CANCEL the container's own RTL
   mirroring (row-reverse under direction:rtl flips right back to a
   left-to-right visual flow — verified empirically, it isn't a no-op) so
   sibling fields keep reading in DOM order. Here Ahmed asked for the
   opposite: "the prefix moves to the right" — true RTL mirroring, prefix
   at the reading-start (right) with the number following it — which is
   exactly what .mphb-gs-sa-phone-group's plain `flex-direction: row`
   already does automatically once the container inherits direction:rtl;
   adding row-reverse here would cancel that and put the prefix back on
   the left, the opposite of what was asked. */

/* The HTML `dir="ltr"` attribute alone loses to the page's own
   `.mphb-gs-standalone-page.is-rtl { direction: rtl }` rule (higher CSS
   specificity beats the attribute's implicit UA rule), which is exactly
   what produced the "216+" bidi bug — force it back explicitly, scoped
   high enough to win. */
.mphb-gs-standalone-page.is-rtl .mphb-gs-sa-phone-group__select,
.mphb-gs-standalone-page.is-rtl .mphb-gs-sa-phone-group__input {
	direction: ltr;
}

.mphb-gs-sa-hint {
	color: var(--sa-muted);
	font-size: 0.875rem;
	margin: 8px 0 0;
}

.mphb-gs-sa-field-error {
	color: var(--sa-error);
	font-size: 0.8125rem;
	margin-top: 6px;
}
.mphb-gs-sa-field-row > .mphb-gs-sa-field-error {
	flex: 1 1 100%;
	order: 1;
	margin-top: 6px;
	text-align: start;
}

/* -- Honeypot: visually hidden but present in the DOM/tab order excluded. */
.mphb-gs-sa-honeypot {
	position: absolute;
	inset-inline-start: 0;
	top: 0;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

/* -- Radios ------------------------------------------------------------- */
.mphb-gs-sa-radio-row {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sa-gap);
	margin-bottom: var(--sa-gap);
}
.mphb-gs-sa-radio {
	display: flex;
	align-items: center;
	gap: 8px;
	color: var(--sa-text);
	cursor: pointer;
}
.mphb-gs-sa-radio[hidden] {
	display: none;
}

/* -- Choice cards -----------------------------------------------------------
   28/07 third pass (Ahmed: "instead of simple button for direction, use
   something more pretty like image" — reference: 3 selectable cards, a
   selection dot, a directional icon, a bold label, a route sub-label).
   Shared by standalone-step-trip.php's transfer-direction radios AND
   standalone-step-dates.php's delivery/pickup radios (Ahmed's own follow-up:
   "apply the same treatment to the car page's equivalent selector, for
   consistency") — one component, two content sets, same as
   `.mphb-gs-sa-choice-row` reusing `.mphb-gs-sa-radio-row`'s base gap/margin
   below rather than duplicating a second row layout.

   Unlike `.mphb-gs-sa-car-card` (this file's existing precedent for a
   card-wrapped radio), the native `<input type="radio">` here is NOT hidden
   off-screen — it renders at a deliberately larger size, tinted with
   `accent-color` so its own native "filled" checked state IS the reference's
   "pastille de sélection à gauche", a shape change any theme/browser
   understands with zero extra markup. The `:has()` rules below are a
   progressive ENHANCEMENT on top of that already-functional base state
   (border + background highlight when checked, a visible focus ring around
   the whole card, not just the small input) — a browser without `:has()`
   support still shows a correctly filled/empty native radio per card, so
   "selected" is never color-only and never depends on `:has()` to be
   understood at all. */
.mphb-gs-sa-choice-row {
	align-items: stretch;
}
.mphb-gs-sa-choice-row > .mphb-gs-sa-choice-card {
	flex: 1 1 220px;
}
/* Predictable one-per-line stacking on phones — see standalone-step-trip.php's
   own comment for why this is verified against the mobile-fold-fix's 414px
   floor: with 3 cards `flex: 1 1 220px` already wraps well before 414px, but
   forcing the column direction here (rather than leaving it to whatever
   flex-wrap happens to produce) keeps every card the same full width instead
   of an uneven last-row remainder. `flex-basis` MUST reset to `auto` here —
   caught by measurement, not assumed: `220px` is a WIDTH hint for the row
   layout above, but once `flex-direction` flips to `column` the exact same
   flex-basis is read as a HEIGHT target instead, stretching every stacked
   card to a fixed 220px tall regardless of its real (much shorter) content. */
@media (max-width: 480px) {
	.mphb-gs-sa-choice-row {
		flex-direction: column;
	}
	.mphb-gs-sa-choice-row > .mphb-gs-sa-choice-card {
		flex: 1 1 auto;
	}
}
.mphb-gs-sa-choice-card {
	align-items: center;
	gap: 10px;
	padding: 12px 14px;
	background: var(--sa-bg-alt);
	border: 1px solid var(--sa-card-border);
	border-radius: var(--sa-radius);
	transition: border-color var(--lw-transition), background-color var(--lw-transition);
}
.mphb-gs-sa-choice-card:hover {
	border-color: var(--sa-accent);
}
/* Selected: border color AND width both change (not color alone) — the
   filled native radio dot is the third, always-present signal underneath
   both. */
.mphb-gs-sa-choice-card:has(.mphb-gs-sa-choice-card__input:checked) {
	border-color: var(--sa-accent);
	border-width: 2px;
	padding: 11px 13px; /* -1px: keeps the card's outer box identical size as the border grows 1px->2px. */
	background: color-mix(in srgb, var(--sa-accent) 8%, var(--sa-bg-alt));
}
.mphb-gs-sa-choice-card:has(.mphb-gs-sa-choice-card__input:focus-visible) {
	outline: 2px solid var(--sa-accent);
	outline-offset: 2px;
}
.mphb-gs-sa-choice-card__input {
	flex: 0 0 auto;
	width: 18px;
	height: 18px;
	margin: 0;
	accent-color: var(--sa-accent);
}
.mphb-gs-sa-choice-card__icon {
	display: flex;
	flex: 0 0 auto;
	align-items: center;
	justify-content: center;
	width: 28px;
	height: 28px;
	color: var(--sa-accent);
}
.mphb-gs-sa-choice-card__icon-svg {
	width: 22px;
	height: 22px;
}
/* Only the transfer-direction icons carry this modifier (the car page's
   office/address pictograms don't — there is no left/right meaning to flip
   for "our office" vs "an address"). Mirrors visually in RTL so the arrow
   keeps pointing the same CONCEPTUAL way (into vs out of the villa) once the
   page's own reading direction flips — same convention already applied to
   the rest of this page's RTL handling (grid columns, stepper numbering).
   The round-trip icon is symmetric, so mirroring it is a harmless no-op. */
.is-rtl .mphb-gs-sa-choice-card__icon--directional .mphb-gs-sa-choice-card__icon-svg {
	transform: scaleX(-1);
}
.mphb-gs-sa-choice-card__text {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
}
.mphb-gs-sa-choice-card__label {
	color: var(--sa-heading);
	font-weight: 600;
	font-size: 0.875rem;
}
.mphb-gs-sa-choice-card__route {
	color: var(--sa-muted);
	font-size: 0.75rem;
}

/* -- Car cards ------------------------------------------------------------*/
.mphb-gs-sa-car-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
	gap: var(--sa-gap);
}
.mphb-gs-sa-car-card {
	display: flex;
	flex-direction: column;
	border: 2px solid var(--sa-card-border);
	border-radius: var(--sa-radius);
	overflow: hidden;
	cursor: pointer;
	background: var(--sa-bg-alt);
	transition: border-color var(--lw-transition);
}
.mphb-gs-sa-car-card:has(.mphb-gs-sa-car-card__radio:checked),
.mphb-gs-sa-car-card.is-active {
	border-color: var(--sa-accent);
}
.mphb-gs-sa-car-card__radio {
	position: absolute;
	inset-inline-start: 0;
	top: 0;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}
.mphb-gs-sa-car-card__media {
	aspect-ratio: 4 / 3;
	overflow: hidden;
	background: var(--sa-card-bg);
}
.mphb-gs-sa-car-card__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	max-width: 100%;
	display: block;
}
.mphb-gs-sa-car-card__body {
	padding: 12px 14px;
	display: flex;
	flex-direction: column;
	gap: 4px;
}
.mphb-gs-sa-car-card__name {
	color: var(--sa-heading);
	font-weight: 600;
}
.mphb-gs-sa-car-card__description {
	color: var(--sa-muted);
	font-size: 0.8125rem;
}
.mphb-gs-sa-car-card__price {
	color: var(--sa-accent);
	font-weight: 600;
	margin-top: 4px;
}

/* -- Price preview ----------------------------------------------------------*/
.mphb-gs-sa-price-preview {
	margin-top: var(--sa-gap);
	padding-top: var(--sa-gap);
	border-top: 1px solid var(--sa-border);
}
.mphb-gs-sa-price-preview__value {
	font-size: 1.5rem;
	font-weight: 700;
	color: var(--sa-heading);
}
.mphb-gs-sa-price-preview__value.is-error {
	color: var(--sa-error);
	font-size: 1rem;
	font-weight: 600;
}
.mphb-gs-sa-price-preview__duration {
	color: var(--sa-muted);
	margin-inline-start: 8px;
}
.mphb-gs-sa-price-preview__note {
	color: var(--sa-muted);
	font-size: 0.8125rem;
	margin: 4px 0 0;
}

/* -- Pax steppers: label + age line on the left, stepper on the right -- */
.mphb-gs-sa-pax-fieldset {
	border: 0;
	margin: var(--sa-gap) 0 0;
	min-width: 0;
	padding: 0;
}
.mphb-gs-sa-pax-legend {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
}
.mphb-gs-sa-pax-row {
	display: flex;
	flex-direction: column;
}
.mphb-gs-sa-pax-stepper {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	padding-block: 16px;
}
.mphb-gs-sa-pax-stepper:first-child {
	padding-top: 0;
}
.mphb-gs-sa-pax-stepper + .mphb-gs-sa-pax-stepper {
	border-top: 1px solid var(--sa-card-border);
}
.mphb-gs-sa-pax-stepper__text {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
}
.mphb-gs-sa-pax-stepper__label {
	font-weight: 600;
}
.mphb-gs-sa-pax-stepper__age {
	color: var(--sa-muted);
	font-size: 0.8125rem;
}
.mphb-gs-sa-pax-stepper__controls {
	align-items: center;
	display: grid;
	flex-shrink: 0;
	gap: 8px;
	grid-template-columns: 44px 48px 44px;
}
.mphb-gs-sa-stepper-btn {
	align-items: center;
	background: var(--sa-input-bg);
	border: 1px solid var(--sa-control-border);
	border-radius: 50%;
	color: var(--sa-input-text);
	cursor: pointer;
	display: grid;
	font-size: 1.25rem;
	height: 44px;
	justify-items: center;
	line-height: 1;
	padding: 0;
	width: 44px;
}
.mphb-gs-sa-stepper-btn:disabled {
	cursor: not-allowed;
	background: transparent;
	border-color: var(--sa-control-disabled-border);
	color: var(--sa-control-disabled-text);
}
.mphb-gs-standalone-page .mphb-gs-sa-pax-stepper .mphb-gs-sa-stepper-input {
	border: 1px solid var(--sa-control-border);
	border-radius: var(--sa-radius-sm);
	box-sizing: border-box;
	font-variant-numeric: tabular-nums;
	font-weight: 600;
	height: 44px;
	padding: 0;
	text-align: center;
	width: 48px;
}

/* -- Flight check (standalone-step-flight.php + standalone-checkout.js)
   ---------------------------------------------------------------------------
   `.mphb-gs-sa-flight-verdict` is the `role="status" aria-live="polite"` box
   JS fills in with one of FlightValidator::OUTCOME_*'s five messages.
   `data-sa-outcome` (set by standalone-checkout.js, never in the server
   markup — it ships without the attribute, i.e. this file's default/neutral
   colors, until a check actually runs) drives the accent color so a guest
   can tell a blocking problem (wrong_airport/malformed, --sa-error) from a
   resolved success (serves, --sa-success) from a "you may still continue"
   note (unknown/ambiguous, --sa-info) without reading the copy — the text
   itself remains the actual source of truth either way (a11y: color is
   never the ONLY signal, the message text says the same thing). */
.mphb-gs-sa-flight-lookup {
	display: flex;
	align-items: center;
	gap: 12px;
	margin-top: 8px;
}
.mphb-gs-sa-flight-verdict {
	margin-top: var(--sa-gap);
	padding: 12px 16px;
	border-radius: var(--sa-radius-sm);
	border-inline-start: 3px solid var(--sa-info);
	background: var(--lw-info-soft);
}
.mphb-gs-sa-flight-verdict[data-sa-outcome="serves"] {
	border-inline-start-color: var(--sa-success);
	background: var(--lw-success-soft);
}
.mphb-gs-sa-flight-verdict[data-sa-outcome="wrong_airport"],
.mphb-gs-sa-flight-verdict[data-sa-outcome="malformed"] {
	border-inline-start-color: var(--sa-error);
	background: var(--lw-error-soft);
}
.mphb-gs-sa-flight-verdict[data-sa-outcome="unknown"],
.mphb-gs-sa-flight-verdict[data-sa-outcome="ambiguous"] {
	border-inline-start-color: var(--sa-info);
	background: var(--lw-info-soft);
}
.mphb-gs-sa-flight-verdict__message {
	margin: 0;
	color: var(--sa-text);
	font-size: 0.875rem;
}
.mphb-gs-sa-flight-verdict__pickup {
	margin: 8px 0 0;
	color: var(--sa-heading);
	font-size: 0.875rem;
}
.mphb-gs-sa-flight-verdict__choices {
	/* Reset the browser's default fieldset chrome (border/padding/min-width)
	   so this reads as part of the same status box, not a nested form panel. */
	margin: 12px 0 0;
	padding: 0;
	border: 0;
	min-width: 0;
}
.mphb-gs-sa-flight-verdict__choices legend {
	padding: 0;
	margin: 0 0 8px;
	color: var(--sa-muted);
	font-size: 0.8125rem;
}
.mphb-gs-sa-flight-verdict__choice-list {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

/* -- Buttons ----------------------------------------------------------------*/
.mphb-gs-sa-btn-primary,
.mphb-gs-sa-btn-secondary {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	padding: 12px 22px;
	border-radius: var(--sa-radius-sm);
	font-weight: 600;
	font-size: 0.9375rem;
	cursor: pointer;
	border: 1px solid transparent;
}
.mphb-gs-sa-btn-primary {
	background: var(--sa-accent);
	color: var(--sa-accent-contrast);
}
.mphb-gs-sa-btn-primary:hover { opacity: 0.9; }
.mphb-gs-sa-btn-secondary {
	background: transparent;
	color: var(--sa-heading);
	border-color: var(--sa-accent);
}
/* "Continue" while its step's required fields aren't all filled yet (Task 6,
   assets/js/modules/standalone-wizard.js) — same opacity/cursor convention
   as .mphb-gs-sa-pay-btn:disabled below, so every disabled CTA on this page
   reads the same way. */
.mphb-gs-sa-btn-primary:disabled,
.mphb-gs-sa-btn-secondary:disabled {
	opacity: 0.6;
	cursor: not-allowed;
}
/* Verified flight check: filled success face, kept at full opacity so the
   confirmation does not read as "unavailable". Fill and text are per-theme
   literals: white fails on the dark-theme green, and the light-theme success
   token is not a fixed green. */
.mphb-gs-sa-btn-secondary.is-sa-verified {
	opacity: 1;
	cursor: default;
	background: var(--sa-verified-bg);
	border-color: var(--sa-verified-bg);
	color: var(--sa-verified-text);
}

/* -- Rules banner -------------------------------------------------------- */
.mphb-gs-sa-rules {
	margin-bottom: var(--sa-gap-lg);
}
.mphb-gs-sa-rules__line {
	margin: 0 0 8px;
	color: var(--sa-muted);
	font-size: 0.875rem;
}
.mphb-gs-sa-rules__line--warning {
	display: flex;
	align-items: flex-start;
	gap: 8px;
	color: var(--sa-text);
}
.mphb-gs-sa-rules__icon {
	display: inline-flex;
	flex: 0 0 auto;
	color: var(--sa-warning);
}
.mphb-gs-sa-rules__line a { color: var(--sa-accent); }

/* -- Payment CTA ------------------------------------------------------------*/
.mphb-gs-sa-payment { margin-top: var(--sa-gap); }
.mphb-gs-sa-form-error,
.mphb-gs-sa-form-success {
	border-radius: var(--sa-radius-sm);
	padding: 12px 16px;
	margin-bottom: var(--sa-gap);
	font-size: 0.9375rem;
}
.mphb-gs-sa-form-error {
	background: var(--lw-error-soft);
	color: var(--sa-error);
}
.mphb-gs-sa-form-success {
	background: var(--lw-success-soft);
	color: var(--sa-success);
}
.mphb-gs-sa-pay-buttons {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sa-gap);
}
.mphb-gs-sa-pay-btn {
	flex: 1 1 200px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	padding: 16px 24px;
	border-radius: var(--sa-radius);
	font-weight: 700;
	font-size: 1rem;
	cursor: pointer;
	border: 1px solid transparent;
	transition: opacity var(--lw-transition);
}
.mphb-gs-sa-pay-btn--stripe {
	background: var(--sa-accent);
	color: var(--sa-accent-contrast);
}
.mphb-gs-sa-pay-btn--paypal {
	background: transparent;
	color: var(--sa-heading);
	border-color: var(--sa-accent);
}
.mphb-gs-sa-pay-btn:disabled {
	opacity: 0.6;
	cursor: not-allowed;
}
.mphb-gs-sa-pay-btn__spinner,
.mphb-gs-sa-btn-secondary[data-sa-flight-check-btn][aria-busy="true"]::before {
	width: 16px;
	height: 16px;
	border-radius: 50%;
	border: 2px solid var(--lw-spinner-track);
	border-top-color: var(--lw-spinner-accent);
	animation: mphb-gs-sa-spin 0.7s linear infinite;
}
.mphb-gs-sa-pay-btn__spinner[hidden] { display: none; }
@keyframes mphb-gs-sa-spin {
	to { transform: rotate(360deg); }
}

/* Gateway icon inside each pay button (card glyph / PayPal wordmark, see
   standalone-payment-icons.php). `currentColor` in the SVGs means no color
   rule is needed here — the icon already inherits the button's own text
   color, so it's --sa-accent-contrast on the gold "Pay by card" button and
   --sa-heading on the outline "Pay with PayPal" button, same as the label
   next to it, in both themes. */
.mphb-gs-sa-pay-btn__icon {
	display: inline-flex;
	align-items: center;
	flex: 0 0 auto;
}
.mphb-gs-sa-pay-btn__icon svg {
	display: block;
	height: 19px;
	width: auto;
}
/* While the button is busy the spinner (its very next sibling in the DOM)
   is shown by clearing its `hidden` attribute (standalone-checkout.js);
   this hides the icon for as long as that's true, so the two never sit
   side by side or overlap — the spinner visually replaces the icon. */
.mphb-gs-sa-pay-btn__spinner:not([hidden]) ~ .mphb-gs-sa-pay-btn__icon {
	display: none;
}

/* -- Status card (order page) ------------------------------------------- */
.mphb-gs-sa-status-card {
	display: flex;
	align-items: flex-start;
	gap: 12px;
	border-radius: var(--sa-radius);
	padding: var(--sa-gap);
	margin-bottom: var(--sa-gap-lg);
	border: 1px solid var(--sa-border);
}
.mphb-gs-sa-status-card__icon {
	width: 24px;
	font-size: 24px;
	line-height: 1;
	flex: 0 0 24px;
}
.mphb-gs-sa-status-card__body { min-width: 0; flex: 1 1 auto; }
.mphb-gs-sa-status-card__label {
	display: block;
	font-size: 1.125rem;
	font-weight: 700;
	color: var(--sa-heading);
}
.mphb-gs-sa-status-card__desc {
	color: var(--sa-muted);
	margin: var(--sa-gap) 0 0;
}
.mphb-gs-sa-status-card__cta {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	margin-top: var(--sa-gap);
	color: var(--sa-heading);
	font-weight: 600;
	text-decoration: underline;
}
.mphb-gs-sa-status-card--success { border-color: var(--sa-success); background: var(--lw-success-soft); }
.mphb-gs-sa-status-card--success .mphb-gs-sa-status-card__icon { color: var(--sa-success); }
.mphb-gs-sa-status-card--pending { border-color: var(--sa-warning); background: var(--lw-warning-soft); }
.mphb-gs-sa-status-card--pending .mphb-gs-sa-status-card__icon { color: var(--sa-warning); }
.mphb-gs-sa-status-card--error { border-color: var(--sa-error); background: var(--lw-error-soft); }
.mphb-gs-sa-status-card--error .mphb-gs-sa-status-card__icon { color: var(--sa-error); }
.mphb-gs-sa-status-card--neutral { border-color: var(--sa-border); }

.mphb-gs-sa-order-total {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: 4px var(--sa-gap);
	margin: 0 0 var(--sa-gap-lg);
}
.mphb-gs-sa-order-total__label { color: var(--sa-muted); }
.mphb-gs-sa-order-total__amount {
	font-size: 1.25rem;
	font-weight: 700;
	color: var(--sa-heading);
}

/* -- Summary list --------------------------------------------------------*/
.mphb-gs-sa-summary { margin: 0; }
.mphb-gs-sa-summary__row {
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	gap: var(--sa-gap);
	padding: 10px 0;
	border-bottom: 1px solid var(--sa-border);
}
.mphb-gs-sa-summary__row:last-child { border-bottom: none; }
.mphb-gs-sa-summary__row dt { color: var(--sa-muted); }
.mphb-gs-sa-summary__row dd { margin: 0; color: var(--sa-heading); text-align: right; }
.mphb-gs-sa-summary__row dd + dd { flex: 1 1 100%; }
.is-rtl .mphb-gs-sa-summary__row dd { text-align: left; }

/* -- Footer ---------------------------------------------------------------*/
.mphb-gs-sa-footer {
	border-top: 1px solid var(--sa-border);
	padding-top: var(--sa-gap);
	margin-top: var(--sa-gap-lg);
	display: flex;
	flex-wrap: wrap;
	gap: var(--sa-gap);
	justify-content: space-between;
	color: var(--sa-muted);
	font-size: 0.875rem;
}
.mphb-gs-sa-footer a { color: var(--sa-accent); }
.mphb-gs-sa-footer__whatsapp {
	color: var(--sa-success);
	font-weight: 600;
}

/* -- Mobile-first tweaks ----------------------------------------------------*/
@media (max-width: 640px) {
	.mphb-gs-sa-shell { padding: 0 16px 48px; }
	.mphb-gs-sa-pay-btn { flex: 1 1 100%; }
	.mphb-gs-sa-car-grid { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); }
	.mphb-gs-sa-header__logo { height: 32px; }
	/* Email + merged phone field: one column on mobile, not a shrink race
	   that would squeeze the calling-code select unreadably narrow. */
	.mphb-gs-sa-field-row--email-phone .mphb-gs-sa-field-group {
		flex: 1 1 100%;
	}
	.mphb-gs-sa-phone-select { width: 92px; }
	.mphb-gs-standalone-page .mphb-gs-sa-pickup-suggestions {
		position: static;
		margin-top: 4px;
	}
	.mphb-gs-sa-lang-switcher__trigger { padding: 6px 8px; font-size: 0.8125rem; }
	.mphb-gs-sa-lang-switcher__panel,
	.mphb-gs-sa-phone-select__panel { min-width: 0; max-width: calc(100vw - 32px); }
	/* Icon-only toggle at mobile widths — the label's meaning still reaches
	   assistive tech via the button's own aria-label regardless.
	   `.mphb-gs-standalone-page` qualifier matches this rule's specificity
	   to the light-theme "show the moon label" rule above (both (0,2,0)) so
	   it wins on source order, no !important needed. */
	.mphb-gs-sa-theme-toggle { padding: 8px; }
	.mphb-gs-standalone-page .mphb-gs-sa-theme-toggle__label { display: none; }
}

/* ==========================================================================
   Wizard shell (Task 5: templates/partials/standalone-wizard.php +
   standalone-summary.php) — stepper, panes, prev/next nav, live summary.
   Task 6 (assets/js/modules/standalone-wizard.js) owns the runtime
   behavior (one pane at a time, Continue gating, live summary values);
   this section owns the structural/responsive rules its brief already
   specifies: the paired [hidden] rule for pane/summary visibility, the
   640px stepper-label breakpoint, and the 900px sticky-aside/bottom-bar
   split. Task 6 may extend these rules (state-transition styling etc.) —
   that is additive, not a conflict.
   ========================================================================== */

.mphb-gs-sa-wizard { margin-bottom: var(--sa-gap-lg); }

/* -- Stepper ----------------------------------------------------------- */
.mphb-gs-sa-stepper { margin-bottom: var(--sa-gap-lg); }
.mphb-gs-sa-stepper__list {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	row-gap: var(--sa-gap);
	column-gap: 48px;
	margin: 0;
	padding: 0;
	list-style: none;
	counter-reset: sa-step;
}
.mphb-gs-sa-stepper__step {
	position: relative;
	display: flex;
	align-items: flex-start;
	gap: 12px;
	color: var(--sa-muted);
	font-size: 0.875rem;
}
/* Numbers come from the step's position in the stepper (CSS counter); the
   markup carries no number text. */
.mphb-gs-sa-stepper__number {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 28px;
	height: 28px;
	border-radius: 50%;
	border: 1px solid var(--sa-border);
	color: var(--sa-muted);
	font-weight: 700;
	font-size: 0.8125rem;
}
.mphb-gs-sa-stepper__step:not([data-sa-step-off]) .mphb-gs-sa-stepper__number::before {
	counter-increment: sa-step;
	content: counter(sa-step);
}
.mphb-gs-sa-stepper__step.is-sa-done .mphb-gs-sa-stepper__number::before {
	content: "\2713";
}
.mphb-gs-sa-stepper__done-sr {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
	padding: 0;
}
.mphb-gs-sa-stepper__step:not(.is-sa-done) .mphb-gs-sa-stepper__done-sr { display: none; }
.mphb-gs-sa-stepper__label {
	min-width: 0;
	padding-top: 3px;
	overflow: hidden;
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
}
/* Connector between pastilles: drawn into the list gap on the start side of
   each step after the first, centred on the 28px pastille (top 13px + 2px
   line). The 48px column gap leaves 10px clear on both sides of the 28px
   line so it never touches the previous label or the next pastille. The
   accent rule carries the list ancestor so it outranks the base connector
   rule. */
.mphb-gs-sa-stepper__step ~ .mphb-gs-sa-stepper__step::before {
	content: "";
	position: absolute;
	inset-block-start: 13px;
	inset-inline-end: calc(100% + 10px);
	width: 28px;
	height: 2px;
	background: var(--sa-border);
}
.mphb-gs-sa-stepper__list .mphb-gs-sa-stepper__step.is-sa-after-done::before {
	background: var(--sa-accent);
}
/* Current step: filled accent circle, heading-weight label. */
.mphb-gs-sa-stepper__step.is-sa-current .mphb-gs-sa-stepper__number {
	border-color: var(--sa-accent);
	background: var(--sa-accent);
	color: var(--sa-accent-contrast);
}
.mphb-gs-sa-stepper__step.is-sa-current .mphb-gs-sa-stepper__label {
	color: var(--sa-heading);
	font-weight: 600;
}
/* Done step: outline accent circle (not filled — filled is reserved for
   "you are here"), text-colored label. */
.mphb-gs-sa-stepper__step.is-sa-done .mphb-gs-sa-stepper__number {
	border-color: var(--sa-accent);
	color: var(--sa-accent);
}
.mphb-gs-sa-stepper__step.is-sa-done .mphb-gs-sa-stepper__label { color: var(--sa-text); }

/* -- Panes --------------------------------------------------------------
   Every .mphb-gs-sa-pane ships fully visible (no [hidden] in the markup,
   no class here ever sets display on it) — that is the no-JS fallback the
   task brief requires. Task 6 adds/removes [hidden] at runtime to show one
   pane at a time; this pairing is what makes that removal actually hide
   the element instead of being silently beaten by a class rule (the exact
   failure mode documented above for .mphb-gs-sa-lang-switcher__panel).

   28/07 layout rework (Ahmed: "la zone de saisie doit avoir des contours
   comme l'étape vos coordonnées"): the shell now gives every pane the same
   card treatment `.mphb-gs-sa-block` already had (background/border/
   radius/padding) — previously only the shared contact-block partial
   carried its OWN wrapper with that look, so every OTHER step (trip,
   passengers, vehicle, dates, driver, payment) rendered as bare text
   floating on the page background, which is exactly what read as "buggy"
   in Ahmed's screenshot. One rule here instead of recopying a wrapper into
   five step partials (spec's own "one shared shell" principle). NOT
   `margin-bottom` though, unlike `.mphb-gs-sa-block`: panes are spaced by
   `.mphb-gs-sa-panes`'s own flex `gap` below, so adding it here would
   double up the gap in the always-fully-visible no-JS fallback. Reusing
   this same card visually merged `standalone-contact-block.php`'s OWN
   `.mphb-gs-sa-block` wrapper into a double card (border-inside-a-border,
   double padding) — removed there; see that file's own docblock. */
.mphb-gs-sa-pane {
	background: var(--sa-card-bg);
	border: 1px solid var(--sa-card-border);
	border-radius: var(--sa-radius);
	padding: var(--sa-gap);
}
.mphb-gs-sa-pane[hidden] { display: none; }
.mphb-gs-sa-stepper__step[data-sa-step-off],
.mphb-gs-sa-pane[data-sa-step-off] {
	display: none;
}
.mphb-gs-sa-pane:focus { outline: none; }
.mphb-gs-sa-pane__placeholder { color: var(--sa-muted); }
/* Subtle entrance when Task 6's JS reveals a pane (removes [hidden]) — never
   the sole way state communicates (that's [hidden] above), purely cosmetic.
   Scoped to `[data-sa-wizard-init]` (set by initWizard() itself once it has
   actually run) so a no-JS visitor — every pane visible at once, none ever
   carrying [hidden] — never gets every pane fading in simultaneously; the
   selector without that scope would have matched them too. Further scoped
   inside `no-preference` so a `prefers-reduced-motion: reduce` visitor gets
   no animation at all rather than a reduced one. */
@media (prefers-reduced-motion: no-preference) {
	.mphb-gs-sa-wizard[data-sa-wizard-init] .mphb-gs-sa-pane:not([hidden]) {
		animation: mphb-gs-sa-pane-in 0.2s ease;
	}
}
@keyframes mphb-gs-sa-pane-in {
	from { opacity: 0; transform: translateY(4px); }
	to { opacity: 1; transform: translateY(0); }
}
.mphb-gs-sa-pane__nav {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	gap: var(--sa-gap);
	margin-top: var(--sa-gap);
}
/* Wraps the hint + "Continue" as one unit (28/07 "why is Continue grey?"
   fix, standalone-wizard.php's own docblock) so the hint sits directly
   above the button it explains, and so pushing "Continue" to the trailing
   edge (see the rule below, moved from the bare button to this wrapper)
   still works whether or not "Previous" is also present. */
.mphb-gs-sa-pane__next-group {
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 6px;
}
/* Pushes the next-group to the trailing edge whether or not "Previous" is
   also present (first pane has no Previous) — avoids a :has() dependency. */
.mphb-gs-sa-pane__nav .mphb-gs-sa-pane__next-group { margin-inline-start: auto; }
/* Empty by default (see standalone-wizard.php's docblock for why this is
   never `[hidden]`): no padding/border of its own, so a `<p>` with no text
   content renders at zero height — nothing to see, nothing announced, but
   still a valid aria-live/aria-describedby target the instant JS gives it
   text. `max-width` keeps a long translation from stretching the button
   row wider than the pane itself before it wraps. */
.mphb-gs-sa-pane__hint {
	margin: 0;
	max-width: 100%;
	color: var(--sa-muted);
	font-size: 0.8125rem;
	text-align: end;
}

/* -- Layout: panes column + reassure/summary right column -----------------
   Three children (28/07 layout rework): `.mphb-gs-sa-panes`,
   `.mphb-gs-sa-reassure` and `.mphb-gs-sa-wizard-summary`, in that DOM
   order (28/07 mobile-fold fix, second pass same day — see
   standalone-wizard.php's own comment: the first pass had reassure BEFORE
   panes, measured on live prod to push the first form field behind the
   fixed bottom bar at 414px). At ≥900px this plain flex column is
   overridden by the grid below, which places each child by named area,
   independent of DOM order — the desktop "reassure above the recap" visual
   is unaffected by this reorder. At <900px, with no grid, this flex column
   renders straight in DOM order: panes, then reassure (full copy, still
   reachable, spec suggestion (a) "under the form"), then the summary card
   (which the <900px media query below takes out of flow into a fixed
   bottom bar anyway, so its position here is moot). */
.mphb-gs-sa-wizard__layout {
	display: flex;
	flex-direction: column;
	gap: var(--sa-gap-lg);
}
.mphb-gs-sa-panes {
	display: flex;
	flex-direction: column;
	gap: var(--sa-gap-lg);
	min-width: 0; /* let a grid/flex sibling shrink instead of overflowing at 414px */
}

/* -- Live summary (sticky aside ≥900px / bottom bar below) --------------- */
.mphb-gs-sa-wizard-summary {
	background: var(--sa-card-bg);
	border: 1px solid var(--sa-card-border);
	border-radius: var(--sa-radius);
	padding: var(--sa-gap);
}
.mphb-gs-sa-wizard-summary__total {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: var(--sa-gap);
}
.mphb-gs-sa-wizard-summary__total-label { color: var(--sa-muted); font-size: 0.875rem; }
.mphb-gs-sa-wizard-summary__total-value { color: var(--sa-heading); font-size: 1.375rem; font-weight: 700; }
.mphb-gs-sa-wizard-summary__note {
	margin: 0 0 var(--sa-gap);
	color: var(--sa-muted);
	font-size: 0.8125rem;
}
/* Disclosure toggle: irrelevant ≥900px (the breakdown is always expanded
   there, see the media query below) — hidden by default, shown only under
   900px. */
.mphb-gs-sa-wizard-summary__toggle {
	display: none;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	width: 100%;
	margin-top: var(--sa-gap);
	padding: 10px 14px;
	border: 1px solid var(--sa-border);
	border-radius: var(--sa-radius-sm);
	background: transparent;
	color: var(--sa-heading);
	font-family: inherit;
	font-weight: 600;
	font-size: 0.875rem;
	cursor: pointer;
}
.mphb-gs-sa-wizard-summary__toggle-chevron {
	width: 14px;
	height: 14px;
	flex: 0 0 auto;
	transition: transform 0.15s ease;
}
.mphb-gs-sa-wizard-summary__toggle[aria-expanded="true"] .mphb-gs-sa-wizard-summary__toggle-chevron {
	transform: rotate(180deg);
}
@media (prefers-reduced-motion: reduce) {
	.mphb-gs-sa-wizard-summary__toggle-chevron { transition: none; }
}
/* Bottom-bar payment action (standalone-summary.php, spec §2.1). Never in
   the ≥900px sticky aside — the payment pane's own buttons are already on
   screen there, a second copy would just be a duplicate CTA — so the base
   rule hides it and only the <900px bar shows it. The `[hidden]` rule comes
   LAST and on a higher-specificity selector on purpose: standalone-wizard.js
   drives visibility per step through that attribute, and a class rule that
   silently outranked it is exactly how a "stuck open" panel shipped once
   before (project memory). `margin-top` keeps it off the total/note block
   above (never two blocks touching). */
.mphb-gs-sa-wizard-summary__pay {
	display: none;
	margin-top: var(--sa-gap);
}
.mphb-gs-sa-wizard-summary__pay .mphb-gs-sa-pay-btn { width: 100%; }
.mphb-gs-sa-wizard-summary__body { margin-top: var(--sa-gap); }
/* Same [hidden] pairing rule as every other disclosure on this page (lang
   switcher panel, pay-button spinner) — ships expanded (no [hidden]) so a
   no-JS visitor always sees the full breakdown; Task 6 collapses it by
   default under 900px, and re-derives that state from the breakpoint itself
   (not just from the toggle click) on every resize that crosses 900px —
   the fix for the stale-[hidden]-after-resize edge case flagged in Task 5's
   report lives in assets/js/modules/standalone-wizard.js's
   `applyBreakpointState()`, driven by a `matchMedia('(min-width: 900px)')`
   listener rather than a plain `resize` handler. */
.mphb-gs-sa-wizard-summary__body[hidden] { display: none; }
.mphb-gs-sa-wizard-summary__row {
	display: flex;
	justify-content: space-between;
	gap: var(--sa-gap);
	padding: 8px 0;
	border-bottom: 1px solid var(--sa-border);
	font-size: 0.875rem;
}
.mphb-gs-sa-wizard-summary__row:last-child { border-bottom: none; }
.mphb-gs-sa-wizard-summary__row[hidden] { display: none; }
.mphb-gs-sa-wizard-summary__row-label { color: var(--sa-muted); }
.mphb-gs-sa-wizard-summary__row-value { color: var(--sa-heading); text-align: right; }
.is-rtl .mphb-gs-sa-wizard-summary__row-value { text-align: left; }
/* `dates`/`total` bidi isolation (Task 9 fix, standalone-summary.php's own
   docblock): those two value nodes carry `dir="ltr"` in the markup because
   their live content mixes LTR date/currency digits with RTL-adjacent
   punctuation/words. Same pitfall already documented above for the phone
   field applies — the page's own `.is-rtl { direction: rtl }` rule beats the
   attribute's implicit UA styling on specificity, so it must be forced back
   explicitly, scoped high enough to win. */
.is-rtl .mphb-gs-sa-wizard-summary__total-value[dir="ltr"],
.is-rtl .mphb-gs-sa-wizard-summary__row-value[dir="ltr"] {
	direction: ltr;
}

@media (min-width: 900px) {
	.mphb-gs-sa-wizard__layout {
		display: grid;
		/* direction: rtl on the page (.is-rtl) mirrors which physical side
		   each track renders on automatically — no separate RTL override
		   needed here, unlike the flex row-reverse pairs elsewhere in this
		   file. */
		grid-template-columns: minmax(0, 1fr) 320px;
		/* Named areas — panes spans both rows in column 1; summary then
		   reassure stack in column 2, in that visual order, independent of
		   DOM order (the mobile-fold fix put reassure AFTER panes in the
		   markup — see standalone-wizard.php's own comment — but named grid
		   areas place children by name, not source position).
		   28/07 density fix (third pass, Ahmed: "le récapitulatif est
		   l'élément opérationnel [...] la réassurance est un argument, pas un
		   outil"): swapped from `"panes reassure" / "panes summary"` (the
		   28/07 second-pass order) to summary FIRST. The summary — filled
		   live while the guest types, the thing they actually consult — no
		   longer waits behind a 250px+ argument-for-trust card at the top of
		   the right column; reassurance now sits below it, where a guest
		   still reaches it but it can never push the summary under the fold
		   on a short viewport (landscape phone, small laptop).
		   `grid-template-rows: auto 1fr` is still load-bearing, not
		   decorative — same mechanism as before the swap, just mirrored: with
		   both rows left at the `auto` default, the grid track-sizing
		   algorithm distributes `panes`' height (much taller than either
		   column-2 card alone) into whichever row is NOT the flexible one,
		   producing a huge gap in front of the row-2 content instead of the
		   intended `--sa-gap-lg`. Row 1 (now summary) stays `auto`-sized to
		   its own content; row 2 (now reassure, `1fr`) absorbs the leftover
		   height `panes` needs — any resulting blank space lands BELOW
		   reassure, past the last real content, not between the two cards. */
		grid-template-rows: auto 1fr;
		grid-template-areas:
			"panes summary"
			"panes reassure";
		align-items: start;
		gap: var(--sa-gap-lg);
	}
	.mphb-gs-sa-panes { grid-area: panes; }
	.mphb-gs-sa-reassure { grid-area: reassure; }
	.mphb-gs-sa-wizard-summary {
		grid-area: summary;
		position: sticky;
		top: 24px;
	}
}

@media (max-width: 899px) {
	/* The fixed bar owns the pay action below 900px; the card's copy would
	   make two visible pay buttons on the payment step. */
	.mphb-gs-sa-wizard .mphb-gs-sa-pay-buttons { display: none; }
	.mphb-gs-sa-shell { padding-bottom: calc(64px + var(--sa-summary-bar-h, 96px)); }
	/* Clearance so the fixed bottom bar never covers the last pane's own
	   content/buttons. Derived from the bar's MEASURED height
	   (`--sa-summary-bar-h`, published by standalone-wizard.js's
	   `syncBarClearance()`) plus one gap of breathing room: the bar is
	   taller on the payment step (it carries the pay button), taller again
	   when the breakdown is expanded, and taller still in the locales whose
	   copy wraps to more lines — the flat 96px this used to be was already
	   short enough at 414px for the bar to sit on the last pane's content.
	   The literal is the no-JS/pre-measurement fallback only. */
	.mphb-gs-sa-wizard { padding-bottom: calc(var(--sa-summary-bar-h, 96px) + var(--sa-gap)); }
	.mphb-gs-sa-wizard-summary {
		position: fixed;
		inset-inline: 0;
		bottom: 0;
		z-index: 40;
		/* OPAQUE once it floats. --sa-card-bg is rgba(255,255,255,0.06):
		   fine for a card sitting in the flow, but as a fixed bar it let the
		   pane scrolling underneath show straight through the total, the
		   step numbers bleeding across the pay button (measured on dev at
		   414px). Same reasoning, same token as the language panel above —
		   --sa-elevated-bg is the page's opaque surface for floating UI and
		   is defined for BOTH themes. */
		background: var(--sa-elevated-bg);
		border-radius: var(--sa-radius) var(--sa-radius) 0 0;
		border-bottom: none;
		box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.15);
		/* Collapsed: total and disclosure toggle share one row. Pay button and
		   breakdown span the full width below. Their margin-top (not a row-gap)
		   carries the spacing, so a hidden pay button or breakdown leaves no
		   empty track behind. */
		display: grid;
		grid-template-columns: minmax(0, 1fr) auto;
		align-items: center;
		column-gap: 12px;
		padding: 12px var(--sa-gap);
	}
	.mphb-gs-sa-wizard-summary__toggle {
		display: flex;
		grid-column: 2;
		width: auto;
		margin-top: 0;
	}
	.mphb-gs-sa-wizard-summary__pay {
		display: block;
		grid-column: 1 / -1;
	}
	.mphb-gs-sa-wizard-summary__body {
		grid-column: 1 / -1;
		max-height: 40vh;
		overflow: auto;
	}
	/* Total stays on one line: a wrapped label made the collapsed bar 76px at
	   390px (budget 72px). The label gives way with an ellipsis, not the value. */
	.mphb-gs-sa-wizard-summary__total { white-space: nowrap; min-width: 0; }
	.mphb-gs-sa-wizard-summary__total-label {
		min-width: 0;
		overflow: hidden;
		text-overflow: ellipsis;
	}
}

/* Wins over the `display: block` above (attribute selector, declared later):
   the per-step visibility standalone-wizard.js sets must always be the last
   word. */
.mphb-gs-sa-wizard-summary__pay[hidden] { display: none; }

@media (max-width: 640px) {
	.mphb-gs-sa-stepper__list {
		display: flex;
		flex-wrap: nowrap;
		column-gap: 8px;
		align-items: flex-start;
	}
	.mphb-gs-sa-stepper__step {
		flex: 1 1 0;
		min-width: 0;
		flex-direction: column;
		align-items: center;
		text-align: center;
		gap: 6px;
	}
	.mphb-gs-sa-stepper__label {
		padding-top: 0;
		font-size: 0.6875rem;
		line-height: 1.2;
		hyphens: auto;
		overflow-wrap: anywhere;
	}
	.mphb-gs-sa-pane__nav {
		display: grid;
		grid-template-columns: 1fr 1fr;
		gap: 12px;
		align-items: stretch;
	}
	.mphb-gs-sa-pane__next-group { display: contents; }
	.mphb-gs-sa-pane__nav .mphb-gs-sa-btn-secondary { width: 100%; }
	.mphb-gs-sa-pane__next-group .mphb-gs-sa-btn-primary {
		grid-column: 2;
		width: 100%;
	}
	.mphb-gs-sa-pane__hint {
		grid-column: 1 / -1;
		order: -1;
		text-align: start;
	}
	/* Single grid row (auto-fit tracks), so the connector spans the previous
	   column: from the previous pastille's edge back across the column gap to
	   this pastille's edge, with 6px clear at each end. */
	.mphb-gs-sa-stepper__step ~ .mphb-gs-sa-stepper__step::before {
		inset-inline-end: auto;
		inset-inline-start: calc(-50% - 8px + 14px + 6px);
		width: calc(100% - 20px - 12px);
	}
	.mphb-gs-sa-flight-lookup .mphb-gs-sa-btn-secondary { width: 100%; }
}
