/*
 * The quote journey, wearing this site's clothes.
 *
 * WHY THIS IS A SEPARATE FILE. `quote.css` and `quote.js` are byte-for-byte
 * copies of the live plugin's own, and they get re-synced whenever the plugin
 * changes. Editing them here would make every future sync a merge, and a merge
 * nobody would remember to do. So the copies stay pristine and everything this
 * site changes about their appearance lives in this one file, loaded after
 * them. Re-syncing stays `cp`.
 *
 * NOTHING HERE CHANGES BEHAVIOUR. The journey's markup comes from quote.js,
 * whose only contact with appearance is five `style.display` toggles on the
 * address suggestion dropdown — show and hide, not decoration. Every class
 * name below is one quote.js already emits. No JS was touched to make this
 * work, which is what keeps the journey identical to the live one.
 *
 * HOW IT WORKS. quote.css is unusually disciplined for its age: 127 of its
 * colour references go through `var(--bsq-*)` custom properties declared on
 * `.bsq-app`, against only 13 hard-coded literals. Redeclaring those
 * properties in terms of the site's own tokens therefore restyles almost the
 * whole journey without touching a single rule. The 13 literals are the
 * exceptions, and they are handled explicitly further down — they are all
 * notice tints, which is precisely why the journey has never worked in dark
 * mode.
 */

/* ------------------------------------------------------------------ *
 * 1. The bridge
 * ------------------------------------------------------------------ */

.bsq-app {
	/*
	 * Straight swaps: same role, this site's value. Because quote.css reads
	 * these everywhere, dark mode arrives for free — the tokens on the right
	 * already flip under prefers-color-scheme.
	 */
	--bsq-white: var(--paper);
	--bsq-bg: var(--wash);
	--bsq-border: var(--line);
	--bsq-grey: var(--ink-soft);
	--bsq-yellow: var(--gold);
	--bsq-pale-yellow: var(--gold-wash);
	--bsq-error: var(--danger);
	--bsq-success: var(--success);

	/*
	 * `--bsq-navy` is the awkward one. quote.css uses it 30 times as text and
	 * 4 times as a border, but also as the solid fill behind secondary buttons
	 * and completed progress dots. Mapped to the text token it would turn
	 * those fills light in dark mode and leave white labels on them, so it
	 * maps to text here and the five fill sites are re-pointed in §2.
	 */
	--bsq-navy: var(--ink);

	/*
	 * These four were never declared at all — quote.css only ever reads them
	 * with inline fallbacks (`var(--bsq-radius, 12px)`), so the journey has
	 * been quietly running on its defaults. Declaring them hands it the site's
	 * geometry instead.
	 */
	--bsq-radius: var(--radius);
	--bsq-btn-radius: var(--radius);
	--bsq-focus: var(--focus);
	--bsq-font-body: inherit;
	--bsq-font-heading: inherit;

	/*
	 * And three more read the same way that the four above missed, so their
	 * light fallbacks showed in BOTH themes: the plan cards on the advert's
	 * price screen kept a pale #DCE7EF edge on the dark page, the line under
	 * every offer question was #4A6076 on dark paper (2.4:1), and the progress
	 * bar ran on a gold of its own.
	 */
	--bsq-line: var(--line);
	--bsq-muted: var(--ink-soft);
	--bsq-accent: var(--gold);

	/* Inter, from the page, rather than the journey's own system stack. */
	font-family: inherit;
	color: var(--ink);
}

/*
 * BORDER-BOX ALL THE WAY DOWN, said outright rather than inherited.
 *
 * quote.css sets `box-sizing: inherit` on everything inside the app. That
 * breaks inside a <details>: what its contents inherit from is the element's
 * own built-in slot, which is content-box. So everything in the discount-code
 * box was content-box -- on a phone the code field ran 30px out of the side of
 * its box, and the Apply button beside it was 75px tall.
 */
.bsq-app *,
.bsq-app *::before,
.bsq-app *::after {
	box-sizing: border-box;
}

/* ------------------------------------------------------------------ *
 * 2. The fills that must stay dark
 * ------------------------------------------------------------------ */

