/**
 * Boss & Bubs Taxi — the booking page (P8, D138; P14 layers; P26 six screens,
 * four since P30).
 *
 * Authored mobile-first. The base rules ARE the 390 layout; two min-width
 * layers add the 834 and 1280 layouts (PRODUCT.md §6, spec/11-REBUILD-BRIEF.md
 * R8). Nothing here is a desktop layout overridden downwards.
 *
 * P14 (items 3/4, 6), P42 (D171): from 834 the operator's photo, full-bleed
 * under a navy shade, with the intro in white on the left and the booking
 * card on the right. On the photo only the shaded intro and opaque cards
 * (booking-backdrop-test.php). The breakdown sheet (a native dialog)
 * carries the trip summary and the fare line by line.
 *
 * P26 (D154): short screens (four since P30, D158), in one card - one column
 * below 834, the right-hand column from 834 (P42). The price sits in the card's header, opposite
 * the step count, and opens the sheet; Back and Continue / Pay sit in normal
 * flow at the card's foot. The sticky bottom bar is deleted, and with it the
 * only sticky element the product had. There is no map on any screen (P27,
 * D155): the connector rail and Screen 4's trip card draw the route.
 *
 * Positioning. Nothing below is absolutely positioned except the address
 * suggestions list, which spans its own input (left: 0; right: 0) and has no
 * width of its own, and the 1px screen-reader-only text (.bb-visually-hidden).
 * The photo and the stack share one grid; the locate chip shares its input's
 * cell. The sheet is a modal dialog, which the browser places in its own top
 * layer.
 *
 * No literal hex, font-size, border-radius or box-shadow value - each one is
 * a var(--...) from tokens.css. Type does not rescale (D50); only layout and
 * spacing respond. Every control a finger lands on is at least 44px (D127).
 * Motion exists only inside prefers-reduced-motion: no-preference.
 */

.bb-scope,
.bb-scope *,
.bb-scope *::before,
.bb-scope *::after {
	box-sizing: border-box;
}

.bb-scope {
	display: block;
}

/* Every element the scripts show and hide stays hidden whatever display its
   own rule gives it (10-PITFALLS.md #10: an empty or hidden status element
   takes no space). */
.bb-scope [hidden] {
	display: none !important;
}

.bb-scope :focus-visible {
	outline: 2px solid var(--focus);
	outline-offset: 2px;
}
/* P9 keyboard pass (D139): a native date or time input takes focus on its
   inner day/month/year or hour/minute segment, so the input itself never
   matches :focus-visible and showed no ring at all. :focus-within on the
   field draws the same ring while any segment has focus. */
.bb-scope input[type="date"]:focus-within,
.bb-scope input[type="time"]:focus-within,
.bb-scope select.bb-select:focus {
	outline: 2px solid var(--focus);
	outline-offset: 2px;
}
/* P32 (D161, A6): the time dropdown takes the same ring as the date beside
   it - a tapped select does not match :focus-visible either - and the
   field's own box (.bb-input): 48px tall, full width, 16px type. */
.bb-select {
	cursor: pointer;
}

/* ===================================================================
 * PAGE LAYOUT (P14, items 3/4; P26; P42)
 *
 * One grid, three things in it:
 * 1. the photo (.bb-booking-backdrop) - bottom, full-bleed, from 834 only;
 * 2. the intro (.bb-booking-intro) - the heading and three lines;
 * 3. the stack - the quote banner (no Maps key only) and the booking card.
 * P42 (D171, spec/14-CORRECTIONS-BRIEF.md): below 834 one column - the
 * intro, then the card, on the page's --base. From 834 two columns inside
 * the 1280 container, the intro on the left in white on the navy-shaded
 * photo, the card on the right. The photo spans every row, so the band is
 * the card's height plus a margin above and below it, and the intro is
 * centred against the card. Later grid items paint over earlier ones: no
 * z-index, no offsets.
 * =================================================================== */

.bb-booking {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	/* 1.2.3: the photo band covers the first two rows (the intro) below 834. */
	grid-template-rows: 16px auto auto 24px;
	max-width: 1280px;
	margin: 0 auto;
}

/* Full-bleed. The grid sits inside the theme's gutter, so the photo steps
   out to the viewport's edges. 100vw includes a desktop scrollbar; the
   theme's .bb-page-card clips that overflow (overflow: clip, D47), so no
   horizontal scrollbar appears. The navy gradient is what shows if no photo
   prints, and under the photo while it loads.
   1.2.3: shown at every width. Below 834 it is a band behind the intro, and
   the card sits under it on the page background; from 834 it runs behind
   both columns. */
.bb-booking-backdrop {
	display: block;
	position: relative;
	grid-column: 1 / -1;
	grid-row: 1 / 3;
	width: 100vw;
	margin-inline: calc(50% - 50vw);
	overflow: hidden;
	overflow: clip;
	background: linear-gradient(160deg, var(--harbour) 0%, var(--harbour-deep) 100%);
}
/* P42 (D171): the navy shade over the photo, 85% on the left to 40% on the
   right. The only thing generated onto the photo (booking-backdrop-test.php):
   it is what the white intro text is measured against. */
.bb-booking-backdrop::after {
	content: '';
	position: absolute;
	inset: 0;
	/* 1.2.3: below 834 the text runs the full width, so the shade is an even
	   85% (white on it over a pure white pixel: 9:1+). The left-to-right
	   gradient starts at 834. */
	background: var(--hero-scrim-left);
}
/* The photo is decoration: it fills the band and is cropped to it. Out of
   flow, so its own height never sizes the band - the card does. */
.bb-booking-backdrop-img {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	max-width: none;
	height: 100%;
	object-fit: cover;
	object-position: center 30%;
}

/* P42 (D171): the heading and three lines, in white on the shaded photo at
   every width (1.2.3). Below 834 they sit above the card. */
.bb-booking-intro {
	grid-column: 1;
	grid-row: 2;
	/* 1.2.1: positioned, so it paints above the positioned photo layer
	   (.bb-booking-backdrop) instead of under it - an unpositioned grid item
	   is painted before every positioned one, whatever the source order. */
	position: relative;
	min-width: 0;
	margin: 0;
	padding: 20px 0 28px;
	color: var(--on-navy);
	--focus: var(--focus-on-dark);
}
.bb-booking-intro-title {
	margin: 0 0 12px;
	font-size: var(--t-24);
	font-weight: 800;
	line-height: 1.2;
	letter-spacing: -0.01em;
	color: inherit;
}
.bb-booking-intro-list {
	display: grid;
	gap: 8px;
	margin: 0;
	padding: 0;
	list-style: none;
}
.bb-booking-intro-item {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	font-size: var(--t-16);
	font-weight: 600;
	line-height: 1.4;
}
/* 1.3.0: each line is a title and one plain sentence under it. */
.bb-booking-intro-text {
	display: flex;
	flex-direction: column;
	gap: 2px;
}
.bb-booking-intro-text strong {
	font-weight: 800;
}
.bb-booking-intro-text > span {
	font-size: var(--t-14);
	font-weight: 500;
	opacity: 0.92;
}
.bb-booking-intro-item .bb-booking-intro-icon {
	flex: none;
	margin: 0;
	color: var(--on-navy);
}
.bb-booking-intro-item .bb-booking-intro-icon svg {
	width: 22px;
	height: 22px;
}

.bb-booking-stack {
	grid-column: 1;
	grid-row: 3;
	/* 1.2.1: positioned, so it paints above the positioned photo layer
	   (.bb-booking-backdrop) instead of under it - an unpositioned grid item
	   is painted before every positioned one, whatever the source order. */
	position: relative;
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 12px;
	min-width: 0;
	/* 1.3.7: never wider than a comfortable form (tablets, wide pages). */
	width: 100%;
	max-width: 560px;
	margin-top: 16px;
}
/* On the photo the card needs a real edge, not the flat page's hairline. */
.bb-booking-stack > .bb-booking-card {
	box-shadow: var(--shadow-pop);
}

/* ===================================================================
 * THE CARD
 * =================================================================== */

.bb-booking-card {
	/* 1.3.7: the same cap when the form is placed on a wide page of its own. */
	max-width: 640px;
	padding: 20px;
	border: 1px solid var(--card-edge);
	border-radius: var(--r-card);
	background: var(--paper);
	box-shadow: var(--shadow-card);
	/* D47, 10-PITFALLS.md #9: `hidden` first as the fallback, `clip` second,
	   so the card crops its corners without becoming a scroll container. */
	overflow: hidden;
	overflow: clip;
}

