/* forms.css, editorial skin for auth + booking form pages.
   Scoped to .im-formpage so it only reskins opted-in pages. Loads inside the
   use_editorial bundle AFTER theme.min.css, so scoped overrides of the legacy
   Bootstrap classes (.form-control/.btn-primary/.card) win on source order +
   specificity. Tokens only. Primary buttons are INK, teal is accent/link/focus
   only (see tokens.css colour-role rule). */

.im-formpage { background: var(--im-paper); min-height: 100dvh; }
/* Full-bleed warm paper on any page carrying a form skin (kills the legacy
   gradient body background from the Bootstrap theme). */
body:has(.im-formpage) { background: var(--im-paper); }

/* Centered column */
.im-formpage__wrap { width: 100%; max-width: 460px; margin-inline: auto;
  padding: var(--im-space-16) var(--im-space-5) var(--im-space-20); }
/* --wide is used on pages that render inside the site chrome (fixed-top nav),
   so it needs extra top clearance the navless auth pages don't. */
.im-formpage__wrap--wide { max-width: 760px; padding-top: var(--im-space-24); }

/* Brand mark */
.im-formpage__brand { display: flex; align-items: center; gap: var(--im-space-2);
  margin-bottom: var(--im-space-8); }
.im-formpage__brand img { height: 40px; width: auto; }

/* Titles */
.im-formpage__title { font-family: var(--im-font-serif); font-weight: 400;
  font-size: clamp(2rem, 4vw, 2.6rem); line-height: 1.05; letter-spacing: var(--im-track-title);
  color: var(--im-ink); margin: 0 0 var(--im-space-2); text-wrap: balance; }
.im-formpage__lede { font-family: var(--im-font-display); font-size: 1rem;
  color: var(--im-text-muted); line-height: 1.55; margin: 0 0 var(--im-space-8); }

/* Inputs, override Bootstrap .form-control / .form-select within scope */
.im-formpage .form-control,
.im-formpage .form-select {
  font-family: var(--im-font-display); font-size: 15px; color: var(--im-ink);
  min-height: 46px; padding: 11px 14px;
  background: var(--im-card-bg); border: 1px solid var(--im-hairline);
  border-radius: var(--im-radius-control); box-shadow: none;
  transition: border-color var(--im-dur) var(--im-ease), box-shadow var(--im-dur) var(--im-ease); }
.im-formpage .form-control::placeholder { color: #9a948a; }
.im-formpage .form-control:focus,
.im-formpage .form-select:focus {
  border-color: var(--im-accent-200);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--im-accent-200) 18%, transparent); }
.im-formpage textarea.form-control { min-height: 110px; }

/* Labels + help */
.im-formpage .form-label { font-family: var(--im-font-display); font-weight: 600;
  font-size: 13px; color: var(--im-ink); margin-bottom: var(--im-space-2); }
.im-formpage .form-text, .im-formpage .text-muted { color: var(--im-text-muted); }

/* Primary button, INK. Legacy shim: the auth pages now use .im-btn (primitives.css).
   This survives only for staff/intake/run.html, the last .im-formpage page still on
   Bootstrap button classes. Delete it when that page migrates. */
.im-formpage .btn-primary {
  background: var(--im-ink); border-color: var(--im-ink); color: var(--im-paper);
  font-family: var(--im-font-display); font-weight: 600;
  border-radius: var(--im-radius-control); min-height: 48px; }
.im-formpage .btn-primary:hover,
.im-formpage .btn-primary:focus { background: #000; border-color: #000; color: var(--im-paper); }
.im-formpage .btn-primary:disabled { opacity: .6; }

/* Outline button, ghost. Same legacy shim as .btn-primary above: only
   staff/intake/run.html still needs it. The .btn-google arm was dropped when the
   sign-in page moved to .im-btn--ghost — at 0,2,0 it out-specified the primitive
   and would have silently won. Google's own brand hover lives in theme.css and is
   !important, so it is unaffected either way. */
.im-formpage .btn-outline-secondary {
  background: var(--im-card-bg); border: 1px solid var(--im-hairline); color: var(--im-ink);
  border-radius: var(--im-radius-control); min-height: 46px; font-weight: 600; }
.im-formpage .btn-outline-secondary:hover { border-color: var(--im-ink); color: var(--im-ink); background: var(--im-band); }

/* Links (not buttons). .im-btn is excluded alongside .btn: an <a class="im-btn">
   would otherwise pick up link colour and the hover underline at 0,2,0. */
.im-formpage a:not(.btn):not(.im-btn) { color: var(--im-accent-200-dark); text-decoration: none; font-weight: 600; }
.im-formpage a:not(.btn):not(.im-btn):hover { text-decoration: underline; }

/* Cards (booking sections) */
.im-formpage .card { background: var(--im-card-bg); border: 1px solid var(--im-hairline);
  border-radius: var(--im-radius-card); box-shadow: none; }
.im-formpage .card-header { background: transparent; border-bottom: 1px solid var(--im-hairline);
  padding: var(--im-space-4) var(--im-space-6); }
.im-formpage .card-header h5 { font-family: var(--im-font-display); font-weight: 600;
  font-size: 15px; color: var(--im-ink); margin: 0; }

/* Checkbox / radio accent */
.im-formpage .form-check-input:checked { background-color: var(--im-accent-200); border-color: var(--im-accent-200); }
.im-formpage .form-check-input:focus { border-color: var(--im-accent-200);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--im-accent-200) 18%, transparent); }

