/* ===========================================================================
   quote-island.css — HALCYON CLEARANCE — "Book a collection" flow styles
   ---------------------------------------------------------------------------
   Styles + keyframes for the ONE booking implementation (quote-react.js).
   Reuses the design tokens from styles.css (var(--ink-900), var(--amber),
   var(--display), var(--ease), …). Loaded ONLY on quote.html. Display type is
   Hanken Grotesk, prices/labels are heavy Hanken (no mono), the teal accent
   folds into amber via the shared --signal token. All motion is ≤500ms
   ease-out and gated behind prefers-reduced-motion at the bottom.

   R18/R20, 2026-07-26 — three steps, one implementation:
     • the van gauge is now the SPINE of the whole flow, not a step-2 aside
       (.qr-split wraps every step; it collapses to a quiet single row above
       the card on mobile, illustration dropped);
     • .qr-group bands the folded step 2 into Access / When / Photos;
     • .qr-duo pairs short fields so folding two steps into one does not
       produce a single 12-field column;
     • the vanilla twin's .result-next block is gone with quote.js.
   ========================================================================= */

/* ---------- static "React never booted" message (quote.html) --------------
   NOT a fallback wizard — R20 deleted that. This is the message React's
   createRoot().render() replaces on mount, and which is left standing when
   JavaScript is off or the vendor scripts never arrive. */
.qr-noboot {
  max-width: 560px; margin: 32px auto; text-align: center;
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-card);
  padding: clamp(22px, 4vw, 36px);
}
.qr-noboot-h { font-family: var(--display); font-weight: 800; color: var(--ink-900); font-size: clamp(1.4rem, 3.4vw, 1.95rem); letter-spacing: -.02em; margin: 0 0 .4em; }
.qr-noboot-p { color: var(--ink-soft); margin: 0 0 20px; }
.qr-noboot-actions { margin: 0; }

.qr-island {
  max-width: 940px;
  margin: 0 auto;
  padding: 8px 0 24px;
}

/* screen-reader-only live region */
.qr-sr {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

/* ---------- intro ---------- */
.qr-intro { text-align: center; margin: 4px auto 22px; max-width: 60ch; }
.qr-eyebrow {
  display: inline-block; font-family: var(--display); font-weight: 700;
  font-size: .74rem; letter-spacing: .11em; text-transform: uppercase;
  color: var(--steel); margin-bottom: 10px;
}
.qr-title { font-family: var(--display); font-weight: 800; color: var(--ink-900); font-size: clamp(1.7rem, 4.4vw, 2.5rem); line-height: 1.04; letter-spacing: -.025em; margin: 0 0 .35em; text-wrap: balance; }
.qr-lead { color: var(--ink-soft); font-size: 1rem; margin: 0; }

/* =======================================================================
   PROGRESS RAIL
   ===================================================================== */
.qr-rail {
  position: relative;
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 4px; margin: 0 0 22px; padding: 6px 6px 0;
}
.qr-rail-track {
  position: absolute; top: 20px; left: 26px; right: 26px; height: 3px;
  background: var(--line-2); border-radius: 3px; z-index: 0;
}
.qr-rail-fill {
  width: 100%; height: 100%; border-radius: 3px;
  background: var(--amber);
  transform-origin: left; transform: scaleX(0);
  transition: transform .3s var(--ease);
}
.qr-rail-node {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 7px;
  flex: 1 1 0; min-width: 0; min-height: 44px;
  background: none; border: 0; padding: 7px 10px; cursor: pointer;
  font: inherit; color: var(--ink-3);
}
.qr-rail-node[disabled] { cursor: default; }
.qr-rail-dot {
  width: 30px; height: 30px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--display); font-weight: 800; font-size: .9rem; font-variant-numeric: tabular-nums;
  background: var(--white); color: var(--ink-3);
  border: 2px solid var(--line); box-shadow: var(--shadow-sm);
  transition: transform .3s var(--ease), background .3s ease, color .3s ease, border-color .3s ease;
}
/* THREE nodes, so the labels stay on at every width (R18). With six they had
   to be hidden below 620px — three fit on a 320px phone, and a rail whose
   steps are unnamed on the device most customers use is a rail that only
   tells you how far you are, not what is coming. */