/* P26 (D154): the step count on the left; P34 (D163): the trip summary on the right. */
.bb-booking-card-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
}
.bb-booking-step {
	flex-shrink: 0;
	/* D106: --muted, not --faint, for active text. */
	color: var(--muted);
	font-size: var(--t-13);
	font-weight: 700;
	white-space: nowrap;
}

/* P34 (D163): the trip summary - route, then date and time - on Screens 2
   to 4 (booking-format.js tripHeadline()). No price. A button, because it
   opens the trip details sheet; the chevron says so. Each line is one line
   at every width, cut with an ellipsis; the full trip is in the sheet. Its
   max width leaves "Step N of 4" room, so the step count never wraps. */
.bb-trip-head {
	display: flex;
	align-items: center;
	gap: 6px;
	min-width: 0;
	max-width: calc(100% - 96px);
	min-height: 44px;
	margin: 0;
	padding: 0;
	border: 0;
	background: transparent;
	color: var(--harbour);
	font-family: var(--font);
	text-align: right;
	cursor: pointer;
}
.bb-trip-head-text {
	display: grid;
	justify-items: end;
	min-width: 0;
}
.bb-trip-head-route,
.bb-trip-head-when {
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	line-height: 1.3;
}
.bb-trip-head-route {
	color: var(--harbour);
	font-size: var(--t-14);
	font-weight: 700;
}
.bb-trip-head-when {
	/* D106: --muted, not --faint, for active text. */
	color: var(--muted);
	font-size: var(--t-12);
	font-weight: 600;
}
.bb-trip-head-chevron {
	flex-shrink: 0;
}

/* P18 (D146): each segment is a button - a 5px bar drawn in the middle of a
   44px-tall target (::before), so a finished step can be tapped to return to
   it. */
.bb-progress {
	margin: 2px 0 0;
}
.bb-progress-list {
	display: flex;
	gap: 6px;
	margin: 0;
	padding: 0;
	list-style: none;
}
.bb-progress-item {
	flex: 1;
	min-width: 0;
}
.bb-progress-seg {
	display: flex;
	align-items: center;
	width: 100%;
	min-height: 44px;
	margin: 0;
	padding: 0;
	border: 0;
	background: transparent;
	cursor: pointer;
}
.bb-progress-seg::before {
	content: '';
	display: block;
	flex: 1;
	height: 5px;
	border-radius: var(--r-pill);
	background: var(--segment-off);
}
.bb-progress-seg:disabled {
	cursor: default;
}
.bb-progress-seg:not(:disabled):hover::before {
	background: var(--signal);
}
.bb-progress-seg.is-filled::before {
	/* Same reason as .bb-route-dot: how far through the booking you are is
	   information, carried by colour alone against --segment-off. Coral
	   there is 2.25:1; the deeper coral is 4.05:1. */
	background: var(--signal-deep);
}
/* P18 (D146, WCAG 3.2.2): the form moves on by itself, and says so first. */
.bb-advance-note {
	margin: 0 0 16px;
	color: var(--muted);
	font-size: var(--t-12);
	line-height: 1.45;
}

/* Each screen is a one-column grid: its gap is the only vertical rhythm, so
   no component carries a margin that could stack against a hidden one. */
.bb-screen {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 16px;
}
.bb-screen > * {
	min-width: 0;
}
/* A screen receives focus only from script, when it is shown (P9, D139); it is
   a region, not a control, so it draws no ring - the next Tab lands on its
   first control, which does. */
.bb-screen:focus {
	outline: none;
}

/* P26 (D154): each screen's heading is the question it asks. */
.bb-screen-question {
	margin: 0;
	color: var(--harbour);
	font-size: var(--t-24);
	font-weight: 800;
	line-height: 1.2;
	letter-spacing: -0.02em;
}

/* P26: the steppers a screen asks together - the two bag sizes, and (P30)
   the three seats. Stacked at 390; the bags side by side from 834. */
.bb-steppers {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 10px;
	min-width: 0;
}

/* ===================================================================
 * FIELDS
 * =================================================================== */

.bb-field {
	display: flex;
	flex-direction: column;
	gap: 6px;
	min-width: 0;
	margin: 0;
}
/* 1.3.7: phone and email - side by side when the card has room, stacked
   when it does not. Plain flex wrap, so every browser lays it out the same. */
.bb-contact-pair {
	display: flex;
	flex-wrap: wrap;
	gap: 16px 12px;
	min-width: 0;
}
.bb-contact-pair > .bb-field {
	flex: 1 1 220px;
}
.bb-field-row--2col {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: 10px;
}
.bb-field-label {
	font-size: var(--t-12);
	font-weight: 700;
	line-height: 1.25;
	color: var(--muted);
	text-transform: uppercase;
	letter-spacing: 0.04em;
}
/* 16px at every width: type does not rescale (D50), and a phone zooms the
   page into any input set smaller. */
.bb-input {
	display: block;
	width: 100%;
	min-width: 0;
	min-height: 48px;
	margin: 0;
	padding: 11px 12px;
	border: 1.5px solid var(--hairline);
	border-radius: var(--r-md);
	background: var(--base);
	color: var(--ink);
	font-family: var(--font);
	font-size: var(--t-16);
}
/* P9 (D139): the browser's default placeholder grey is 4.28:1 on --base;
   --muted is 4.57:1. Opacity 1 because Firefox fades placeholders. */
.bb-input::placeholder {
	color: var(--muted);
	opacity: 1;
}
/* 1.3.0: the date box keeps to its half of the row and the time box's
   height. iPhone Safari gives a date input its own minimum width and a
   taller box, so it ran under the time beside it. */
.bb-date-wrap {
	position: relative;
	display: block;
	min-width: 0;
}
.bb-scope input.bb-input[type="date"] {
	box-sizing: border-box;
	max-width: 100%;
	height: 48px;
	line-height: 24px;
}
/* 1.3.8: the date needs more room than the time ("10/21/2026" and its
   calendar icon); on a small phone the first digit was cut off. */
.bb-field-row--2col:has(.bb-date-wrap) {
	grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
}
@media (max-width: 400px) {
	.bb-scope input.bb-input[type="date"],
	.bb-scope .bb-select {
		padding-left: 10px;
		padding-right: 8px;
	}
}
.bb-scope input.bb-input[type="date"]::-webkit-date-and-time-value {
	min-height: 24px;
	margin: 0;
	text-align: left;
}
/* iPhone shows an empty date as a blank box: the format, as a hint. */
@supports (-webkit-touch-callout: none) {
	.bb-scope input.bb-input[type="date"] {
		-webkit-appearance: none;
		appearance: none;
	}
}
/* 1.3.0: "More than 7 passengers? Fill out this form or contact our office." */
.bb-group-note {
	margin: 0;
	font-size: var(--t-14);
	line-height: 1.45;
	color: var(--slate);
}
.bb-group-note a {
	color: var(--harbour);
	font-weight: 700;
}
.bb-textarea {
	min-height: 72px;
	resize: vertical;
	line-height: 1.45;
}

/* P14 (item 8): a field's standing explanation (what an optional email is
   for), as opposed to .bb-field-status, which reports a problem. */
.bb-field-note {
	display: block;
	margin: 0;
	font-size: var(--t-12);
	line-height: 1.45;
	color: var(--muted);
}
.bb-field-status {
	display: block;
	margin: 0;
	font-size: var(--t-12);
	line-height: 1.45;
	color: var(--signal-deep);
}
.bb-field-status:empty {
	display: none;
}
/* P10: a sent enquiry is good news - it no longer reads in the warning colour. */
.bb-field-status--ok {
	color: var(--muted);
}

/* P7 (correction 11): what an address resolved to, beside its field.

   P14: its space is RESERVED from the first paint - two lines at 390, one
   from 834 - whether or not there is anything to say yet. It used to take
   no space until the quote came back, then appear and push every control
   below it down, sometimes under a finger already on its way to one. A
   longer text is clamped to the reserved lines (its whole text is also its
   tooltip, and a screen reader reads all of it). */