/* Alerts / scope notice → editorial inset */
.im-formpage .alert { border: 0; border-left: 3px solid var(--im-accent-200);
  border-radius: 0 var(--im-radius-control) var(--im-radius-control) 0;
  background: var(--im-band); color: var(--im-text-200); }
.im-formpage .alert-success { border-left-color: #3f7d5a; background: color-mix(in srgb, #3f7d5a 10%, var(--im-paper)); }
.im-formpage .alert-danger { border-left-color: var(--im-danger-ink); background: color-mix(in srgb, var(--im-danger-ink) 8%, var(--im-paper)); }

/* Divider ("or continue with") */
.im-formpage__divider { display: flex; align-items: center; gap: var(--im-space-3);
  color: var(--im-text-muted); font-family: var(--im-font-display); font-size: 12px;
  margin: var(--im-space-8) 0 var(--im-space-5); }
.im-formpage__divider::before, .im-formpage__divider::after { content: ""; flex: 1; height: 1px; background: var(--im-hairline); }

/* ============================================================================
   Booking page (consultation/book.html), split-screen. One viewport-height ground:
   a sticky brand/value aside on the left, the form panel on the right. The page
   opens as a single screen; only a long form scrolls past the sticky aside. Reuses
   the im-formpage input skin. Tokens only.
   ========================================================================== */

.im-book { display: grid; grid-template-columns: minmax(340px, 5fr) 7fr;
  min-height: 100dvh; align-items: stretch; }

/* Left aside: brand (top), value (middle), regulatory + legal (bottom), spread by
   space-between. Sticky so it holds the screen while a long form scrolls. Band
   tint + hairline set it off from the paper form panel. */
.im-book__aside { position: sticky; top: 0; align-self: start; min-height: 100dvh;
  box-sizing: border-box; display: flex; flex-direction: column;
  justify-content: space-between; gap: var(--im-space-8);
  padding: var(--im-space-10) var(--im-space-8);
  background: var(--im-band); border-right: 1px solid var(--im-hairline); }

/* Single-question mode: one card at a time (GOV.UK question-pages shape).
   The engine appends question nodes and Back deletes the last one, so
   :last-child IS the current question and Back reveals the previous with no
   engine change. `is-reviewing` shows the answered trail, dimmed and inert
   (their inputs are already disabled by the engine). */
.im-book__questions--single > div:not(:last-child) { display: none; }
.im-book__questions--single > div:last-child { animation: im-q-enter 0.22s ease-out; }
.im-book__questions--single.is-reviewing > div:not(:last-child) {
  display: block; opacity: 0.55; pointer-events: none;
  border-bottom: 1px solid var(--im-hairline);
  padding-bottom: var(--im-space-5); margin-bottom: var(--im-space-5); }
@keyframes im-q-enter {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .im-book__questions--single > div:last-child { animation: none; } }

/* The rail copies of the run furniture. */
.im-book__aside .im-runbar { margin-top: var(--im-space-7); margin-bottom: 0; }
.im-book__review-toggle { align-self: flex-start; margin-top: var(--im-space-3);
  border: 0; padding: 0; background: none; color: var(--im-ink-soft, inherit);
  font: inherit; font-size: 0.9em; text-decoration: underline;
  text-underline-offset: 3px; cursor: pointer; }
.im-book__review-toggle[aria-pressed="true"] { font-weight: 600; }

/* Rail small print: the legal links + identity line the hidden footer used to
   carry. Reads as a colophon, not as content. */
.im-book__aside-legal { font-size: 11.5px; line-height: 1.5;
  color: var(--im-text-muted); }
.im-book__aside-legal-links { display: flex; gap: var(--im-space-4);
  margin-bottom: var(--im-space-2); }
.im-book__aside-legal-links a { color: inherit; }
.im-book__aside-legal-reg { margin: 0; }

/* The review toggle sits with the questions it reveals, top-right of the
   panel, out of the answer flow. */
.im-book__review-row { display: flex; justify-content: flex-end; }
.im-book__review-row .im-book__review-toggle { margin-top: 0; }

/* Rail reference block: the published requirements beside the result. Quiet
   reading, not an action — hairline above, compact list, a text link out. */
.im-book__rail-info { border-top: 1px solid var(--im-hairline);
  padding-top: var(--im-space-5); margin-top: var(--im-space-2); }
.im-book__rail-info-label { margin: 0 0 var(--im-space-3);
  font-size: 11px; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--im-text-muted); }
.im-book__rail-info-link { display: inline-block;
  font-size: 13px; font-weight: 600; color: inherit;
  text-underline-offset: 3px; }

/* The finished run celebrates in motion, not in copy: a drawn check, the rail
   bar filling, the letter easing in. Every piece stands down for visitors who
   asked for reduced motion. */
.im-result__mark { width: 56px; height: 56px; color: var(--im-accent, var(--im-ink));
  margin-bottom: var(--im-space-4); }
.im-result__mark-ring { stroke-dasharray: 158; stroke-dashoffset: 158;
  animation: im-draw 0.7s ease-out 0.15s forwards; }
.im-result__mark-tick { stroke-dasharray: 34; stroke-dashoffset: 34;
  animation: im-draw 0.45s ease-out 0.75s forwards; }
