:root {
	--bg: #f6f5f2;
	--card: #ffffff;
	--text: #1d1d1b;
	--muted: #6b6a66;
	--line: #dcdad4;
	--accent: #1f5f8b;
	--accent-text: #ffffff;
	--primary: #0b6bff; /* platform primary button */
	--primary-text: #ffffff;
	--error: #b3261e;
	--error-bg: #fbeaea;
	--ok: #2e7d32;
	--warn: #8a5a00;
	--warn-strong: #6b4600;
	--warn-bg: #fdf0d9;
	--warn-line: #e0b35c;
	--error-line: #e5a29d;
	/* Job statuses: a soft pill with dark text, a bright dot in the status menu. */
	--status-quoted: #14498f;
	--status-quoted-bg: #e3edfb;
	--status-booked: #12692a;
	--status-booked-bg: #d9f7e0;
	--status-completed: #6f8a74;
	--status-completed-line: #b9cfbe;
	--dot-quoted: #4f8ff0;
	--dot-booked: #34c759;
	--dot-cancelled: #e5484d;
	/* The toast is the other theme's surface: dark on a light page, light on a dark one. */
	--toast-bg: #22211f;
	--toast-text: #f5f4f1;
	--toast-mark-text: #12110f;
	--toast-error-mark: #f2a49d;
	--toast-ok-mark: #2e7d32;
	--toast-info-mark: #0b6bff;
	--knob: #ffffff;
	/* Type: seven sizes, no others (decision 0038). */
	--text-xs: 0.75rem;
	--text-sm: 0.875rem;
	--text-base: 1rem;
	--text-md: 1.125rem;
	--text-lg: 1.5rem;
	--text-bar: 1.75rem;
	--text-price: 2.5rem;
	/* Corners: controls, cards and what floats, the bottom sheet's top. */
	--radius-sm: 8px;
	--radius: 10px;
	--radius-sheet: 18px;
	/* Shadows: one for what floats; the bars and the sheet keep their own edge. */
	--shadow-float: 0 8px 28px rgba(0, 0, 0, 0.18);
	--shadow-bar: 0 -2px 12px rgba(0, 0, 0, 0.08);
	--shadow-header: 0 1px 12px rgba(0, 0, 0, 0.06);
	--shadow-sheet: 0 -8px 30px rgba(0, 0, 0, 0.2);
}
@media (prefers-color-scheme: dark) {
	:root {
		--bg: #161615;
		--card: #21211f;
		--text: #ecebe7;
		--muted: #a3a29c;
		--line: #3a3936;
		--accent: #6fb3e0;
		--accent-text: #0e1a22;
		--primary: #4c9aff;
		--primary-text: #0b1620;
		--error: #f28b82;
		--error-bg: #3a2020;
		--ok: #81c995;
		--warn: #f0c069;
		--warn-strong: #f0c069;
		--warn-bg: #3b2f16;
		--warn-line: #7a5c26;
		--error-line: #6e3431;
		--status-quoted: #9dc4f5;
		--status-quoted-bg: #17304f;
		--status-booked: #8ee5a3;
		--status-booked-bg: #143a20;
		--status-completed: #7f9a84;
		--status-completed-line: #3f5645;
		--toast-bg: #f5f4f1;
		--toast-text: #1d1d1b;
		--toast-mark-text: #ffffff;
		--toast-error-mark: #b3261e;
	}
}

* { box-sizing: border-box; }
body {
	margin: 0;
	background: var(--bg);
	color: var(--text);
	font: 16px/1.45 system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
}
main { max-width: 640px; margin: 0 auto; padding: 16px 16px calc(24px + env(safe-area-inset-bottom)); }
/* System UI throughout (Mark's font pick, September 30, 2026): headings and the price are
   tightened a little, as on the marketing site, to sit with the logo. */
h1 { font-size: var(--text-lg); margin: 8px 0 4px; letter-spacing: -0.02em; text-wrap: balance; }
/* No help line or paragraph ends on one word alone, as on the marketing site. */
p, .help, .lead { text-wrap: pretty; }
h2 { font-size: var(--text-md); margin: 20px 0 8px; }
p.lead { color: var(--muted); margin: 0 0 16px; }
.step { color: var(--muted); font-size: var(--text-sm); margin-top: 8px; }

.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px; margin: 12px 0; }
/* A heading that opens a card: the card's padding is the space above it. Its own top
   margin would stack on top of that and sit the title lower than everything else. */
.card > h2:first-child { margin-top: 0; }
.field { margin: 0 0 16px; }
.field:last-child { margin-bottom: 0; }
.field > label, .label { display: block; font-weight: 600; margin-bottom: 4px; }
.help { color: var(--muted); font-size: var(--text-sm); margin-top: 4px; }

input[type='text'], input[type='number'], input[type='tel'], input[type='email'], input[type='date'], select {
	width: 100%;
	font: inherit;
	color: var(--text);
	background: var(--card);
	border: 1px solid var(--line);
	border-radius: var(--radius-sm);
	padding: 10px 12px;
	min-height: 44px;
}
/* Every dropdown draws its own arrow (Mark, October 11, 2026): the phone's own was black on
   the dark card and all but invisible. One chevron in the text colour, the same in every
   browser and both themes. Files, not inline images: the content policy allows only our own. */
select {
	-webkit-appearance: none;
	appearance: none;
	padding-right: 40px;
	background-image: url('/img/chevron-down.svg');
	background-repeat: no-repeat;
	background-position: right 14px center;
	background-size: 14px 8px;
}
@media (prefers-color-scheme: dark) {
	select { background-image: url('/img/chevron-down-dark.svg'); }
}
/* One focus ring everywhere (decision 0038): inputs on tap, every other control from the keyboard.
   Rows inside a menu or sheet draw theirs inset, below, so it isn't clipped. */
input:focus, select:focus, textarea:focus { outline: 2px solid var(--primary); outline-offset: 2px; }
:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
input.invalid { border-color: var(--error); background: var(--error-bg); }

.unit { display: flex; align-items: center; gap: 6px; }
.unit input { flex: 1; min-width: 0; }
.unit span { color: var(--muted); white-space: nowrap; }

.check { display: flex; gap: 10px; align-items: flex-start; }
.check input { width: 22px; height: 22px; margin: 2px 0 0; flex: none; }
.check label { font-weight: 400; }