/*
 * The five places `--bsq-navy` meant "a solid brand block" rather than "text".
 * `--brand-solid` stays dark in both themes and `--brand-on` stays white, so
 * the label keeps its contrast whichever way the page goes.
 */
.bsq-app .bsq-btn--secondary,
.bsq-app .bsq-progress__step.is-done .bsq-progress__dot {
	background: var(--brand-solid);
	color: var(--brand-on);
	border-color: var(--brand-solid);
}

/*
 * `.bsq-complete__icon` looks like it belongs in that list and does not: it is
 * a pale-gold disc with a navy tick, not a navy fill. Its gold wash inverts on
 * its own through --bsq-pale-yellow, so the only thing it needs is a mark dark
 * enough to read against the wash in both themes. --gold-deep was not: 1.9:1
 * on the pale wash in light. --gold-text is the gold made to be read.
 */
.bsq-app .bsq-complete__icon {
	background: var(--gold-wash);
	color: var(--gold-text);
}

/*
 * WORDS ON GOLD, AND GOLD AS WORDS.
 *
 * The "Recommended" badge is a gold fill in both themes, and quote.css gives
 * its words --bsq-navy -- which is the TEXT colour, so it flips: near-white on
 * gold in dark, 1.42:1. The advert's offer line on the price card is the same
 * gold fill. --on-gold is the one colour for words on gold.
 *
 * "Delivered Reliably." is the opposite case: gold AS the words. quote.css
 * wrote it for a dark hero; here it sits on the light page, where the brand
 * gold is 1.46:1. --gold-text is darker gold in light and the brand gold in
 * dark.
 */
.bsq-app .bsq-quotecard__badge,
.bsq-app .bsq-quotecard__offer {
	color: var(--on-gold);
}

.bsq-app .bsq-highlight {
	color: var(--gold-text);
}

/* ------------------------------------------------------------------ *
 * 3. The literals that escaped the variables
 * ------------------------------------------------------------------ */

/*
 * Thirteen hard-coded colours, every one a notice background. On a white page
 * they are gentle tints; on a dark one they are glaring panels with unreadable
 * text, which is the whole of why dark mode looked broken here. Re-pointed at
 * washes that invert.
 */
.bsq-app .bsq-error-summary {
	background: var(--danger-wash);
	border-color: var(--danger);
	color: var(--danger);
}

.bsq-app .bsq-error-summary h3,
.bsq-app .bsq-error-summary a {
	color: var(--danger);
}

/* Its links' underline is their own red, not the page-wide pale link-blue. */
.bsq-app .bsq-error-summary a {
	text-decoration-color: currentColor;
}

.bsq-app .bsq-notice {
	background: var(--gold-wash);
	border-color: var(--gold);
	color: var(--ink);
}

.bsq-app .bsq-notice--success {
	background: var(--success-wash);
	border-color: var(--success);
	color: var(--success);
}

.bsq-app .bsq-notice--warn {
	background: var(--warn-wash);
	border-color: var(--warn-edge);
	color: var(--warn);
}

.bsq-app .bsq-previewbar {
	background: var(--warn-wash);
	border-color: var(--warn-edge);
	color: var(--warn);
	box-shadow: none;
}

.bsq-app .bsq-previewbar strong {
	color: var(--warn);
}

/* A native dropdown paints its own list; it needs real values, not tints. */
.bsq-app option {
	background: var(--paper);
	color: var(--ink);
}

.bsq-app .bsq-codebox {
	background: var(--paper);
	border-color: var(--line);
}

/* The ticks beside the advert's three promises: a fixed dark green, 2.9:1 on
   the dark card. */
.bsq-app .bsq-offer__points li::before {
	border-color: var(--success);
}

/*
 * THE WINDOW ON THE ADVERT PAGE IS ALWAYS DAYLIGHT.
 *
 * The glass is drawn in fixed pale blues and white in both themes, so the
 * words on it want a fixed dark ink. quote.css gives each one its own, but
 * they are paragraphs and `.bsq-app p` outranks them with --bsq-grey, which
 * here flips: in dark "Your first clean", the price, the terms and "Wipe the
 * glass" were pale grey on the pale glass, about 1.1:1.
 */