@keyframes im-draw { to { stroke-dashoffset: 0; } }
.im-result--celebrate > *:not(.im-result__mark) { animation: im-q-enter 0.5s ease-out backwards; }
.im-result--celebrate > *:nth-child(2) { animation-delay: 0.25s; }
.im-result--celebrate > *:nth-child(3) { animation-delay: 0.35s; }
.im-result--celebrate > *:nth-child(4) { animation-delay: 0.45s; }
.im-result--celebrate > *:nth-child(n+5) { animation-delay: 0.55s; }
.im-book__aside .im-runbar__fill[aria-valuenow="100"] {
  animation: im-fill-up 0.9s ease-out; }
@keyframes im-fill-up { from { width: 0; } }
@media (prefers-reduced-motion: reduce) {
  .im-result__mark-ring, .im-result__mark-tick { animation: none; stroke-dashoffset: 0; }
  .im-result--celebrate > *:not(.im-result__mark),
  .im-book__aside .im-runbar__fill[aria-valuenow="100"] { animation: none; } }

/* Run exits: in the aside under the lede; ways of leaving, not part of answering.
   The gap above separates them from the progress/review block they are not part of. */
.im-book__aside-exits { display: flex; flex-wrap: wrap; gap: var(--im-space-3);
  margin-top: var(--im-space-9); }

/* Back-to-site: a quiet ghost-pill button (the brand logo below also links home). */
.im-book__back { display: inline-flex; align-items: center; gap: var(--im-space-2);
  padding: var(--im-space-2) var(--im-space-4); border: 1px solid var(--im-hairline);
  border-radius: 999px; background: transparent;
  font-family: var(--im-font-display); font-size: 12px; font-weight: 600;
  color: var(--im-text-muted); text-decoration: none;
  transition: color var(--im-dur) var(--im-ease), border-color var(--im-dur) var(--im-ease), background var(--im-dur) var(--im-ease); }
.im-book__back:hover { color: var(--im-ink); border-color: var(--im-ink); background: var(--im-card-bg); }
.im-book__back-arrow { font-size: 14px; line-height: 1; }

/* Brand lockup: logo sits on its own line above the title. */
.im-book__brand { display: block; margin-bottom: var(--im-space-6); }
.im-book__brand img { height: 44px; width: auto; }

.im-book__title { font-family: var(--im-font-serif); font-weight: 400;
  font-size: clamp(1.75rem, 1.3rem + 1.6vw, 2.5rem); line-height: 1.15;
  color: var(--im-ink); margin: 0 0 var(--im-space-3); }
.im-book__lede { font-family: var(--im-font-display); font-size: 1rem;
  line-height: 1.55; color: var(--im-text-200); margin: 0 0 var(--im-space-6);
  max-width: 42ch; }

/* Audience toggle, top-right of the form panel (server-nav, works without JS;
   aria-current marks active). */
.im-book__toggle { align-self: flex-end; display: flex; gap: var(--im-space-1);
  margin: 0 0 var(--im-space-6); padding: var(--im-space-1); background: var(--im-band);
  border: 1px solid var(--im-hairline); border-radius: var(--im-radius-control);
  width: 100%; max-width: 360px; }
.im-book__toggle-opt { flex: 1; min-height: 44px; display: flex; align-items: center;
  justify-content: center; text-align: center; padding: var(--im-space-2) var(--im-space-3);
  font-family: var(--im-font-display); font-weight: 600; font-size: 13px;
  color: var(--im-text-muted); text-decoration: none; border-radius: calc(var(--im-radius-control) - 3px);
  transition: color var(--im-dur) var(--im-ease), background var(--im-dur) var(--im-ease); }
.im-book__toggle-opt:hover { color: var(--im-ink); }
.im-book__toggle-opt.is-active { background: var(--im-paper); color: var(--im-ink);
  box-shadow: 0 1px 2px rgba(0,0,0,.06); }

/* Trust list, quiet ticks, stacked. */
.im-book__trust { list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: var(--im-space-2); }
.im-book__trust-item { position: relative; padding-left: var(--im-space-5);
  font-family: var(--im-font-display); font-size: 13px; color: var(--im-text-200); }
.im-book__trust-item::before { content: "✓"; position: absolute; left: 0; top: 0;
  color: var(--im-accent-200); font-weight: 700; }

/* Aside foot: compact legal + regulatory links, no paragraph. */
.im-book__legal { display: flex; flex-wrap: wrap; gap: var(--im-space-2) var(--im-space-4); }
.im-book__legal a { font-family: var(--im-font-display); font-size: 12px; font-weight: 600;
  color: var(--im-text-muted); text-decoration: none; }
.im-book__legal a:hover { color: var(--im-ink); }

/* Right panel: the form, vertically centred, comfortable measure. */
.im-book__panel { box-sizing: border-box; width: 100%; max-width: 640px; margin-inline: auto;
  padding: var(--im-space-10) var(--im-space-8);
  display: flex; flex-direction: column; justify-content: center; }

.im-book__form { display: flex; flex-direction: column; gap: var(--im-space-4); }
.im-book__legend { font-family: var(--im-font-display); font-size: 12px;
  color: var(--im-text-muted); margin: 0; }

/* Field grid: two columns on desktop, short fields pair up; --full fields (the
   message box) span both. One column below the split breakpoint. */
