/* --- Elementor Global Kit override guard: the `:not(#vdm-never)` marker ---
   The active Elementor kit styles bare <input>/<button> descendants at (0,3,1)
   — e.g. `.elementor-kit-33 input:not([type="button"]):not([type="submit"])` —
   which outranks this file's plain class rules. The plugin's design was simply
   not applying: ghost and secondary buttons rendered in the KIT's coral, so
   `Back` looked identical to the primary action, and every field used the kit's
   radius and background rather than ours. 17 rules were measured losing in the
   browser; this file had been describing a design the page never rendered.

   `#vdm-never` is a sentinel id that is never rendered. `:not(#vdm-never)` adds
   id-level specificity WITHOUT changing which elements match — the whole point:
   `.vdm-btn` is also used by My Policies, OUTSIDE `.vdm-quote`, so scoping these
   rules to the wizard would have stripped that page instead.

   The marker is applied to all 65 rules of every family that contains a losing
   rule, NOT only to the 17 that lose. Boosting selectively inverts this file's
   own cascade: `.vdm-step__num` would outrank `.is-active .vdm-step__num`,
   `.vdm-btn--ghost` would outrank its `:hover`, and the mobile `@media`
   overrides would lose to the very rules they exist to override. A uniform +1
   across a family preserves every relationship inside it.

   Adding a rule to one of these families? Give it the marker, or it will lose to
   its own siblings. Adding one the kit also targets? Verify it actually applies.
   No !important anywhere in this file. */

/* VDM Insurance quote UI. Look & feel from the cowork prototype; COLOR + FONT come from the
   Elementor Global Kit (via --e-global-* variables + inheritance) — we never set font-family. */