.bb-field-resolved {
	--resolved-lines: 2;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: var(--resolved-lines);
	min-height: calc(var(--t-12) * 1.45 * var(--resolved-lines));
	overflow: hidden;
	font-size: var(--t-12);
	line-height: 1.45;
	color: var(--muted);
	overflow-wrap: anywhere;
}
.bb-field-resolved.is-error {
	color: var(--signal-deep);
}
/* 1.3.6: the line is shown only when it says something new (a corrected
   address or a problem), so no empty space is kept for it. */
.bb-field-resolved:empty {
	min-height: 0;
}
/* P26 (prototype): a resolved address reads as confirmed - a tick and the
   address in harbour (8.9:1 on --paper). "We will use:" is still read by a
   screen reader. */
.bb-field-resolved.is-resolved {
	color: var(--harbour);
	font-weight: 600;
}
.bb-resolved-tick {
	display: inline-block;
	margin-right: 4px;
	vertical-align: -1px;
}

/* ===================================================================
 * ADDRESS SUGGESTIONS (D71) - spans its input, no width of its own.
 * =================================================================== */

.bb-address-input-wrap {
	position: relative;
	display: block;
}
.bb-address-suggestions {
	position: absolute;
	top: calc(100% + 4px);
	left: 0;
	right: 0;
	z-index: 30;
	max-height: 264px;
	overflow-y: auto;
	padding: 6px;
	border: 1px solid var(--hairline);
	border-radius: var(--r-md);
	background: var(--paper);
	box-shadow: var(--shadow-pop);
}
.bb-address-suggestion {
	display: block;
	width: 100%;
	min-height: 44px;
	margin-bottom: 2px;
	padding: 10px;
	border: none;
	border-radius: var(--r-sm);
	background: transparent;
	color: var(--ink);
	font-family: var(--font);
	font-size: var(--t-13);
	font-weight: 600;
	text-align: left;
	white-space: normal;
	cursor: pointer;
}
.bb-address-suggestion.is-selected {
	background: var(--signal-deep);
	color: var(--paper);
}

/* ===================================================================
 * THE DRAFT NOTICE, AND THE TEXT LINK
 * =================================================================== */

/* P14 (item 9): the restore notice. Harbour and calm when it only says the
   trip was kept; the warning colours when the draft carries a booking
   reference, because then it is telling a parent they may already have paid
   for this trip. The reset control is a real 44px target (D127). */
.bb-draft-notice {
	/* 1.3.7: one compact line - the note, then "Start over" beside it. */
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0 12px;
	padding: 2px 14px;
	border-radius: var(--r-md);
	background: var(--harbour-tint);
}
.bb-draft-notice[hidden] {
	display: none;
}
.bb-draft-notice-text {
	margin: 0;
	font-size: var(--t-14);
	line-height: 1.45;
	color: var(--harbour);
}
.bb-draft-notice--booked {
	border: 1px solid var(--notice-edge);
	background: var(--signal-soft);
}
.bb-draft-notice--booked .bb-draft-notice-text {
	color: var(--notice-ink);
	font-weight: 600;
}
/* P21 (D149): THE text link. Every text-style action and every link in running
   text wears one look - teal, bold, underlined - in every stylesheet that has
   one (theme.css, booking.css, content-pages.css, confirmation.css hold the
   same declarations; theme/bossandbubs/tests/text-link-test.php keeps them
   identical). Size follows the text around it. Navigation lists (the header
   nav, the drawer, the footer, the legal page pills) are not text links and
   stay without an underline; the closing band's phone keeps this look in its
   light on-teal colour. Before P21 there were seven looks: underlined or not,
   teal or grey, at weights 400, 600 and 700. */
.bb-link-btn,
.bb-draft-reset,
.bb-add-stop,
.bb-scope p a:not([class]),
.bb-scope li a:not([class]) {
	color: var(--harbour);
	font-weight: 700;
	text-decoration: underline;
	text-underline-offset: 3px;
}
.bb-link-btn:hover,
.bb-draft-reset:hover,
.bb-add-stop:not(:disabled):not([aria-disabled="true"]):hover,
.bb-scope p a:not([class]):hover,
.bb-scope li a:not([class]):hover {
	color: var(--signal-deep);
}

.bb-draft-reset {
	justify-self: start;
	min-height: 44px;
	margin: 0;
	padding: 0;
	border: 0;
	background: transparent;
	font-family: var(--font);
	font-size: var(--t-14);
	cursor: pointer;
}

/* P26 (D154): there is no lead-time notice. The lead time is said only when
   the chosen time is too soon, as the date and time's own error
   (#bb-when-error, a .bb-field-status). */

/* ===================================================================
 * ROUTE - pickup, stops and drop-off on the dot-to-square connector.
 * =================================================================== */

.bb-route {
	display: flex;
	gap: 10px;
}
.bb-route-connector {
	display: flex;
	flex-direction: column;
	align-items: center;
	flex-shrink: 0;
	padding-top: 36px;
	/* Level with the drop-off input's middle, above the reserved line. */
	padding-bottom: calc(24px + var(--t-12) * 1.45 * 2);
}
.bb-route-dot {
	flex-shrink: 0;
	width: 12px;
	height: 12px;
	border-radius: var(--r-pill);
	/* --signal-deep, not --signal: this dot is a meaningful non-text UI
	   mark (WCAG 1.4.11, 3:1). Coral on --paper is 2.91:1 and fails;
	   the deeper coral is 5.24:1 and reads as the same colour family. */
	background: var(--signal-deep);
}
.bb-route-stop-dot {
	flex-shrink: 0;
	width: 8px;
	height: 8px;
	border: 2px solid var(--muted);
	border-radius: var(--r-pill);
	background: var(--base);
}
.bb-route-square {
	flex-shrink: 0;
	width: 11px;
	height: 11px;
	background: var(--harbour);
}
.bb-route-line {
	flex: 1;
	width: 2px;
	margin: 4px 0;
	background: repeating-linear-gradient(180deg, var(--connector) 0 6px, transparent 6px 12px);
}
.bb-route-fields {
	display: flex;
	flex-direction: column;
	flex: 1;
	gap: 12px;
	min-width: 0;
}

/* The locate chip shares the input's grid cell, aligned to its end. The
   wrapper is also the suggestions list's containing block, so the list
   spans this input and not the page. */
.bb-input-with-action {
	position: relative;
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	align-items: center;
}
.bb-input-with-action > * {
	grid-area: 1 / 1;
}
.bb-input-with-action .bb-input {
	/* Clears the 44px chip and its 6px inset. */
	padding-right: 54px;
	min-height: 52px;
}
.bb-locate-chip {
	justify-self: end;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	margin-right: 4px;
	padding: 0;
	border: 1.5px solid var(--harbour);
	border-radius: var(--r-pill);
	background: var(--paper);
	color: var(--harbour);
	cursor: pointer;
}
.bb-locate-chip.is-busy {
	opacity: 0.5;
	cursor: default;
}

.bb-stop-rows {
	display: flex;
	flex-direction: column;
	gap: 12px;
}
.bb-stop-rows:empty {
	display: none;
}
.bb-stop-row {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 44px;
	column-gap: 8px;
}
.bb-stop-remove {
	align-self: start;
	/* Level with the input: past the label's line and the field's gap. */
	margin-top: calc(var(--t-12) * 1.25 + 8px);
	width: 44px;
	height: 44px;
	border: 1.5px solid var(--hairline);
	border-radius: var(--r-md);
	background: var(--paper);
	color: var(--signal-deep);
	font-family: var(--font);
	font-size: var(--t-16);
	font-weight: 700;
	cursor: pointer;
}

.bb-add-stop-row {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 4px 10px;
}
/* P21 (D149): was grey (--muted) and not underlined; now the text link. */
.bb-add-stop {
	display: flex;
	align-items: center;
	gap: 6px;
	min-height: 44px;
	padding: 0 4px 0 0;
	border: none;
	background: transparent;
	font-family: var(--font);
	font-size: var(--t-13);
	cursor: pointer;
}
.bb-add-stop:disabled {
	/* WCAG 1.4.3 exempts a disabled control's text (D106). */
	color: var(--faint);
	cursor: not-allowed;
}

/* ===================================================================
 * STEPPERS, TOGGLES AND THEIR PANELS
 * =================================================================== */