.bsq-app .bsq-offer__glass,
.bsq-app .bsq-offer__glass p {
	color: var(--navy);
}

/* ------------------------------------------------------------------ *
 * 4. Surfaces
 * ------------------------------------------------------------------ */

/*
 * quote.css gives every card a flat 1px border and a fixed shadow. The site's
 * --shadow is a two-layer one — a tight contact shadow plus a wide soft cast —
 * which reads as depth rather than as an outline, and it already has a dark
 * variant.
 */
.bsq-app .bsq-card {
	background: var(--paper);
	border: 1px solid var(--line);
	border-radius: var(--radius);
	box-shadow: var(--shadow);
}

/* ------------------------------------------------------------------ *
 * 5. Controls
 * ------------------------------------------------------------------ */

/*
 * 48px minimum, up from the journey's 44/46. The floor is not really about
 * fingers on a still phone: BrightSide's customers book on the move and its
 * cleaners work the staff app one-handed, outdoors and often wet.
 */
.bsq-app .bsq-btn {
	min-height: var(--tap-min);
	border-radius: var(--radius);
	/* A label that wraps stays centred in its pill: "Continue to secure
	   payment" broke onto two left-aligned lines on a narrow phone. */
	text-align: center;
	transition:
		transform var(--tap) var(--ease),
		box-shadow var(--tap) var(--ease),
		background var(--tap) var(--ease);
}

.bsq-app .bsq-btn--primary {
	background: var(--gold);
	color: var(--on-gold); /* Gold is a light surface in BOTH themes. */
}

.bsq-app .bsq-btn--primary:hover:not(:disabled) {
	background: var(--gold-deep);
	box-shadow: var(--shadow);
	transform: translateY(-1px);
}

.bsq-app .bsq-btn--secondary:hover:not(:disabled) {
	box-shadow: var(--shadow);
	transform: translateY(-1px);
}

.bsq-app .bsq-btn--ghost {
	background: transparent;
	color: var(--ink);
	border-color: var(--line);
}

/* An outlined button said nothing under the pointer. A tint of its own words,
   so it follows the theme without a colour of its own. */
.bsq-app .bsq-btn--ghost:hover:not(:disabled) {
	background: color-mix(in srgb, currentColor 10%, transparent);
}

.bsq-app .bsq-btn--link:hover {
	color: var(--ink);
}

/*
 * A BUTTON THAT CANNOT BE PRESSED YET LOOKS IT.
 *
 * "Continue to secure payment" is a link marked aria-disabled until Stripe's
 * page is ready, and it looked and hovered exactly like the live one: gold,
 * lifting, darkening. The same look as quote.css gives a disabled <button>,
 * and under the pointer it stays where it rests.
 */
.bsq-app .bsq-btn[aria-disabled="true"] {
	opacity: 0.55;
	cursor: not-allowed;
	box-shadow: none;
	transform: none;
}

.bsq-app .bsq-btn--primary[aria-disabled="true"]:hover {
	background: var(--gold);
	box-shadow: none;
	transform: none;
}

/* The padlock beside "Hosted by Stripe" shrank to 8px as the words wrapped. */
.bsq-app .bsq-secure-note svg {
	flex: none;
}

.bsq-app .bsq-input,
.bsq-app .bsq-select,
.bsq-app .bsq-textarea {
	min-height: var(--tap-min);
	/* background-COLOR, not the shorthand: the shorthand resets
	   background-image, which is where quote.css draws the select's chevron --
	   and a dropdown with no chevron reads as a box to type into. */
	background-color: var(--paper);
	color: var(--ink);
	/* --edge: 3:1 on the card in both themes, where --line was 1.2:1 (app.css). */
	border: 1.5px solid var(--edge);
	border-radius: calc(var(--radius) * 0.7);
	/* 16px floor: iOS Safari zooms the whole page on focus below it, and the
	   page never zooms back out. */
	font-size: max(1rem, var(--step-0));
}