.qr-rail-label {
  font-family: var(--display); font-size: .7rem; font-weight: 600;
  letter-spacing: .01em; text-align: center; line-height: 1.2;
  color: var(--ink-3); max-width: 12ch;
}
.qr-rail-done .qr-rail-dot { background: var(--amber); border-color: var(--amber); color: var(--amber-ink); }
.qr-rail-done .qr-rail-label { color: var(--ink-soft); }
.qr-rail-current .qr-rail-dot {
  background: var(--ink-900); border-color: var(--amber); color: var(--white);
  transform: scale(1.16);
  box-shadow: 0 0 0 4px rgba(242,169,0,.22), var(--shadow-sm);
}
.qr-rail-current .qr-rail-label { color: var(--ink-900); font-weight: 800; }
@media (max-width: 620px) {
  .qr-rail { gap: 0; padding: 6px 0 0; }
  .qr-rail-node { padding: 7px 4px; }
  .qr-rail-label { font-size: .64rem; max-width: 10ch; }
  .qr-rail-track { top: 18px; left: 20px; right: 20px; }
}

/* =======================================================================
   CARD SHELL + STEP PANEL TRANSITIONS
   ===================================================================== */
.qr-card-shell {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  padding: clamp(18px, 3.5vw, 34px);
  overflow: hidden;
}
.qr-panel { will-change: transform, opacity; }
/* symmetric settle both directions: short opacity + 6px rise, no directional X
   slide (the outgoing panel unmounts instantly, so a one-sided X slide implied a
   missing partner exit — this reads as a clean settle in either direction). */
.qr-in-fwd { animation: qrSlideInR .3s var(--ease) both; }
.qr-in-back { animation: qrSlideInL .3s var(--ease) both; }
.qr-fade-in { animation: qrFade .45s var(--ease) both; }