.bb-stepper {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	margin: 0;
	padding: 6px 8px 6px 14px;
	border: 1.5px solid var(--hairline);
	border-radius: var(--r-md);
	background: var(--base);
}
.bb-stepper-label {
	min-width: 0;
	font-size: var(--t-14);
	font-weight: 600;
	line-height: 1.35;
	color: var(--ink);
}
/* D143: "(under 13)" wraps as a whole, never "(under / 13)". */
.bb-stepper-qualifier {
	white-space: nowrap;
}
.bb-stepper-controls {
	display: flex;
	flex-shrink: 0;
	align-items: center;
	gap: 12px;
}
.bb-stepper-btn {
	width: 44px;
	height: 44px;
	padding: 0;
	border: 1.5px solid var(--harbour);
	border-radius: var(--r-pill);
	background: var(--paper);
	color: var(--harbour);
	font-family: var(--font);
	font-size: var(--t-16);
	font-weight: 700;
	cursor: pointer;
}
.bb-stepper-btn--fill {
	background: var(--harbour);
	color: var(--paper);
}
.bb-stepper-btn:disabled,
.bb-stepper-btn[aria-disabled="true"] {
	opacity: 0.4;
	cursor: not-allowed;
}
/* A focused control that became unavailable keeps focus as aria-disabled
   (P9, D139) and looks exactly as its disabled state does. */
.bb-add-stop[aria-disabled="true"] {
	color: var(--faint);
	cursor: not-allowed;
}
.bb-btn[aria-disabled="true"] {
	cursor: not-allowed;
}
/* D143: a disabled Continue / Pay looks disabled. Only the aria-disabled
   state (a focused control, P9) was dimmed, so on first paint the bar's
   disabled Continue was full coral and read as a button that did nothing
   when tapped. WCAG 1.4.3 exempts an inactive control's text. */
.bb-btn--primary:disabled,
.bb-btn--primary[aria-disabled="true"] {
	opacity: 0.6;
}
.bb-stepper-value {
	min-width: 20px;
	font-size: var(--t-15);
	font-weight: 700;
	color: var(--harbour);
	text-align: center;
}

/* A toggle is the whole bordered row: the label is the target, not the box. */
.bb-checkbox-row {
	display: flex;
	align-items: center;
	gap: 12px;
	min-height: 48px;
	margin: 0;
	padding: 10px 14px;
	border: 1.5px solid var(--hairline);
	border-radius: var(--r-md);
	background: var(--base);
	cursor: pointer;
}
.bb-checkbox-row input[type="checkbox"] {
	flex-shrink: 0;
	width: 18px;
	height: 18px;
	margin: 0;
	accent-color: var(--harbour);
	cursor: pointer;
}
/* D143 (item 5): a toggle's label over a short sub-line (the coffee fee). */
.bb-toggle-text {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
}
.bb-toggle-sub {
	font-size: var(--t-12);
	line-height: 1.35;
	color: var(--muted);
}

/* A toggle's revealed fields hang from it on a rule, so a long form still
   reads as "this belongs to that switch". */
.bb-toggle-panel {
	display: flex;
	flex-direction: column;
	gap: 12px;
	min-width: 0;
	padding-left: 12px;
	border-left: 2px solid var(--hairline);
}

.bb-extra-note {
	margin: 0;
	font-size: var(--t-12);
	line-height: 1.5;
	color: var(--muted);
}

/* P30 (D158): a seat's stepper - its name over the band's age range, from
   the Child Seats settings. The text takes what the buttons leave and wraps;
   the buttons never shrink. */
.bb-stepper-text {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
}
.bb-stepper-hint {
	font-size: var(--t-12);
	line-height: 1.4;
	color: var(--muted);
}

/* R5.1: asked once, for both legs. */
.bb-airport-question {
	display: flex;
	flex-direction: column;
	gap: 4px;
	min-width: 0;
	margin: 0;
	padding: 12px 14px;
	border: 1.5px solid var(--hairline);
	border-radius: var(--r-md);
	background: var(--base);
}
.bb-airport-question legend {
	float: left;
	width: 100%;
	margin-bottom: 4px;
	padding: 0;
}
.bb-radio-row {
	display: flex;
	align-items: center;
	gap: 10px;
	min-height: 44px;
	font-size: var(--t-14);
	font-weight: 600;
	color: var(--ink);
	cursor: pointer;
}
.bb-radio-row input[type="radio"] {
	width: 18px;
	height: 18px;
	margin: 0;
	accent-color: var(--harbour);
}

/* R5.2-R5.5: each leg's airport fields, in its own box. */
.bb-airport-legs {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 12px;
}
.bb-airport-legs:empty {
	display: none;
}
.bb-airport-leg {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 10px;
	min-width: 0;
	padding: 12px 14px;
	border: 1.5px solid var(--hairline);
	border-radius: var(--r-md);
	background: var(--base);
}
.bb-airport-leg-title {
	margin: 0;
	font-size: var(--t-13);
	font-weight: 700;
	line-height: 1.35;
	color: var(--harbour);
}
.bb-airport-leg .bb-input,
.bb-airport-leg .bb-checkbox-row {
	background: var(--paper);
}

/* R7.2, P26: Enquire, on Screen 2 (P30) when no class fits (and always without a
   Maps key), below the trip it will send, on a rule of its own. */
.bb-enquire-panel {
	display: flex;
	flex-direction: column;
	gap: 10px;
	padding-top: 16px;
	border-top: 1px solid var(--rule);
}

/* ===================================================================
 * SCREEN 3 - VEHICLE CARDS (P13; D144 item 3; P40, D169)
 * P40 (spec/14-CORRECTIONS-BRIEF.md #3, the client's call): the photo sits
 * full width across the top of every car card, 16:10, as on Our cars and the
 * homepage - the shared .bb-car-photo block in content-pages.css. D144's
 * thumbnail beside the name, which kept several totals on one screen, is
 * gone; a card is taller and the list scrolls.
 * - 390: the name, then this trip's total; the description; the badges, then
 *   Choose across the card.
 * - From 834: the name and total on one line; the capacity and Choose share
 *   the last row.
 * =================================================================== */

.bb-vehicle-list {
	display: flex;
	flex-direction: column;
	gap: 12px;
}
.bb-vehicle-card {
	display: flex;
	flex-direction: column;
	margin: 0;
	padding: 0;
	overflow: hidden;
	overflow: clip;
	border: 1.5px solid var(--hairline);
	border-radius: var(--r-card);
	background: var(--paper);
	font-family: var(--font);
}
/* Selected: a harbour edge plus a soft ring, so the choice reads without
   relying on colour alone (the button below also says "Chosen"). */
.bb-vehicle-card.is-selected {
	border-color: var(--harbour);
	box-shadow: var(--shadow-ring);
}
.bb-vehicle-card.is-unfit {
	opacity: 0.6;
	/* 1.3.6: cars that fit come first; the rest follow, greyed. */
	order: 1;
}
/* 1.3.6: on a phone the photo is a wide strip, so the cars are not a long
   scroll; from 834 it keeps the 16:10 shape of Our cars. */
/* 1.3.8: a wide strip at every width - the booking card is a narrow column
   on a computer too. */
.bb-vehicle-list .bb-car-photo-img {
	aspect-ratio: 2 / 1;
}
.bb-vehicle-card.is-unfit .bb-car-photo-img {
	filter: grayscale(1);
}

/* P40 (D169): the photo is the shared .bb-car-photo block (content-pages.css),
   full width across the top of the card; the body below it: the name and
   this trip's total, the description, then the badges and Choose. */
.bb-vehicle-card-body {
	display: flex;
	flex-direction: column;
	gap: 10px;
	min-width: 0;
	padding: 12px 12px 14px;
}
/* At 390: the name, then this trip's total under it. */
.bb-vehicle-card-head {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 4px;
	min-width: 0;
}
.bb-vehicle-card-heading {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
}
.bb-vehicle-card-name {
	margin: 0;
	font-size: var(--t-18);
	font-weight: 700;
	line-height: 1.2;
	color: var(--ink);
}
/* The price column sizes to its content and does not shrink, so the name
   beside it (from 834) wraps instead of the FIGURE breaking mid-number
   ("AU$53 0.93" is worse than a wrapped class name). flex-shrink lives here
   on the wrapper, never on .bb-vehicle-card-amount itself: the amount keeps
   min-width:0 and overflow-wrap:anywhere as its last-resort valve, so an
   amount too long for the whole card still breaks instead of overflowing
   it (P8/D138, pinned by the mobile audit). */