.bsq-app .bsq-input::placeholder,
.bsq-app .bsq-textarea::placeholder {
	color: var(--whisper);
}

/*
 * One focus treatment across the site. quote.css outlines in navy, which is
 * nearly invisible against a dark page.
 *
 * Not `[tabindex="-1"]`. That is every screen's heading and the error box,
 * which quote.js focuses after each step so a screen reader reads the new
 * screen out -- nobody can tab to them, and quote.css switches their ring off
 * on purpose. Listing them here put a hard gold box round "Where will we be
 * cleaning?" on every screen of the journey.
 */
.bsq-app :is(a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])):focus-visible {
	outline: 3px solid var(--focus);
	outline-offset: 2px;
}

/*
 * The same ring when a box is clicked into. quote.css draws navy at 25% here,
 * which on the dark page is no ring at all -- and a select clicked with the
 * mouse is not :focus-visible, so it got only that.
 */
.bsq-app .bsq-input:focus,
.bsq-app .bsq-select:focus,
.bsq-app .bsq-textarea:focus {
	outline: 3px solid var(--focus);
	outline-offset: 2px;
}

/*
 * A FIELD THAT IS WRONG LOOKS WRONG.
 *
 * When a step is refused, quote.js marks each box at fault aria-invalid and
 * writes a note under it, and quote.css colours both red. Neither colour
 * reached the screen. The note is a paragraph, so `.bsq-app p` outranks
 * `.bsq-field__error`: "Enter your first name" was grey, at body size, touching
 * the box. And the box rule above sits later than quote.css's red edge at the
 * same weight, so the box kept its ordinary pale one. Only the summary at the
 * top was red, and the box at fault looked like the ones that were right, in
 * both themes. The red edge stays while the box is clicked into, inside the
 * ring.
 *
 * No margin below the note: under a select the field is the grid in the
 * chevron rule further down, where margins do not fold together, so the
 * paragraph's 14px sat on top of the field's own and pushed the next question
 * away.
 */
.bsq-app p.bsq-field__error {
	color: var(--danger);
	font-size: 0.85rem;
	margin: 5px 0 0;
}

.bsq-app :is(.bsq-input, .bsq-select, .bsq-textarea)[aria-invalid="true"] {
	border-color: var(--danger);
}

/*
 * The choice cards hide their radio and ring the card instead, in --bsq-navy:
 * the text colour, so off-white in dark rather than the site's ring.
 */
.bsq-app .bsq-cardgrid__option input:focus-visible + .bsq-cardgrid__card,
.bsq-app .bsq-quotecard input:focus-visible + .bsq-quotecard__card {
	outline: 3px solid var(--focus);
	outline-offset: 2px;
}

.bsq-app .bsq-planpick input:focus-visible + .bsq-planpick__top {
	outline: 3px solid var(--focus);
	outline-offset: 3px;
}

/*
 * A SELECT'S CHEVRON FOLLOWS THE THEME.
 *
 * quote.css draws it as an SVG in a data URI, and a colour inside a data URI
 * is fixed: #3E4C59, which on the dark field is next to nothing. So the same
 * shape is used as a MASK over a token colour instead, on the field around
 * the select (a select cannot carry a ::after of its own). The select and the
 * chevron share the second row of a one-column grid, so the chevron sits in
 * the middle of the select whatever the label above it does, and an error
 * note that arrives later takes the row below.
 *
 * A grid keeps its children's margins inside it. app.css puts 1rem above
 * every label, and in an ordinary field that margin folds into the gap
 * between fields; inside the grid it did not, so the label over a select --
 * the advert's address picker, a configured question -- sat 16px lower than
 * every other label on the screen. The 1rem moves from the label to the
 * field, where it folds as before.
 *
 * Only where :has() works: without it the select keeps quote.css's own.
 */