.rows { display: grid; gap: 8px; }
.row { display: grid; gap: 8px; align-items: end; }
.row .field { margin: 0; }
.row .label { font-size: var(--text-sm); font-weight: 600; color: var(--muted); }
.row-tiers { grid-template-columns: 1.2fr 1fr 1fr auto; }
@media (max-width: 620px) {
	.row-extras { grid-template-columns: 1fr 1fr 1fr; }
	.row-extras .grow { grid-column: span 3; }
}
.saved { background: var(--card); border: 1px solid var(--ok); color: var(--ok); border-radius: var(--radius-sm); padding: 12px 16px; margin: 12px 0; }
.pick button b { display: block; }
.pick button .help { font-weight: 400; margin-top: 2px; }
/* Quote screen at the free limit: the upgrade card alone, nothing to adjust beneath it. */
.limited > :not(#result) { display: none; }
.bar-hint { max-width: 640px; margin: 0 auto 8px; color: var(--muted); font-size: var(--text-sm); text-align: center; }
.optional { font-weight: 400; color: var(--muted); } /* "USDOT number (optional)" */
.tip h2 { margin-top: 0; }
.tip p { margin: 0 0 8px; }
.plain { font-weight: 400; } /* "My plan – Free": the value beside a bold label */
/* …in colour only when it needs attention: "Ends Oct 26", "Payment failed". */
.plain.warn { color: var(--warn); }
.plain.danger { color: var(--error); }
.row-rates { grid-template-columns: minmax(64px, 1fr) minmax(92px, 1.1fr) minmax(84px, 1fr); align-items: center; gap: 10px; }
.row-rates.head { color: var(--muted); font-size: var(--text-sm); padding-bottom: 2px; }
.row-rates.head span:not(:first-child) { padding-left: 2px; }
.row-rates .tier-name { font-weight: 600; }
.row-rates .unit span { font-size: var(--text-sm); }
.row-rates input { padding: 10px 8px; }

/* Job type on the left, price on the right. */
.amount-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--line); }
.amount-row:last-child { border-bottom: 0; }
.amount-row label { font-weight: 600; }
.amount-row .amount { flex: none; width: 110px; }
@media (max-width: 520px) {
	.row-addons { grid-template-columns: 1fr 1fr; }
	.row-addons .grow { grid-column: 1 / -1; }
	.row-tiers { grid-template-columns: 1fr 1fr; }
	.row-tiers .grow { grid-column: 1 / -1; }
	.rows > .row { border-bottom: 1px solid var(--line); padding-bottom: 10px; }
	.rows > .row.head { border-bottom: 0; padding-bottom: 2px; }
}
.static { min-height: 44px; display: flex; align-items: center; color: var(--muted); }

button, .button {
	font: inherit;
	border-radius: var(--radius-sm);
	min-height: 44px;
	padding: 10px 16px;
	cursor: pointer;
	border: 1px solid var(--line);
	background: var(--card);
	color: var(--text);
}
button.primary { background: var(--primary); color: var(--primary-text); border-color: var(--primary); font-weight: 600; }
button.primary:disabled { opacity: 1; background: var(--line); border-color: var(--line); color: var(--muted); }
button.link { border: 0; background: none; color: var(--accent); padding: 10px 0; text-decoration: underline; }
a.link { display: inline-block; color: var(--accent); padding: 10px 0; font-size: var(--text-base); }
button.remove { min-width: 44px; padding: 0; color: var(--muted); }
button:disabled { opacity: 0.5; cursor: default; }

/* Buttons sit at the end of the screen's own content, not in a fixed bar. */
.nav { display: flex; gap: 8px; align-items: center; margin: 20px 0 0; }
.nav .primary { flex: 1; } /* Next/Finish fills the row; Back keeps its size */

details { margin: 8px 0 0; }
summary { cursor: pointer; color: var(--accent); padding: 8px 0; min-height: 44px; }

.quote-profit b { color: var(--text); font-weight: 600; }
.choice { display: grid; gap: 8px; }
/* One of a few: a card each, and the chosen one wears the blue outline a chosen plan does.
   No radio dial (Mark, October 10, 2026: nothing else in the app has one). The input is
   still there for the keyboard and screen readers, only not drawn. */
.choice label { position: relative; display: flex; gap: 10px; border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 12px; font-weight: 400; cursor: pointer; }
.choice input[type='radio'] { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; pointer-events: none; }
.choice label:has(input[type='radio']:checked) { border-color: var(--primary); box-shadow: inset 0 0 0 1px var(--primary); }
.choice label:has(input[type='radio']:focus-visible) { outline: 2px solid var(--primary); outline-offset: 2px; }
.choice b { display: block; }
/* The fuel price's three choices (Settings → Costs): short rows, each with its price at the
   right, so the card stays short on a phone. */
.fuel-choice { gap: 8px; margin-top: 10px; }
.fuel-choice label { align-items: center; padding: 8px 14px; min-height: 52px; }
.fuel-choice .fuel-name { flex: 1; min-width: 0; }
.fuel-choice .fuel-name small { display: block; color: var(--muted); font-size: var(--text-sm); line-height: 1.3; }
.fuel-choice .fuel-price { flex: none; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.fuel-choice .unit.fuel-price { font-weight: 400; gap: 6px; }
.fuel-choice .unit.fuel-price input { width: 5.25em; min-height: 40px; margin: 0; padding: 6px 8px; text-align: right; }

/* Tier-mode preview: the same three hauls priced both ways, so the difference between
   the modes is visible before one is chosen. Fixed layout so it cannot outgrow a phone. */
table.tier-preview {
	width: 100%;
	table-layout: fixed;
	border-collapse: collapse;
	margin-top: 12px;
	font-size: var(--text-sm);
	font-variant-numeric: tabular-nums;
}
table.tier-preview caption {
	caption-side: top;
	text-align: left;
	color: var(--muted);
	font-size: var(--text-sm);
	padding-bottom: 6px;
}
table.tier-preview th, table.tier-preview td {
	padding: 8px 4px;
	text-align: right;
	border-bottom: 1px solid var(--line);
	white-space: nowrap;
}
table.tier-preview tr > *:first-child { width: 28%; text-align: left; }
table.tier-preview thead th { color: var(--muted); font-size: var(--text-xs); font-weight: 600; }
table.tier-preview tbody th { font-weight: 600; color: var(--muted); }
table.tier-preview tbody tr:last-child > * { border-bottom: 0; }
/* The mode in use, marked in both the heading and its column. */
table.tier-preview .on { color: var(--text); font-weight: 600; }
table.tier-preview thead th.on { color: var(--primary); }

.errors { background: var(--error-bg); color: var(--error); border-radius: var(--radius-sm); padding: 12px 16px; margin: 12px 0; }
.errors ul { margin: 6px 0 0; padding-left: 18px; }
.notice { color: var(--muted); font-size: var(--text-sm); margin-top: 6px; }

/* The list floats over the page rather than sitting in it: appearing in the flow shoved
   every field below it down, and yanked them back when it closed. */
.suggest { position: relative; }
.suggest ul {
	position: absolute;
	left: 0;
	right: 0;
	top: 100%;
	z-index: 20;
	list-style: none;
	margin: 4px 0 0;
	padding: 0;
	border: 1px solid var(--line);
	border-radius: var(--radius-sm);
	background: var(--card);
	overflow: hidden;
	box-shadow: var(--shadow-float);
}
.suggest li { padding: 10px 12px; cursor: pointer; border-bottom: 1px solid var(--line); }
.suggest li:last-of-type { border-bottom: 0; }
.suggest li.active, .suggest li:hover { background: var(--bg); }
.suggest .searching { color: var(--muted); cursor: default; }
.suggest .searching:hover { background: none; }
.suggest .attribution { font-size: var(--text-xs); color: var(--muted); padding: 6px 12px; background: var(--bg); cursor: default; }
/* The small print at the foot of the quote's Price step: what the numbers aren't, and the map credit. */
.fineprint { color: var(--muted); font-size: var(--text-xs); line-height: 1.5; text-align: center; margin: 24px 0 8px; text-wrap: balance; }
.ok-check { color: var(--ok); margin-left: 8px; font-size: 1.35em; line-height: 1; vertical-align: -0.08em; }

/* Toggle rows: the whole row is tappable; the control is a real checkbox with role="switch". */
.switch-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	padding: 14px 0;
	border-bottom: 1px solid var(--line);
	font-weight: 600;
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
}
.switch-row:first-child { padding-top: 4px; }
.switch-row:last-of-type { border-bottom: 0; padding-bottom: 4px; }
.switch {
	appearance: none;
	-webkit-appearance: none;
	flex: none;
	position: relative;
	width: 52px;
	height: 32px;
	min-height: 0;
	margin: 0;
	padding: 0;
	border: 0;
	border-radius: 999px;
	background: var(--line);
	cursor: pointer;
	transition: background 0.2s ease;
}
.switch::after {
	content: '';
	position: absolute;
	top: 3px;
	left: 3px;
	width: 26px;
	height: 26px;
	border-radius: 50%;
	background: var(--knob);
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
	transition: transform 0.2s ease;
}
.switch:checked { background: var(--primary); }
.switch:checked::after { transform: translateX(20px); }
.switch:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.switch:active::after { width: 30px; }
@media (prefers-reduced-motion: reduce) {
	.switch, .switch::after { transition: none; }
}