.bb-vehicle-card-price {
	display: flex;
	flex-direction: column;
	flex-shrink: 0;
	align-items: flex-start;
	gap: 1px;
	max-width: 100%;
	margin: 0;
	text-align: left;
}
/* No white-space:nowrap and no flex-shrink:0 here, deliberately: P8/D138
   found a long amount genuinely cut off mid-word at 390px with those set.
   The figure may shrink and break rather than overflow the card. */
.bb-vehicle-card-amount {
	min-width: 0;
	overflow-wrap: anywhere;
	font-size: var(--t-24);
	font-weight: 800;
	line-height: 1.15;
	color: var(--harbour);
	font-variant-numeric: tabular-nums;
}
.bb-vehicle-card-tax-note {
	font-size: var(--t-12);
	line-height: 1.3;
	color: var(--muted);
}
.bb-vehicle-card-description {
	margin: 0;
	font-size: var(--t-14);
	line-height: 1.45;
	color: var(--slate);
}
.bb-vehicle-card-foot {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 10px;
	min-width: 0;
}
/* P28 (D156): the capacity badges and the sub-badge are every card's, so
   their rules live with the content cards' in content-pages.css, which the
   booking page always loads (class-bb-taxi-plugin.php). */
.bb-vehicle-card-reason {
	margin: 0;
	padding: 10px 12px;
	border-radius: var(--r-sm);
	background: var(--signal-soft);
	font-size: var(--t-13);
	line-height: 1.45;
	color: var(--notice-ink);
}
.bb-vehicle-card-choose {
	width: 100%;
	min-height: 48px;
	margin: 0;
	padding: 12px 18px;
	border: 0;
	border-radius: var(--r-md);
	background: var(--harbour);
	color: var(--paper);
	font-size: var(--t-15);
	font-weight: 700;
}
.bb-vehicle-card.is-selected .bb-vehicle-card-choose {
	background: var(--harbour-deep);
}
.bb-vehicle-card-choose:disabled,
.bb-vehicle-card-choose[aria-disabled="true"] {
	background: var(--segment-off);
	color: var(--muted);
}

/* D144 (item 4), P26 (the prototype's trip card): Screen 4's reminder of
   what is being paid for. The route on a rail - a coral dot at the pickup, a
   ringed dot per stop, a harbour square at the drop-off, joined by dashes, as
   on Screen 1 - then the car, when and the return as short facts. Each point
   is a two-row grid: the marker beside its label, the dashes beside its
   address, running on to the next point's marker. No positioning. */
.bb-trip-card {
	display: grid;
	gap: 14px;
	padding: 16px 18px;
	border: 1px solid var(--hairline);
	border-radius: var(--r-card);
	background: var(--paper);
}
.bb-trip-route {
	display: grid;
	margin: 0;
	padding: 0;
	list-style: none;
}
/* P31 (D160): the return's own route, under the outbound's, ruled off like the facts. */
.bb-trip-route--return {
	padding-top: 14px;
	border-top: 1px solid var(--hairline);
}
.bb-trip-point {
	display: grid;
	grid-template-columns: 12px minmax(0, 1fr);
	grid-template-rows: auto 1fr;
	column-gap: 12px;
}
.bb-trip-point::before {
	content: '';
	grid-column: 1;
	grid-row: 1;
	align-self: center;
	justify-self: center;
	width: 11px;
	height: 11px;
	background: var(--harbour);
}
/* The pickup's dot - --signal-deep, a meaningful mark (WCAG 1.4.11), as on
   Screen 1's rail. */
.bb-trip-point[data-point="pickup"]::before {
	width: 12px;
	height: 12px;
	border-radius: var(--r-pill);
	background: var(--signal-deep);
}
.bb-trip-point[data-point="stop"]::before {
	width: 10px;
	height: 10px;
	border: 2px solid var(--muted);
	border-radius: var(--r-pill);
	background: var(--base);
}
.bb-trip-point::after {
	content: '';
	grid-column: 1;
	grid-row: 2;
	justify-self: center;
	width: 2px;
	margin: 4px 0;
	background: repeating-linear-gradient(180deg, var(--connector) 0 6px, transparent 6px 12px);
}
.bb-trip-point:last-child::after {
	display: none;
}
.bb-trip-point-label {
	grid-column: 2;
	grid-row: 1;
	/* D106: --muted, not --faint, for active text. */
	color: var(--muted);
	font-size: var(--t-12);
	font-weight: 700;
	line-height: 1.3;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}
.bb-trip-point-text {
	grid-column: 2;
	grid-row: 2;
	min-width: 0;
	padding-bottom: 12px;
	color: var(--ink);
	font-size: var(--t-14);
	font-weight: 600;
	line-height: 1.4;
	overflow-wrap: anywhere;
}
.bb-trip-point:last-child .bb-trip-point-text {
	padding-bottom: 0;
}
.bb-trip-facts {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin: 0;
	padding-top: 14px;
	border-top: 1px solid var(--hairline);
}
.bb-trip-fact {
	display: flex;
	flex-wrap: wrap;
	gap: 0 6px;
	min-width: 0;
	padding: 6px 12px;
	border-radius: var(--r-pill);
	background: var(--harbour-tint);
	font-size: var(--t-13);
	line-height: 1.4;
}
.bb-trip-fact dt {
	color: var(--muted);
}
.bb-trip-fact dd {
	min-width: 0;
	margin: 0;
	color: var(--harbour);
	font-weight: 700;
	overflow-wrap: anywhere;
}

/* P37 (D166, spec/14 #1): the one charges notice - the sheet, Screens 3 and
   4, and the confirmation page. The same rule is in content-pages.css for
   the Services page. */
.bb-charges-notice {
	display: grid;
	gap: 8px;
	padding: 12px 16px;
	border: 1px solid var(--hairline);
	border-radius: var(--r-md);
	background: var(--fog);
	font-size: var(--t-14);
	line-height: 1.5;
	color: var(--slate);
}
.bb-charges-notice p {
	margin: 0;
}
.bb-charges-notice a {
	color: var(--harbour);
}

/* ===================================================================
 * THE FARE BREAKDOWN - the pay screen and the confirmation page share it.
 *
 * Correction 8: on a return booking each leg ends with its own tax row,
 * labelled like the booking's. The labels stay as stored; the layout groups
 * them. Each leg's rows hang indented under its heading on a rule and close
 * with the leg's total; the booking's subtotal, tax and total follow flush,
 * below a heavier rule. A one-way booking has no heading and no indent.
 * Rows are styled by data-row-kind, which both surfaces print.
 * =================================================================== */

/* P13: the breakdown carries the same visual language as the vehicle
   cards - a white card, hairline-ruled rows, tabular figures in the right
   column, and one harbour rule above the total. Matches the prototype's
   `.bd-row` set. This is the screen where the customer checks our
   arithmetic, so every row is a plain ruled line, nothing decorative. */
.bb-fare-table {
	display: flex;
	flex-direction: column;
	padding: 16px 18px;
	border: 1px solid var(--hairline);
	border-radius: var(--r-card);
	background: var(--paper);
}
#bb-fare-lines {
	display: contents;
}
.bb-fare-row {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 12px;
	padding: 9px 0;
	border-bottom: 1px solid var(--hairline);
	font-size: var(--t-14);
	line-height: 1.4;
}
.bb-fare-row span:first-child {
	min-width: 0;
	color: var(--slate);
}
.bb-fare-row span:last-child {
	flex-shrink: 0;
	color: var(--ink);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	text-align: right;
	white-space: nowrap;
}
.bb-fare-row--rule {
	margin-top: 6px;
	padding-top: 10px;
	border-top: 1px solid var(--rule);
}