@supports selector(:has(*)) {
	.bsq-app .bsq-field:has(> .bsq-select) {
		display: grid;
		grid-template-columns: minmax(0, 1fr);
		margin-top: 1rem;
	}

	.bsq-app .bsq-field:has(> .bsq-select) > label {
		margin-top: 0;
	}

	.bsq-app .bsq-field:has(> .bsq-select) > .bsq-select {
		grid-row: 2;
		grid-column: 1;
		background-image: none;
	}

	.bsq-app .bsq-field:has(> .bsq-select)::after {
		content: "";
		grid-row: 2;
		grid-column: 1;
		justify-self: end;
		align-self: center;
		width: 12px;
		height: 8px;
		margin-right: 14px;
		pointer-events: none;
		background-color: var(--ink-soft);
		-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1.5 1.75 6 6.25l4.5-4.5' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
		mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1.5 1.75 6 6.25l4.5-4.5' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
	}
}

/* ------------------------------------------------------------------ *
 * 6. Motion
 * ------------------------------------------------------------------ */

/*
 * Nothing needed here. quote.css already carries a `prefers-reduced-motion`
 * block scoped to `.bsq-app *` with !important, and app.css carries one for
 * the rest of the site — between them the journey is covered. A third copy
 * here would win the cascade by being last and change nothing, which is the
 * kind of rule that survives for years because deleting it looks risky.
 *
 * The transitions this file adds use --tap, which those blocks already zero.
 */

/* ------------------------------------------------------------------ *
 * 7. Undoing WordPress
 * ------------------------------------------------------------------ */

/*
 * quote.css spends its whole `max-width: 640px` block fighting a page shell
 * that does not exist here.
 *
 * On the live site the journey is a block inside a WordPress constrained
 * layout, which pins `alignwide` children with `margin: auto !important`. To
 * reach the screen edges it breaks out with `width: 100vw` and
 * `margin-inline: calc(50% - 50vw) !important`, then cancels its own gutter
 * with negative margins on each card so they run edge to edge.
 *
 * None of that applies to this site — the journey is mounted straight into
 * <main> with no constrained parent — and two parts of it actively hurt:
 *
 *   - `width: 100vw` is wider than the content box wherever a scrollbar takes
 *     layout space, which is a horizontal scroll on the highest-value page on
 *     the site. It is invisible on iOS, where scrollbars are overlaid, and
 *     very visible on some Android browsers.
 *
 *   - Edge-to-edge cards with `border-radius: 0` were a 2018 answer to narrow
 *     screens. Now they just read as a page that has lost its styling.
 *
 * So the breakout is reverted and the cards keep their shape.
 */
@media (max-width: 640px) {
	.bsq-appwrap {
		width: auto;
		max-width: 100%;
		margin-left: 0 !important;
		margin-right: 0 !important;
	}

	/* A real gutter, and one that clears a notch in landscape. */
	.bsq-app.bsq-mode-embedded {
		padding-left: max(1rem, env(safe-area-inset-left));
		padding-right: max(1rem, env(safe-area-inset-right));
	}

	.bsq-app.bsq-mode-embedded .bsq-card {
		margin-left: 0;
		margin-right: 0;
		padding: 1.25rem;
		border: 1px solid var(--line);
		border-radius: var(--radius);
	}
}

/* ------------------------------------------------------------------ *
 * 8. Typography
 * ------------------------------------------------------------------ */

/*
 * The journey had its own clamp() scale, close to the marketing pages' but not
 * the same — the mismatch is most obvious stepping from the home page into the
 * quote, where the headings change size for no reason the visitor can see.
 * One scale, shared.
 */
.bsq-app h1 { font-size: var(--step-4); }
.bsq-app h2 { font-size: var(--step-3); }
.bsq-app h3 { font-size: var(--step-1); }
.bsq-app p,
.bsq-app label,
.bsq-app .bsq-btn { font-size: var(--step-0); }

/* A hint stays smaller than the words it explains, at the size of the site's
   own .hint. `.bsq-app p` above had caught the paragraph ones, so "No VAT is
   charged." came out bigger than the price breakdown it sits under. */
.bsq-app p.bsq-hint { font-size: 0.9rem; }

/* The same for "Hosted by Stripe. We never see or store your card number.",
   which quote.css means as small print and `.bsq-app p` made body size. */
.bsq-app p.bsq-secure-note { font-size: 0.9rem; }