@keyframes qrSlideInR {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes qrSlideInL {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes qrFade { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* Each step is a <section>, and styles.css:115 gives every <section> on the
   estate `padding: 64px 0 72px`. Inside a card that already has its own
   padding that is 136px of dead space wrapped around each step — measured, not
   guessed (2026-07-26 layout pass: the step eyebrow sat 111px below the top of
   its own card). The steps are cards, not page bands. */
.qr-step { padding: 0; }

.qr-step-eyebrow {
  display: inline-block; font-family: var(--display); font-weight: 700;
  font-size: .68rem; letter-spacing: .11em; text-transform: uppercase;
  color: var(--steel); margin-bottom: 8px;
}
.qr-step-h { font-family: var(--display); font-weight: 800; color: var(--ink-900); font-size: clamp(1.35rem, 3.4vw, 1.9rem); letter-spacing: -.02em; margin: 0 0 .35em; outline: none; }
.qr-step-help { color: var(--ink-soft); font-size: .96rem; margin: 0 0 20px; }
.qr-lbl { font-family: var(--display); font-weight: 700; color: var(--ink-900); font-size: .96rem; margin-bottom: 10px; }
.qr-mt { margin-top: 26px; }
.qr-req { color: var(--red); }
.qr-hint { font-size: .82rem; color: var(--ink-3); margin: 10px 0 0; }

/* ---------- GROUP BANDS (the folded step 2, and step 3's summary) ---------
   Six steps became three, so step 2 now asks three genuinely different
   questions in one screen: what the crew will face, when it suits, and what it
   looks like. The bands encode that — one hairline rule and one small legend
   per question, nothing decorative. The first band needs no top rule (the step
   heading is already the divider above it). */
.qr-group { margin-top: 28px; padding-top: 22px; border-top: 1px solid var(--line); }
.qr-group:first-of-type { margin-top: 24px; }
.qr-group-h {
  font-family: var(--display); font-weight: 800; color: var(--ink-900);
  font-size: .74rem; letter-spacing: .12em; text-transform: uppercase;
  margin: 0 0 14px;
}
.qr-group-h::after {
  content: ""; display: block; width: 26px; height: 2px;
  background: var(--amber); border-radius: 2px; margin-top: 7px;
}
.qr-group-help { color: var(--ink-soft); font-size: .9rem; margin: -4px 0 16px; }

/* ---------- fields ---------- */
.qr-field { margin-bottom: 16px; }
/* Two short fields side by side on anything wider than a phone — folding
   "your details" and "review" into one step otherwise produced a single
   twelve-element column. */
.qr-duo { display: grid; grid-template-columns: 1fr; gap: 0 20px; }
@media (min-width: 560px) { .qr-duo { grid-template-columns: 1fr 1fr; } }
.qr-duo .qr-field input { max-width: 100%; }
.qr-field label { display: block; font-family: var(--display); font-weight: 700; color: var(--ink-900); font-size: .9rem; margin-bottom: 7px; }
.qr-field input,
.qr-field textarea {
  font: inherit; padding: 12px 13px;
  border: 1.5px solid var(--line); border-radius: 9px;
  background: var(--white); color: var(--ink);
  width: 100%; max-width: 460px;
  transition: border-color .18s ease, box-shadow .18s ease;
}
.qr-field textarea { max-width: 560px; resize: vertical; }
.qr-field input:focus,
.qr-field textarea:focus {
  outline: 2px solid var(--ink-900); outline-offset: 2px; border-color: var(--amber);
  box-shadow: 0 0 0 3px rgba(242,169,0,.18);
}
.qr-invalid { border-color: #d9433f !important; box-shadow: 0 0 0 3px rgba(217,67,63,.14) !important; }
.qr-error { color: #c0322e; font-size: .82rem; font-weight: 600; margin: 6px 0 0; }

/* ---------- card grids (radio) ---------- */
.qr-cardgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 11px; }
/* 118px, not 130px: the access questions mostly have FOUR answers, and beside
   the gauge a 130px track fits only three of them — so every one of those
   groups wrapped 3+1 and the fourth answer read as an afterthought rather than
   a peer. At 118px all four sit on one row on desktop and 2×2 on a phone. */
.qr-cardgrid.qr-compact { grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); }
/* THE LOAD LADDER IS A 2×2, ALWAYS. Auto-fill gave three columns beside the
   gauge (so "Full" sat alone on a second row, reading as an afterthought
   rather than the top rung), four at tablet width (crushing the truck
   illustration under its 132px box), and — because a 298px column is 13px
   short of two 150px tracks — ONE on a phone, four full-height cards deep.
   The ladder is four comparable rungs; a fixed 2×2 says that at every width.
   Below 340px there is genuinely only room for one. */
.qr-cardgrid.qr-fractions { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 339px) { .qr-cardgrid.qr-fractions { grid-template-columns: 1fr; } }
.qr-card {
  position: relative; text-align: left; cursor: pointer;
  display: flex; flex-direction: column; gap: 5px;
  background: var(--paper-2); border: 1.5px solid var(--line);
  border-radius: 12px; padding: 13px 14px; font: inherit; color: var(--ink);
  transition: border-color .18s ease, background .18s ease, transform .16s var(--ease), box-shadow .18s ease;
}
.qr-card:hover { border-color: var(--amber); box-shadow: var(--shadow-sm); }
.qr-card:active, .qr-chip:active { transform: translateY(0) scale(.97); }
.qr-card.is-sel {
  border-color: var(--amber); background: #fffaf0;
  box-shadow: 0 0 0 2px rgba(242,169,0,.32), var(--shadow-sm);
}
.qr-compact .qr-card { padding: 11px 12px; }
.qr-card-name { font-family: var(--display); font-weight: 700; color: var(--ink-900); font-size: .92rem; }
.qr-frac-price { font-family: var(--display); font-weight: 800; color: var(--ink-900); font-size: .95rem; font-variant-numeric: tabular-nums; }
.qr-frac-desc { font-size: .78rem; color: var(--ink-soft); line-height: 1.3; }

/* W6 S6 — the £50 slot-book card, React twin. Mirrors .fraction-option.is-unsized
   in styles.css so the two wizards read the same. DARK at HEAD.

   IT HAS TO OBEY THE GRAMMAR OF THE FOUR CARDS IT SITS WITH (design pass,
   2026-07-26). Its siblings all read truck → name → price → description; this
   one had no illustration at all (the only one of five), a QUESTION where the
   name goes, and a SENTENCE where the price goes — so scanning the price row of
   the grid gave "£89 · £165 · £235 · £300 · £50 to book a slot" and the card
   read as a promo tile dropped into a picker rather than a fifth option. It now
   fills the same four slots in the same order: a mark in the illustration box,
   a noun, a figure, a description. The DASHED border is what says "different
   kind of choice" — so it has to be visible doing it; at rgb(223,227,232) on
   rgb(237,239,243) it was not. */
.qr-card.qr-fraction.is-unsized { border-style: dashed; border-color: #9CAEBE; }
.qr-card.qr-fraction.is-unsized:hover { border-color: var(--amber); }
.qr-card.qr-fraction.is-unsized.is-sel { border-style: solid; border-color: var(--amber); }
/* Same box as .qr-frac-truck, so the four slots line up across all five cards
   and the grid keeps one vertical rhythm. */
.qr-frac-mark {
  display: flex; align-items: center; justify-content: center;
  width: 100%; max-width: 132px; aspect-ratio: 132 / 62; margin: 0 auto 2px;
  border: 1.5px dashed #9CAEBE; border-radius: 10px;
  font-family: var(--display); font-weight: 800; font-size: 1.6rem; color: #7D91A4;
  background: rgba(255,255,255,.5);
}
.qr-frac-price small { display: block; font-size: .72rem; font-weight: 600; color: var(--ink-soft); margin-top: 1px; }
/* ONE SIZE FOR THE BINDING SENTENCE. The same operator-approved terms line
   renders on the card and again under the review block; at .7rem on the card it
   was 11.2px — the smallest type on the page, carrying the non-refundability
   term — against 13.12px in the review. Both now use this. */
.qr-terms-line, .qr-frac-terms { font-size: .8rem; line-height: 1.45; color: var(--ink-soft); }
.qr-frac-terms { border-top: 1px solid var(--line); padding-top: 8px; margin-top: 4px; }

/* fraction card truck (shared <truck-fill> component) */
.qr-frac-truck { display: block; width: 100%; max-width: 132px; margin: 0 auto 2px; }

/* ---------- chip grids (multi) ---------- */
.qr-chipgrid { display: flex; flex-wrap: wrap; gap: 9px; }
.qr-chip {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  background: var(--paper-2); border: 1.5px solid var(--line);
  border-radius: 999px; padding: 9px 15px; font: inherit; font-family: var(--display); font-weight: 600;
  color: var(--ink); font-size: .88rem;
  transition: border-color .18s ease, background .18s ease, transform .16s var(--ease);
}
.qr-chip:hover { border-color: var(--amber); }
.qr-chip-tick {
  width: 16px; height: 16px; border-radius: 5px; flex: none;
  border: 1.6px solid var(--line); background: var(--white);
  position: relative; transition: background .18s ease, border-color .18s ease;
}
.qr-chip.is-on { border-color: var(--amber); background: #fffaf0; color: var(--ink-900); }
.qr-chip.is-on .qr-chip-tick { background: var(--amber); border-color: var(--amber); }
.qr-chip.is-on .qr-chip-tick::after {
  content: ""; position: absolute; left: 4.5px; top: 1px;
  width: 4px; height: 8px; border: solid #241900; border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

/* =======================================================================
   THE SPLIT — every step's content + the persistent van gauge
   ===================================================================== */
.qr-split { display: grid; grid-template-columns: 1fr; gap: 22px; }
.qr-split-main { min-width: 0; }
.qr-split-aside { order: -1; }
@media (min-width: 860px) {
  .qr-split { grid-template-columns: 1fr 300px; align-items: start; }
  .qr-split-aside { order: 0; }
  /* Sticky on the inner wrapper — see quote-react.js: a sticky grid ITEM is
     painted 84px low at rest in Chrome. */
  .qr-gauge-stick { position: sticky; top: 84px; }
}

/* ---------- van gauge (data viz — kept, de-mono'd) ---------- */
.qr-gauge {
  background: linear-gradient(155deg, var(--ink-900) 0%, var(--ink-800) 62%, var(--ink-850) 100%);
  border-radius: 14px; padding: 16px 16px 18px;
  box-shadow: var(--shadow-card); color: var(--white);
}
.qr-gauge-readout { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 6px; }
.qr-gauge-k {
  font-family: var(--display); font-size: .64rem; font-weight: 600; letter-spacing: .1em;
  text-transform: uppercase; color: #a9bccf;
}
.qr-gauge-v { font-family: var(--display); font-weight: 800; font-size: 1.5rem; color: var(--amber); font-variant-numeric: tabular-nums; }
.qr-truck { display: block; width: 100%; }

.qr-gauge-price { border-top: 1px solid rgba(255,255,255,.14); margin-top: 10px; padding-top: 12px; }
.qr-gp-k { font-family: var(--display); font-size: .64rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: #a9bccf; display: block; margin-bottom: 3px; }
.qr-gp-v { font-family: var(--display); font-weight: 800; font-size: 1.7rem; color: var(--white); font-variant-numeric: tabular-nums; display: flex; flex-direction: column; }
.qr-gp-v small { font-size: .68rem; font-weight: 600; color: #D1DBE6; margin-top: 2px; }
.qr-gp-pending { color: #a9bccf; font-size: .86rem; }
/* An unsized job has no percentage to show, so the readout says what IS true
   rather than a misleading 0%. Same slot, same baseline, quieter voice. */
.qr-gauge-pending { font-family: var(--display); font-weight: 700; font-size: .92rem; color: #D1DBE6; }

/* MOBILE — the gauge follows the customer through all three steps, so on a
   phone it must not cost half a screen at the top of every one. It collapses
   to a single quiet row: the truck illustration comes off (the figure is the
   information), the two readouts sit side by side, and the block is shallow
   enough to scroll past without hiding the step heading. */
@media (max-width: 859px) {
  .qr-gauge {
    display: flex; align-items: center; justify-content: space-between;
    gap: 16px; padding: 12px 16px; border-radius: 12px;
  }
  .qr-truck { display: none; }
  .qr-gauge-readout { display: block; margin-bottom: 0; min-width: 0; }
  .qr-gauge-v { font-size: 1.15rem; display: block; }
  .qr-gauge-pending { font-size: .84rem; display: block; }
  .qr-gauge-price { border-top: 0; border-left: 1px solid rgba(255,255,255,.14); margin-top: 0; padding: 0 0 0 16px; text-align: right; }
  .qr-gp-v { font-size: 1.25rem; align-items: flex-end; }
  .qr-gp-v small { font-size: .62rem; }
}

/* =======================================================================
   PHOTOS
   ===================================================================== */
/* Four tiles, so 2×2 or 4×1 — never the 3+1 auto-fill produced beside the
   gauge, which made the fourth slot look like a different thing. */
.qr-photogrid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
@media (min-width: 560px) { .qr-photogrid { grid-template-columns: repeat(4, 1fr); } }
.qr-photo {
  position: relative; aspect-ratio: 4 / 3; border-radius: 12px;
  border: 1.6px dashed var(--line); background: var(--paper-2);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  overflow: hidden; cursor: pointer; color: var(--ink-soft);
  transition: border-color .18s ease, background .18s ease, transform .16s var(--ease);
}
.qr-photo-empty:hover { border-color: var(--amber); background: #fffaf0; }
.qr-photo-empty input[type=file] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.qr-photo-empty input[type=file]:focus-visible + .qr-photo-plus,
.qr-photo-empty:focus-within { outline: 3px solid var(--ink-900); outline-offset: 2px; }
.qr-photo-plus { font-size: 1.9rem; font-weight: 300; line-height: 1; color: var(--amber); }
.qr-photo-add { font-size: .78rem; font-weight: 600; margin-top: 4px; }
.qr-photo-filled { border-style: solid; border-color: var(--line); cursor: default; }
.qr-photo-filled img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; animation: qrPhotoIn .28s var(--ease) both; }
@keyframes qrPhotoIn { from { opacity: 0; transform: scale(1.04); } to { opacity: 1; transform: none; } }
.qr-photo-meta {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 1;
  background: linear-gradient(transparent, rgba(17,24,32,.82));
  color: #fff; font-size: .64rem; font-weight: 600;
  padding: 14px 8px 6px; text-align: left;
}
.qr-photo-x {
  position: absolute; top: 6px; right: 6px; z-index: 2;
  width: 26px; height: 26px; border-radius: 50%; border: 0; cursor: pointer;
  background: rgba(17,24,32,.82); color: #fff; font-size: .82rem; line-height: 1;
  display: flex; align-items: center; justify-content: center;
}
.qr-photo-x::before {
  content: ""; position: absolute; inset: -9px;
}
.qr-photo-x:hover { background: #c0322e; }
.qr-photo-busy { cursor: default; }
.qr-spin {
  width: 26px; height: 26px; border-radius: 50%;
  border: 3px solid var(--line-2); border-top-color: var(--amber);
  animation: qrSpin .8s linear infinite;
}
@keyframes qrSpin { to { transform: rotate(360deg); } }
.qr-photo-labels { margin-top: 16px; }
.qr-compress-note {
  display: flex; gap: 10px; align-items: flex-start; margin-top: 18px;
  background: var(--paper-2); border: 1px solid var(--line); border-radius: 11px;
  padding: 12px 14px; font-size: .84rem; color: var(--ink-soft);
}

/* =======================================================================
   CONSENT + REVIEW
   ===================================================================== */
.qr-consent { display: flex; gap: 11px; align-items: flex-start; margin-top: 8px; padding: 12px 14px; border: 1.5px solid var(--line); border-radius: 11px; background: var(--paper-2); }
.qr-consent input { margin-top: 3px; width: 18px; height: 18px; flex: none; accent-color: var(--amber); }
.qr-consent label { font-size: .88rem; color: var(--ink-soft); line-height: 1.45; }
.qr-consent label strong { color: var(--ink-900); }
.qr-consent-bad { border-color: #d9433f; background: #fdf3f2; }

.qr-review dl, .qr-result-summary dl {
  display: grid; grid-template-columns: minmax(120px, auto) 1fr; gap: 0;
  border: 1px solid var(--line); border-radius: 12px; overflow: hidden; margin: 0 0 16px;
}
.qr-review dt, .qr-result-summary dt { padding: 10px 14px; font-family: var(--display); font-weight: 700; color: var(--ink-900); font-size: .86rem; background: var(--paper-2); border-bottom: 1px solid var(--line); align-content: start; }
.qr-review dd, .qr-result-summary dd { padding: 10px 14px; margin: 0; color: var(--ink); font-size: .9rem; line-height: 1.42; border-bottom: 1px solid var(--line); align-content: start; }
.qr-review dt:last-of-type, .qr-review dd:last-of-type,
.qr-result-summary dt:last-of-type, .qr-result-summary dd:last-of-type { border-bottom: 0; }
/* Longer rows (Contact, Waste types, Notes) squeeze badly next to a 120px
   label column on a 390px phone — stack label-above-value below 480px so
   nothing wraps into a cramped sliver. */
@media (max-width: 480px) {
  .qr-review dl, .qr-result-summary dl { grid-template-columns: 1fr; }
  .qr-review dt, .qr-result-summary dt {
    border-bottom: 0; padding: 9px 14px 2px; font-size: .74rem;
    letter-spacing: .03em; text-transform: uppercase; color: var(--ink-3); font-weight: 700;
  }
  .qr-review dd, .qr-result-summary dd { padding: 0 14px 12px; border-bottom: 1px solid var(--line); }
  .qr-review dt:last-of-type, .qr-review dd:last-of-type,
  .qr-result-summary dt:last-of-type, .qr-result-summary dd:last-of-type { border-bottom: 0; }
}
.qr-review-price {
  display: flex; justify-content: space-between; align-items: center;
  background: linear-gradient(155deg, var(--ink-900), var(--ink-800));
  color: #fff; border-radius: 12px; padding: 16px 18px;
}
.qr-review-price > span:first-child { font-family: var(--display); font-size: .72rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: #a9bccf; }
.qr-rp-amount { display: flex; flex-direction: column; align-items: flex-end; font-family: var(--display); font-weight: 800; font-size: 1.7rem; font-variant-numeric: tabular-nums; }
.qr-rp-amount small { font-size: .66rem; font-weight: 600; color: #D1DBE6; margin-top: 2px; }

/* ---------- "What happens next" (confirmation page, W1.2/W1.3) ---------- */
.qr-result-next {
  text-align: left;
  background: var(--paper-2); border: 1px solid var(--line); border-radius: 12px;
  padding: 16px 18px; margin: 0 0 20px;
}
.qr-result-next-h {
  font-family: var(--display); font-weight: 800; color: var(--ink-900);
  font-size: .8rem; letter-spacing: .04em; text-transform: uppercase; margin: 0 0 12px;
}
.qr-result-next-list { margin: 0; padding-left: 1.3em; display: flex; flex-direction: column; gap: 9px; }
.qr-result-next-list li { color: var(--ink-soft); font-size: .89rem; line-height: 1.42; }
.qr-result-next-list li::marker { font-family: var(--display); font-weight: 800; color: var(--amber); }

/* (The vanilla twin's .result-next block lived here until R20 deleted
   public/quote.js — no rule is left behind for markup that no longer ships.) */

/* =======================================================================
   NAV BUTTONS
   ===================================================================== */
.qr-nav { display: flex; justify-content: space-between; gap: 12px; margin-top: 26px; padding-top: 20px; border-top: 1px solid var(--line); }

/* =======================================================================
   RESULT (fallback) SCREEN
   ===================================================================== */
.qr-result {
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-card);
  padding: clamp(22px, 4vw, 40px); text-align: center; max-width: 640px; margin: 0 auto;
}
.qr-result-icon { font-size: 2.6rem; margin-bottom: 8px; }
.qr-result-h { font-family: var(--display); font-weight: 800; color: var(--ink-900); font-size: clamp(1.4rem, 3.4vw, 1.95rem); letter-spacing: -.02em; margin: 0 0 .4em; outline: none; }
.qr-result-lead { color: var(--ink-soft); margin: 0 0 20px; }
.qr-result-summary { text-align: left; margin: 0 0 20px; }
.qr-result-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.qr-call-disabled { opacity: .6; cursor: default; pointer-events: none; }
.qr-result-fine { font-size: .8rem; color: var(--ink-3); margin: 18px 0 0; }
.qr-result-reset { margin-top: 22px; }

/* =======================================================================
   STAGGER ENTRANCE (cards/chips on step entry)
   ===================================================================== */
.qr-stagger {
  animation: qrPop .4s var(--ease) both;
  animation-delay: calc(min(var(--i, 0), 6) * 40ms + 60ms);
}
@keyframes qrPop {
  from { opacity: 0; transform: translateY(12px) scale(.98); }
  to   { opacity: 1; transform: none; }
}

/* =======================================================================
   HOVER-LIFT GATING — only where a real pointer can hover (no sticky
   :hover on touch). Colour/border/background hover states stay ungated.
   ===================================================================== */
@media (hover: hover) and (pointer: fine) {
  .qr-card:hover { transform: translateY(-2px); }
  .qr-chip:hover { transform: translateY(-1px); }
  .qr-photo-empty:hover { transform: translateY(-2px); }
}

/* =======================================================================
   REDUCED MOTION — everything instant
   ===================================================================== */
@media (prefers-reduced-motion: reduce) {
  .qr-in-fwd, .qr-in-back, .qr-fade-in, .qr-stagger, .qr-spin,
  .qr-photo-filled img { animation: none !important; }
  .qr-rail-fill, .qr-rail-dot, .qr-card, .qr-chip, .qr-photo,
  .qr-field input, .qr-field textarea { transition: none !important; }
  .qr-card:active, .qr-chip:active { transform: none !important; }
  .qr-stagger { opacity: 1 !important; transform: none !important; }
}

/* =======================================================================
   R17 — THE SLOT PICKER
   -----------------------------------------------------------------------
   These are not "preferred time" cards any more. Each one is a real window
   with real capacity behind it, so the affordance has to read as a diary
   entry, not a preference: a day heading with its open windows under it,
   and nothing rendered at all for a day that is full. A greyed-out
   unavailable slot would be worse than absent — it invites a click that can
   only ever be refused, on the screen where the customer is deciding
   whether this business can actually take their job.
   ===================================================================== */
.qr-slots { display: grid; gap: 10px; margin-top: 6px; }
.qr-slotday {
  display: grid; grid-template-columns: minmax(120px, 34%) 1fr; gap: 12px;
  align-items: center;
  background: var(--paper-2); border: 1.5px solid var(--line);
  border-radius: 12px; padding: 10px 12px;
}
.qr-slotday-h {
  font-family: var(--display); font-weight: 700; color: var(--ink-900);
  font-size: .92rem;
}
.qr-slotday-windows { display: flex; gap: 8px; flex-wrap: wrap; }
.qr-slot {
  position: relative; cursor: pointer; font: inherit; color: var(--ink);
  display: inline-flex; flex-direction: column; gap: 2px; align-items: flex-start;
  background: var(--white); border: 1.5px solid var(--line);
  border-radius: 10px; padding: 9px 14px; min-height: 44px;  /* tap target */
  transition: border-color .18s ease, background .18s ease, box-shadow .18s ease;
}
.qr-slot:hover { border-color: var(--amber); box-shadow: var(--shadow-sm); }
.qr-slot.is-sel {
  border-color: var(--amber); background: #fffaf0;
  box-shadow: 0 0 0 2px rgba(242,169,0,.32), var(--shadow-sm);
}
.qr-slot-w { font-family: var(--display); font-weight: 700; font-size: .9rem; color: var(--ink-900); }
/* Scarcity is READ OFF THE SERVER's remaining-units figure, never guessed —
   an invented "last one" on a real business is a lie with a price on it. */
.qr-slot-last { font-size: .72rem; color: #8a5a00; font-weight: 700; letter-spacing: .02em; }

@media (max-width: 560px) {
  .qr-slotday { grid-template-columns: 1fr; gap: 8px; }
}

/* =======================================================================
   R17/R19 — THE BOOKED SUMMARY + THE IN-PAGE CARD FORM
   -----------------------------------------------------------------------
   The pay-surface classes (.pay-panel, .pay-card-host, .pay-submit, …) are
   square-pay.js's own markup and are styled for the account page in
   account.css against a DARK ink sheet. This page has no such sheet, so the
   rules below are scoped inside .qr-pay-host and restate the handful of
   colour-dependent ones on a light ground. They deliberately do not touch
   any .pay-* selector outside this container, so the two surfaces cannot
   affect each other. (Follow-up worth doing when someone owns both files:
   lift the shared shell into one pay.css and delete both copies.)
   ===================================================================== */
.qr-booked {
  text-align: left; background: var(--paper-2);
  border: 1.5px solid var(--line); border-radius: 14px;
  padding: 16px 18px; margin: 0 0 20px;
}
.qr-booked-row {
  display: flex; justify-content: space-between; align-items: baseline; gap: 16px;
  padding: 7px 0; font-size: .92rem;
}
.qr-booked-row + .qr-booked-row { border-top: 1px solid var(--line-2); }
.qr-booked-k { color: var(--ink-soft); }
.qr-booked-v { font-variant-numeric: tabular-nums; color: var(--ink-900); font-weight: 600; }
.qr-booked-row.is-total .qr-booked-k,
.qr-booked-row.is-total .qr-booked-v {
  font-family: var(--display); font-weight: 800; color: var(--ink-900); font-size: 1.05rem;
}
.qr-booked-note { font-size: .78rem; color: var(--ink-soft); margin: 10px 0 0; line-height: 1.4; }

.qr-pay-host { text-align: left; margin: 0 0 8px; }
.qr-pay-host .pay-panel { margin-top: 0; }
.qr-pay-host .pay-card-host {
  background: var(--white); border: 1.5px solid var(--line); border-radius: 12px;
  padding: 14px; min-height: 92px;
}
.qr-pay-host .pay-wallets { display: grid; gap: 8px; margin-bottom: 12px; }
.qr-pay-host .pay-wallet-btn { min-height: 48px; }
.qr-pay-host .pay-or {
  display: flex; align-items: center; gap: 12px;
  color: var(--ink-soft); font-size: .875rem; margin: 0 0 12px;
}
.qr-pay-host .pay-or::before, .qr-pay-host .pay-or::after {
  content: ""; flex: 1 1 auto; height: 1px; background: var(--line);
}
.qr-pay-host .pay-loading { color: var(--ink-soft); font-size: .875rem; margin: 0; }
.qr-pay-host .pay-submit { margin-top: 14px; }
/* An error on a money screen is read by somebody with a card in their hand:
   high contrast on the light ground, never the dark-sheet pink. */
.qr-pay-host .pay-msg { color: #a3231b; font-size: .9rem; margin: 10px 0 0; font-weight: 600; }
.qr-pay-host .pay-safe,
.qr-pay-host .pay-alt,
.qr-pay-host .pay-hosted-sub { color: var(--ink-soft); font-size: .875rem; margin: 10px 0 0; }
.qr-pay-host .pay-alt a { color: #8a5a00; text-decoration: underline; text-underline-offset: 3px; }
.qr-pay-host .pay-note {
  background: #fffaf0; border: 1px solid #f0dca8; border-radius: 10px;
  padding: 10px 12px; color: var(--ink); font-size: .875rem; margin: 0 0 12px;
}
.qr-pay-host .pay-consent {
  display: flex; gap: 10px; align-items: flex-start;
  color: var(--ink); font-size: .875rem; margin: 14px 0 0; cursor: pointer;
}
.qr-pay-host .pay-consent input { margin-top: 3px; width: 18px; height: 18px; flex: 0 0 auto; }
.qr-pay-host .pay-done .dep-line { color: var(--ink-900); }
.qr-pay-host .dep-line { font-size: .95rem; margin: 0; display: flex; gap: 8px; align-items: baseline; }
.qr-pay-host .dep-spin {
  display: inline-block; flex: none; width: 15px; height: 15px; border-radius: 50%;
  border: 3px solid #e4d3a0; border-top-color: #b8860b; transform: translateY(3px);
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: translateY(3px) rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .qr-slot { transition: none !important; }
  .qr-pay-host .dep-spin { animation: none !important; }
}