.close {
	float: right;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	margin: -4px -8px 0 0;
	font-size: 1.25rem; /* the × glyph, not text: off the type scale on purpose */
	color: var(--muted);
	text-decoration: none;
	border-radius: var(--radius-sm);
}
.close:hover { background: var(--card); color: var(--text); }

/* Sections that zip open and shut */
.collapse { display: grid; grid-template-rows: 0fr; opacity: 0; transition: grid-template-rows 0.28s ease, opacity 0.2s ease; }
.collapse > .collapse-inner { overflow: hidden; min-height: 0; }
.collapse.open { grid-template-rows: 1fr; opacity: 1; }
@media (prefers-reduced-motion: reduce) {
	.collapse { transition: none; }
}

/* Tappable list of hauling types */
.pick { display: grid; gap: 8px; }
.pick button {
	width: 100%;
	text-align: left;
	font-size: var(--text-md);
	font-weight: 600;
	padding: 16px;
	min-height: 56px;
}
.pick button:hover { border-color: var(--primary); }

/* Grouped menu: a heading over one card of rows (menuGroup in ui.js). */
.menu-group { margin: 0 0 20px; }
.menu-group-title { margin: 0 0 8px 4px; font-size: var(--text-xs); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.menu-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.menu-row {
	display: flex;
	align-items: center;
	gap: 14px;
	width: 100%;
	min-height: 64px;
	padding: 12px 14px;
	text-align: left;
	background: none;
	border: 0;
	border-radius: 0;
	color: inherit;
	font: inherit;
}
.menu-row + .menu-row { border-top: 1px solid var(--line); }
@media (hover: hover) { .menu-row:hover { background: var(--bg); } }
.menu-row:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.menu-icon {
	flex: none;
	display: grid;
	place-items: center;
	width: 36px;
	height: 36px;
	border-radius: var(--radius);
	color: var(--primary);
	background: color-mix(in srgb, var(--primary) 14%, transparent);
}
.menu-text { flex: 1; min-width: 0; display: grid; gap: 2px; }
.menu-text b { font-weight: 600; }
.menu-text .help { margin: 0; font-size: var(--text-sm); line-height: 1.3; }
.menu-chevron { flex: none; width: 8px; height: 8px; border-right: 2px solid var(--muted); border-top: 2px solid var(--muted); transform: rotate(45deg); margin-right: 4px; opacity: 0.7; }

/* Sticky actions at the foot of a settings page */
.action-bar {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	background: var(--card);
	border-top: 1px solid var(--line);
	padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
	box-shadow: var(--shadow-bar);
	z-index: 10;
}
.action-bar-inner { max-width: 640px; margin: 0 auto; display: flex; gap: 8px; align-items: center; }
.action-bar .primary { flex: 1; }

/* The price stays in view, in the thumb zone */
.quote-bar {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	background: var(--card);
	border-top: 1px solid var(--line);
	padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
	box-shadow: var(--shadow-bar);
	z-index: 10;
}
.quote-bar-inner { max-width: 640px; margin: 0 auto; display: flex; align-items: center; gap: 12px; }
.quote-bar .amount { font-size: var(--text-bar); font-weight: 700; line-height: 1.1; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.quote-bar .sub { color: var(--muted); font-size: var(--text-sm); }
/* The right of the bar says where the save stands: a nudge to add a customer, Saving…,
   ✓ Saved, or a retry. Quotes save themselves, so there is no Save button. */
.bar-side { flex: none; margin-left: auto; text-align: right; font-size: var(--text-sm); color: var(--muted); display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.bar-side .bar-status { font-size: var(--text-xs); font-weight: 600; padding: 0; min-height: 0; }
.bar-side button.link { padding: 10px 0; text-decoration: none; font-weight: 600; font-size: var(--text-base); }
.bar-side .saved-flag { color: var(--ok); font-weight: 600; }
.quote-bar.working .amount { opacity: 0.5; }
/* Out of free quotes on a saved quote: the way to upgrade, at the foot of each step. Outlined
   like Install, so Next in the bar stays the screen's one filled button. */
.upgrade-card { display: flex; align-items: center; gap: 12px; margin-top: 16px; }
.upgrade-card > div { flex: 1; min-width: 0; }
.upgrade-card button { flex: none; margin: 0; background: transparent; border-color: var(--primary); color: var(--primary); font-weight: 600; }
/* Out of free quotes: the bar is an announcement, not a price. */
.quote-bar.announce .amount { font-size: var(--text-base); line-height: 1.3; letter-spacing: 0; }
.quote-bar.announce .sub { font-size: var(--text-sm); margin-top: 2px; }
body.has-bar main { padding-bottom: calc(128px + env(safe-area-inset-bottom)); } /* room to scroll anything above the bar */

/* Quote result */
#result.working { opacity: 0.55; transition: opacity 0.15s ease; }
.quote { text-align: center; }
.quote-total { font-size: var(--text-price); font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
.amount-row > span:last-child { font-variant-numeric: tabular-nums; white-space: nowrap; font-weight: 600; }
.amount-row .help { font-weight: 400; }
a.button { display: inline-flex; align-items: center; justify-content: center; text-decoration: none; }
a.button.primary { background: var(--primary); color: var(--primary-text); border-color: var(--primary); font-weight: 600; }
#result h2, #form h2 { margin-top: 0; }

/* Toasts: one style everywhere. Bottom centre, above any sticky footer. */
.toasts {
	position: fixed;
	left: 0;
	right: 0;
	bottom: calc(16px + env(safe-area-inset-bottom));
	z-index: 50;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 8px;
	padding: 0 16px;
	pointer-events: none;
}
body.has-bar .toasts { bottom: calc(80px + env(safe-area-inset-bottom)); }
.toast {
	pointer-events: auto;
	display: flex;
	align-items: flex-start;
	gap: 10px;
	width: 100%;
	max-width: 480px;
	padding: 12px 14px;
	border-radius: var(--radius);
	background: var(--toast-bg);
	color: var(--toast-text);
	font-size: var(--text-base);
	line-height: 1.35;
	box-shadow: var(--shadow-float);
	opacity: 0;
	transform: translateY(12px) scale(0.98);
	transition: opacity 0.2s ease, transform 0.2s ease;
	cursor: pointer;
}
.toast.in { opacity: 1; transform: none; }
.toast-mark {
	flex: none;
	width: 20px;
	height: 20px;
	border-radius: 50%;
	display: grid;
	place-items: center;
	font-size: var(--text-xs);
	font-weight: 700;
	color: var(--toast-mark-text);
	background: var(--toast-ok-mark);
}
.toast-error .toast-mark { background: var(--toast-error-mark); }
.toast-info .toast-mark { background: var(--toast-info-mark); color: var(--knob); }
/* On a dark page a dark toast disappears, so it flips to light, with an edge and a lift. */
@media (prefers-color-scheme: dark) {
	.toast { box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.15); }
}
@media (prefers-reduced-motion: reduce) {
	.toast { transform: none; transition: opacity 0.2s ease; }
}

[hidden] { display: none !important; }

/* ---- Home ---- */
/* The app shell header: pinned to the top and frosted, so the page slides under it.
   Home shows the company name; a sub-page shows a back arrow and, once its own heading
   has scrolled under the bar, that heading's echo in the centre. */
.app-header {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	z-index: 15;
	padding-top: env(safe-area-inset-top);
	background: var(--bg);
	background: color-mix(in srgb, var(--bg) 82%, transparent);
	-webkit-backdrop-filter: blur(20px) saturate(180%);
	backdrop-filter: blur(20px) saturate(180%);
	/* The hairline is always there, so the header reads as a header at the top of the page
	   too (Mark, September 26, 2026); the shadow comes in once anything slides under it. */
	border-bottom: 1px solid var(--line);
	transition: box-shadow 0.2s ease;
}
.app-header.scrolled { box-shadow: var(--shadow-header); }
.app-header-inner {
	max-width: 640px;
	min-height: 52px;
	margin: 0 auto;
	padding: 4px 16px;
	display: grid;
	grid-template-columns: 1fr 44px;
	align-items: center;
	gap: 8px;
}
/* Back on the left, menu on the right, the same width each, so the title is truly centred. */
.app-header.sub .app-header-inner { grid-template-columns: 44px 1fr 44px; padding: 4px 12px; }
.app-header-title {
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	text-align: center;
	font-weight: 600;
	opacity: 0;
	transform: translateY(6px);
	transition: opacity 0.2s ease, transform 0.2s ease;
}
.app-header.titled .app-header-title { opacity: 1; transform: none; }
.icon-button.back { color: var(--text); }
body.has-header main { padding-top: calc(60px + env(safe-area-inset-top)); }
/* Anything scrolled into view, by script or anchor, stops below the bar rather than under it. */
html { scroll-padding-top: calc(64px + env(safe-area-inset-top)); }
@media (prefers-reduced-motion: reduce) {
	.app-header, .app-header-title { transition: none; }
}
.app-title {
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	color: var(--text);
	text-decoration: none;
	font-weight: 700;
	font-size: var(--text-md);
}
.app-title:hover { color: var(--accent); }
/* Our logo at the foot of the gear sheet: small and muted, never competing with their name. */
.sheet-brand { display: flex; justify-content: center; padding: 14px 0 4px; opacity: 0.55; }
.sheet-brand img { display: block; height: 18px; width: auto; }

/* The first of the two things the app does, sized so it can't be missed on a phone.
   On the home page it sits in the sticky action bar, within thumb reach. */
.big-action {
	display: flex;
	align-items: center;
	justify-content: center;
	min-height: 56px;
	margin: 16px 0 8px;
	background: var(--primary);
	color: var(--primary-text);
	border-radius: var(--radius);
	font-size: var(--text-md);
	font-weight: 600;
	text-decoration: none;
}
.big-action:active { filter: brightness(0.94); }

/* Signed out: the front door. Logo and the one promise above, the way in at the foot within
   thumb reach, on a soft glow of the brand blue so it reads as ours rather than a blank form. */
body.welcome { background: radial-gradient(120% 60% at 50% 0%, color-mix(in srgb, var(--primary) 16%, transparent), transparent 70%) var(--bg) no-repeat; }
body.welcome main { min-height: 100vh; min-height: 100dvh; display: flex; padding-top: calc(16px + env(safe-area-inset-top)); }
body.welcome #app { flex: 1; display: flex; flex-direction: column; }
.welcome-top { flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; padding: 32px 8px; }
.welcome-logo { margin-bottom: 28px; }
.welcome-logo img { display: block; height: 38px; width: auto; }
.welcome-top h1 { font-size: clamp(1.9rem, 8vw, 2.4rem); line-height: 1.1; margin: 0 0 12px; max-width: 14ch; }
.welcome-top .lead { font-size: var(--text-md); margin: 0; max-width: 30ch; }
.welcome-actions { display: grid; gap: 10px; }
.welcome-actions .big-action { margin: 0; }
.welcome-actions .help { margin: 2px 0 0; }
a.button.welcome-create { min-height: 52px; font-size: var(--text-md); font-weight: 600; color: var(--text); background: transparent; }
.welcome-consent { color: var(--muted); font-size: var(--text-sm); line-height: 1.5; text-align: center; text-wrap: balance; margin: 10px 0 0; }
.welcome-consent a { color: var(--muted); text-decoration: underline; text-underline-offset: 2px; padding: 14px 0; }
.welcome-consent + .welcome-links { margin-top: 2px; }
.welcome-links { display: flex; justify-content: center; gap: 20px; margin: 14px 0 0; font-size: var(--text-sm); }
.welcome-links a { color: var(--muted); text-decoration: none; padding: 8px 0; }
@media (hover: hover) { .welcome-links a:hover { color: var(--text); } }
/* On a computer there is no thumb to reach for: the whole thing sits together in the middle. */
@media (min-width: 700px) {
	body.welcome #app { justify-content: center; }
	.welcome-top { flex: 0 0 auto; padding-bottom: 36px; }
	.welcome-actions { width: 100%; max-width: 380px; margin: 0 auto; }
}
.action-bar .big-action { flex: 1; margin: 0; }

.quote-list { display: grid; gap: 8px; }
/* A job card: three short lines in two columns (see quoteRow in js/home.js). The name is
   the link and stretches over the whole card; the status pill sits above it as its own button. */
.quote-row {
	position: relative;
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto;
	align-items: center;
	column-gap: 12px;
	row-gap: 2px;
	background: var(--card);
	border: 1px solid var(--line);
	border-radius: var(--radius);
	padding: 10px 14px;
	color: inherit;
}
@media (hover: hover) { .quote-row:has(.quote-row-name:hover) { border-color: var(--primary); } }
.quote-row-name { font-size: var(--text-md); font-weight: 600; color: inherit; text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
a.quote-row-name::after { content: ''; position: absolute; inset: 0; border-radius: inherit; }
a.quote-row-name:focus-visible { outline: none; }
.quote-row:has(a.quote-row-name:focus-visible) { outline: 2px solid var(--primary); outline-offset: 2px; }
.quote-row-amount { text-align: right; font-size: var(--text-md); font-weight: 700; font-variant-numeric: tabular-nums; }
.quote-row-route, .quote-row-date, .quote-row-type { color: var(--muted); font-size: var(--text-sm); }
.quote-row-route, .quote-row-type { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.quote-row-date { text-align: right; }
.quote-row-status { justify-self: end; position: relative; z-index: 1; }
.empty { text-align: center; color: var(--muted); }
.empty p { margin: 0 0 4px; font-weight: 400; }

/* ---- Gear menu: everywhere else you can get to from home ---- */
.menu-wrap { position: relative; flex: none; }
.icon-button {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	border-radius: 999px;
	color: var(--muted);
	background: none;
	border: 0;
}
@media (hover: hover) {
	.icon-button:hover { background: var(--card); color: var(--text); }
}
.icon-button[aria-expanded='true'] { background: var(--card); color: var(--text); }
.menu {
	position: absolute;
	right: 0;
	top: calc(100% + 6px);
	z-index: 20;
	min-width: 232px;
	padding: 6px;
	background: var(--card);
	border: 1px solid var(--line);
	border-radius: var(--radius);
	box-shadow: var(--shadow-float);
}
.menu-brand { padding: 10px 12px 12px; margin-bottom: 4px; border-bottom: 1px solid var(--line); }
.menu-brand img { display: block; height: 18px; width: auto; }
.menu [role='menuitem'] {
	display: block;
	width: 100%;
	min-height: 44px;
	padding: 10px 12px;
	text-align: left;
	background: none;
	border: 0;
	border-radius: var(--radius-sm);
	color: inherit;
	text-decoration: none;
	font-size: var(--text-base);
}
@media (hover: hover) {
	.menu [role='menuitem']:hover { background: var(--bg); }
}
.menu [role='menuitem']:focus-visible { background: var(--bg); outline: 2px solid var(--primary); outline-offset: -2px; }

/* ---- Status pills ---- */
/* Four are stored; Expired is derived from the expiry date (see js/status.js). */
.pill {
	flex: none;
	border-radius: 999px;
	padding: 2px 10px;
	font-size: var(--text-xs);
	font-weight: 600;
	line-height: 1.5;
	border: 1px solid transparent;
}
.pill.quoted { background: var(--status-quoted-bg); color: var(--status-quoted); }
.pill.booked { background: var(--status-booked-bg); color: var(--status-booked); }
/* Completed is the same green, stepped back: the job is done and needs no attention. */
.pill.completed { background: transparent; color: var(--status-completed); border-color: var(--status-completed-line); }
.pill.cancelled { background: var(--error-bg); color: var(--error); }
.pill.expired { background: var(--warn-bg); color: var(--warn); }

/* ---- Saving a quote ---- */
/* A required field is marked on the label, not left for the server to discover. */
.field.req > label::after { content: ' *'; color: var(--error); }
.req-mark { color: var(--error); } /* the same star, where the label also carries a tick */
.field-error { color: var(--error); font-size: var(--text-sm); margin-top: 4px; }
.field-error + .field-error { display: none; }
textarea {
	width: 100%;
	font: inherit;
	padding: 12px;
	border: 1px solid var(--line);
	border-radius: var(--radius-sm);
	background: var(--card);
	color: var(--text);
	resize: vertical;
}
h2.flush { margin: 0; }

/* Tappable one-word choices: ready-made detail fields, status changes. */
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0; }
.chips button { min-height: 44px; }

button.danger { color: var(--error); border-color: var(--error); background: none; }

/* Job-detail fields: short answers, so the label sits beside the box rather than above it. */
.field.inline { display: grid; grid-template-columns: 1fr minmax(110px, 42%); align-items: center; gap: 12px; }
.field.inline > .label { margin-bottom: 0; font-weight: 600; }
.field.inline input { width: 100%; min-width: 0; }
/* iOS gives a date box an intrinsic width that ignores the column; take that away. */
.field.inline:has(input[type='date']) { grid-template-columns: 1fr minmax(150px, 50%); } /* "Nov 18, 2026" on one line, even zoomed */
.field.inline input[type='date'] { -webkit-appearance: none; appearance: none; }

/* Says which saved customer this quote is attached to. */
.linked { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 6px; color: var(--muted); font-size: var(--text-sm); }
.linked button.link { padding: 0; }
.suggest li b { display: block; }

/* The footer holds the price and one action; neither may wrap onto a second line. */
.quote-bar button { white-space: nowrap; }
.quote-bar .bar-next { min-width: 112px; min-height: 48px; padding: 0 22px; }
.quote-bar .bar-back { flex: none; margin-left: -8px; color: var(--text); }
@media (max-width: 380px) { .quote-bar .amount { font-size: var(--text-lg); } .quote-bar .bar-next { min-width: 96px; padding: 0 16px; } }
/* Up to two lines before it gives up: the miles matter more than a single tidy line. */
.quote-bar .sub { overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-height: 1.25; }
.quote-bar-inner > div:first-child { min-width: 0; }

/* ---- Disclosure: one consistent way to open a section ---- */
.disclosure {
	display: flex;
	width: 100%;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	min-height: 48px;
	padding: 12px 0;
	border: 0;
	background: none;
	color: var(--accent);
	font-weight: 600;
	font-size: var(--text-base);
	text-align: left;
}
.disclosure .chev { font-size: var(--text-md); line-height: 1; transition: transform 0.2s ease; }
.disclosure[aria-expanded='true'] .chev { transform: rotate(180deg); }
/* The panel is centred inside the quote card; its contents are not. */
.quote .disclosure-wrap { text-align: left; margin-top: 8px; border-top: 1px solid var(--line); }
.quote .disclosure { justify-content: center; gap: 8px; }

/* ---- Segmented control ---- */
.tabs {
	position: relative;
	display: flex;
	gap: 4px;
	padding: 4px;
	margin: 4px 0 8px;
	background: var(--bg);
	border: 1px solid var(--line);
	border-radius: var(--radius);
}
.tab {
	/* Content-sized, sharing what is left over. flex:1 forces equal widths, which cuts
	   off the longest label while the shortest sits in white space. */
	flex: 1 1 auto;
	min-width: 0;
	min-height: 40px;
	padding: 8px 8px;
	font-size: var(--text-sm);
	white-space: nowrap;
	border: 0;
	border-radius: calc(var(--radius) - 3px);
	background: none;
	color: var(--muted);
	font-weight: 600;
	position: relative;
	z-index: 1;
	transition: color 0.2s ease;
}
/* The selected tab sits in a blue outline that slides between tabs (tabs() in ui.js).
   An outline, not a fill: a tab is a place to look, not the primary action. */
.tab[aria-selected='true'] { color: var(--primary); }
.tab-indicator {
	position: absolute;
	top: 4px;
	bottom: 4px;
	left: 0;
	width: 0;
	border-radius: calc(var(--radius) - 3px);
	background: var(--card);
	border: 1.5px solid var(--primary);
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.14);
}
.tabs.ready .tab-indicator { transition: transform 0.25s cubic-bezier(0.3, 0.7, 0.2, 1), width 0.25s cubic-bezier(0.3, 0.7, 0.2, 1); }
.tab-panels { overflow-x: clip; }
.tab-panels > .from-right { animation: tab-from-right 0.22s ease-out; }
.tab-panels > .from-left { animation: tab-from-left 0.22s ease-out; }
@keyframes tab-from-right { from { opacity: 0; transform: translateX(24px); } }
@keyframes tab-from-left { from { opacity: 0; transform: translateX(-24px); } }
@media (prefers-reduced-motion: reduce) {
	.tabs.ready .tab-indicator, .tab { transition: none; }
	.tab-panels > .from-right, .tab-panels > .from-left { animation: none; }
}
@media (prefers-reduced-motion: reduce) {
	.disclosure .chev { transition: none; }
}

/* Two ways to price the haul, presented as cards you pick between. The card is the
   control: it looked tappable, so it is. */
/* The two ways to price the haul, one above the other, each read left to right: what it
   is and why on the left, the price and whether it is in use on the right. Side by side
   they were two thin columns on a phone. Mile rate first, flat rate second. */
.compare { display: grid; gap: 10px; }
.plan {
	display: grid;
	grid-template-columns: 1fr auto;
	grid-template-areas: 'head price' 'notes notes' 'pick pick';
	column-gap: 14px;
	row-gap: 6px;
	align-items: start;
	padding: 14px 14px;
	text-align: left;
	background: var(--card);
	border: 1px solid var(--line);
	border-radius: var(--radius);
	color: inherit;
	min-height: 0;
	width: 100%;
}
.plan.active { border-color: var(--primary); box-shadow: inset 0 0 0 1px var(--primary); }
.plan-head { grid-area: head; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-height: 22px; }
.plan-name { color: var(--muted); font-size: var(--text-sm); font-weight: 600; }
.plan-price { grid-area: price; text-align: right; font-size: var(--text-lg); font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
/* Notes take the full width: beside the pick they wrapped every few words. */
.plan-per { font-size: var(--text-sm); font-weight: 600; color: var(--muted); margin-left: 1px; }
/* Compact plan card: name and one line on the left, price on the right. Three of these
   and the usage card fit one phone screen. */
.plan.compact { grid-template-areas: 'head price' 'sub price' 'meter meter'; row-gap: 6px; align-items: center; padding: 18px 16px; }
.compare:has(.plan.compact) { gap: 12px; }
.plan.compact .plan-name { color: var(--text); font-size: var(--text-md); }
.plan.compact .plan-price { font-size: var(--text-lg); }
.plan-sub { grid-area: sub; color: var(--muted); font-size: var(--text-sm); line-height: 1.35; }
.tag { border: 1px solid var(--primary); color: var(--primary); border-radius: 999px; padding: 0 7px; font-size: var(--text-xs); font-weight: 600; }
/* A plan that's been cancelled but is still running: amber, the Expired pill's colours. */
.tag.ending { border-color: var(--warn-line); color: var(--warn); background: var(--warn-bg); }
.plan-ending { background: var(--warn-bg); border-color: var(--warn-line); padding: 14px 16px; }
.plan-ending-title { font-weight: 700; color: var(--warn-strong); }
/* A failed payment: the same card in red, the Cancelled pill's colours. */
.plan-failed { background: var(--error-bg); border-color: var(--error-line); padding: 14px 16px; }
.plan-failed .plan-ending-title, .plan-failed .help { color: var(--error); }
.plan-failed .help { margin-top: 4px; }
.plan-ending .help { color: var(--warn-strong); margin-top: 4px; }
.card.usage { padding: 12px 14px; }
.usage-line { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.usage-line + .usage-line { margin-top: 6px; }
.card.usage .meter { margin: 8px 0 0; }
.plan.compact .meter { grid-area: meter; margin: 8px 0 0; }
.card.usage .help { margin-top: 8px; }
/* How much of something is used: the free plan's quotes this month. */
.meter { height: 6px; border-radius: 999px; background: var(--line); overflow: hidden; margin: 8px 0 4px; }
.meter span { display: block; height: 100%; background: var(--primary); border-radius: inherit; transition: width 0.3s ease; }
@media (prefers-reduced-motion: reduce) { .meter span { transition: none; } }
.plan-notes { grid-area: notes; margin: 0; padding: 0; list-style: none; display: grid; gap: 4px; }
.plan-notes li { color: var(--muted); font-size: var(--text-sm); line-height: 1.3; padding-left: 14px; position: relative; }
.plan-notes li::before { content: '·'; position: absolute; left: 4px; }
.plan-pick {
	grid-area: pick;
	align-self: end;
	text-align: right;
	white-space: nowrap;
	font-size: var(--text-sm);
	font-weight: 600;
	color: var(--accent);
}
.plan.active .plan-pick { color: var(--primary); }
.in-use {
	background: var(--primary);
	color: var(--primary-text);
	border-radius: 999px;
	padding: 1px 7px;
	font-size: var(--text-xs);
	font-weight: 600;
}

/* A value that belongs to the profile, shown where it applies and edited in place. */
.stat-line { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding-top: 12px; color: var(--muted); }
.stat-line button.link { padding: 0; }
.stat-line .unit { flex: 1; min-width: 140px; }
.inline-edit { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 0 0 10px; }
.inline-edit .unit { flex: 1; min-width: 120px; }
.help.centered { text-align: center; }
/* The Trip step's one-line reminder that a price covers the drive from home base and back. */
.round-trip { margin-top: 12px; }

/* ---- Editable lists: read at a glance, edit one at a time ---- */
.item-list { display: grid; gap: 10px; }
.item-card {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	background: var(--bg);
	border: 1px solid var(--line);
	border-radius: var(--radius);
	padding: 12px 14px;
}
.item-card.open { display: block; }
.item-card.open .field:last-of-type { margin-bottom: 0; }
.item-summary { min-width: 0; }
.item-summary b { display: block; overflow-wrap: anywhere; }
.item-summary .help { margin-top: 2px; }
.item-card > button { flex: none; min-height: 44px; }
/* Outside the list, so it reads as an action rather than another item. */
.list-add { margin-top: 12px; }
.list-add button { width: 100%; min-height: 48px; font-weight: 600; }

@media (max-width: 380px) {
	.tab { font-size: var(--text-sm); padding: 8px 5px; }
	.tabs { gap: 2px; padding: 3px; }
	.tab-indicator { top: 3px; bottom: 3px; }
}

/* Setup left unfinished: the saved quotes are still there, they just can't be opened yet. */
.notice-card {
	background: var(--card);
	border: 1px solid var(--primary);
	border-radius: var(--radius);
	padding: 14px 16px;
	margin: 12px 0;
}
.notice-card .button { margin-top: 12px; }
/* The offer to put the app on the home screen: one card on the home page until answered. */
.install-card .nav { margin-top: 12px; }
.install-card .nav button { margin-top: 0; }
.hotel-card .unit { flex: none; margin: 0; }
.hotel-card .unit input { width: 5.5em; margin: 0; text-align: right; }
.install-card .install-go { flex: 1; background: transparent; border-color: var(--primary); color: var(--primary); font-weight: 600; }
.install-steps { margin: 10px 0 0; padding-left: 1.3em; color: var(--text); }
.install-steps li { margin: 4px 0; }
.install-more { display: inline-block; padding: 0 0.45em; border: 1px solid var(--line); border-radius: 999px; font-size: 0.7em; letter-spacing: 0.12em; line-height: 1.9; vertical-align: 0.15em; color: var(--text); }
.install-share { display: inline-block; width: 1.15em; height: 1.15em; vertical-align: -0.2em; fill: none; stroke: var(--primary); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
/* No connection: what the page can't do right now, and a way back. */
.offline-card { border-color: var(--line); }
.offline-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.quote-row.locked { opacity: 0.6; }
.quote-row.locked:hover { border-color: var(--line); }

/* Deleting a saved quote: on its own, at the foot of the page, nowhere near anything else. */
.danger-card { margin-top: 24px; }
.danger-card button { width: 100%; }
/* A popup that wants an answer (modal() in ui.js): the page and its bars grey out behind it. */
.modal {
	width: min(440px, calc(100vw - 32px));
	padding: 0;
	border: 1px solid var(--line);
	border-radius: var(--radius);
	background: var(--card);
	color: var(--text);
}
.modal::backdrop { background: rgba(0, 0, 0, 0.6); }
.modal-inner { padding: 16px; }
.modal-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 8px; }
.modal-head h2 { margin: 0; font-size: var(--text-md); }
.modal-close { margin: -8px -8px -8px 0; }
.modal .field { margin-top: 14px; }
.modal .nav { margin-top: 14px; }
.modal .nav button { margin-top: 0; }
/* The button that backs out fills the row, outlined like Install, so nothing in a popup
   competes with the page's one filled button. */
.modal .nav .keep { flex: 1; background: transparent; border-color: var(--primary); color: var(--primary); font-weight: 600; }

/* ---- Bottom nav bar: on every page with nothing to save ---- */
.icon { display: inline-flex; line-height: 0; }
.nav-bar .action-bar-inner { gap: 10px; }
.nav-gear {
	flex: none;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 2px;
	width: 64px;
	min-height: 56px;
	padding: 4px 0;
	background: none;
	border: 0;
	border-radius: var(--radius);
	color: var(--muted);
	font-size: var(--text-xs);
	font-weight: 600;
}
.nav-gear[aria-expanded='true'] { color: var(--primary); }
@media (hover: hover) {
	.nav-gear:hover { color: var(--text); }
}
.nav-bar .big-action { flex: 1; margin: 0; }

/* ---- The sheet the gear opens: account, settings, sign out ---- */
body.sheet-open { overflow: hidden; }
.sheet-scrim {
	position: fixed;
	inset: 0;
	z-index: 30;
	background: rgba(0, 0, 0, 0.42);
	opacity: 0;
	transition: opacity 0.25s ease;
}
.sheet-scrim.open { opacity: 1; }
.sheet {
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 31;
	max-width: 640px;
	max-height: 85vh;
	margin: 0 auto;
	overflow-y: auto;
	padding: 6px 12px calc(14px + env(safe-area-inset-bottom));
	background: var(--card);
	border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
	box-shadow: var(--shadow-sheet);
	transform: translateY(100%);
	transition: transform 0.25s ease;
}
.sheet.open { transform: translateY(0); }
.sheet-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding: 6px 4px 12px;
	border-bottom: 1px solid var(--line);
	margin-bottom: 6px;
}
.sheet-head b { display: block; }
.sheet-head .help { overflow-wrap: anywhere; margin-top: 0; }
.sheet-list { display: grid; }
.sheet-item {
	display: block;
	width: 100%;
	min-height: 44px;
	padding: 8px 12px;
	text-align: left;
	background: none;
	border: 0;
	border-radius: var(--radius-sm);
	color: inherit;
	font-size: var(--text-base);
}
@media (hover: hover) {
	.sheet-item:hover { background: var(--bg); }
}
.sheet-item:focus-visible { background: var(--bg); outline: 2px solid var(--primary); outline-offset: -2px; }
.sheet .sheet-dev { color: var(--muted); }
/* The group headings, as on the Settings page's menuGroup. */
.sheet-group-title { margin: 10px 12px 2px; font-size: var(--text-xs); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.sheet-group-title:first-child { margin-top: 4px; }
/* A line between the groups, and each group's rows set in under their heading. */
.sheet-group-title:not(:first-child) { border-top: 1px solid var(--line); margin-top: 8px; padding-top: 12px; margin-left: 0; margin-right: 0; padding-left: 12px; }
.sheet-list .sheet-item:not(.sheet-dev) { padding-left: 28px; }
/* Signing out is not a setting, so it sits apart from them. */
.sheet-signout { border-top: 1px solid var(--line); margin: 6px 0 0; padding-top: 6px; }
@media (prefers-reduced-motion: reduce) {
	.sheet, .sheet-scrim { transition: none; }
}

/* ---- Stepper: the quote as a short walkthrough, one step on screen at a time ---- */
.stepper { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; margin: 0 0 8px; } /* as many equal columns as there are steps */
.walk-step {
	position: relative;
	display: grid;
	justify-items: center;
	gap: 6px;
	padding: 6px 0;
	background: none;
	border: 0;
	border-radius: var(--radius-sm);
	color: var(--muted);
	font-size: var(--text-xs);
	font-weight: 600;
}
/* opacity: 1 overrides the general button:disabled fade, which made each dimmed step its own
   layer and let the next step's line run through its dot (September 30, 2026). */
.walk-step:disabled { opacity: 1; color: color-mix(in srgb, var(--muted) 55%, transparent); }
/* Faded by colour, not opacity: an unreachable dot stays solid, so the line never shows through it. */
.walk-step:disabled .walk-dot { color: color-mix(in srgb, var(--muted) 55%, transparent); border-color: color-mix(in srgb, var(--line) 70%, transparent); }
/* The line joins this dot to the previous one; it lights up once the previous step is done. */
.walk-step:not(:first-child)::before {
	content: '';
	position: absolute;
	top: 18px;
	left: -50%;
	width: 100%;
	height: 2px;
	background: var(--line);
}
.walk-dot {
	position: relative;
	z-index: 1;
	width: 26px;
	height: 26px;
	border-radius: 50%;
	border: 2px solid var(--line);
	background: var(--bg);
	display: grid;
	place-items: center;
	font-size: var(--text-sm);
	line-height: 1;
	transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}
/* Filled = where you are; blue outline with a tick = done; grey outline = not reached yet
   (Mark, September 30, 2026: the filled done-steps read as being on them). */
.walk-step.done .walk-dot { background: var(--card); border-color: var(--primary); color: var(--primary); }
.walk-step.done::before, .walk-step.current::before, .walk-step.done + .walk-step::before { background: var(--primary); }
.walk-step.current { color: var(--text); }
.walk-step.current .walk-dot { background: var(--primary); border-color: var(--primary); color: var(--primary-text); }
.walk-step:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
/* What has been answered so far, in one line under the steps. */
.walk-summary {
	color: var(--muted);
	font-size: var(--text-sm);
	text-align: center;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	min-height: 1.3em;
	margin: 0 0 12px;
}
.pick button[aria-pressed='true'] { border-color: var(--primary); box-shadow: inset 0 0 0 1px var(--primary); }
@media (prefers-reduced-motion: reduce) {
	.walk-dot { transition: none; }
}

/* Contact support: the honeypot is off-screen rather than display:none, which some bots skip. */
.hp { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
.turnstile { min-height: 65px; margin: 4px 0 16px; }
/* A link inside running text: the accent, not the browser's default blue. */
.help a, .errors a, .notice-card a, p a { color: var(--accent); }

/* ---- Changing a job's status: the pill is the button (statusButton in js/status.js) ---- */
.pill-button { display: inline-flex; align-items: center; gap: 7px; min-height: 34px; padding: 4px 12px 4px 14px; font-size: var(--text-sm); cursor: pointer; }
.pill-caret { width: 6px; height: 6px; border-right: 1.75px solid currentColor; border-bottom: 1.75px solid currentColor; transform: translateY(-2px) rotate(45deg); opacity: 0.8; }
/* A bigger invisible target than the pill itself: 44px of thumb without a bigger pill. */
.pill-button { position: relative; }
.pill-button::after { content: ''; position: absolute; inset: -8px -6px; }
.status-menu {
	position: fixed;
	z-index: 40;
	min-width: 180px;
	padding: 6px;
	background: var(--card);
	border: 1px solid var(--line);
	border-radius: var(--radius);
	box-shadow: var(--shadow-float);
	animation: menu-in 0.14s ease-out;
}
@keyframes menu-in { from { opacity: 0; transform: translateY(-4px) scale(0.98); } }
@media (prefers-reduced-motion: reduce) { .status-menu { animation: none; } }
.status-option {
	display: flex;
	align-items: center;
	gap: 10px;
	width: 100%;
	min-height: 44px;
	padding: 8px 10px;
	border: 0;
	border-radius: var(--radius-sm);
	background: none;
	color: inherit;
	font: inherit;
	text-align: left;
}
.status-option:focus-visible, .status-option:hover { background: var(--bg); outline: none; }
.status-option[aria-checked='true'] { font-weight: 600; }
.status-tick { margin-left: auto; color: var(--primary); }
.status-dot { width: 10px; height: 10px; border-radius: 50%; flex: none; }
.status-dot.quoted { background: var(--dot-quoted); }
.status-dot.booked { background: var(--dot-booked); }
.status-dot.completed { background: transparent; border: 2px solid var(--status-completed); }
.status-dot.cancelled { background: var(--dot-cancelled); }

/* Job status on a saved quote: one row, the pill on the right is the control. */
.status-card { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 14px; }
.status-card-text { min-width: 0; }
.status-card-name { margin: 0; font-size: var(--text-lg); line-height: 1.2; overflow-wrap: anywhere; }
.status-card-text .help { margin-top: 2px; }

/* A link-button sitting inside a line of text, at the text's own size. */
/* A date that opens the calendar where it is: an invisible date input over the link text. */
.date-pick { position: relative; color: var(--accent); text-decoration: underline; cursor: pointer; }
.date-pick input { position: absolute; inset: -12px -8px; width: calc(100% + 16px); height: calc(100% + 24px); opacity: 0; font-size: 16px; border: 0; padding: 0; cursor: pointer; }
button.link.inline-link { position: relative; padding: 0; min-height: 0; font-size: inherit; }
button.link.inline-link::after { content: ""; position: absolute; inset: -12px -8px; } /* a thumb-sized target */

/* Onboarding's skippable screens: the way past them, quietly, under the card. */
.skip { text-align: center; margin-top: 12px; }
.skip .help { margin-top: 0; }

/* What's being hauled, on the Trip step: one tap on a chip, and only when there's a choice. */
.type-row { margin-bottom: 14px; }
.area-note { margin: 2px 0 10px; }
.suggest-hint { margin-top: 6px; }
.type-label { font-weight: 600; margin-bottom: 8px; }
/* A saved quote: only the chosen type, and Edit on the right to show the rest. */
.type-line { display: flex; align-items: center; gap: 8px; }
.type-line .chips { flex: 1; min-width: 0; }
.type-edit { display: none; flex: none; font-weight: 600; }
.type-row.collapsed .chip[aria-pressed='false'] { display: none; }
.type-row.collapsed .type-edit { display: inline-flex; align-items: center; min-height: 44px; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.common-types { margin: 12px 0 4px; }
.common-types .help { margin: 0 0 8px; }
.chip { min-height: 40px; padding: 0 14px; border-radius: 999px; border: 1px solid var(--line); background: var(--bg); color: var(--text); font: inherit; font-size: var(--text-base); }
.chip[aria-pressed='true'] { border-color: var(--primary); color: var(--primary); box-shadow: inset 0 0 0 1px var(--primary); background: var(--card); font-weight: 600; }

/* A new quote's status, on the Customer step under the name. */
.status-row { margin: 4px 0 14px; }
.status-row-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.status-row .label { font-weight: 600; }
.status-row .help { margin-top: 4px; }
.pill-waiting { opacity: 0.55; }

/* ---- the picture language: hauling-type icons, menu icons in the sheet, small scenes ---- */
.rig { display: inline-flex; flex: none; width: 1.35em; height: 1.35em; vertical-align: -0.3em; margin-right: 0.45em; color: var(--muted); }
.rig svg { width: 100%; height: 100%; }
.chip { display: inline-flex; align-items: center; }
.chip .rig { vertical-align: 0; }
.chip[aria-pressed='true'] .rig { color: var(--primary); }
.switch-row > span { display: inline-flex; align-items: center; }
.switch-row .rig { width: 1.6em; height: 1.6em; margin-right: 0.6em; }
.quote-row-type .rig { width: 1.25em; height: 1.25em; margin-right: 0.35em; }
.sheet-item { display: flex; align-items: center; gap: 12px; }
.sheet-icon { display: inline-flex; flex: none; color: var(--muted); }
.sheet-list .sheet-item:not(.sheet-dev) { padding-left: 12px; }
.sheet-dev .sheet-icon { opacity: 0.7; }
/* An empty saved-quotes list: a picture of what it is waiting for, not a blank box. */
.empty.first { padding: 28px 16px 8px; }
.empty.first p { color: var(--text); font-size: var(--text-md); font-weight: 600; margin: 14px 0 4px; }
.empty.first .help { max-width: 30ch; margin: 0 auto; }
.empty-scene { color: var(--muted); display: flex; justify-content: center; }
.empty-scene svg { width: min(200px, 62%); height: auto; }
/* Setup: how far along, as a bar under "Step 2 of 7". */
.progress { height: 4px; border-radius: 999px; background: var(--line); margin: 8px 0 14px; overflow: hidden; }
.progress::before { content: ''; display: block; height: 100%; width: calc(var(--done, 0) * 100%); border-radius: inherit; background: var(--primary); transition: width 0.25s ease; }
@media (prefers-reduced-motion: reduce) { .progress::before { transition: none; } }

/* Our logo at the top of pages that stand outside the app's shell: setup, not-open-yet. */
.page-brand { display: block; margin: 6px 0 14px; }
.page-brand img { display: block; height: 22px; width: auto; }
/* Small pictures for moments: setup finished, a message sent, no connection. */
.scene { display: inline-flex; }
.scene-done { display: flex; color: var(--ok); margin: 28px 0 14px; }
.scene-done svg { width: 56px; height: 56px; }
.sent { padding: 8px 0 4px; }
.sent h2 { font-size: var(--text-lg); letter-spacing: -0.02em; margin: 0 0 6px; }
.offline-title { display: flex; align-items: center; gap: 8px; }
.offline-title .scene { color: var(--muted); }
h1.with-icon { display: flex; align-items: center; gap: 10px; }
h1.with-icon .menu-icon { font-size: var(--text-base); }
.reply-to { margin-top: 8px; }
.reply-to button.link { padding: 0; min-height: 0; font-size: inherit; }