/*
 * A centred screen centres its paragraphs as blocks as well. The site caps
 * every paragraph at a readable measure, and a capped paragraph sits at the
 * left of its card -- so on a laptop the words of "You're all set!" were
 * centred inside a box that was not, and ran off to one side of the tick
 * above them.
 */
.bsq-app .bsq-complete p {
	margin-left: auto;
	margin-right: auto;
}

/* ------------------------------------------------------------------ *
 * 9. The selection grids
 * ------------------------------------------------------------------ */

/*
 * Property type and price cards are the two screens where the visitor is
 * choosing rather than typing, so the selected state has to be unmistakable at
 * arm's length. quote.css marks it with a border colour and a tint, which on a
 * bright phone outdoors is close to invisible.
 */
.bsq-app .bsq-cardgrid__card,
.bsq-app .bsq-quotecard__card {
	background: var(--paper);
	border: 2px solid var(--line);
	border-radius: var(--radius);
	transition:
		border-color var(--tap) var(--ease),
		box-shadow var(--tap) var(--ease),
		background var(--tap) var(--ease);
}

/*
 * The edge of the chosen card is the site's "selected" colour: navy in light,
 * as the live journey has it, and gold in dark. It was gold in both, and gold
 * on the white card is 1.6:1 -- in light the chosen house was told from the
 * others mostly by its tick.
 */
.bsq-app .bsq-cardgrid__option input:checked + .bsq-cardgrid__card,
.bsq-app .bsq-quotecard input:checked + .bsq-quotecard__card {
	border-color: var(--chosen);
	background: var(--gold-wash);
	/* A ring as well as a border: colour alone is not a safe signal, and this
	   one still reads for a red-green colour-blind visitor. */
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--chosen) 35%, transparent);
}

/* A price card firms its edge under the pointer, as the house cards already
   do in quote.css; it had no hover at all. */
.bsq-app .bsq-quotecard input:not(:checked):hover + .bsq-quotecard__card {
	border-color: var(--ink-soft);
}

/* On a laptop the price card is a flex column, which stretched "Select" to the
   card's width and parked it at the left above a centred price. */
.bsq-app .bsq-quotegrid .bsq-quotecard__state {
	align-self: center;
}

.bsq-app .bsq-cardgrid__icon { color: var(--ink); }
.bsq-app .bsq-cardgrid__label { color: var(--ink); }
.bsq-app .bsq-cardgrid__desc { color: var(--ink-soft); }
.bsq-app .bsq-quotecard__price { color: var(--ink); }

/*
 * THE TICK ON THE ONE CHOSEN, in the site's "selected" pair: a navy disc in
 * light, a gold one in dark. It was --brand-solid, a dark navy that on the
 * dark gold wash of a chosen card is 1.2:1 -- the disc vanished and left a
 * floating tick. On a price card the disc beside "Selected" is a gold wash on
 * the gold wash of the chosen card, so it vanished in both themes.
 */
.bsq-app .bsq-cardgrid__tick,
.bsq-app .bsq-quotecard input:checked + .bsq-quotecard__card .bsq-check {
	background: var(--chosen);
	color: var(--chosen-on);
	border-color: var(--chosen);
}

/*
 * TWO CHOICES TO A ROW ON A PHONE, as the live journey has. quote.css drops
 * to one column once the journey is narrower than 360px, and this site's 16px
 * gutter puts a 390px phone at 358 -- so five house types became five
 * full-width cards and "Continue" was three screens down. Two columns hold
 * down to a 300px column, where a label still fits.
 */