.im-book__grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--im-space-4); }
.im-book__field { display: flex; flex-direction: column; min-width: 0; }
.im-book__field--full { grid-column: 1 / -1; }
.im-book__field .form-label { margin-bottom: var(--im-space-2); }
.im-book__optional { color: var(--im-text-muted); font-weight: 400; }
.im-book__form .form-check { display: block; }
.im-book__form .form-check .form-check-input { margin-top: var(--im-space-1); }
.im-book__microcopy { margin: var(--im-space-6) 0 0; text-align: left;
  font-family: var(--im-font-display); font-size: 12px; color: var(--im-text-muted); }

/* Keyboard focus for plain links: the global theme strips a:focus. WCAG 2.4.7. */
.im-formpage a:not(.btn):not(.im-btn):focus-visible { outline: 2px solid var(--im-accent-200);
  outline-offset: 2px; border-radius: 2px; }

/* Error text / required asterisk: darkened to clear 4.5:1 on paper. WCAG 1.4.3. */
.im-formpage .invalid-feedback, .im-formpage .text-danger { color: var(--im-danger-ink); }

/* Error summary (GOV.UK pattern): role="alert" announces it, jump-links to fields. */
.im-book__error-summary { border: 2px solid var(--im-danger-ink); border-radius: var(--im-radius-control);
  padding: var(--im-space-4) var(--im-space-5); margin: 0 0 var(--im-space-5); }
.im-book__error-summary-title { font-family: var(--im-font-display); font-weight: 700;
  font-size: 15px; color: var(--im-ink); margin: 0 0 var(--im-space-2); }
.im-book__error-summary-list { margin: 0; padding-left: var(--im-space-4);
  font-size: 13px; color: var(--im-text-200); }
.im-book__error-summary-list a { color: var(--im-danger-ink); font-weight: 600; }
/* Body copy inside the summary: used by the intake page's <noscript> notice,
   which is a problem statement rather than a list of field errors. */
.im-book__error-summary p { font-family: var(--im-font-display); font-size: 13px;
  line-height: 1.55; color: var(--im-text-200); margin: 0; }

/* Stack below the split breakpoint.

   TWO phone layouts share this block, and the split is load-bearing. The
   default is the plain stack every `.im-book` consumer gets — the booking
   page, the business signup, the intake runner. The screening funnel's
   reorder-and-compact treatment is opt-in via `.im-book--flow` because it
   assumes the FUNNEL rail's hierarchy (`aside-mid` wrapping everything,
   `aside-legal` closing the aside, `rail-info` inside the mid block).
   Applied unscoped it broke every sibling page whose rail differs: their
   `aside-top` and `__legal` children matched no order/padding rule, so they
   painted first, flush against the viewport edge (caught live on the booking
   page, 2026-08-30). */
@media (max-width: 860px) {
  .im-book { grid-template-columns: 1fr; }
  .im-book__aside { position: static; min-height: 0; border-right: 0;
    border-bottom: 1px solid var(--im-hairline); gap: var(--im-space-5);
    padding: var(--im-space-8) var(--im-space-6); }
  .im-book__panel { padding: var(--im-space-8) var(--im-space-6);
    justify-content: flex-start; }
  .im-book__grid { grid-template-columns: 1fr; }

  /* ── Screening funnel only (`.im-book--flow`: the run and result pages) ──
     REORDER: identity and progress, then the questions, then the reference
     link and the small print as one closing block.

     Stacking the rail whole put the progress bar, the requirements link and
     the privacy/regulatory small print above question one, so a phone visitor
     scrolled past the disclaimers to reach the first thing they came to do.
     Dissolving the rail's box with `display: contents` makes its children
     layout siblings of the panel, which is what lets `order` move the small
     print below it.

     The DOM is untouched, so the tab order and the screen-reader order still
     read title -> questions -> small print. Only the painted order moves.
     That is an acknowledged visual/DOM order divergence and it is the right
     one here: the reading order stays the logical one while the scroll order
     stops burying the task. */
  /* A flex column, not the grid: as grid rows, the dissolved rail's children
     each took an equal slice of the spare 100dvh (align-content stretch), so
     the band header ballooned to half the screen on short pages (Rohan,
     2026-08-30). In a column the header children keep their natural heights
     and the PANEL absorbs every spare pixel — tight band on top, the
     questions get the room. `order` works the same in flex. */
  .im-book--flow { background: var(--im-band); display: flex;
    flex-direction: column; }
  .im-book--flow .im-book__panel { flex: 1 1 auto; }

  /* Both boxes go, not just the outer one: `.im-book__rail-info` lives inside
     `.im-book__aside-mid`, and a child cannot be ordered past a box its parent
     still draws. (The default aside padding/border above stop painting the
     moment the box dissolves, so they need no un-setting.) */
  .im-book--flow .im-book__aside,
  .im-book--flow .im-book__aside-mid { display: contents; }

  /* `display: contents` takes the aside's own box away, and with it the side
     padding and the band tint the rail was painting. The grid carries the tint
     now; the children carry the padding, and the panel re-declares paper so the
     questions still read as the sheet you write on. */
  .im-book--flow .im-book__aside-mid > * { padding-inline: var(--im-space-6); }

  .im-book--flow .im-book__aside-mid > * { order: 1; }
  .im-book--flow .im-book__panel { order: 2; background: var(--im-paper); }

  /* The legal block (Privacy/Terms + the SRA identity paragraph) hides on
     phones entirely — Rohan's call, 2026-08-30, flagged to Dhruti with the
     funnel's footer-to-rail relocation. Desktop keeps the disclosure; the
     phone page closes on the requirements link, which reads on PAPER, not
     the band tint (the band stays the identity header's colour only), and
     brings its own hairline from the base rule. */
  .im-book--flow .im-book__rail-info { order: 3; margin-top: 0;
    padding-block: var(--im-space-6); background: var(--im-paper); }
  .im-book--flow .im-book__aside-legal { display: none; }

  /* Phone header compaction (Rohan, 2026-08-29): the questions are the page;
     everything above them shrinks to one glance. The lede hidden here is the
     RAIL's guidance line only — the result panel's own title and lede keep
     their size, which is why every selector below goes through the aside. */
  .im-book--flow .im-book__brand { margin-bottom: var(--im-space-3); }
  .im-book--flow .im-book__brand img { height: 30px; }
  .im-book--flow .im-book__aside-mid > :first-child { padding-top: var(--im-space-6); }
  .im-book--flow .im-book__aside-mid > .im-book__title { font-size: 1.375rem; margin-bottom: var(--im-space-2); }
  .im-book--flow .im-book__aside-mid > .im-book__lede { display: none; }
  .im-book--flow .im-book__aside .im-runbar { margin-top: var(--im-space-3); }

  /* Restart/Exit demote from buttons to quiet links on a phone: they are ways
     of leaving, not actions the page promotes. Same forms underneath, so the
     behaviour and the tap target (44px minimum) survive the restyle. */
  .im-book--flow .im-book__aside-exits { display: flex; align-items: center;
    gap: var(--im-space-6); margin-top: var(--im-space-2);
    padding-bottom: var(--im-space-5); }
  .im-book--flow .im-book__aside-exits form { margin: 0; }
  .im-book--flow .im-book__aside-exits .btn { border: 0; background: transparent;
    padding: 0; min-height: 44px; display: inline-flex; align-items: center;
    font-family: var(--im-font-display); font-size: 13px; font-weight: 500;
    color: var(--im-text-muted); text-decoration: underline;
    text-underline-offset: 3px; border-radius: 0; }
  .im-book--flow .im-book__aside-exits .btn:hover,
  .im-book--flow .im-book__aside-exits .btn:focus-visible { color: var(--im-ink);
    background: transparent; }
}