/* A leg heading ("Outbound", "Return") - the prototype's `.bd-leg`. */
.bb-fare-row[data-row-kind="heading"] {
	margin-top: 10px;
	padding-top: 14px;
	border-top: 1px solid var(--rule);
	border-bottom: 0;
}
#bb-fare-lines > .bb-fare-row[data-row-kind="heading"]:first-child,
.bb-fare-table > .bb-fare-row[data-row-kind="heading"]:first-child {
	margin-top: 0;
	padding-top: 4px;
	border-top: 0;
}
.bb-fare-row[data-row-kind="heading"] span:first-child {
	color: var(--harbour);
	font-weight: 700;
}
.bb-fare-row[data-row-kind="heading"] span:last-child {
	flex-shrink: 1;
	color: var(--slate);
	white-space: normal;
}
.bb-fare-table:has([data-row-kind="heading"]) .bb-fare-row:is([data-row-kind="line"], [data-row-kind="discount"], [data-row-kind="leg_tax"], [data-row-kind="leg_total"]) {
	margin-left: 4px;
	padding-left: 12px;
	border-left: 2px solid var(--hairline);
}
.bb-fare-row[data-row-kind="leg_total"] span {
	color: var(--harbour);
	font-weight: 700;
}
.bb-fare-row[data-row-kind="discount"] span:last-child {
	color: var(--signal-deep);
}
.bb-fare-table:has([data-row-kind="heading"]) .bb-fare-row[data-row-kind="subtotal"] {
	margin-top: 14px;
	padding-top: 12px;
	border-top: 2px solid var(--harbour);
}
/* The total: one 2px harbour rule above it and no rule below, so the
   figure the customer is about to pay is the last thing on the card. */
.bb-fare-row--total {
	margin-top: 6px;
	padding-top: 12px;
	border-top: 2px solid var(--harbour);
	border-bottom: 0;
}
.bb-fare-row--total span:first-child {
	color: var(--harbour);
	font-size: var(--t-13);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.04em;
}
.bb-fare-row--total span:last-child {
	color: var(--harbour);
	font-size: var(--t-18);
	font-weight: 800;
}
/* The last plain line before the total carries no rule of its own. */
.bb-fare-row:last-child {
	border-bottom: 0;
}

/* P14 (item 6): the pay screen's inline subtotal, tax and total - the same rows,
   with the full breakdown one tap away. */
.bb-fare-table--pay {
	padding-bottom: 8px;
}
/* 1.3.0 (client): Screen 4 shows only the total fare including GST. */
.bb-fare-table--pay .bb-fare-row:not(.bb-fare-row--total) {
	display: none !important;
}
.bb-fare-table--pay .bb-fare-row--total {
	margin-top: 0;
	padding-top: 0;
	border-top: 0;
}
.bb-link-btn {
	align-self: flex-start;
	min-height: 44px;
	margin: 2px 0 0;
	padding: 0;
	border: 0;
	background: transparent;
	font-family: var(--font);
	font-size: var(--t-14);
	cursor: pointer;
}

/* ===================================================================
 * SCREEN 6 - HOW PAYMENT HAPPENS (no card field on this origin -
 * PRODUCT.md §4.2, §4.3)
 * =================================================================== */

/* P25 (D153, O24): a note, not a control - no border, no marker, nothing that
   reads as tappable. The label is the field labels' own class. */
.bb-payment-note {
	display: grid;
	gap: 4px;
}
.bb-payment-note p {
	margin: 0;
}
.bb-payment-note-body {
	font-size: var(--t-14);
	line-height: 1.5;
	color: var(--ink);
}

/* ===================================================================
 * BUTTONS AND MESSAGES
 * P26 (D154): Back and Continue / Pay sit side by side at the foot of the
 * card, in normal flow (the bottom bar is deleted).
 * =================================================================== */

.bb-btn {
	min-height: 48px;
	padding: 12px 22px;
	border: none;
	border-radius: var(--r-md);
	font-family: var(--font);
	font-size: var(--t-16);
	font-weight: 700;
	cursor: pointer;
}
.bb-btn:disabled {
	cursor: not-allowed;
}
/* D143: one rule. It was defined twice; the second set only background and
   colour, so the first's --paper background never applied while its border
   did. What rendered - the harbour edge on the harbour tint - is kept. */
.bb-btn--ghost {
	border: 1.5px solid var(--harbour);
	background: var(--harbour-tint);
	color: var(--harbour);
}
.bb-btn--primary {
	flex: 1;
	/* P42 (D171): the ONE action that moves the customer forward is navy with
	   white text (14.6:1), deepening on hover (17.3:1). It was coral with
	   --on-signal text from P13. theme.css .bb-header-cta is held identical
	   (primary-button-test.php). */
	background: var(--harbour);
	color: var(--paper);
	box-shadow: var(--shadow-cta);
}
.bb-btn--primary:hover:not(:disabled):not([aria-disabled="true"]) {
	background: var(--harbour-deep);
	color: var(--paper);
}
/* P20 (D148): Enquire is the primary action of its panel - the only way on
   when no car fits or nothing can be priced - so it wears the primary look
   (the markup adds .bb-btn--primary). It was harbour teal. Here it only stops
   growing: the panel is a column, and the primary's flex: 1 is for the bar. */
.bb-btn--enquire {
	flex: none;
}

/* P26 (D154): the card's foot - an announced move (P18), the reason the
   button is unavailable (D144), then Back and Continue / Pay. */
.bb-booking-foot {
	display: grid;
	gap: 8px;
	margin-top: 20px;
	padding-top: 16px;
	border-top: 1px solid var(--rule);
}
/* P18 (D146): an automatic move to the next screen, said before it happens,
   with a way to stay. */
.bb-advance-notice {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: flex-end;
	gap: 0 12px;
	min-width: 0;
	color: var(--harbour);
	font-size: var(--t-14);
	font-weight: 700;
}
.bb-advance-cancel {
	margin: 0;
}
/* D144 (item 5): why Continue / Pay is unavailable, directly above the
   button, aligned to its end so it reads as the button's caption. An empty
   line keeps its place in the accessibility tree (a live region is never
   display: none) and takes no height: an empty paragraph with no margin and
   no padding has none. */
.bb-action-reason {
	min-width: 0;
	margin: 0;
	/* D106: --muted, not --faint, for active text. */
	color: var(--muted);
	font-size: var(--t-13);
	font-weight: 600;
	line-height: 1.35;
	text-align: right;
}
.bb-foot-buttons {
	display: flex;
	align-items: center;
	gap: 10px;
}
.bb-back {
	flex: 0 0 auto;
	padding: 12px 18px;
}
/* The primary's flex: 1 fills the rest of the row. Sizes only (P20, D148):
   the primary look is untouched. */
.bb-continue {
	padding: 12px 22px;
}

.bb-booking-luggage-warning {
	margin: 0;
	font-size: var(--t-13);
	font-weight: 700;
	line-height: 1.45;
	color: var(--signal-deep);
}

/* ===================================================================
 * THE BREAKDOWN SHEET (P14, item 6)
 * A native <dialog> opened as a modal (booking-sheet.js) from the price in the
 * card header and from Screen 4's "See full breakdown": a bottom sheet
 * below 834, a centred panel from 834. It scrolls inside itself; the page
 * behind is locked. It slides in only for a visitor who has not asked for
 * reduced motion.
 * =================================================================== */

.bb-sheet {
	width: 100%;
	max-width: 100%;
	max-height: 88vh;
	max-height: 88dvh;
	margin: auto 0 0;
	padding: 0;
	border: 0;
	border-radius: var(--r-card) var(--r-card) 0 0;
	background: var(--paper);
	color: var(--ink);
	font-family: var(--font);
	box-shadow: var(--shadow-pop);
	overflow: hidden;
}
/* Only while open: a closed dialog must keep the browser's display: none. */
.bb-sheet[open] {
	display: flex;
	flex-direction: column;
}
.bb-sheet::backdrop {
	background: var(--scrim);
}
/* The body scrolls, not the dialog. With the page pinned (booking-sheet.js)
   and the dialog itself scrolling, Chrome on a phone treated the route
   map's frame as off screen and never painted it. */
.bb-sheet-body {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	align-content: start;
	gap: 16px;
	min-height: 0;
	padding: 4px 20px calc(24px + env(safe-area-inset-bottom, 0px));
	overflow-y: auto;
	overscroll-behavior: contain;
}
.bb-sheet-head {
	display: flex;
	flex-shrink: 0;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding: 12px 20px 8px;
}
.bb-sheet-title {
	margin: 0;
	color: var(--harbour);
	font-size: var(--t-18);
	font-weight: 700;
}
.bb-sheet-close {
	flex-shrink: 0;
	width: 44px;
	height: 44px;
	padding: 0;
	border: 1.5px solid var(--hairline);
	border-radius: var(--r-pill);
	background: var(--paper);
	color: var(--harbour);
	font-family: var(--font);
	font-size: var(--t-24);
	line-height: 1;
	cursor: pointer;
}
.bb-sheet-section {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 10px;
	padding-top: 16px;
	border-top: 1px solid var(--rule);
}
.bb-sheet-subtitle {
	margin: 0;
	color: var(--signal-deep);
	font-size: var(--t-12);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.06em;
}
.bb-sheet-note {
	margin: 0;
	color: var(--muted);
	font-size: var(--t-14);
	line-height: 1.45;
}