@container bsq (min-width: 300px) and (max-width: 359px) {
	.bsq-app .bsq-cardgrid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/*
 * THE ADVERT'S PLAN CARDS SHOW WHICH ONE IS CHOSEN.
 *
 * quote.js marks the chosen card with .is-on when it draws the screen and
 * never again, so choosing the other plan left the first one looking chosen.
 * The look follows the radio instead, and it is the same look as every other
 * choice in the journey: the "selected" edge, the gold wash and a ring.
 * Without :has() the card keeps quote.css's .is-on.
 */
@supports selector(:has(*)) {
	.bsq-app .bsq-planpick.is-on {
		border-color: var(--line);
		border-width: 1px;
		padding: 16px 17px;
	}

	.bsq-app .bsq-planpick:hover {
		border-color: var(--ink-soft);
	}

	.bsq-app .bsq-planpick:has(input:checked) {
		border-color: var(--chosen);
		border-width: 2px;
		padding: 15px 16px;
		background: var(--gold-wash);
		box-shadow: 0 0 0 3px color-mix(in srgb, var(--chosen) 35%, transparent);
	}
}

/* The progress rail, on the site's line colour rather than its own grey. */
.bsq-app .bsq-progress__step::before { background: var(--line); }
.bsq-app .bsq-progress__step.is-done::before,
.bsq-app .bsq-progress__step.is-current::before { background: var(--brand-solid); }

.bsq-app .bsq-progress__dot {
	background: var(--paper);
	border-color: var(--line);
	color: var(--ink-soft);
}

.bsq-app .bsq-progress__step.is-current .bsq-progress__dot {
	background: var(--gold-wash);
	border-color: var(--gold);
	color: var(--ink);
	box-shadow: 0 0 0 4px color-mix(in srgb, var(--gold) 30%, transparent);
}

/* The advert's one-question bar: its track was black at 8%, which on the dark
   card is no track at all. The gold that fills it comes from --bsq-accent. */
.bsq-app .bsq-step__bar { background: var(--line); }

/* ------------------------------------------------------------------ *
 * 10. The sixteen inline styles the CSP throws away
 * ------------------------------------------------------------------ */

/*
 * THIS SECTION IS NOT COSMETIC — it is repairing real breakage.
 *
 * quote.js writes sixteen `style="…"` attributes into its template strings.
 * On the live WordPress site they work. Here they do not: this site's CSP is
 * `style-src 'self'` with no 'unsafe-inline', so the browser drops every one
 * of them — silently. No console error, no warning, no visual clue that a rule
 * was ever meant to be there. It is the same trap that ate the marketing
 * page's inline styles earlier in this build.
 *
 * What was actually broken, before this section existed:
 *   - the address suggestions rendered as a bulleted list of narrow, centred
 *     buttons, and a long list had no scroll
 *   - the terms and marketing checkboxes lost their flex row, so the box and
 *     its label stacked
 *   - the discount-code input and its Apply button stacked instead of sitting
 *     side by side
 *   - the postcode field ran full width and stopped upper-casing
 *
 * Reproduced faithfully rather than improved, so the journey still matches the
 * live one. The alternative — loosening the CSP to 'unsafe-inline' — would
 * re-enable every inline style on every page, on a site that takes addresses
 * and card details, to save writing this out. Not a trade worth making.
 *
 * If quote.js is ever re-synced and gains a new inline style, it will fail the
 * same silent way. `grep -o 'style="[^"]*"' quote.js` is the check.
 *
 * SINCE THEN the policy allows style ATTRIBUTES (style-src-attr, for the map's
 * tiles -- see src/csp.ts), so these inline styles apply again and the rules
 * below are the fallback. Which sets the one rule for this section: a rule
 * here must never match MORE than the element whose inline style it stands
 * in for. The validity-note rule once matched every hint paragraph, and so
 * centred the whole cancellation policy under the payment button, nine
 * ragged lines.
 */

/* L133/135 — the bedroom-count icon strip. */
.bsq-app .bsq-beds {
	display: flex;
	flex-wrap: wrap;
	gap: 4px;
	justify-content: center;
	max-width: 96px;
}

.bsq-app .bsq-beds > span {
	width: 30px;
	display: inline-block;
}

/* L453 — postcode: short field, and shouty, because postcodes are. */
.bsq-app #bsq-postcode {
	max-width: 200px;
	text-transform: uppercase;
}

/*
 * L459 — the address suggestion listbox.
 *
 * `display: none` here is the INITIAL state only. quote.js drives visibility
 * through `list.style.display`, which is a CSSOM property assignment and is
 * NOT blocked by the CSP — only the attribute in the HTML string was. So the
 * element must start hidden in CSS and the script takes over from there.
 */