/* ============================================================================
   Consultation success page (consultation/success.html): a single centred column,
   full-screen, matching the booking editorial skin. Tokens only.
   ========================================================================== */
.im-success { min-height: 100dvh; box-sizing: border-box; max-width: 620px;
  margin-inline: auto; padding: var(--im-space-10) var(--im-space-6);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; }
.im-success__icon { width: 64px; height: 64px; border-radius: 999px;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, #3f7d5a 12%, var(--im-paper)); color: #3f7d5a;
  font-size: 30px; line-height: 1; margin-bottom: var(--im-space-6); }
.im-success__title { font-family: var(--im-font-serif); font-weight: 400;
  font-size: clamp(1.75rem, 1.3rem + 1.6vw, 2.5rem); line-height: 1.15;
  color: var(--im-ink); margin: 0 0 var(--im-space-3); }
.im-success__lede { font-family: var(--im-font-display); font-size: 1.05rem;
  line-height: 1.55; color: var(--im-text-200); margin: 0 0 var(--im-space-4);
  max-width: 46ch; }
.im-success__note { font-family: var(--im-font-display); font-size: 13px;
  color: var(--im-text-muted); margin: 0 0 var(--im-space-8); }
.im-success__actions { display: flex; flex-wrap: wrap; gap: var(--im-space-3);
  justify-content: center; }
.im-success__btn { display: inline-flex; align-items: center; min-height: 44px;
  padding: var(--im-space-2) var(--im-space-5); border: 1px solid var(--im-hairline);
  border-radius: 999px; background: transparent; font-family: var(--im-font-display);
  font-size: 14px; font-weight: 600; color: var(--im-ink); text-decoration: none;
  transition: border-color var(--im-dur) var(--im-ease), background var(--im-dur) var(--im-ease); }
.im-success__btn:hover { border-color: var(--im-ink); background: var(--im-band); }
/* .im-success centres itself in the viewport, which assumes the navless funnel
   base it was written for (consultation/success.html on base-funnel.html).
   --in-chrome is the same block on a page that keeps the site nav and footer:
   the viewport is already spoken for, so it clears the fixed nav and takes its
   own vertical rhythm instead of fighting the chrome for full height. */
.im-success--in-chrome { min-height: 0;
  padding-top: calc(var(--im-nav-h) + var(--im-space-16));
  padding-bottom: var(--im-space-20); }

/* ============================================================================
   Funnel footer (parts/footer-funnel.html), the slim close for standalone
   booking / conversion pages. Legal links + regulatory identity + copyright,
   no route columns or destinations band. Sits outside .im-formpage, so it
   restates the focus ring the global theme strips. Tokens only.
   ========================================================================== */
.im-funnel-footer { border-top: 1px solid var(--im-hairline); background: var(--im-paper);
  margin-top: var(--im-space-16); padding: var(--im-space-8) var(--im-space-6); }
.im-funnel-footer__inner { max-width: 720px; margin-inline: auto; text-align: center;
  display: flex; flex-direction: column; gap: var(--im-space-3); }
.im-funnel-footer__links { display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--im-space-2) var(--im-space-5); }
.im-funnel-footer__links a { font-family: var(--im-font-display); font-size: 13px;
  font-weight: 600; color: var(--im-text-muted); text-decoration: none; }