/* The trip summary: the deleted rail's rows, same ids. */
.bb-summary-list {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 10px;
	margin: 0;
}
.bb-summary-row {
	display: flex;
	justify-content: space-between;
	gap: 12px;
	font-size: var(--t-13);
	line-height: 1.4;
}
.bb-summary-row dt {
	flex-shrink: 0;
	/* D106: --muted, not --faint, for active text. */
	color: var(--muted);
}
.bb-summary-row dd {
	min-width: 0;
	margin: 0;
	color: var(--ink);
	font-weight: 600;
	text-align: right;
	overflow-wrap: anywhere;
}
/* P24 (D152): one stop per line. */
.bb-summary-stops {
	white-space: pre-line;
}

/* Set on <html> while the sheet is open; booking-sheet.js also pins the body,
   which is what actually holds iOS Safari still. */
.bb-scroll-locked {
	overflow: hidden;
}

@keyframes bb-sheet-rise {
	from {
		opacity: 0;
		transform: translateY(32px);
	}
	to {
		opacity: 1;
		transform: none;
	}
}
@keyframes bb-sheet-fade {
	from {
		opacity: 0;
	}
	to {
		opacity: 1;
	}
}
@media (prefers-reduced-motion: no-preference) {
	.bb-sheet[open] {
		animation: bb-sheet-rise 0.22s ease-out;
	}
	.bb-sheet[open]::backdrop {
		animation: bb-sheet-fade 0.22s ease-out;
	}
}

/* Read by a screen reader, drawn nowhere: the price button's "trip details"
   suffix, which the chevron stands for on screen, and "We will use:" before a
   resolved address. The same clip theme.css uses for the header phone's text
   at 390. */
.bb-visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

/* ===================================================================
 * 834 - TABLET
 * =================================================================== */

@media (min-width: 834px) {
	/* P42 (D171): two columns - the intro, and the card at 400px. The photo
	   runs 48px above and below the card. */
	.bb-booking {
		grid-template-columns: minmax(0, 1fr) 400px;
		column-gap: 32px;
		grid-template-rows: 48px auto 48px;
	}
	.bb-booking-backdrop {
		grid-row: 1 / -1;
	}
	.bb-booking-backdrop::after {
		background: linear-gradient(90deg, var(--hero-scrim-left) 0%, var(--hero-scrim-right) 100%);
	}
	/* White on the shade: the intro sits in the left half of the viewport,
	   where the shade is at least 62.5% (tokens.css, --hero-scrim-left). */
	.bb-booking-intro {
		grid-column: 1;
		grid-row: 2;
		align-self: center;
		margin: 0;
		padding: 0;
		color: var(--on-navy);
		/* P43 (D172): on the navy shade, the gold ring. */
		--focus: var(--focus-on-dark);
	}
	.bb-booking-intro-list {
		gap: 12px;
	}
	.bb-booking-intro-item .bb-booking-intro-icon {
		color: var(--on-navy);
	}
	.bb-booking-stack {
		grid-column: 2;
		grid-row: 2;
		gap: 16px;
		margin-top: 0;
	}

	.bb-field-resolved {
		--resolved-lines: 1;
	}
	.bb-route-connector {
		padding-bottom: calc(24px + var(--t-12) * 1.45);
	}

	.bb-booking-card {
		padding: 28px;
	}

	/* P26: check-in bags beside cabin bags. P30: the three seats stay one
	   under another - each carries an age range to read. P40 (D169):
	   Passengers, with its hint, across the row above the two bag counts. */
	/* 1.3.8: the counters stay one per row - two side by side in a 400-480px
	   card squeezed "Check-in bags" onto three lines. */

	/* Each leg's pair of fields side by side; its title, VIP toggle and
	   notes span the box. */
	.bb-airport-leg {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: 12px;
		/* A pair's inputs line up even when one label wraps ("Departure flight
		   number (optional)" does in a narrow card). */
		align-items: end;
	}
	.bb-airport-leg > :not(.bb-field) {
		grid-column: 1 / -1;
	}

	/* D144 (item 3), P40 (D169): under the full-width photo, the name and
	   total on one line, the description, then the capacity and Choose on
	   one row. */
	.bb-vehicle-card-body {
		gap: 8px;
		padding: 14px 18px 18px;
	}
	.bb-vehicle-card-head {
		flex-direction: row;
		justify-content: space-between;
		gap: 12px;
	}
	.bb-vehicle-card-price {
		align-items: flex-end;
		max-width: 60%;
		text-align: right;
	}
	/* P29 (D157): the badges keep their one line at its full width; Choose
	   sits beside them only when 128px is left over, and otherwise wraps to
	   its own full-width row below. */
	.bb-vehicle-card-foot {
		display: flex;
		flex-wrap: wrap;
		align-items: flex-end;
		gap: 10px 12px;
	}
	.bb-vehicle-card-foot > .bb-car-badges {
		flex: 0 0 auto;
	}
	.bb-vehicle-card-choose {
		flex: 1 0 128px;
		width: auto;
	}

	.bb-fare-table {
		padding: 16px 18px;
	}


	.bb-sheet {
		width: min(560px, calc(100% - 64px));
		max-height: 85vh;
		max-height: 85dvh;
		margin: auto;
		border-radius: var(--r-card);
	}
	.bb-sheet-head {
		padding: 16px 28px 8px;
	}
	.bb-sheet-body {
		padding: 4px 28px 28px;
	}
}

/* ===================================================================
 * 1280 - DESKTOP
 * =================================================================== */

@media (min-width: 1280px) {
	/* P42 (D171): the card at 480px. */
	.bb-booking {
		grid-template-columns: minmax(0, 1fr) 480px;
		column-gap: 64px;
		grid-template-rows: 64px auto 64px;
	}
	.bb-booking-intro-title {
		font-size: var(--t-34);
	}
	.bb-booking-intro-item {
		font-size: var(--t-18);
	}
	.bb-booking-intro-text > span {
		font-size: var(--t-16);
	}

	.bb-booking-card {
		padding: 32px;
	}
}

/* ===================================================================
 * P13 - THE QUOTE BANNER
 * Shown when there is no live distance. The form below it is complete and
 * usable; only the figure is withheld. Never styled as an error: nothing
 * has gone wrong from the customer's side.
 * =================================================================== */

/* The banner has to be the FIRST thing on the page: it explains why no
   figure is coming before the customer starts filling the form in. Since P14
   it is the first card in the stack, above the booking card, at every
   width. It sits on the photo, so it is opaque (--signal-soft). */
.bb-quote-banner {
	margin: 0;
	padding: 16px;
	border-radius: var(--r-card);
	background: var(--signal-soft);
	color: var(--notice-ink);
}
.bb-quote-banner p {
	margin: 0;
	font-size: var(--t-14);
	line-height: 1.5;
}
/* Qualified by the element and the parent so it simply outranks
   `.bb-quote-banner p` above (0,2,1 beats 0,1,1). The first cut used
   !important, which the token audit rejects on a restricted property —
   correctly: `var(--t-16) !important` is not a bare token reference, and
   the rule exists so nobody wins a specificity fight with a flag. */
.bb-quote-banner p.bb-quote-banner-title {
	margin: 0 0 6px;
	font-size: var(--t-16);
	font-weight: 700;
}
.bb-quote-banner a {
	color: inherit;
	font-weight: 700;
}

/* 1.3.10: "Good to know" under Back and Pay. */
.bb-foot-notice {
	margin-top: 16px;
}

/* ===================================================================
 * 1.3.11 (client): A CAR'S PHOTO OPENS FULL SIZE. The photo is a button
 * marked "Enlarge"; the viewer is a dark full-screen layer with the car's
 * name and a close button. Tapping anywhere, Esc or the phone's Back closes it.
 * =================================================================== */