.vdm-quote {
	/* The Global Kit's ACCENT is coral (the prototype's CTA/highlight color); its SECONDARY is
	   teal; its PRIMARY is dark navy. Map to the prototype's colour roles accordingly. */
	--vdm-primary: var(--e-global-color-accent, #D54318);    /* coral — CTAs, selected, badges, active step */
	--vdm-accent:  var(--e-global-color-secondary, #1E8A9E); /* teal — secondary highlights, coverage ticks */
	--vdm-navy:    var(--e-global-color-primary, #0E2B39);
	--vdm-text:    var(--e-global-color-text, #16242B);
	--vdm-surface: #fff;
	--vdm-muted:   color-mix(in srgb, var(--vdm-text) 62%, transparent);
	--vdm-line:    color-mix(in srgb, var(--vdm-text) 14%, transparent);
	--vdm-line-2:  color-mix(in srgb, var(--vdm-text) 22%, transparent);
	--vdm-tint:    color-mix(in srgb, var(--vdm-accent) 10%, transparent);
	--vdm-shadow:  0 14px 34px -20px color-mix(in srgb, var(--vdm-text) 55%, transparent);
	--vdm-shadow-sm: 0 8px 20px -14px color-mix(in srgb, var(--vdm-text) 50%, transparent);

	/* PLUGIN-SCOPED accessibility overrides (R4, 2026-09-10 audit S5/S6/M8). The Global Kit has no
	   "border" or "text-safe accent" role of its own, so these two tokens are ours.

	   MEASURED 2026-09-11 (whole-branch review I6), from the site's own generated Elementor CSS
	   (wp-content/uploads/elementor/css/post-*.css) — the kit's real values, not assumptions:

	       --e-global-color-accent:    #D54318   (coral — set on stage 2026-09-11 by the controller;
	                                               replaces the earlier shipped shade, retired same
	                                               day, David's decision — docs/BACKLOG.md, "The
	                                               brand orange becomes #D54318 everywhere")
	       --e-global-color-secondary: #1E8A9E   (teal — unchanged)
	       --e-global-color-primary:   #0E2B39   (unchanged)
	       --e-global-color-text:      #16242B   (unchanged)

	   All four match the fallbacks above exactly, so every ratio stated in this file is guaranteed
	   as the site stands rather than merely assumed. What is NOT guaranteed is future drift: the
	   kit is editable from Elementor by anyone with the Kit permission, and a change there
	   silently moves these ratios with nothing in the test suite able to notice. That is why the
	   go-live checklist carries a line to re-check these four hexes — docs/GO-LIVE-CHECKLIST.md,
	   beside the two Stripe accessibility walks. A CSS comment is not where anyone looks at
	   go-live.

	   --vdm-border: a fixed, kit-independent neutral gray — not derived from --vdm-text — because
	   no percentage of --vdm-text reaches 3:1 without overshooting into --vdm-muted's own territory
	   (62% text, i.e. --vdm-muted itself, is the first mix that clears 3:1, and reusing that would
	   make the border and muted TEXT colour indistinguishable). #767676 vs white = 4.54:1 (needs
	   3:1, WCAG 1.4.11). */
	--vdm-border: #767676;
	/* --vdm-accent-text: teal darkened 15% toward black, for TEXT-sized uses on white AND on the
	   accent tints (S6) — also reused as the active term-pill FILL so its white label clears 4.5:1.
	   #1A7586 vs white = 5.34:1, vs the 12% tier-pill tint (#E4F1F3) = 4.62:1, vs the 10% notice
	   tint (#E9F3F5) = 4.73:1 (all need 4.5:1). Plain --vdm-accent stays for non-text highlights
	   (coverage ticks, resting term/field borders, hover states).

	   --vdm-primary-text retired 2026-09-11: it used to darken the brand coral 18% toward black
	   (#BF5131, 4.73:1) because the shipped coral alone only cleared 3.33:1. #D54318 clears 4.5:1
	   on its own (4.52:1, WCAG 1.4.3), so ONE orange now does every job — buttons, badges, the
	   eyebrow, links — and every rule that read --vdm-primary-text now reads --vdm-primary. */
	--vdm-accent-text: color-mix(in srgb, #000 15%, var(--vdm-accent));

	--vdm-r: 16px;
	--vdm-r-sm: 11px;
	/* M5, 2026-09-10 accessibility audit: written by updateStickyOffset() in quote-app.js (which
	   calls stickyHeaderOffset() for the live measurement) onto this root once per step change and
	   on resize (debounced) — see scroll-margin-top below. 0px default so a page where JS never
	   runs (or before the first write) reserves nothing. */
	--vdm-sticky-offset: 0px;
	max-width: 940px;
	margin: 0 auto;
	color: var(--vdm-text);
	padding-bottom: 50px; /* keep the nav buttons off the site footer */
}
/* Mobile.
   - Horizontal padding: the wizard is edge-to-edge on a phone otherwise, so the Back/Continue
     buttons, headings and fields sit hard against the screen edge.
   - Top padding: the theme's header/menu overlaps the start of the page; 1.25rem was not enough
     to clear it. */
@media (max-width: 767px) {
	.vdm-quote { padding-top: 2.5rem; padding-left: 1.1rem; padding-right: 1.1rem; }
}
.vdm-quote,
.vdm-quote *,
.vdm-quote *::before,
.vdm-quote *::after { box-sizing: border-box; }

/* ===== Stepper (numbered) ===== */
.vdm-quote__progress:not(#vdm-never) { display: flex; gap: .35rem .5rem; list-style: none; padding: 0; margin: 0 0 2.25rem; flex-wrap: wrap; align-items: center; }
/* S6 (2026-09-10 audit): this used to also carry `opacity: .55`, taking the already-muted label
   text down to 2.09:1. --vdm-muted alone is 4.56:1 on white — plenty — so the dimming for a
   not-yet-reached step is left to is-active/is-done's own border/fill colours below, not to a
   second multiplier stacked on the text. */
.vdm-quote__progress:not(#vdm-never) li { flex: 0 1 auto; display: flex; align-items: center; gap: .5rem; color: var(--vdm-muted); }
.vdm-step__num:not(#vdm-never) {
	width: 24px; height: 24px; border-radius: 50%; flex: 0 0 auto;
	display: inline-flex; align-items: center; justify-content: center;
	border: 1.5px solid var(--vdm-line-2); background: var(--vdm-surface);
	font-size: .74em; font-weight: 800; color: var(--vdm-muted); transition: .18s;
}
.vdm-quote__progress:not(#vdm-never) li:not(:last-child)::after {
	content: ""; width: 22px; height: 2px; background: var(--vdm-line); border-radius: 2px; margin-left: .25rem;
}
.vdm-quote__progress:not(#vdm-never) li.is-active { opacity: 1; color: var(--vdm-text); }
.vdm-quote__progress:not(#vdm-never) li.is-active .vdm-step__num { background: var(--vdm-primary); border-color: var(--vdm-primary); color: #fff; }
.vdm-quote__progress:not(#vdm-never) li.is-done { opacity: 1; }
.vdm-quote__progress:not(#vdm-never) li.is-done .vdm-step__num { background: var(--vdm-accent); border-color: var(--vdm-accent); color: #fff; }
.vdm-quote__progress:not(#vdm-never) li.is-nav button { cursor: pointer; background: none; border: none; color: inherit; font: inherit; padding: 0; }
.vdm-quote__progress:not(#vdm-never) li.is-nav button:hover,
.vdm-quote__progress:not(#vdm-never) li.is-nav button:focus-visible { color: var(--vdm-primary); }
/* S5: the stepper's only focusable control (the desktop step-label button); a solid ring rather
   than relying on the browser default, matching every other interactive element in this file. */
.vdm-quote__progress:not(#vdm-never) li.is-nav button:focus-visible {
	outline: 2px solid var(--vdm-accent); outline-offset: 2px;
}

/* On a phone the six labelled steps wrap to three lines and eat the top of the screen, so the
   stepper becomes numbers only — the full name stays in the accessibility tree via the
   role="img" aria-label on each .vdm-step__num circle (quote-app.php), which is unaffected by
   this rule hiding the visible <button>/<span> label, so a screen reader still hears
   "Step 2 of 6: Vehicle".
   Tapping a completed step to jump back goes with the labels; the Back button covers that, and a
   24px circle was a poor tap target anyway. */
@media (max-width: 767px) {
	.vdm-quote__progress:not(#vdm-never) { gap: .25rem; margin-bottom: 1.6rem; flex-wrap: nowrap; justify-content: space-between; }
	.vdm-quote__progress:not(#vdm-never) li { gap: 0; }
	.vdm-quote__progress:not(#vdm-never) li > button,
	.vdm-quote__progress:not(#vdm-never) li > span:not(.vdm-step__num) { display: none; }
	.vdm-quote__progress:not(#vdm-never) li:not(:last-child)::after { width: 100%; min-width: .5rem; margin-left: .25rem; }
	.vdm-quote__progress:not(#vdm-never) li:not(:last-child) { flex: 1 1 auto; }
}

/* ===== Section heading block ===== */
.vdm-quote__step { min-height: 8rem; }
/* M5, 2026-09-10 accessibility audit: stickyHeaderOffset() (quote-app.js) only ever scrolled the
   page itself into the right place — scrollWizardTo() subtracts it before an programmatic scroll.
   It did nothing for a scroll the BROWSER performs on its own, which is every Tab press down a
   long form: the newly focused field could land directly under the theme's fixed Elementor
   header, so a keyboard-only buyer typing their address kept typing into a field they could not
   see. scroll-margin-top tells the browser's own scroll-into-view (Tab included) to leave this
   much room above the target — reading --vdm-sticky-offset, which updateStickyOffset() keeps
   current.
   Fix round 1 (I1, 2026-09-10 review): `scroll-margin-*` applies to the element being scrolled
   INTO view, never to an ancestor of it — the browser's Tab-driven scroll targets the focused
   CONTROL (the <input>/<select>/<button> itself), not `.vdm-field`, the <label> that wraps it
   (see quote-step-2-dl.php: `<label class="vdm-field"><span…><input…></label>`). The original
   three selectors were therefore never consulted by the one scroll this rule exists for — kept
   below because they cost nothing and .vdm-quote__h/.vdm-card are still valid targets for a
   FUTURE scrollIntoView, but the `:is(...)` selector is the one doing the actual work today. */
.vdm-quote :is(input, select, textarea, button, [tabindex]),
.vdm-field, .vdm-card, .vdm-quote__h { scroll-margin-top: var(--vdm-sticky-offset, 0px); }
/* S6: coral text at 11.5px needs a colour that clears 4.5:1 for text-sized use — brand
   --vdm-primary (#D54318) measures 4.52:1 on its own since the 2026-09-11 darkening, so it is
   used directly here; the ::before bar below stays the same fill since it carries no text. */
.vdm-eyebrow {
	display: inline-flex; align-items: center; gap: .6rem;
	color: var(--vdm-primary); text-transform: uppercase;
	font-size: .72em; font-weight: 800; letter-spacing: .18em; margin-bottom: .6rem;
}
.vdm-eyebrow::before { content: ""; width: 26px; height: 2px; background: var(--vdm-primary); border-radius: 2px; }
.vdm-quote__h { margin: 0 0 .5rem; line-height: 1.05; }
.vdm-quote__h-sub { color: var(--vdm-muted); font-weight: 600; margin: -.15rem 0 .6rem; }
.vdm-sub { color: var(--vdm-muted); max-width: 56ch; margin: 0 0 1.75rem; }

/* ===== Buttons ===== */
.vdm-btn:not(#vdm-never) {
	display: inline-flex; align-items: center; justify-content: center;
	min-height: 46px; padding: .75rem 1.5rem; border-radius: var(--vdm-r-sm);
	border: 0; cursor: pointer; font: inherit; font-weight: 700; transition: transform .12s, box-shadow .2s, background .2s;
}
.vdm-btn:active:not(#vdm-never) { transform: translateY(1px); }
/* S5: an explicit ring on every button — Continue/Back/Complete purchase — rather than leaving it
   to whatever the browser (or the Elementor kit reset above) happens to draw by default.
   Fix round 1 (task-27-review.md, Critical #1): this button's own coral fill does NOT sit behind
   the ring — `outline-offset` paints its 2px gap with whatever is behind the button in normal
   flow (the white page/card), not the button's own background, because nothing else wraps it the
   way .vdm-term-wrap wraps a term pill. Computed: --vdm-accent (#1E8A9E) on white = 4.05:1 — well
   clear of the 3:1 non-text floor. No override needed here. */
.vdm-btn:not(#vdm-never):focus-visible { outline: 2px solid var(--vdm-accent); outline-offset: 2px; }
/* S6: "Continue" / "See my rates" / "Complete purchase" is white-on-coral at normal size (never
   the 18.66px-bold/24px large-text exemption) — brand --vdm-primary (#D54318, 4.52:1) clears the
   4.5:1 floor on its own since the 2026-09-11 darkening, so the fill IS the brand coral. Hover
   darkens further from that same token. */
.vdm-btn--primary:not(#vdm-never) { background: var(--vdm-primary); color: #fff; box-shadow: 0 10px 22px -12px color-mix(in srgb, var(--vdm-primary) 90%, transparent); }
.vdm-btn--primary:hover:not(#vdm-never) { background: color-mix(in srgb, var(--vdm-primary) 88%, #000); }
.vdm-btn--primary:disabled:not(#vdm-never) { opacity: .5; cursor: not-allowed; box-shadow: none; }
.vdm-btn--ghost:not(#vdm-never) { background: transparent; border: 1.5px solid var(--vdm-line-2); color: var(--vdm-muted); }
.vdm-btn--ghost:hover:not(#vdm-never) { border-color: var(--vdm-text); color: var(--vdm-text); }
.vdm-btn--secondary:not(#vdm-never) { background: var(--vdm-accent); color: #fff; }

/* ===== Card (form wrapper) ===== */
.vdm-card {
	background: var(--vdm-surface); border: 1px solid var(--vdm-line);
	border-radius: var(--vdm-r); padding: 1.6rem; box-shadow: var(--vdm-shadow-sm);
}

/* ===== Product cards ===== */
/* grid-auto-rows: 1fr equalises the ROWS, so every card is as tall as the tallest in the picker
   rather than each row sizing to its own content. Without it a description that wraps to two
   lines makes its whole row 30px taller than the other, which reads as a layout bug rather than
   as a longer description. Copy-length-proof: it holds however the descriptions change. */
.vdm-products:not(#vdm-never) { display: grid; gap: 1rem; grid-template-columns: 1fr; grid-auto-rows: 1fr; max-width: 760px; }
/* The Global Kit sets `white-space: nowrap` on these <button> descendants at a specificity the
   bare .vdm-product__desc below cannot beat, so a description long enough to exceed the card
   renders as one unbroken line. That line becomes the grid item's minimum content width, which
   widens the COLUMN — so a single long description blows out the whole picker and pushes the
   page into horizontal scroll, not just its own card. It stayed hidden while every description
   was ~40 characters; the 251-character Any-Vehicle copy took the page to 2691px in a 1523px
   viewport. The wrap rule below is what fixes it.

   The grid-template-columns restatement that used to sit here has been REMOVED: at (1,2,0) it
   outranked the `@media (min-width: 700px)` two-column rule at (1,1,0) and flattened the picker
   into four stacked rows. The base `.vdm-products` rule already beats the kit now that every rule
   in this file carries the marker, so the restatement was redundant as well as harmful. */
.vdm-quote:not(#vdm-never) .vdm-products .vdm-product__title,
.vdm-quote:not(#vdm-never) .vdm-products .vdm-product__desc { white-space: normal; }
/* Force a white card even though the Global Kit styles <button> with the coral background. */
.vdm-quote:not(#vdm-never) .vdm-products .vdm-product {
	position: relative; text-align: left; padding: 1.5rem;
	border: 1.5px solid var(--vdm-line); border-radius: var(--vdm-r);
	background: #fff; color: var(--vdm-text); cursor: pointer;
	transition: transform .18s, box-shadow .2s, border-color .2s;
}
.vdm-product__title:not(#vdm-never), .vdm-product__desc:not(#vdm-never) { overflow-wrap: anywhere; }
.vdm-quote:not(#vdm-never) .vdm-products .vdm-product:not([disabled]):hover { transform: translateY(-2px); box-shadow: var(--vdm-shadow-sm); border-color: var(--vdm-accent); }
/* S5: the product cards are clickable buttons; give them the same solid ring as every other
   control instead of the browser default (which the kit's own button reset elsewhere in this
   file tends to strip inconsistently).
   Fix round 1 (task-27-review.md, Critical #1): unlike the active term pill, .is-selected below
   keeps `background: #fff` regardless of state — the ring always sits on white (4.05:1). No
   filled-surface override needed here. */
.vdm-quote:not(#vdm-never) .vdm-products .vdm-product:focus-visible { outline: 2px solid var(--vdm-accent); outline-offset: 2px; }
.vdm-quote:not(#vdm-never) .vdm-products .vdm-product.is-selected { background: #fff; border-color: var(--vdm-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--vdm-primary) 16%, transparent); }
.vdm-quote:not(#vdm-never) .vdm-products .vdm-product[disabled] { opacity: 1; cursor: not-allowed; background: color-mix(in srgb, var(--vdm-text) 5%, #fff); }
/* The boat card carries a (?) that must NOT be inside its <a> — see quote-step-1-product.php. The
   wrapper becomes the grid item so the card still stretches to the row height that
   `.vdm-products { grid-auto-rows: 1fr }` sets, and the trigger is pinned to the card's corner.
   `margin: 0` clears hints.css's usual inline-flow margin (a negative pull-back tuned for a
   trigger sitting in text) — irrelevant and actively wrong for an absolutely positioned one,
   where `top`/`right` alone place the box. The 24px hit-target padding from hints.css still
   applies and grows the box inward from this same top-right corner, which nudges the visible
   circle a few px further into the card; that is the accepted trade already made by pinning the
   trigger over the card's own corner instead of leaving it fully clear of the link. */
.vdm-product-wrap:not(#vdm-never) { position: relative; display: grid; }
.vdm-product-wrap > .vdm-hint-trigger:not(#vdm-never) { position: absolute; top: .55rem; right: .55rem; z-index: 1; margin: 0; }
.vdm-product__icon:not(#vdm-never) { display: block; width: 46px; height: 46px; margin: 0 0 .9rem; }
.vdm-product__title:not(#vdm-never) { display: block; font-weight: 700; color: var(--vdm-text); }
.vdm-product__desc:not(#vdm-never) { display: block; color: var(--vdm-muted); margin-top: .15rem; }
.vdm-product[disabled]:not(#vdm-never) .vdm-product__title { color: var(--vdm-muted); }
/* Boat links out to the carrier's own quoter instead of being a product in this wizard. It keeps
   the greyed "not part of this flow" colour the disabled card had — the [disabled] rules above
   cannot reach it, because an <a> has no disabled state — but unlike that card it IS clickable,
   so it keeps the pointer cursor and picks up the hover lift from the :not([disabled]) rule
   above. Placed after the base .vdm-product background so it wins on source order at equal
   specificity. */
.vdm-quote:not(#vdm-never) .vdm-products .vdm-product--external { background: color-mix(in srgb, var(--vdm-text) 5%, #fff); text-decoration: none; }
.vdm-product--external:not(#vdm-never) .vdm-product__title { color: var(--vdm-muted); }
/* Currently UNUSED: Boat was the only "Coming soon" product and now links out to the carrier's
   quoter instead. Kept because the next unreleased product will want the badge back and this is
   the styling for it — not because anything renders it today. */
.vdm-product__soon:not(#vdm-never) {
	position: absolute; top: .9rem; right: .9rem;
	font-size: .62em; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
	color: var(--vdm-accent); background: var(--vdm-tint); padding: .25rem .55rem; border-radius: 20px;
}
.vdm-product__check:not(#vdm-never) {
	position: absolute; top: .9rem; right: .9rem; width: 24px; height: 24px; border-radius: 50%;
	background: var(--vdm-primary); color: #fff; display: none; align-items: center; justify-content: center; font-size: .8rem;
}
.vdm-product.is-selected:not(#vdm-never) .vdm-product__check { display: inline-flex; }

/* ===== Fields ===== */
.vdm-field:not(#vdm-never) { display: block; margin: 0 0 1rem; }
.vdm-field:not(#vdm-never) > span, .vdm-field:not(#vdm-never) { font-weight: 600; }
/* S5 (2026-09-10 audit): the field has almost no fill (background is a 3% text wash), so its
   border is the only thing saying "type here". var(--vdm-line-2) (22% text) measured 1.66:1 —
   below the 3:1 WCAG 1.4.11 floor. --vdm-border (#767676 fallback, 4.54:1) replaces it. */
.vdm-field:not(#vdm-never) select, .vdm-field:not(#vdm-never) input, .vdm-field:not(#vdm-never) textarea {
	display: block; width: 100%; min-height: 46px; padding: .7rem .8rem; margin-top: .35rem;
	border: 1.5px solid var(--vdm-border); border-radius: 10px; font: inherit; font-weight: 400;
	color: var(--vdm-text); background: color-mix(in srgb, var(--vdm-text) 3%, #fff); transition: .15s;
}
/* S5: the office screen already does this (admin-sell-policy.css ~113-117, "a payment form and
   focus must stay obvious") — the member's own payment form gets the same solid ring instead of
   the 18%-teal box-shadow wash that measured 1.24:1. `outline: none` above is gone; `:focus-visible`
   (not `:focus`) so a mouse click doesn't draw a ring a keyboard user never asked to see removed. */
.vdm-field:not(#vdm-never) select:focus-visible, .vdm-field:not(#vdm-never) input:focus-visible, .vdm-field:not(#vdm-never) textarea:focus-visible {
	outline: 2px solid var(--vdm-accent); outline-offset: 2px;
	border-color: var(--vdm-accent); background: #fff;
}
.vdm-field:not(#vdm-never) input[readonly] { background: color-mix(in srgb, var(--vdm-text) 6%, transparent); }
/* A-S8, 2026-09-10 accessibility audit: a <select> has no [readonly] of its own (the attribute is
   invalid on it and browsers ignore it), so the locked State/Province select — kept ENABLED, see
   quote-step-6-checkout.php — gets the same greyed background via a class instead, applied only
   while policyholderLocked, matching the [readonly] look above exactly. */
.vdm-field:not(#vdm-never) select.is-readonly { background: color-mix(in srgb, var(--vdm-text) 6%, transparent); }
.vdm-field-hint:not(#vdm-never) { display: block; font-weight: 400; font-size: 0.85em; opacity: 0.7; margin-top: 0.35rem; }
.vdm-field-row:not(#vdm-never) { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
/* Side-by-side fields whose labels wrap to different line counts would otherwise start their
   controls at different heights. Reserving two lines for the label text keeps the selects on
   the same line as each other; single-column (mobile) needs no reservation. */
.vdm-field-row:not(#vdm-never) .vdm-field__label { display: block; min-height: 2.7em; line-height: 1.35; }
@media (max-width: 560px) {
	.vdm-field-row:not(#vdm-never) { grid-template-columns: 1fr; }
	.vdm-field-row:not(#vdm-never) .vdm-field__label { min-height: 0; }
}

/* ===== Additional items (towed units) ===== */
.vdm-additional { margin-top: 1.75rem; }
.vdm-additional:not(#vdm-never) .vdm-field { max-width: 360px; }
/* The towing disclosure. It carries .vdm-sub for its width, but must NOT read as fine print:
   .vdm-sub is muted and sits 1.75rem clear of what follows, which would float a warning away
   from the field it is warning about. Doubled selector because the theme styles `p` colour. */
.vdm-additional .vdm-towed-notice:not(#vdm-never) {
	color: inherit; max-width: 62ch; margin: 0 0 1rem;
}
.vdm-towed { margin-top: 1rem; }
.vdm-towed h4 { margin: 0 0 1rem; font-weight: 700; }

/* ===== Coverage add-on section label =====
   The row styling that used to sit here (.vdm-addon, its checkbox, its (?) trigger placement)
   targeted a checkbox per add-on. The only add-on that ever rendered here was MexVisit/extended
   travel, removed 2026-08-21 on the underwriter's instruction (see the comment in
   templates/partials/quote-step-3-trip.php) — no template has carried a `.vdm-addon` element
   since, so that block was dead CSS and is gone (2026-09-11 tidy-up sweep). This label alone is
   still live markup. */
.vdm-addons__label { display: block; margin: 1.5rem 0 .7rem; font-weight: 700; text-transform: uppercase; font-size: .72em; letter-spacing: .1em; color: var(--vdm-muted); }

/* ===== Term toggle (segmented) — override the kit's coral <button> fill so only the active pill fills ===== */
.vdm-terms { display: inline-flex; flex-wrap: wrap; gap: .25rem; margin: 0 0 1.5rem; padding: .3rem; border: 1.5px solid var(--vdm-line-2); border-radius: 30px; background: var(--vdm-surface); }
/* The wrapper IS the pill — it holds the term button and its (?) together, so the trigger sits
   inside the selected pill instead of floating beside it. Active state lives here because a
   <button> cannot contain another <button>. */
.vdm-term-wrap { display: inline-flex; align-items: center; padding-right: .9rem; border-radius: 24px; background: transparent; transition: .18s; }
/* S6: the selected pill carries white text (the term name, and the tagline below) at normal
   size, so the fill needs --vdm-accent-text (5.34:1 for white-on-fill), not the brand --vdm-accent
   (4.05:1 — under the 4.5:1 floor even at full opacity). */
.vdm-term-wrap.is-active { background: var(--vdm-accent-text); box-shadow: 0 6px 14px -8px color-mix(in srgb, var(--vdm-accent-text) 90%, transparent); }
/* N3, 2026-09-10 accessibility audit: 44px, not merely the 24px SC 2.5.8 floor the spacing
   exception already cleared — this audience skews older, and 44px is the comfortable-touch
   guideline. */
.vdm-quote .vdm-terms .vdm-term { min-height: 44px; padding: .5rem .5rem .5rem 1.3rem; border: 1.5px solid transparent; /* reserves the box the .is-muted dashed border fills, so a live flip to muted does not shift the row */ border-radius: 24px; background: transparent; color: var(--vdm-muted); cursor: pointer; font: inherit; font-weight: 700; box-shadow: none; transition: .18s; }
.vdm-quote .vdm-terms .vdm-term:hover { color: var(--vdm-text); }
.vdm-quote .vdm-terms .vdm-term.is-active,
.vdm-quote .vdm-terms .vdm-term.is-active:hover { color: #fff; }
/* S5: term pills are buttons too. */
.vdm-quote .vdm-terms .vdm-term:focus-visible { outline: 2px solid var(--vdm-accent); outline-offset: 2px; }
/* Fix round 1 (task-27-review.md, Critical #1): the <button> itself is transparent — its ANCESTOR
   .vdm-term-wrap.is-active carries the fill (--vdm-accent-text, above), so the outline-offset gap
   paints with THAT fill, not the page behind it. --vdm-accent (#1E8A9E) on --vdm-accent-text
   (#1A7586) is 1.32:1 — invisible, under the 3:1 non-text floor. White on that same fill is
   5.34:1 (the identical white-on-fill pair already used for the fill itself), so only the
   already-selected pill's ring switches to white; every other pill's ring still sits on the white
   page (--vdm-accent, 4.05:1) and is left alone. */
.vdm-quote .vdm-term-wrap.is-active .vdm-term:focus-visible { outline-color: #fff; }
/* Deliberately NOT `calc(.1rem - var(--vdm-hint-pad))`: the term button sits only 1.6px away
   (S7, 2026-09-10 audit), so this trigger's 24px hit box must not grow leftward into it. Setting
   only margin-left here (not the shorthand) leaves hints.css's negative top/right/bottom margin
   in place, so the box still grows up, right (into this wrap's own `padding-right: .9rem`) and
   down — just not toward the button.
   `:not(#vdm-never)` is load-bearing, not decoration (task-24-review.md, fix round 1, measured in
   a real browser: computed margin-left came back 0.17px, not .1rem). hints.css sets this SAME
   margin shorthand via `.vdm-quote .vdm-hint-trigger:not(:hover):not(:focus)` — two classes plus
   two pseudo-classes, specificity (0,0,4,0) — which beats this selector's plain two classes
   (0,0,2,0) no matter which stylesheet loads last, so without the boost this rule never applied
   at all; the box was one accidental 0.2px of UA-default button font-size away from bleeding left
   into the term button. `:not(#vdm-never)` adds ID-level specificity (the same trick already used
   below for the boat-card override), so this now unconditionally wins. */
.vdm-term-wrap .vdm-hint-trigger:not(#vdm-never) { margin-left: .1rem; }
/* On the selected pill the accent background swallows an accent-coloured circle, so it inverts.
   hints.css sets the resting colours via `.vdm-quote .vdm-hint-trigger:not(:hover):not(:focus)`,
   which is four selectors deep — these carry `.vdm-terms` as well so they win regardless of the
   order the two stylesheets happen to be enqueued in. Targets the inner `span` because hints.css
   now draws the circle there, not on the button (S7 — the button is the invisible 24px hit box). */
.vdm-quote .vdm-hint-trigger.is-on-active-term span,
.vdm-quote .vdm-hint-trigger.is-on-active-term:not(:hover):not(:focus) span {
	border-color: #fff; background: transparent; color: #fff;
}
.vdm-quote .vdm-hint-trigger.is-on-active-term:hover span,
.vdm-quote .vdm-hint-trigger.is-on-active-term:focus-visible span {
	background: #fff; border-color: #fff; color: var(--vdm-accent);
}
/* Chip contents stack: product name over its one-line explanation. The chip stays a chip on
   desktop; the tagline is what makes Tourist and Annual Tourist distinguishable at a glance. */
.vdm-quote .vdm-terms .vdm-term { display: flex; flex-direction: column; gap: .1rem; text-align: center; }
.vdm-term__name { display: block; }
/* S6: this used to carry `opacity: .8` (resting) / `.92` (active), measuring 3.15:1 / 3.69:1. The
   resting state inherits --vdm-muted from .vdm-term (4.56:1 on white — no multiplier needed); the
   active state inherits #fff, which now sits on --vdm-accent-text above (5.34:1) instead of the
   plain accent, so full-opacity white also clears the floor. */
.vdm-term__tagline { display: block; font-size: .72rem; font-weight: 500; line-height: 1.25; }
/* The Tourist -> Annual price comparison, under the term row. The bottom margin clears the
   "Recommended" badge, which is positioned to overhang the top of the first rate card — without
   it the second line of this sentence renders underneath the badge. */
.vdm-term-value { margin: .6rem 0 1.5rem; font-size: .9rem; line-height: 1.5; color: var(--vdm-muted); }
/* The Daily pill when a six-month policy costs the same or less (quote-app.js termMuted). Visible
   but INACTIVE — the button carries `disabled` too, so this only has to look the part. The buyer is
   not asked to take the comparison on trust: the message above the cards names both prices, so the
   claim stands without this tab opening.
   M8 (2026-09-10 audit): this used to also set `opacity: .72` here, which — stacked on the .vdm-term
   text already being --vdm-muted — measured 2.74:1, though the comment claimed the 4.5:1 floor.
   --vdm-muted's own margin over white is only 4.56:1, so ANY opacity below 100% pushes it back
   under 4.5:1; there is no dimmer value that is both "visibly muted" and compliant. The floor now
   holds literally (no opacity multiplier at all, 4.56:1) and the dashed border + `cursor:
   not-allowed` below carry the "this one's off" cue instead of a fainter fill. Disabled controls
   are exempt from 1.4.3 either way — this is about the comment's claim being true, not a failure.
   Fix round 1 (task-27-review.md, Critical #2): the base `.vdm-term` rule three lines up sets
   `border: 0`, which zeroes border-WIDTH — `border-style: dashed` alone paints nothing at 0 width,
   so the "carry the cue" sentence above was not actually true until this longhand was added. A
   real 1.5px width is what makes the dashed style visible; --vdm-border (4.54:1, non-text so no
   floor applies to a decorative border anyway) keeps it visually related to the rest of the
   wizard's line-work rather than introducing a new grey. */
.vdm-quote .vdm-terms .vdm-term.is-muted { border-width: 1.5px; border-style: dashed; border-color: var(--vdm-border); cursor: not-allowed; }
.vdm-quote .vdm-terms .vdm-term.is-muted:hover { background: transparent; }
/* The six-months-for-less message. Reads as good news rather than a warning — the buyer is being
   offered longer cover for less money — so it borrows the accent, not an alert colour. */
.vdm-term-value--better { border-left: 3px solid var(--vdm-accent); padding-left: .75rem; }
.vdm-term-value strong { color: var(--vdm-text); }
/* Helper line under a field label, and the precise mechanics at the foot of a hint dialog. */
/* Visually hidden but readable by assistive tech — used for "(opens in a new tab)" and similar
   context that sighted users get from the surrounding layout. */
.vdm-sr-only {
	position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
	overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
/* Task 27 carry-over, 2026-09-10 accessibility audit: a link inside the .8rem help text needs
   --vdm-accent-text (5.34:1) — plain --vdm-accent measured 4.05:1, under the 4.5:1 text floor. */
.vdm-field__help:not(#vdm-never) a { color: var(--vdm-accent-text); text-decoration: underline; }
.vdm-field__help:not(#vdm-never) { display: block; margin-top: .35rem; font-size: .8rem; font-weight: 400; line-height: 1.45; color: var(--vdm-muted); }
.vdm-hint__fine { margin-top: .9rem; padding-top: .75rem; border-top: 1px solid color-mix(in srgb, var(--vdm-muted) 25%, transparent); font-size: .85rem; color: var(--vdm-muted); }

/* ===== Rate anchor ===== */
.vdm-rate-anchor { display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem; margin: 0 0 1.25rem; color: var(--vdm-muted); }
.vdm-rate-anchor__price { color: var(--vdm-text); font-weight: 800; margin-left: .15rem; }

/* ===== Plan (rate) cards ===== */
/* M7: align-items: stretch, not start — now that the name/tier reservations above are a floor
   (min-height) rather than a fixed ceiling, a card whose text wraps further under enlarged text
   can grow past its neighbours'. Stretching every card in the row to the tallest keeps the Select
   buttons roughly level without clipping anything, which was the point of the fixed heights this
   replaces. */
.vdm-rates:not(#vdm-never) { display: grid; gap: 1.25rem; grid-template-columns: 1fr; align-items: stretch; }
.vdm-rate {
	--vdm-name-line: 1.35rem; --vdm-tier-line: 1.25rem;
	position: relative; border: 1.5px solid var(--vdm-line); border-radius: var(--vdm-r);
	padding: 1.5rem; background: var(--vdm-surface); box-shadow: var(--vdm-shadow-sm); transition: .2s;
}
.vdm-rate.is-recommended { border-color: var(--vdm-primary); order: -1; }
/* Reissue banner on the vehicle step. Teal tint rather than the coral CTA colour: it is telling
   the member what happened, not asking them to act. */
.vdm-reissue-banner {
	border: 1.5px solid var(--vdm-accent); border-left-width: 5px; background: var(--vdm-tint);
	border-radius: var(--vdm-r-sm); padding: .9rem 1.1rem; margin: 0 0 1.25rem;
}
.vdm-reissue-banner__title { margin: 0 0 .2rem; }
.vdm-reissue-banner__body { margin: 0; font-size: .92em; color: var(--vdm-muted); }

/* S6: "Recommended" is white-on-coral at .68em (~10.9px) — brand --vdm-primary (#D54318, 4.52:1)
   clears the 4.5:1 floor on its own since the 2026-09-11 darkening, so the fill IS the brand
   coral.
   Fix round 1 (task-27-review.md, Critical #1): this is a plain <span>/<div> label, not a
   focusable control (no button/link/tabindex in quote-step-4-rates.php), so there is no focus
   ring here to check against its own fill. */
.vdm-rate__badge {
	position: absolute; top: -.75rem; left: 1.5rem; background: var(--vdm-primary); color: #fff;
	font-size: .68em; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
	padding: .3rem .7rem; border-radius: 20px;
}
/* "You had this last time" — only ever on a reissue.
   Pinned to the OPPOSITE corner from __badge, which is absolutely positioned top-LEFT: a card can
   legitimately be both the recommended plan and the one they bought before, and two badges on the
   same corner would sit on top of each other.
   Teal rather than coral, and quieter than __badge on purpose. "Recommended" is our editorial claim
   about the best plan; this is a memory aid, and if it shouted louder it would read as advice.
   Task 27 carry-over, 2026-09-10 accessibility audit: white text at .62em needs --vdm-accent-text
   (5.34:1), the same darkened fill __badge above already uses for the identical reason — plain
   --vdm-accent measured only 4.05:1, under the 4.5:1 text floor. */
.vdm-rate__previous {
	position: absolute; top: -.75rem; right: 1.5rem; background: var(--vdm-accent-text); color: #fff;
	font-size: .62em; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
	padding: .3rem .7rem; border-radius: 20px;
}
/* Fixed box, not max-height: underwriter logos have different intrinsic heights, and with
   `max-height` a shorter logo reserves less vertical space — so every row below it (name, price,
   the Select button) rides up and the cards stop lining up side by side.
   `scale-down` rather than `contain`, because the carrier's logos are tiny (ABA ships 50x17, GNP
   50x40) and `contain` stretched ABA to 2x its intrinsic height — visibly blurry, and twice as
   wide as GNP's. `scale-down` shrinks what is too big and leaves what is too small alone, so both
   render sharp inside the same reserved box. */
.vdm-rate__logo {
	display: block; width: 120px; height: 30px;
	/* TOP, not center: ABA ships a 50x17 logo and GNP a 50x40 one, so in a fixed box `center`
	   floated the short one 8px down while the tall one sat flush — the two cards looked
	   misaligned before any other element came into it. Top-aligning starts both at the same y.
	   `scale-down` still refuses to upscale, so neither goes blurry. */
	object-fit: scale-down; object-position: left top; margin-bottom: .4rem;
}
/* The tier always takes its own line, which makes every heading the same two lines tall. Left to
   wrap naturally, "ABA Vagabundos" fits its pill inline (one line) while "Grupo Nacional
   Provincial" pushes it down (two) — so the Select buttons stop lining up the moment the two
   brands sit side by side rather than paired by row. min-height is the backstop for a name long
   enough to wrap on its own. */
.vdm-rate__name {
	display: flex; align-items: center; flex-wrap: wrap; align-content: flex-start;
	gap: .25rem .45rem; margin: .3rem 0 .1rem; font-weight: 700;
	/* Heights below are pinned in rem, NOT em. The card's inherited font-size differs between
	   themes and browser zoom levels, so an em-based reservation is a different number of pixels
	   on different machines — it held here and not on David's window. rem is the same everywhere. */
	min-height: calc(var(--vdm-name-line) * 2 + var(--vdm-tier-line) + .25rem);
}
/* Reserves room for two lines at the DEFAULT line-height, so "ABA Vagabundos" (one line) and
   "Grupo Nacional Provincial" (wraps to two once cards narrow to ~370px) start their Select
   buttons at roughly the same height without clipping either one.
   M7, 2026-09-10 accessibility audit: this used to be a fixed `height` with `-webkit-line-clamp:
   2; overflow: hidden` — a user stylesheet raising line-height for WCAG 1.4.12 (Text Spacing), or
   a browser minimum font size, clipped the underwriter name and cut it off mid-word (WCAG 1.4.4
   Resize Text). `min-height` is a floor, not a ceiling: text that needs more room takes it, and
   nothing is ever hidden. The remaining risk — cards in the same row ending at different heights
   when a name genuinely wraps to three lines under enlarged text — is left to `.vdm-rates`'
   `align-items: stretch` below, which is a layout trade worth making over silently losing text. */
.vdm-rate__name > span:first-child {
	flex: 1 1 100%;
	line-height: var(--vdm-name-line);
	min-height: calc(var(--vdm-name-line) * 2);
}
/* Coverage tier, alongside the underwriter name — one name spans two cards, so this is the
   only thing distinguishing them (quote-step-4-rates.php:167-175). Sized to read as a qualifier,
   not a second heading.
   S6: at 3.51:1 this was the least legible text on the most important screen — teal on its own
   12% tint. --vdm-accent-text keeps the teal pill/text pairing (rather than switching to plain
   --vdm-text) at 4.62:1 against this exact tint. */
/* M7: min-height, not height — see the note on .vdm-rate__name > span:first-child above; the
   same enlarged-text/user-stylesheet cases that clipped the underwriter name also clipped this
   pill's own text at a fixed height. white-space stays nowrap: the tier label is short by design
   ("Standard", "Diamond") and wrapping it would look broken well before it needs to. */
.vdm-rate__tier { min-height: var(--vdm-tier-line); display: inline-flex; align-items: center; padding: 0 .5rem; border-radius: 999px; background: color-mix(in srgb, var(--vdm-accent) 12%, transparent); color: var(--vdm-accent-text); font-size: .68em; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; white-space: nowrap; }
.vdm-rate__term { color: var(--vdm-muted); text-transform: uppercase; letter-spacing: .1em; font-size: .72em; font-weight: 700; margin: 0 0 .75rem; }


.vdm-rate__price { margin: .25rem 0; font-weight: 800; font-size: 1.9em; line-height: 1; }
.vdm-rate__through,
.vdm-rate__ded { margin: 0 0 .2rem; color: var(--vdm-muted); font-size: .82em; }
/* Task 8, Maria 2026-09-11: the carrier's "liability only" restriction, next to its (?) trigger.
   Set apart from the muted through/ded lines above it — it changes what the plan covers, not
   merely describes it — using the same accent pairing as .vdm-notice below. */
.vdm-rate__limited { margin: 0 0 .2rem; display: flex; align-items: center; gap: .35em; color: var(--vdm-accent-text); font-size: .82em; font-weight: 700; }

/* "Not included on this plan" — deliberately quiet. It exists so a customer can see what a
   cheaper plan gives up, not to argue them out of it, so it sits muted, unstriped, and with a
   dash in place of the tick. */
.vdm-rate__missing { margin-top: 1rem; }
.vdm-rate__missing-label { display: block; color: var(--vdm-muted); font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; }
.vdm-rate__list--missing { border-top: 0; padding-top: .35rem; margin-top: .35rem; }
.vdm-rate__list--missing .vdm-cov__desc { display: none; }
.vdm-cov--missing { color: var(--vdm-muted); }
.vdm-cov--missing:nth-child(even) { background: transparent; }
.vdm-cov--missing .vdm-cov__name { font-weight: 600; }
.vdm-cov--missing .vdm-cov__val { color: var(--vdm-muted); font-weight: 600; }
.vdm-cov--missing::before { content: "—"; color: var(--vdm-muted); font-weight: 700; }

.vdm-rate__list { list-style: none; padding: 1rem 0 0; margin: 1rem 0 0; border-top: 1px solid var(--vdm-line); display: flex; flex-direction: column; gap: 0; }
/* Zebra-striped coverage rows: alternate a light-gray background for scannability. */
.vdm-cov { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 .5rem; padding: .55rem .7rem .55rem 2rem; position: relative; border-radius: 8px; }
.vdm-cov:nth-child(even) { background: #f3f3f4; }
/* N4, 2026-09-10 accessibility audit: the alternate-text syntax (`"✓" / ""`) hides the glyph from
   assistive tech in browsers that support it, so VoiceOver does not read "check mark" on a row
   that already says everything in text — harmless, but noisy.
   Whole-branch review C3, 2026-09-11: the alt-text grammar is Chrome 77+, Safari 17.4+ and
   Firefox 133+ only. An older engine treats the WHOLE declaration as invalid, falls back to
   `content: normal`, and then generates no ::before at all — every tick silently disappears. The
   plain declaration MUST come first: old engines keep it, new ones win on source order. Do not
   collapse these two lines into one. */
.vdm-cov::before { content: "✓"; content: "✓" / ""; position: absolute; left: .65rem; top: .55rem; color: var(--vdm-accent); font-weight: 800; }
/* Plan-feature type is intentionally smaller than the kit default (prototype sizing) to tidy the list. */
.vdm-cov__name { font-weight: 700; flex: 1 1 60%; font-size: .875rem; }
/* S6: on the zebra rows' #f3f3f4 background, --vdm-muted measured 4.37:1 — under the floor.
   --vdm-text on the same background is 14.33:1. */
.vdm-cov__desc { color: var(--vdm-text); flex: 1 1 100%; font-size: .78rem; }
.vdm-cov__val { color: var(--vdm-text); font-weight: 700; margin-left: auto; text-align: right; white-space: nowrap; font-size: .82rem; }
.vdm-rate:not(#vdm-never) .vdm-btn { width: 100%; margin-top: 1.25rem; }

/* The control that reveals the rest of the coverage list is `.vdm-rate__more`, styled in
   hints.css alongside the other theme-button overrides it needs. */

/* Whole-branch review Minor 4, 2026-09-11: #vdm-card-error is the only error paragraph on the
   checkout step that is always in the document flow — every other one is x-show'd away. Empty, it
   still carried its own margin plus the theme's <p> bottom margin, leaving dead space between the
   card field and the "processed securely by Stripe" note. It cannot be x-show'd: checkout.js is a
   standalone Stripe wrapper with no access to the wizard's reactive state, so :empty is what
   stands in for it. */
#vdm-card-error:empty { display: none; }

/* ===== Trust strip ===== */
.vdm-trust { display: flex; flex-wrap: wrap; gap: .5rem 1.5rem; margin-top: 1.5rem; padding: 1rem 1.25rem; border: 1px solid var(--vdm-line); border-radius: 12px; background: color-mix(in srgb, var(--vdm-text) 3%, transparent); }
.vdm-trust span { display: inline-flex; align-items: center; gap: .5rem; color: var(--vdm-muted); font-size: .92em; }
/* N4: same alternate-text syntax as .vdm-cov::before above, with the same C3 plain-string
   fallback ahead of it. */
.vdm-trust span::before { content: "✓"; content: "✓" / ""; color: var(--vdm-accent); font-weight: 800; }

/* ===== Nav ===== */
.vdm-quote__nav { margin-top: 2rem; display: flex; align-items: center; justify-content: flex-end; gap: .75rem; }
.vdm-quote__nav:not(#vdm-never) .vdm-btn--ghost { margin-right: auto; }

/* ===== Shared spinner (build once, reuse everywhere) ===== */
.vdm-spinner { display:inline-block; width:1em; height:1em; border:2px solid currentColor; border-right-color:transparent; border-radius:50%; animation:vdm-spin .6s linear infinite; vertical-align:-0.15em; }
.vdm-spinner--btn { margin-right:.5em; }
@keyframes vdm-spin { to { transform:rotate(360deg); } }

/* ===== Required-field marker ===== */
/* Task 27 carry-over, 2026-09-10 accessibility audit: `aria-hidden="true"` on every use (the field
   label already says what is required in its own accessible name), so the 4.5:1 text floor does
   not apply — but it is still a visual cue a sighted user reads meaning from, so it is held to the
   3:1 non-text floor (WCAG 1.4.11) instead. Brand --vdm-primary on white measures 4.52:1, already
   clear; no darkening needed here the way the (non-decorative) badges above needed it. */
.vdm-req { color: var(--vdm-primary); margin-left:.15em; }

/* ===== Messages ===== */
.vdm-loading { color: var(--vdm-muted); }
.vdm-error { color: #c0392b; margin: 0 0 1rem; }
.vdm-field-error:not(#vdm-never) { color: #c0392b; font-size: .85em; margin-top: .3rem; }
/* S6: body text at 3.59:1 on its own 10% tint (--vdm-tint). --vdm-accent-text is 4.73:1 against
   that same tint. */
.vdm-notice {
	color: var(--vdm-accent-text); background: var(--vdm-tint);
	border: 1px solid color-mix(in srgb, var(--vdm-accent) 30%, transparent);
	border-radius: var(--vdm-r-sm); padding: .75rem 1rem; margin: 0 0 1rem;
}
/* Task 8, Maria 2026-09-11: the collected "why some rates are liability only" notice
   (quote-step-4-rates.php) reuses .vdm-notice's box but carries a heading + list rather than a
   single line of text. */
.vdm-notice__title { margin: 0 0 .5rem; font-weight: 700; }
.vdm-notice__list { margin: 0; padding-left: 1.25em; }
.vdm-notice__list li { margin-bottom: .3em; }
.vdm-notice__list li:last-child { margin-bottom: 0; }

/* ===== Checkout: the price moved before we charged the card =====
   Deliberately louder than .vdm-notice. This is the one thing on the checkout step a buyer must
   read rather than skim: the amount has changed and nothing happens until they answer it. The
   sentence is set larger for the same reason — most of the membership is over sixty. */
.vdm-price-change { border-color: var(--vdm-primary); border-width: 2px; margin: 0 0 1.5rem; }
.vdm-price-change__lead { font-size: 1.15em; font-weight: 600; margin: 0 0 .75rem; }
.vdm-price-change__note { color: var(--vdm-muted); margin: .75rem 0 0; }
.vdm-price-change__actions:not(#vdm-never) { margin-top: 1.25rem; }

/* ===== Review step: line items ===== */
.vdm-line-item { margin: 0 0 1.25rem; }
/* Task 27 carry-over, 2026-09-10 accessibility audit: teal text on the --vdm-tint (10% accent mix)
   background needs --vdm-accent-text (4.73:1 against this exact tint, already measured for
   .vdm-notice above) — plain --vdm-accent falls under the 4.5:1 text floor here. */
.vdm-line-item__tag {
	display: inline-block; text-transform: uppercase; font-weight: 800;
	font-size: .68em; letter-spacing: .1em; color: var(--vdm-accent-text);
	background: var(--vdm-tint); padding: .3rem .7rem; border-radius: 20px; margin-bottom: .9rem;
}
.vdm-line-item__head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: .5rem 1rem; }
.vdm-line-item__title { margin: 0; font-weight: 700; }
/* S6: "Change plan" is coral text at normal size — brand --vdm-primary (#D54318, 4.52:1) clears
   the 4.5:1 floor on its own since the 2026-09-11 darkening. Hover darkens further from that
   same token. */
/* N3, 2026-09-10 accessibility audit: "Change plan" was bare text at ~21px tall — under the 44px
   comfortable-touch guideline for this audience even though the spacing exception already cleared
   SC 2.5.8's 24px floor. `display: inline-block` + vertical padding grows the tap target without
   touching the font-size, so the visible text is unchanged. */
.vdm-line-item__change:not(#vdm-never) { display: inline-block; background: none; border: 0; padding: .6rem 0; cursor: pointer; font: inherit; font-weight: 700; color: var(--vdm-primary); text-decoration: underline; }
.vdm-line-item__change:hover:not(#vdm-never) { color: color-mix(in srgb, var(--vdm-primary) 88%, #000); }
.vdm-line-item__meta { display: flex; flex-wrap: wrap; gap: .3rem 1rem; color: var(--vdm-muted); margin-top: .35rem; }
.vdm-line-item__note { color: var(--vdm-muted); margin: .9rem 0 0; }
.vdm-line-item__price { display: flex; justify-content: space-between; gap: 1rem; margin: 1rem 0 0; padding-top: .9rem; border-top: 1px solid var(--vdm-line); }

/* ===== Review step: order summary ===== */
.vdm-order-summary {
	margin: 1.5rem 0; padding: 1.25rem 1.5rem; border-radius: var(--vdm-r);
	background: color-mix(in srgb, var(--vdm-text) 4%, transparent); border: 1px solid var(--vdm-line);
}
.vdm-order-summary__row:not(#vdm-never) { display: flex; justify-content: space-between; gap: 1rem; padding: .5rem 0; border-bottom: 1px solid var(--vdm-line); }
.vdm-order-summary__row:last-of-type:not(#vdm-never) { border-bottom: 0; }
.vdm-order-summary__row--total:not(#vdm-never) { padding-top: .8rem; font-size: 1.1em; }
.vdm-order-summary__note { color: var(--vdm-muted); margin: .75rem 0 0; }
/* Membership coupon code (2026-09-14): the box and its Apply/Remove button share a row, wrapping on a phone. */
.vdm-order-summary__coupon { display: flex; flex-wrap: wrap; align-items: flex-end; gap: .5rem; margin: .75rem 0 0; }
.vdm-order-summary__coupon .vdm-field { flex: 1 1 10rem; margin: 0; }
.vdm-order-summary__coupon [role="status"] { flex-basis: 100%; margin: 0; }

/* ===== Checkout step ===== */
.vdm-co-grid { display: grid; grid-template-columns: 1fr 340px; gap: 1.75rem; align-items: start; }
.vdm-co-left { display: flex; flex-direction: column; gap: 1.25rem; }
.vdm-card__title { margin: 0 0 1rem; font-weight: 700; }
.vdm-card__note { color: var(--vdm-muted); font-size: .85em; margin: .75rem 0 0; }
/* Stripe CardElement mounts an iframe here — border/padding/background live on this
   container (Stripe's documented approach; the iframe itself can't be styled from the
   page). Padding/min-height/margin here are load-bearing; border-radius/background below
   are a FALLBACK ONLY — checkout.js's applyContainerStyle() overwrites them as inline
   styles at mount time with the *live* computed values from a sibling .vdm-field input,
   because on this site the Elementor Global Kit's `.elementor-kit-33 input` rule outranks
   `.vdm-field input`'s specificity and overrides its border-radius/background, so matching
   quote.css's own values here (as this rule does) would NOT match a rendered field. These
   values only apply if JS fails or no reference input exists in the DOM. Stripe adds state
   classes to this element itself (StripeElement--focus / --invalid / --complete / --empty);
   :focus-within can't see into the cross-origin iframe, so the focus ring is driven by
   StripeElement--focus instead. Its border-color/background carry !important because
   checkout.js sets those same properties as inline styles (which otherwise always win over
   a selector-based rule), so !important is required for the state classes to still be able
   to override the resting look. */
#vdm-payment-element {
	display: block; width: 100%; min-height: 46px; padding: .7rem .8rem; margin-top: .35rem;
	border: 1.5px solid var(--vdm-border); border-radius: 10px;
	background: color-mix(in srgb, var(--vdm-text) 3%, #fff);
	/* Scoped, not `all`: mountPaymentElement() overwrites radius/background with inline
	   styles copied from a live input right after first paint; animating that hand-off
	   causes a visible flash. Only the focus affordances should transition. */
	transition: border-color .15s, box-shadow .15s;
}
/* Stripe 4, 2026-09-10 accessibility audit: this used to be a box-shadow wash at 18% opacity
   (measured 1.24:1) — the same fix S5 already gave our own fields above: a solid outline ring
   at full --vdm-accent, which clears the 3:1 non-text floor. */
#vdm-payment-element.StripeElement--focus {
	border-color: var(--vdm-accent) !important; background: #fff !important;
	outline: 2px solid var(--vdm-accent); outline-offset: 2px;
}
#vdm-payment-element.StripeElement--invalid { border-color: #c0392b !important; }
.vdm-checkout-summary { position: sticky; top: 1rem; margin: 0; align-self: start; }
/* S6: "Already a member? Sign in" / "Add another driver" — coral text at normal size; brand
   --vdm-primary (#D54318, 4.52:1) clears the 4.5:1 floor on its own since the 2026-09-11
   darkening. */
/* N3, 2026-09-10 accessibility audit: same treatment as .vdm-line-item__change below — vertical
   padding grows the tap target to the 44px comfortable-touch guideline without enlarging the text. */
.vdm-link:not(#vdm-never) {
	display: inline-block; margin-top: .75rem; padding: .6rem 0; border: 0; background: none;
	color: var(--vdm-primary); font: inherit; font-weight: 700; text-decoration: underline; cursor: pointer;
}
.vdm-link:hover:not(#vdm-never) { color: color-mix(in srgb, var(--vdm-primary) 88%, #000); }
.vdm-check-terms { display: flex; align-items: flex-start; gap: .6rem; margin-top: .25rem; color: var(--vdm-muted); cursor: pointer; }
.vdm-check-terms input[type="checkbox"] { width: 20px; height: 20px; margin-top: .1rem; flex: 0 0 auto; accent-color: var(--vdm-accent); }
@media (max-width: 820px) {
	.vdm-co-grid { grid-template-columns: 1fr; }
	.vdm-checkout-summary { position: static; }
}

/* ===== Confirmation (terminal view, purchaseState === 'done') ===== */
.vdm-confirmation { max-width: 640px; margin: 0 auto; }
.vdm-confirm-hero { text-align: center; margin: 0 0 2rem; }
.vdm-confirm-seal {
	display: inline-flex; align-items: center; justify-content: center;
	width: 64px; height: 64px; margin: 0 auto 1.1rem; border-radius: 50%;
	background: var(--vdm-primary); color: #fff; font-size: 1.9rem; font-weight: 800;
	box-shadow: 0 14px 28px -14px color-mix(in srgb, var(--vdm-primary) 90%, transparent);
}
.vdm-confirm-hero .vdm-quote__h { margin-bottom: .4rem; }
.vdm-confirm-hero .vdm-sub { margin: 0 auto; }
.vdm-confirm-card {
	background: var(--vdm-surface); border: 1px solid var(--vdm-line);
	border-radius: var(--vdm-r); padding: 1.6rem; box-shadow: var(--vdm-shadow-sm);
	margin: 0 0 1.25rem;
}
.vdm-confirm-card__policy-num { margin: 0 0 .5rem; font-size: 1.05em; }
.vdm-confirm-card__links { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1.25rem; }
.vdm-confirm-card__links:not(#vdm-never) .vdm-btn { flex: 1 1 auto; }
.vdm-confirm-next {
	margin-top: 1.75rem; padding: 1.25rem 1.5rem; border-radius: var(--vdm-r);
	background: color-mix(in srgb, var(--vdm-text) 4%, transparent); border: 1px solid var(--vdm-line);
}
.vdm-confirm-next__title { margin: 0 0 .75rem; font-weight: 700; }
.vdm-confirm-next ul { margin: 0; padding-left: 1.2rem; display: flex; flex-direction: column; gap: .5rem; color: var(--vdm-muted); }
/* "Print a paper copy before you go" + the member-account button (member path only, 2026-09-14). Same panel as "What happens next" so the receipt reads as one family. */
.vdm-confirm-print {
	margin: 0 0 1.25rem; padding: 1.25rem 1.5rem; border-radius: var(--vdm-r);
	background: color-mix(in srgb, var(--vdm-text) 4%, transparent); border: 1px solid var(--vdm-line);
}
.vdm-confirm-print p { margin: 0 0 .75rem; color: var(--vdm-muted); }
.vdm-confirm-print .vdm-btn { margin-top: .25rem; }
.vdm-confirm-upsell {
	margin-top: 1.25rem; padding: 1.25rem 1.5rem; border-radius: var(--vdm-r);
	background: color-mix(in srgb, var(--vdm-accent) 8%, transparent);
	border: 1px solid color-mix(in srgb, var(--vdm-accent) 35%, transparent);
}
.vdm-confirm-upsell__title { margin: 0 0 .35rem; font-weight: 700; }
.vdm-confirm-upsell__body { margin: 0 0 1rem; color: var(--vdm-muted); }

/* ===== Responsive ===== */
@media (min-width: 700px) {
	.vdm-products:not(#vdm-never) { grid-template-columns: repeat(2, 1fr); }
	.vdm-rates:not(#vdm-never) { grid-template-columns: repeat(2, 1fr); }
}

/* ===== Reduced motion (M9, 2026-09-10 accessibility audit) ===== */
/* Every step change runs a full-page-height smooth scroll (scrollWizardTo() in quote-app.js,
   now gated on this same media query — see its own comment), a common vestibular trigger the
   wizard performs on the buyer's own action six times per purchase; the product-card hover lift
   and button press animate a transform on every interaction; and the busy spinner spins forever
   with no way to pause or stop it (WCAG 2.2.2), which a `prefers-reduced-motion: reduce` reader
   has already told the system it does not want. Collapsing transition/animation durations to
   near-zero removes the MOTION — the hover/active states, and the spinner's gap, still change —
   without removing the states themselves or requiring a second, motion-specific set of rules
   for every animated selector in this file. */
@media (prefers-reduced-motion: reduce) {
	.vdm-quote *, .vdm-quote *::before, .vdm-quote *::after {
		transition-duration: .001ms !important; transition-delay: 0ms !important;
		animation-duration: .001ms !important; animation-delay: 0ms !important; animation-iteration-count: 1 !important;
	}
}