.im-funnel-footer__links a:hover { color: var(--im-ink); text-decoration: underline; }
.im-funnel-footer__reg { font-family: var(--im-font-display); font-size: 12px;
  line-height: 1.6; color: var(--im-text-muted); margin: 0; }
.im-funnel-footer__reg a { color: var(--im-accent-200-dark); font-weight: 600; }
.im-funnel-footer__copyright { font-family: var(--im-font-display); font-size: 12px;
  color: var(--im-text-muted); margin: 0; }
.im-funnel-footer a:focus-visible { outline: 2px solid var(--im-accent-200);
  outline-offset: 2px; border-radius: 2px; }

/* ============================================================================
   Client intake run (intake/run.html + documents/questionnaire/question.html). Sits on top of
   the .im-book split: only the question rhythm, the plain progress line and the
   two run controls are new. Tokens only.
   ========================================================================== */
.im-formpage .im-intake__progress { font-family: var(--im-font-display);
  font-size: 13px; color: var(--im-text-muted); margin: 0; }

/* The run page's polite live region. Off-screen rather than display:none: it
   has to stay in the accessibility tree, because a region that is not rendered
   at the moment it changes is not announced. Sighted users get the same
   information from the question focus moves to. */
.im-formpage .im-intake__status { position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0);
  white-space: nowrap; border: 0; }

/* The one rule that gives this page its vertical rhythm, and it has to match
   the DOM the engine builds rather than the one the template describes.
   questionnaire.js wraps every fetched fragment in a fresh anonymous div before
   appending, so the .im-intake__question elements are cousins and never
   siblings, and answered questions are not removed. Targeting the wrappers is
   the only selector that separates question two onwards. */
.im-formpage #questionnaire > * + * { margin-top: var(--im-space-6); }

.im-formpage .im-intake__label { font-family: var(--im-font-display); font-weight: 600;
  font-size: 1.125rem; line-height: 1.45; color: var(--im-ink); }
.im-formpage .im-intake__label-list { margin: var(--im-space-2) 0 0;
  padding-left: var(--im-space-5); font-size: 14px; color: var(--im-text-200); }
.im-formpage .im-intake__hint { font-family: var(--im-font-display); font-size: 13px;
  line-height: 1.55; color: var(--im-text-muted); margin: 0 0 var(--im-space-2); }
.im-formpage .im-intake__error { font-family: var(--im-font-display); font-weight: 600;
  font-size: 13px; color: var(--im-danger-ink); margin: 0 0 var(--im-space-2); }

/* documents/questionnaire/question.html renders the three aria-describedby targets on every
   question so their ids always resolve, whether or not they carry text. These
   collapse the empty ones. :empty is exact, so the fragment keeps no
   whitespace inside those elements. */
.im-formpage .im-intake__error:empty,
.im-formpage .im-intake__label-list:empty,
.im-formpage .im-intake__hint:empty { display: none; }

.im-formpage .im-intake__choices { border: 0; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: var(--im-space-2); }
/* The legend, detail lines and hint sit inside the fieldset (a legend has to be
   its first child), so the flex gap already spaces them. */
.im-formpage .im-intake__choices > .im-intake__label-list,
.im-formpage .im-intake__choices > .im-intake__hint { margin: 0; }

/* Section marker between groups of questions (q_type "title"). */
.im-formpage .im-intake__section { font-family: var(--im-font-serif); font-weight: 400;
  font-size: 1.375rem; line-height: 1.25; color: var(--im-ink); margin: 0; }
.im-formpage .im-intake__section-list { margin: var(--im-space-2) 0 0;
  padding-left: var(--im-space-5); font-size: 14px; color: var(--im-text-200); }

.im-formpage .im-intake__question--notice { text-align: center; }
.im-formpage .im-intake__notice-title { font-family: var(--im-font-serif); font-size: 1.25rem;
  color: var(--im-ink); margin: 0 0 var(--im-space-2); }
.im-formpage .im-intake__notice-body { font-family: var(--im-font-display); font-size: 14px;
  color: var(--im-text-200); margin: 0; }

.im-formpage .im-intake__actions { display: flex; justify-content: flex-end;
  gap: var(--im-space-3); margin-top: var(--im-space-6); }
/* Declared AFTER the base rule on purpose: equal specificity, so source order
   is the tiebreak. The result page reads like a letter — its actions align
   with the text they conclude; the question page keeps flex-end. */
.im-formpage .im-intake__actions--start { justify-content: flex-start; }
.im-formpage .im-intake__continue { margin-top: var(--im-space-6); }

/* ---- Run progress bar (visa/scr/que.html only) ----------------------------
   Public screening keeps a bar; intake deliberately has none, so this lives
   with the page and never in the shared question fragment.

   It replaces a Bootstrap .progress-bar-striped.progress-bar-animated in
   bg-primary: an animated barber-pole is motion nobody asked for on a form
   (WCAG 2.2.2), and .bg-primary is one of the Bootstrap utilities the editorial
   bundle does not re-skin, so it rendered in the legacy blue beside ink and
   accent. Tokens only, no animation, and the fill transitions width because
   questionnaire.js writes that property directly. --------------------------- */
.im-formpage .im-runbar { margin-bottom: var(--im-space-6); }
.im-formpage .im-runbar__head { display: flex; align-items: baseline;
  justify-content: space-between; gap: var(--im-space-4);
  margin-bottom: var(--im-space-2); }