.bb-car-zoom {
	position: relative;
	display: block;
	width: 100%;
	margin: 0;
	padding: 0;
	border: 0;
	font: inherit;
	color: inherit;
	text-align: inherit;
	cursor: zoom-in;
	-webkit-appearance: none;
	appearance: none;
}
.bb-car-zoom:focus-visible {
	outline: 3px solid var(--focus);
	outline-offset: -3px;
}
.bb-car-zoom-label {
	position: absolute;
	right: 8px;
	bottom: 8px;
	display: inline-flex;
	align-items: center;
	gap: 4px;
	padding: 4px 9px;
	border-radius: 999px;
	background: rgba(12, 26, 51, 0.8);
	color: #fff;
	font-family: var(--font);
	font-size: var(--t-12);
	font-weight: 700;
	line-height: 1.2;
	pointer-events: none;
}
.bb-car-zoom-label svg {
	flex: none;
	width: 14px;
	height: 14px;
}
html.bb-viewer-open {
	overflow: hidden;
}
.bb-photo-viewer {
	position: fixed;
	inset: 0;
	z-index: 100000;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 72px 16px 24px;
	background: rgba(12, 26, 51, 0.94);
	font-family: var(--font);
	cursor: zoom-out;
}
.bb-photo-viewer[hidden] {
	display: none;
}
.bb-photo-viewer-img {
	display: block;
	width: auto;
	height: auto;
	max-width: 100%;
	max-height: 100%;
	object-fit: contain;
	border-radius: var(--r-md);
}
.bb-photo-viewer-name {
	position: absolute;
	top: 0;
	left: 16px;
	right: 76px;
	margin: 0;
	padding-top: max(24px, env(safe-area-inset-top));
	color: #fff;
	font-size: var(--t-16);
	font-weight: 700;
	line-height: 1.3;
	overflow-wrap: anywhere;
}
.bb-photo-viewer-close {
	position: absolute;
	top: max(12px, env(safe-area-inset-top));
	right: 12px;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 48px;
	height: 48px;
	margin: 0;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: #fff;
	color: var(--harbour);
	cursor: pointer;
}
.bb-photo-viewer-close svg {
	width: 22px;
	height: 22px;
}
.bb-photo-viewer-close:focus-visible {
	outline: 3px solid #fff;
	outline-offset: 3px;
}

/* ===================================================================
 * 1.3.10 (client): PICK A CAR ON A PHONE - compact cards. A small photo
 * beside the name, this trip's price and what the car takes; the
 * description kept to two lines; Choose across the foot. About three
 * cars to a screen instead of one. The whole card can be tapped.
 * =================================================================== */
@media (max-width: 599px) {
	.bb-vehicle-list {
		gap: 10px;
	}
	.bb-vehicle-list .bb-vehicle-card {
		display: grid;
		grid-template-columns: 96px minmax(0, 1fr);
		column-gap: 12px;
		padding: 12px;
		cursor: pointer;
	}
	.bb-vehicle-list .bb-vehicle-card > .bb-car-photo {
		grid-column: 1;
		grid-row: 1;
		align-self: start;
		border-radius: var(--r-md);
	}
	.bb-vehicle-list .bb-car-photo-img {
		aspect-ratio: 4 / 3;
		border-radius: var(--r-md);
	}
	/* The body's parts sit straight in the card's grid: the details beside
	   the photo, Choose across the foot. */
	.bb-vehicle-list .bb-vehicle-card-body,
	.bb-vehicle-list .bb-vehicle-card-foot {
		display: contents;
	}
	.bb-vehicle-list .bb-vehicle-card > .bb-car-photo {
		grid-row: 1 / span 2;
	}
	.bb-vehicle-list .bb-vehicle-card-head,
	.bb-vehicle-list .bb-vehicle-card-description {
		grid-column: 2;
		margin-bottom: 6px;
	}
	/* What the car takes, and why it does not fit: one line across the card. */
	.bb-vehicle-list .bb-vehicle-card-reason,
	.bb-vehicle-list .bb-car-badges {
		grid-column: 1 / -1;
		margin-top: 4px;
	}
	/* A car that does not fit: its name and why, nothing more. */
	.bb-vehicle-list .bb-vehicle-card.is-unfit {
		cursor: default;
	}
	.bb-vehicle-list .bb-vehicle-card.is-unfit .bb-car-photo,
	.bb-vehicle-list .bb-vehicle-card.is-unfit .bb-vehicle-card-description,
	.bb-vehicle-list .bb-vehicle-card.is-unfit .bb-vehicle-card-price,
	.bb-vehicle-list .bb-vehicle-card.is-unfit .bb-car-sub-badge,
	.bb-vehicle-list .bb-vehicle-card.is-unfit .bb-car-badges,
	.bb-vehicle-list .bb-vehicle-card.is-unfit .bb-vehicle-card-choose {
		display: none;
	}
	.bb-vehicle-list .bb-vehicle-card.is-unfit .bb-vehicle-card-head,
	.bb-vehicle-list .bb-vehicle-card.is-unfit .bb-vehicle-card-reason {
		grid-column: 1 / -1;
		margin: 0;
	}
	.bb-vehicle-list .bb-vehicle-card.is-unfit .bb-vehicle-card-reason {
		margin-top: 6px;
	}
	.bb-vehicle-list .bb-vehicle-card-name {
		font-size: var(--t-16);
	}
	.bb-vehicle-list .bb-vehicle-card-amount {
		font-size: var(--t-20);
	}
	.bb-vehicle-list .bb-vehicle-card-description {
		display: -webkit-box;
		-webkit-box-orient: vertical;
		-webkit-line-clamp: 2;
		overflow: hidden;
		font-size: var(--t-13);
		line-height: 1.4;
	}
	.bb-vehicle-list .bb-vehicle-card-reason {
		padding: 6px 8px;
		font-size: var(--t-12);
	}
	.bb-vehicle-list .bb-car-badges {
		gap: 4px;
	}
	.bb-vehicle-list .bb-car-badges li {
		padding: 3px 6px 3px 4px;
		font-size: 11px;
	}
	.bb-vehicle-list .bb-car-sub-badge {
		font-size: 11.5px;
		line-height: 1.3;
	}
	/* Choose spans the whole card, under the photo and the details. */
	.bb-vehicle-list .bb-vehicle-card-choose {
		grid-column: 1 / -1;
		margin-top: 4px;
		min-height: 44px;
		padding: 10px 16px;
	}
	/* 1.3.11: "Enlarge" across the foot of the small photo. */
	.bb-vehicle-list .bb-car-zoom-label {
		left: 4px;
		right: 4px;
		bottom: 4px;
		justify-content: center;
		padding: 3px 4px;
		font-size: 11px;
	}
	.bb-vehicle-list .bb-car-zoom-label svg {
		width: 12px;
		height: 12px;
	}
}

/* 1.3.10 (client): a field's (i) tip - fields start empty; the tip says what
   goes in, when asked. */
.bb-field-label-row {
	display: flex;
	align-items: center;
	justify-content: flex-start;
	gap: 6px;
}
.bb-field-label-row > .bb-field-label {
	flex: 0 1 auto;
	min-width: 0;
}
.bb-info-btn {
	/* A 40px tap area around a 20px circle. */
	position: relative;
	flex: 0 0 auto;
	/* 1.3.10: 40 wide, 28 tall - it never reaches into the field below. */
	width: 40px;
	height: 28px;
	margin: -5px -10px -5px -8px;
	padding: 0;
	border: 0;
	background: transparent;
	color: transparent;
	font-size: 0;
	cursor: pointer;
}
.bb-info-btn::before {
	content: 'i';
	position: absolute;
	top: 50%;
	left: 50%;
	width: 18px;
	height: 18px;
	transform: translate(-50%, -50%);
	border: 1.5px solid var(--harbour);
	border-radius: 50%;
	color: var(--harbour);
	font-family: Georgia, 'Times New Roman', serif;
	font-size: 12px;
	font-style: italic;
	font-weight: 700;
	line-height: 18px;
	text-align: center;
}
.bb-info-btn[aria-expanded="true"]::before {
	background: var(--harbour);
	color: var(--paper);
}
.bb-info-btn:focus-visible {
	outline: 2px solid var(--focus);
	outline-offset: -6px;
	border-radius: 50%;
}
.bb-info-tip {
	display: block;
	padding: 8px 10px;
	border-radius: var(--r-sm);
	background: var(--harbour-tint);
	font-size: var(--t-13);
	line-height: 1.45;
	color: var(--harbour);
}