.bsq-app #bsq-address-list {
	display: none;
	list-style: none;
	margin: 6px 0 0;
	padding: 6px;
	max-height: 280px;
	overflow: auto;
	/* Kinetic scrolling on iOS, and a scroll that does not chain to the page
	   behind it once the list bottoms out. */
	overscroll-behavior: contain;
	-webkit-overflow-scrolling: touch;
}

/* L537 — each suggestion fills its row and reads left, like a list should. */
.bsq-app #bsq-address-list .bsq-btn--link {
	width: 100%;
	text-align: left;
	justify-content: flex-start;
	/* Not in the original: a suggestion is a primary target on a phone and
	   was inheriting the 44px link height. */
	min-height: var(--tap-min);
}

/* L892 — the numeric answer to a configured question (conservatory count). */
.bsq-app .bsq-input[type="number"] {
	max-width: 140px;
}

/*
 * L950/954 — the terms and marketing rows. These labels carry no class of
 * their own, so they are matched by what they contain.
 */
.bsq-app .bsq-field > label:has(> input[type="checkbox"]) {
	display: flex;
	gap: 10px;
	align-items: flex-start;
	font-weight: 400;
}

/* L951/955 — and the boxes themselves, which are otherwise 13px. */
.bsq-app #bsq-terms,
.bsq-app #bsq-marketing {
	width: 22px;
	height: 22px;
	flex: none;
	margin-top: 2px;
}

/*
 * The "offers and news" tick on the landing screen and on the offer journey's
 * last question. It carries no id, and app.css gives every input a width, so
 * inside the label's flex row the box grew to half the card and pushed its own
 * words into a narrow column beside it -- on the advert page, at phone width,
 * on the screen that asks for a mobile number.
 */
.bsq-app .bsq-check-label > input[type="checkbox"] {
	width: 22px;
	height: 22px;
	flex: none;
	margin: 0;
}

/*
 * L963/1122 — the validity note under the price.
 *
 * Matched by the inline style it stands in for, which is still in the markup
 * whether or not the policy lets it apply. Not every `p.bsq-hint`: the VAT
 * line, the cancellation policy and the areas we cover are hints too, and on
 * the live journey none of them is centred.
 */
/*
 * A ONE-LINE HINT UNDER THE BUTTONS, ON A PHONE: "Nothing is taken today.",
 * "My address is not listed". Below 600px the actions stack (quote.css) into a
 * full-width button over a centred Back, and a hint left-aligned under that
 * column sat off to one side as the last line of the card. Centred with the
 * column there; left-aligned beside the row they make on a wider screen, as
 * on the live journey. Only the hint straight after the actions, or after the
 * form that holds them: the payment step's cancellation policy comes after
 * the secure note, runs to several lines, and keeps its left edge.
 */
@media (max-width: 599.98px) {
	.bsq-app .bsq-stage-actions + p.bsq-hint,
	.bsq-app form:has(> .bsq-stage-actions) + p.bsq-hint {
		text-align: center;
		margin-left: auto;
		margin-right: auto;
	}
}

.bsq-app p.bsq-hint[style*="text-align:center"] {
	text-align: center;
	margin-top: 10px;
	/* Centred as a block too: the site caps a paragraph at the measure, and a
	   capped one sits at the left of the card with its words centred in it. */
	margin-left: auto;
	margin-right: auto;
}

/* L1116/1117 — the discount code row: input grows, Apply sits beside it. */
.bsq-app .bsq-field:has(#bsq-code) {
	display: flex;
	gap: 8px;
	align-items: flex-end;
	flex-wrap: wrap;
	margin-top: 10px;
}

.bsq-app .bsq-field > div:has(> #bsq-code) {
	flex: 1;
	min-width: 180px;
}

/*
 * L1121/1256 — cards nested inside another card. A shadow on an inner panel
 * reads as a rendering fault, which matters more now the site's shadow is a
 * real two-layer one rather than the flat original.
 */
.bsq-app .bsq-card:has(> .bsq-inclusions),
.bsq-app .bsq-paywrap .bsq-card {
	box-shadow: none;
}