.im-formpage .im-runbar__label { font-family: var(--im-font-display); font-size: 13px;
  color: var(--im-text-muted); margin: 0; }
.im-formpage .im-runbar__value { font-family: var(--im-font-display); font-weight: 600;
  font-size: 13px; color: var(--im-accent-200); margin: 0;
  font-variant-numeric: tabular-nums; }
.im-formpage .im-runbar__track { height: 6px; border-radius: var(--im-radius-pill);
  background: var(--im-hairline); overflow: hidden; }
.im-formpage .im-runbar__fill { height: 100%; border-radius: var(--im-radius-pill);
  background: var(--im-accent-200); transition: width .4s ease; }
@media (prefers-reduced-motion: reduce) {
  .im-formpage .im-runbar__fill { transition: none; }
}

/* ---- Password field + its Show/Hide control (business/register.html) -------
   Its own two rules rather than .im-field__prefixed, which is the currency
   group and assumes a .im-field__prefix BEFORE the control with the borders
   collapsed accordingly. The control takes the slack; the button stays at its
   own width so the label does not reflow when it changes from Show to Hide.
   --------------------------------------------------------------------------- */
.im-formpage .im-book__reveal { display: flex; align-items: stretch;
  gap: var(--im-space-2); max-width: 100%; }
.im-formpage .im-book__reveal > .form-control { flex: 1 1 auto; min-width: 0; }

/* ---- The run exits, at the foot of the panel ------------------------------
   .im-book__legal is a row of quiet links in the aside; these are the same row
   holding two POST forms, and they sit under a rule because they end the run
   rather than continue it. In the panel and not the aside deliberately: the
   aside stacks FIRST on a narrow viewport, so an exit placed there is the
   first thing a phone shows someone who came to answer questions.
   --------------------------------------------------------------------------- */
.im-formpage .im-book__legal--exits { margin-top: var(--im-space-8);
  padding-top: var(--im-space-5); border-top: 1px solid var(--im-hairline); }

/* =========================================================================
   .im-field — the shared field vocabulary (2026-08)

   Everything above this line reskins Bootstrap classes INSIDE a scope
   (.im-formpage). This block is the opposite: its own class names, unscoped,
   owning their own appearance. Consume it on new forms instead of writing
   .form-control and then re-styling .form-control per page — which is how the
   salary calculator and the processing-times share form ended up with two
   vocabularies for the same six controls.

   Widths come from the --im-ctl-* tokens (tokens.css) and go on the element
   that WRAPS the text: the control itself, or .im-field__prefixed when there
   is a currency prefix. Not on .im-field, because the label and hint beside a
   6.5rem input still need the full column to wrap in.

   Loads in the use_editorial bundle only, so it cannot reach a legacy page.
   ========================================================================= */

/* ---- The card a form sits in. Not .im-card (primitives.css): that one is a
   link target and lifts on hover, which a container holding focusable controls
   must not do. ---- */
.im-form-card { background: var(--im-card-bg); border: 1px solid var(--im-hairline);
  border-radius: var(--im-radius-card); }
.im-form-card--accent { border-top: 3px solid var(--im-accent-200); }
.im-form-card__body { padding: clamp(var(--im-space-6), 4vw, var(--im-space-10)); }

/* ---- Form + row layout. Spacing is the grid's, never a per-field margin. ---- */
.im-form { display: grid; gap: var(--im-space-6); }
.im-form__row { display: grid; gap: var(--im-space-4); }
@media (min-width: 560px) {
  /* Equal columns by default; --im-form-cols overrides per row. */
  .im-form__row { grid-template-columns: repeat(var(--im-form-cols, 2), minmax(0, 1fr)); }
  /* --fit lets fixed-width controls sit at their natural size and gives the
     slack to the first column, which is what a "select + money + number" row
     wants. */
  .im-form__row--fit { grid-template-columns: minmax(0, 1fr) auto auto; }
  .im-form__row--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.im-form__rule { border: 0; border-top: 1px solid var(--im-hairline); margin: 0; }

/* Section marker inside a form. Same voice as .im-seclab in blocks.css, but
   that one only exists on editorial page sections, not inside a card. */
.im-form__seclab { font-family: var(--im-font-display); font-weight: 600;
  font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--im-text-muted); margin: 0; }
/* An "optional" marker on a section label must not inherit the label's caps and
   tracking, or it reads as another word in the heading rather than a note about
   the fields under it. */
.im-form__seclab .im-field__optional { text-transform: none; letter-spacing: 0;
  font-size: 11.5px; }

/* Actions sit below a rule so the submit can never collide with the last
   field's hint — the exact defect this replaces on the calculator. */
.im-form__actions { display: grid; gap: var(--im-space-2);
  padding-top: var(--im-space-5); border-top: 1px solid var(--im-hairline); }
.im-form__actions--inline { grid-auto-flow: column; grid-auto-columns: max-content;
  justify-content: start; gap: var(--im-space-3); align-items: center; }
.im-form__meta { font-family: var(--im-font-display); font-size: 11.5px;
  letter-spacing: .04em; color: var(--im-text-muted); text-align: center; margin: 0; }

/* ---- The field ---- */
.im-field { display: grid; gap: var(--im-space-2); min-width: 0; }
.im-field__label { font-family: var(--im-font-display); font-weight: 600;
  font-size: 13px; line-height: 1.35; color: var(--im-ink); }
/* Mark what IS optional rather than starring what is not (GOV.UK convention);
   on the calculator that removes eleven asterisks and adds two words. */
.im-field__optional { font-weight: 400; font-size: 12px; color: var(--im-text-muted); }
.im-field__hint { font-family: var(--im-font-body); font-size: 12px; line-height: 1.45;
  color: var(--im-text-muted); margin: 0; }
.im-field__hint a { color: var(--im-accent-200); text-decoration: underline;
  text-underline-offset: 2px; }
.im-field__error { font-family: var(--im-font-display); font-weight: 600; font-size: 12.5px;
  line-height: 1.45; color: var(--im-danger-ink); margin: 0; }

/* ---- Controls ---- */
.im-field__control { font-family: var(--im-font-body); font-size: 15px;
  color: var(--im-ink); width: 100%; max-width: 100%; min-height: 44px;
  padding: 10px 13px; background: var(--im-card-bg);
  border: 1px solid var(--im-hairline); border-radius: var(--im-radius-control);
  font-variant-numeric: tabular-nums;
  transition: border-color var(--im-dur) var(--im-ease), box-shadow var(--im-dur) var(--im-ease); }
/* --im-text-muted, not --im-stone-400: placeholders here carry real content
   ("45000", "37.5", "you@example.com"), and the quarry step is 2.68:1 on a card
   where muted is 5.59:1. tokens.css scopes stone-400 to illustration and empty
   states for exactly this reason. */
.im-field__control::placeholder { color: var(--im-text-muted); }
.im-field__control:focus-visible,
.im-field__control:focus { outline: none; border-color: var(--im-accent-200);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--im-accent-200) 18%, transparent); }
/* Windows High Contrast paints no box-shadow and overrides border-color, so the
   outline:none above would leave these controls with no focus indicator at all.
   Every other focusable primitive (.im-btn, .im-disclose__summary) uses a real
   outline and is unaffected. */
@media (forced-colors: active) {
  .im-field__control:focus-visible,
  .im-field__control:focus { outline: 2px solid Highlight; outline-offset: 2px; }
}
/* Tab-scrolling can land a control under the fixed navbar (WCAG 2.4.11). */
.im-field__control { scroll-margin-top: calc(var(--im-nav-h) + var(--im-space-4)); }
.im-field__control[aria-invalid="true"] { border-color: var(--im-danger-ink); }
textarea.im-field__control { min-height: 110px; line-height: 1.5; }

/* Native select chrome varies by platform, so it is replaced with one caret
   that matches the hairline colour. The SVG is inline because a CDN-hosted or
   {% static %} image here would be a request per control. */
select.im-field__control { appearance: none; -webkit-appearance: none;
  padding-right: var(--im-space-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%2363675C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right var(--im-space-3) center; }

/* Width rungs. --im-ctl-* are in tokens.css; both the bare control and the
   prefixed group take them, because the group is what wraps the text when
   there is a currency symbol. */
.im-field__control--xs, .im-field__prefixed--xs { width: var(--im-ctl-xs); }
.im-field__control--sm, .im-field__prefixed--sm { width: var(--im-ctl-sm); }
.im-field__control--md, .im-field__prefixed--md { width: var(--im-ctl-md); }

/* ---- Currency / unit prefix ---- */
.im-field__prefixed { display: flex; align-items: stretch; max-width: 100%; }
.im-field__prefix { display: flex; align-items: center; padding: 0 var(--im-space-3);
  font-family: var(--im-font-display); font-weight: 600; font-size: 14px;
  color: var(--im-text-200); background: var(--im-band);
  border: 1px solid var(--im-hairline); border-right: 0;
  border-radius: var(--im-radius-control) 0 0 var(--im-radius-control); }
.im-field__prefixed .im-field__control { border-radius: 0 var(--im-radius-control) var(--im-radius-control) 0;
  min-width: 0; }

/* ---- Checkbox / radio row ---- */
.im-check { display: flex; align-items: flex-start; gap: var(--im-space-3);
  font-family: var(--im-font-body); font-size: 13.5px; line-height: 1.5;
  color: var(--im-text-200); cursor: pointer; }
.im-check__input { flex: 0 0 auto; width: 18px; height: 18px; margin: 1px 0 0;
  accent-color: var(--im-accent-200); cursor: pointer; }
.im-check__input:focus-visible { outline: 2px solid var(--im-accent-200); outline-offset: 2px; }
.im-check__note { display: block; color: var(--im-text-muted); font-size: 12.5px; }

/* ---- Non-field error inset ---- */
.im-form__errors { background: color-mix(in srgb, var(--im-danger-ink) 8%, var(--im-paper));
  border-left: 3px solid var(--im-danger-ink); border-radius: 0 var(--im-radius-control) var(--im-radius-control) 0;
  padding: var(--im-space-3) var(--im-space-4); font-family: var(--im-font-body);
  font-size: 13.5px; color: var(--im-text-200); margin: 0; }

/* ---- Theme password-toggle, made focus-visible ----
   The theme hides the toggle checkbox (opacity:0, z-index:-1), which hides
   the UA focus ring with it, and defines no :focus-visible of its own — so
   keyboard users tabbed onto an invisible control. Ring the indicator glyph
   instead. Fallback colour for surfaces that missed tokens.css. */
.im-formpage .password-toggle-check:focus-visible ~ .password-toggle-indicator {
  outline: 2px solid var(--im-accent-200, #00668c);
  outline-offset: 2px;
  border-radius: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .im-field__control { transition: none; }
}
