/* ============================================================================
   MPM Intake Widget — brand tokens
   v1.1 (2026-08-13)

   Values taken from the LIVE SITE (manhattanpainmedicine.com) via computed styles,
   per "build it to match mpainmed.com". Where the Brand Standards Manual (06.29.26)
   differs, the site wins and the delta is noted inline.

   Single light theme by deliberate choice: this widget renders inside a light-only
   site, and a dark variant would read as a different product mid-flow.
   ============================================================================ */

@import url('fonts.css');   /* self-hosted — never call a third-party font CDN from a patient-facing page */

:root {
  /* --- Brand core ------------------------------------------------------- */
  --maroon:        #42212E;   /* site h1 + dark grounds. Manual says #481f2f     */
  --doc-paper:     #FFFDFA;   /* a consent document's card. Read by the scroll fade */
  --maroon-2:      #752946;   /* second stop of the site's dark gradient          */
  --cta:           #982B55;   /* primary button. Not in the manual — site only    */
  --cta-hover:     #7f2447;
  --blue:          #1C6493;   /* PMS 647 C — matches the manual exactly           */
  --blue-2:        #3C75AE;
  --gold:          #E8C35E;   /* hero gradient mid-stop                           */
  --gold-deep:     #B5912C;   /* manual #bb9031                                   */
  --gold-pale:     #FFF0C3;
  --gold-wash:     #F2EFCD;   /* secondary button fill                            */

  /* --- Neutrals: warm, biased toward the maroon rather than pure grey ---- */
  --ink:           #0E0A0C;   /* site body copy                                   */
  --ink-2:         #4A3F44;
  --ink-3:         #6E6167;
  --cream:         #F7F4EC;   /* site section ground                              */
  --surface:       #FFFFFF;
  --line:          #E6DFD4;
  --line-soft:     #F0EAE0;

  /* --- Semantic (separate from the accent, never doubles as brand) ------- */
  --ok:            #2E7D5B;
  --ok-wash:       #E8F3ED;
  --warn:          #9A6B12;
  --warn-wash:     #FBF3DF;
  --err:           #A32C2C;
  --err-wash:      #FBEDED;
  --auto:          #1C6493;   /* the "we filled this in" cue                      */
  --auto-wash:     #EAF2F8;

  /* --- Type ------------------------------------------------------------- */
  --font-display: Alice, Georgia, 'Times New Roman', serif;
  --font-body:    Montserrat, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  --step--1: 0.8125rem;
  --step-0:  1rem;
  --step-1:  1.125rem;   /* site body = 18px */
  --step-2:  1.375rem;
  --step-3:  1.75rem;
  --step-4:  2.25rem;

  /* --- Shape ------------------------------------------------------------ */
  --r-pill:  9999px;     /* site buttons */
  --r-field: 12px;       /* text inputs: pill radius hurts multi-line legibility */
  --r-card:  20px;
  --shadow:  0 1px 2px rgba(66,33,46,.05), 0 8px 24px rgba(66,33,46,.06);
  --shadow-lift: 0 2px 4px rgba(66,33,46,.07), 0 14px 34px rgba(66,33,46,.10);

  --gap: 1rem;
  --measure: 34rem;

  /* "opens in a new tab" glyph, masked so it inherits whatever color it sits on */
  --ext: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M4 1h7v7' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/><path d='M11 1L5 7' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round'/><path d='M9 8v2H2V3h2' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>");
}

/* ============================================================================
   Base
   ========================================================================== */
/* ---- responsive foundation ---------------------------------------------
   From the Responsive QA audit, 2026-08-23, section 1.

   CONTAIN OVERFLOW AT THE COMPONENT, NEVER AT THE PAGE. The audit is explicit and it is the right
   instinct: `overflow: hidden` on the page would stop the horizontal scrollbar and hide whatever
   was causing it, so a patient with a long document name would simply never reach the Remove
   button. The fix belongs on the element that is too wide.

   `min-width: 0` on the layout elements is the load-bearing line and the least obvious. A grid or
   flex child defaults to `min-width: auto`, which refuses to shrink below its content — so one
   unbreakable filename or email address pushes the whole page wider and nothing else on the page
   can prevent it. */
*, *::before, *::after { box-sizing: border-box; }

img, svg, video { display: block; max-width: 100%; height: auto; }
canvas { max-width: 100%; }
input, select, textarea, button { max-width: 100%; }
main, section, aside, article, .card, .pane { min-width: 0; }

/* A phone's visible height changes when the address bar retracts or the keyboard opens. `100vh`
   is the height as if neither had happened, so a modal sized that way is taller than the screen
   and its buttons sit under the keyboard. */
.processing, .gate-back { min-height: 100dvh; }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--step-1);
  line-height: 1.56;
  color: var(--ink);
  background: var(--cream);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--maroon);
  letter-spacing: -0.02em;
  text-wrap: balance;
  margin: 0;
}
h1 { font-size: clamp(1.9rem, 1.4rem + 2.2vw, 2.6rem); line-height: 1.08; }
h2 { font-size: var(--step-3); line-height: 1.15; }
h3 { font-size: var(--step-2); line-height: 1.2; }

p { margin: 0; }
a { color: var(--blue); }

:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--cta) 55%, white);
  outline-offset: 2px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ============================================================================
   Shell
   ========================================================================== */
.widget {
  max-width: 46rem;
  margin: 0 auto;
  padding: clamp(1rem, 3vw, 2rem);
}

.card {
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-card);
  box-shadow: var(--shadow);
  padding: clamp(1.25rem, 3vw, 2.25rem);
}

/* Masthead — echoes the site's gold gradient without competing with it */
.masthead {
  border-radius: var(--r-card) var(--r-card) 0 0;
  background: linear-gradient(286deg, var(--gold-pale) 13%, var(--gold) 53%, #FFF0C7 92%);
  padding: 1.25rem clamp(1.25rem, 3vw, 2.25rem) 1.5rem;
  border: 1px solid var(--line-soft);
  border-bottom: none;
}
.masthead .eyebrow {
  font-size: var(--step--1); font-weight: 600; letter-spacing: .1em;
  text-transform: uppercase; color: color-mix(in srgb, var(--maroon) 75%, transparent);
  margin-bottom: .35rem;
}
.masthead h1 { font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2rem); }
.masthead + .card { border-radius: 0 0 var(--r-card) var(--r-card); }

/**
 * The block directly under the masthead, when it is a greeting rather than the form itself.
 *
 * Per J.S. the middle section wanted indenting: on the signing page the greeting was a bare
 * heading and paragraph, so it sat at the page's own edge while every document card indented
 * past it by the card padding — two left margins on one screen. Making it a card settles the
 * alignment, and squaring its top joins it to the gold band instead of stacking a second
 * rounded box against it.
 */
.card.intro {
  border-top: none;
  border-radius: 0 0 var(--r-card) var(--r-card);
  margin-bottom: 1.25rem;
}
.card.intro h2 { margin-bottom: .35rem; }
.card.intro .sub:last-child { margin-bottom: 0; }

/* --- The date-of-birth gate -----------------------------------------------
 *
 * ONE CARD, TEN PAGES — see js/dobgate.js.
 *
 * THE BUTTON USED TO REST ON THE DATE FIELD, reported by J.S. on 2026-08-26. `.field-err` has no
 * margin of its own, so with nothing to report the paragraph collapsed to zero height and
 * Continue came to sit against the input. The message line holds its space either way now, which
 * also stops the card jumping when an error appears under a cursor.
 */
.dobgate .gate-field { margin-top: .9rem; }
.dobgate .gate-field input { width: 100%; }
.dobgate .gate-msg { min-height: 1.25rem; margin: .5rem 0 0; }
.dobgate .gate-go { margin-top: .75rem; }

/* The way to the other kind of input. A button, because it acts on this page rather than going
   anywhere — styled as a link because that is what it behaves like to a reader. */
.linkish {
  background: none; border: 0; padding: .25rem 0; margin-top: .4rem;
  font: inherit; font-size: var(--step--1); color: var(--maroon);
  text-decoration: underline; cursor: pointer;
}
.linkish:hover, .linkish:focus { color: var(--ink-1); }

/* ============================================================================
   Progress
   ========================================================================== */
.progress { display: flex; gap: .375rem; margin-top: 1rem; }
.progress .seg {
  height: 4px; flex: 1; border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--maroon) 14%, transparent);
  transition: background .3s ease;
}
.progress .seg.done { background: var(--maroon); }
.progress .seg.now  { background: var(--cta); }

.step-count {
  font-size: var(--step--1); color: var(--ink-3);
  font-variant-numeric: tabular-nums; margin-top: .5rem;
}

/* ============================================================================
   Questions
   ========================================================================== */
.step-head { margin-bottom: 1.5rem; }
.step-intro {
  color: var(--ink-2); font-size: var(--step-0);
  max-width: var(--measure); margin-top: .625rem;
}

.qs { display: flex; flex-direction: column; gap: 1.5rem; }
.q { display: flex; flex-direction: column; gap: .5rem; }
/* THE f- NAMES ARE THE SAME THINGS UNDER A SECOND NAME.
   public/js/cards.js, decline.js and forms.js were written with an `f-` prefix while the engine
   used `q-`, and nothing ever defined the `f-` half: on the live site a .f-help paragraph
   computed identically to a bare <p>, so twenty lines of quiet helper text across the patient
   forms were rendering at full body size and full-strength ink, competing with the questions
   they were meant to sit under. Found with getComputedStyle on the deployed page, not by
   reading the stylesheet.
   They are added to the existing selectors rather than given rules of their own, so there is
   still one description of what helper text looks like. */
.q-label, .f-label { font-weight: 600; font-size: var(--step-0); color: var(--maroon); }
.q-label .req { color: var(--cta); margin-left: .15rem; }
.q-help, .f-help { font-size: var(--step--1); color: var(--ink-3); margin-top: -.15rem; }
/* A second line under the first, so the two do not read as one paragraph. */
.f-help.f-sub { margin-top: .35rem; }

/* Opens in a new tab — the arrow says so before the click, not after. */
.link-out {
  color: var(--blue); font-weight: 600; text-decoration: none;
  border-bottom: 1.5px solid color-mix(in srgb, var(--blue) 35%, transparent);
  padding-bottom: 1px;
}
.link-out:hover { border-bottom-color: var(--blue); }
.link-out::after {
  content: ''; display: inline-block; width: .6em; height: .6em; margin-left: .35em;
  background: currentColor; vertical-align: baseline;
  -webkit-mask: var(--ext) no-repeat center / contain;
          mask: var(--ext) no-repeat center / contain;
}

.row2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap); }
@media (max-width: 34rem) { .row2 { grid-template-columns: 1fr; } }

input[type=text], input[type=email], input[type=tel], input[type=date], textarea, select,
.f-input {
  font-family: var(--font-body);
  font-size: var(--step-0);
  color: var(--ink);
  background: var(--surface);
  border: 1.5px solid var(--line);
  border-radius: var(--r-field);
  padding: .8rem .95rem;
  width: 100%;
  transition: border-color .16s ease, box-shadow .16s ease;
}
textarea { min-height: 6.5rem; resize: vertical; line-height: 1.5; }
select { appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8'><path d='M1 1l5 5 5-5' fill='none' stroke='%2342212E' stroke-width='1.8' stroke-linecap='round'/></svg>");
  background-repeat: no-repeat; background-position: right 1rem center; padding-right: 2.5rem; }

input:hover, textarea:hover, select:hover { border-color: color-mix(in srgb, var(--maroon) 30%, var(--line)); }
input:focus, textarea:focus, select:focus {
  outline: none; border-color: var(--cta);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--cta) 15%, transparent);
}
input.invalid, textarea.invalid, select.invalid { border-color: var(--err); }

/**
 * KEYBOARD FOCUS SURVIVES THE FIELD STYLING.
 *
 * `:focus-visible` above draws a strong outline. `input:focus` below removes it — deliberately,
 * so a mouse click does not leave a ring — but that rule is MORE SPECIFIC, so it won every time
 * and a keyboard user got only a pale border and a low-opacity shadow to tell them where they
 * were. Found by the outside reviewer, 2026-08-24.
 *
 * These restore the outline for keyboard focus only. The mouse behaviour is unchanged: a click
 * still gives the quiet border, because :focus-visible does not match a pointer.
 */
input:focus-visible, textarea:focus-visible, select:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--cta) 55%, white);
  outline-offset: 2px;
}


.field-err { font-size: var(--step--1); color: var(--err); font-weight: 500; }

/* --- Auto-filled cue: clears on first edit -------------------------------- */
input.autofilled, select.autofilled {
  background: var(--auto-wash);
  border-color: color-mix(in srgb, var(--auto) 45%, var(--line));
}
.autofill-tag {
  display: inline-flex; align-items: center; gap: .3rem;
  font-size: var(--step--1); font-weight: 600; color: var(--auto);
}
.autofill-tag::before {
  content: ''; width: .5rem; height: .5rem; border-radius: 50%;
  background: var(--auto);
}

/* ============================================================================
   Choices — pills, matching the site's button language
   ========================================================================== */
.choices { display: flex; flex-direction: column; gap: .5rem; }
.choices.inline { flex-direction: row; flex-wrap: wrap; }

.choice {
  display: flex; align-items: flex-start; gap: .7rem;
  border: 1.5px solid var(--line);
  border-radius: var(--r-field);
  padding: .8rem 1rem;
  cursor: pointer;
  background: var(--surface);
  transition: border-color .15s ease, background .15s ease, box-shadow .15s ease;
}
.choices.inline .choice { border-radius: var(--r-pill); padding: .65rem 1.15rem; }
.choice:hover { border-color: color-mix(in srgb, var(--cta) 45%, var(--line)); background: #FFFDFB; }
.choice input { margin: 0; accent-color: var(--cta); flex: none; margin-top: .18rem; }
.choices.inline .choice input { margin-top: 0; }
.choice.on {
  border-color: var(--cta);
  background: color-mix(in srgb, var(--cta) 5%, var(--surface));
  box-shadow: 0 0 0 1px var(--cta) inset;
}
.choice-body { display: flex; flex-direction: column; gap: .15rem; }
.choice-label { font-size: var(--step-0); line-height: 1.35; }
.choice-help  { font-size: var(--step--1); color: var(--ink-3); }

/* ============================================================================
   Upload / dropzone
   ========================================================================== */
.drop {
  border: 2px dashed color-mix(in srgb, var(--gold-deep) 50%, var(--line));
  border-radius: var(--r-card);
  background: linear-gradient(180deg, #FFFDF6, var(--surface));
  padding: 1.75rem 1.25rem; text-align: center; cursor: pointer;
  transition: border-color .16s ease, background .16s ease;
}
.drop:hover, .drop.over { border-color: var(--gold-deep); background: #FFFBEE; }
.drop .big { font-weight: 600; color: var(--maroon); }
.drop .small { font-size: var(--step--1); color: var(--ink-3); margin-top: .3rem; }

.files { display: flex; flex-direction: column; gap: .5rem; margin-top: .75rem; }
.file {
  display: flex; align-items: center; gap: .65rem;
  border: 1px solid var(--line); border-radius: var(--r-field);
  padding: .6rem .8rem; background: var(--surface); font-size: var(--step-0);
}
.file .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file .state { font-size: var(--step--1); font-weight: 600; }
.file .state.reading   { color: var(--blue); }
.file .state.uploading { color: var(--blue); }
.file .state.done      { color: var(--ok); }
/* Sent means the bytes are in the practice's Drive — worth saying in the affirmative color,
   because until this existed the word "Attached" was not true. */
.file .state.stored    { color: var(--ok); }
.file .state.failed    { color: var(--err); }
.file.file-failed      { border-color: var(--err); background: var(--err-wash); }
.file .file-err        { font-size: var(--step--1); color: var(--err); }
/* Which box it was dropped in, on the confirmation list. */
.file .doc-type { font-size: var(--step--1); color: var(--ink-3); }

/**
 * Remove a file that should not be there.
 *
 * A real target size (44px) rather than a bare glyph: it is next to a filename on a phone, and
 * a mis-tap on a destructive control is why the confirm exists. Muted until hovered or focused
 * so it does not read as the main thing to do with an attached document.
 */
.file-remove {
  flex: none; width: 2.75rem; height: 2.75rem; margin: -.6rem -.5rem -.6rem 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: 0; cursor: pointer; font-size: var(--step-0);
  color: var(--ink-3); border-radius: var(--r-field);
}
.file-remove:hover { color: var(--err); background: var(--err-wash); }
.file-remove:focus-visible { outline: 2px solid var(--err); outline-offset: -2px; }

/**
 * The documents disagree about who the patient is. Loud, but not an error state: the referrer
 * may have a good reason, and the form does not block on it.
 */
.doc-mismatch {
  margin-top: .75rem; padding: .8rem 1rem; border-radius: var(--r-field);
  background: var(--warn-wash); border-left: 3px solid var(--warn);
}
/**
 * "Processing your request" while a submission is in flight.
 *
 * Covers the whole viewport rather than the widget: the widget is in an iframe of unknown
 * height, and a spinner below the fold is a spinner nobody sees. It also makes a second press
 * of Send impossible, which on a form that creates a patient record matters more than the
 * reassurance does.
 */
.processing {
  position: fixed; inset: 0; z-index: 100;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--ink) 45%, transparent);
  padding: 1.5rem;
}
.processing-card {
  background: var(--surface); border-radius: var(--r-md, 10px);
  padding: 1.75rem 2rem; max-width: 24rem; text-align: center;
  box-shadow: 0 10px 40px rgba(14, 10, 12, .28);
  display: flex; flex-direction: column; align-items: center; gap: .6rem;
}
.processing-t { margin: 0; font-weight: 700; font-size: var(--step-1); color: var(--ink); }
.processing-sub { margin: 0; font-size: var(--step--1); color: var(--ink-3); }
.spinner-lg { width: 2rem; height: 2rem; border-width: 3px; }

/* Help that sits under the control it qualifies, explaining the answer just given rather than
   how to answer. Indented to read as belonging to the choice above it. */
.q-help-below { margin-top: .5rem; }

/* What happens next, on the confirmation page. */
.next-step {
  margin-top: 1.75rem; padding: 1rem 1.15rem; border-radius: var(--r-md, 8px);
  background: var(--cream); border-left: 3px solid var(--gold-deep);
}
.next-step h3 { margin: 0 0 .4rem; font-size: var(--step-1); }
.next-step p { margin: 0; color: var(--ink-2); }
.next-step .btn { margin-top: .85rem; display: inline-flex; }

/* The two ways out of a failed submission, side by side and equally weighted. */
.fail-actions { display: flex; gap: .6rem; flex-wrap: wrap; margin-top: .75rem; }
.fail-actions .btn { flex: 0 1 auto; }
@media (max-width: 30rem) { .fail-actions .btn { flex: 1 1 auto; justify-content: center; } }

.doc-mismatch p { margin: 0 0 .4rem; font-size: var(--step--1); color: var(--ink-2); }
.doc-mismatch p:last-child { margin-bottom: 0; }
.doc-mismatch-t { font-weight: 700; color: var(--ink); }

/**
 * A field with a sentence beside it. Side by side where there is room; stacked underneath on a
 * narrow screen, where "to the right" would mean a 12rem column of two-word lines.
 */
.field-with-aside { display: flex; gap: 1.25rem; align-items: flex-start; }
.field-with-aside .field-main { flex: 1 1 60%; min-width: 0; }
.field-aside {
  flex: 1 1 40%; font-size: var(--step--1); color: var(--ink-3);
  border-left: 2px solid var(--line); padding-left: .9rem;
}
.field-aside p { margin: 0 0 .35rem; }
@media (max-width: 40rem) {
  .field-with-aside { flex-direction: column; gap: .6rem; }
  .field-aside { border-left: 0; border-top: 1px solid var(--line);
                 padding-left: 0; padding-top: .6rem; }
}

.spinner {
  width: 1rem; height: 1rem; border-radius: 50%; flex: none;
  border: 2px solid color-mix(in srgb, var(--blue) 25%, transparent);
  border-top-color: var(--blue);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ============================================================================
   Consent
   ========================================================================== */
.doc {
  border: 1px solid var(--line); border-radius: var(--r-field);
  background: var(--doc-paper);
}
.doc-head {
  padding: .85rem 1.1rem; font-weight: 600; color: var(--maroon);
  border-bottom: 1px solid var(--line-soft);
  display: flex; justify-content: space-between; align-items: center; gap: 1rem;
}
.doc-meta { font-size: var(--step--1); color: var(--ink-3); font-weight: 400; }
.doc-body {
  max-height: 15rem; overflow-y: auto; padding: 1rem 1.1rem;
  font-size: .9375rem; line-height: 1.6; color: var(--ink-2);
}
.doc-body h4 {
  font-family: var(--font-body); font-size: var(--step--1); font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--maroon);
  margin: 1.1rem 0 .35rem;
}
.doc-body h4:first-child { margin-top: 0; }
.doc-body p + p { margin-top: .7rem; }

.sig-pad {
  border: 1.5px solid var(--line); border-radius: var(--r-field);
  background: var(--surface); touch-action: none; width: 100%; height: 9rem;
  display: block; cursor: crosshair;
}
.sig-tools { display: flex; justify-content: space-between; align-items: center; margin-top: .5rem; }

/* ============================================================================
   Buttons
   ========================================================================== */
.btn {
  font-family: var(--font-body); font-weight: 600; font-size: var(--step-0);
  border-radius: var(--r-pill); padding: 1rem 1.5rem;
  border: 1px solid transparent; cursor: pointer;
  display: inline-flex; align-items: center; gap: .55rem;
  transition: background .16s ease, box-shadow .16s ease, transform .1s ease;
}
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--cta); border-color: var(--cta); color: #fff; }
.btn-primary:hover { background: var(--cta-hover); box-shadow: var(--shadow-lift); }
.btn-secondary { background: var(--gold-wash); border-color: var(--gold); color: color-mix(in srgb, var(--maroon) 88%, transparent); }
.btn-secondary:hover { background: #EDE9C2; }
.btn-ghost { background: transparent; border-color: transparent; color: var(--ink-3); padding-left: .5rem; padding-right: .5rem; }
.btn-ghost:hover { color: var(--maroon); }
.btn[disabled] { opacity: .45; cursor: not-allowed; }

.actions {
  display: flex; align-items: center; gap: .75rem;
  margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid var(--line-soft);
}
.actions .spacer { flex: 1; }

/* On a phone the three controls fight for one row and the skip label wraps to three
   lines. Stack instead, with the primary action full-width and first under the thumb —
   Back and Skip are secondary and read fine below it. */
@media (max-width: 30rem) {
  .actions { flex-direction: column; align-items: stretch; gap: .35rem; }
  .actions .spacer { display: none; }
  .actions .btn { width: 100%; justify-content: center; }
  .actions .btn-primary { order: -1; padding: 1.05rem 1.5rem; }
  .actions .btn-ghost { padding: .7rem 1rem; }
}

/* ============================================================================
   Callouts + review
   ========================================================================== */
.note {
  border-left: 3px solid var(--blue); background: var(--auto-wash);
  padding: .85rem 1rem; border-radius: 0 var(--r-field) var(--r-field) 0;
  font-size: var(--step-0); color: var(--ink-2);
}
.note.warn { border-left-color: var(--warn); background: var(--warn-wash); }

.zone-list { display: flex; flex-wrap: wrap; gap: .45rem; }
.zone {
  border-radius: var(--r-pill); padding: .4rem .85rem;
  font-size: var(--step--1); font-weight: 600; border: 1.5px solid;
}
.zone.red    { color: var(--maroon); border-color: var(--maroon); background: color-mix(in srgb, var(--maroon) 7%, white); }
.zone.yellow { color: #7A5E12; border-color: var(--gold-deep); background: color-mix(in srgb, var(--gold) 18%, white); }

/* Resource cards on the completion screen */
.resources {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: .75rem; margin-top: 1rem;
}
.resource {
  display: flex; flex-direction: column; gap: .3rem;
  border: 1.5px solid var(--line); border-radius: var(--r-field);
  padding: 1rem 1.1rem; background: var(--surface); text-decoration: none;
  transition: border-color .16s ease, box-shadow .16s ease, transform .1s ease;
}
.resource:hover {
  border-color: var(--gold-deep); box-shadow: var(--shadow); transform: translateY(-1px);
}
.resource-title {
  font-family: var(--font-display); font-size: var(--step-1); color: var(--maroon);
  display: flex; align-items: baseline; gap: .4em;
}
.resource-title::after {
  content: ''; width: .5em; height: .5em; flex: none;
  background: var(--blue);
  -webkit-mask: var(--ext) no-repeat center / contain;
          mask: var(--ext) no-repeat center / contain;
}
.resource-blurb { font-size: var(--step--1); color: var(--ink-3); line-height: 1.45; }

.summary { display: grid; grid-template-columns: auto 1fr; gap: .5rem 1rem; font-size: var(--step-0); }
.summary dt { color: var(--ink-3); }
.summary dd { margin: 0; color: var(--ink); }

/* Debug rail — prototype only, never ships */
.debug {
  margin-top: 1.25rem; border: 1px dashed var(--line);
  border-radius: var(--r-field); background: #FCFAF6; padding: .9rem 1.1rem;
  font-size: var(--step--1); color: var(--ink-3);
}
.debug summary { cursor: pointer; font-weight: 600; color: var(--maroon); }
.debug pre { margin: .7rem 0 0; white-space: pre-wrap; word-break: break-word;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .75rem; color: var(--ink-2); }

/* Save state — visible, never blocking. A patient must be able to finish the form even
   when we cannot store their progress. */
.save-state { font-size: var(--step--1); margin-top: .6rem; line-height: 1.45; }
.save-state.ok     { color: var(--ok); }
.save-state.failed {
  color: var(--warn); background: var(--warn-wash);
  border-left: 3px solid var(--warn); border-radius: 0 8px 8px 0;
  padding: .55rem .8rem; max-width: var(--measure);
}

/* Clear is deliberately quiet — available on every step, never competing with Continue. */
.btn-clear { color: var(--ink-3); }
.btn-clear:hover { color: var(--err); }
@media (max-width: 30rem) { .actions .btn-clear { order: 2; } }

/* ---- patient signing ---------------------------------------------------- */
.consent-card { margin-bottom: 1.25rem; }
.consent-card h3 { margin-bottom: .5rem; }
.consent-card h4 { margin-top: 1rem; }
.consent-card p { margin-bottom: .6rem; }
.consent-card .lead { font-size: var(--step-1); color: var(--ink-2); }
.ack { background: var(--cream); border-left: 3px solid var(--gold-deep);
       padding: .8rem 1rem; border-radius: var(--r-sm); margin: 1rem 0; }
.ack p { margin: 0; font-weight: 600; }
.signblock { border-top: 1px solid var(--line-soft); margin-top: 1.2rem; padding-top: 1rem; }
.signblock input { width: 100%; max-width: 24rem; }
.ok-note { color: var(--ok, #2E7D5B); font-weight: 600; }

/* ---- what happens next, on the completion screen ------------------------ */
.pathway {
  margin-top: 2rem; padding: 1.25rem 1.4rem;
  background: var(--cream); border-left: 3px solid var(--gold-deep);
  border-radius: var(--r-md);
}
.pathway h3 { margin-bottom: .5rem; }
.pathway-lead { color: var(--ink-2); font-size: var(--step-1); margin-bottom: .9rem; }
.pathway-point { margin-bottom: .7rem; }
.pathway-point strong { color: var(--maroon); }
.pathway-close { color: var(--ink-3); font-size: var(--step--1); margin-top: .9rem; }

/* ---------------------------------------------------------------------------
   Signing page
   v0.1 (2026-08-10)

   The document is the page. Long consent text has to be readable at length, and the check that
   ends each one has to be unmistakably part of that document rather than of the next.
   --------------------------------------------------------------------------- */

.consent-card { margin-bottom: 1.5rem; }
.consent-card h4.fgroup-label { margin: 1.1rem 0 .3rem; }
.consent-card p { line-height: 1.6; white-space: pre-line; }

.consent-card .ack {
  margin: 1.1rem 0 .25rem; padding: .85rem 1rem;
  background: var(--gold-wash, #F2EFCD);
  border-left: 3px solid var(--gold-deep, #B5912C);
  border-radius: 0 var(--radius-sm, 6px) var(--radius-sm, 6px) 0;
}
.consent-card .ack p { margin: 0; font-weight: 600; }

/* The check reads as the last line of the document, not as a control floating beneath it. */
.agree {
  display: flex; gap: .7rem; align-items: flex-start;
  margin-top: 1.2rem; padding-top: 1rem;
  border-top: 1px solid var(--rule, #E2D8CC);
  cursor: pointer; font-weight: 600;
}
.agree input { margin-top: .2rem; width: 1.15rem; height: 1.15rem; flex: 0 0 auto; }

/* Deliberately NOT sticky: pinning it to the viewport floated the signature above documents
   still waiting to be read, which is the wrong order to present them in. */
.signblock-card { margin-top: .5rem; }
.signblock-card .sig-pad { margin-top: .5rem; }

/* The parts of a document only the patient can complete. */
.pfields { margin: 1.2rem 0 .5rem; padding: 1rem; background: var(--surface-2, #FBF8F0);
           border-radius: var(--r-field, 6px); }
.pfields .f { margin-bottom: .9rem; }
.pfields .pill { display: flex; margin: .25rem 0; }

/**
 * Numbered instructions on the upload page.
 *
 * Generous line spacing and room between steps because these are read one at a time, at a
 * computer, by somebody holding a disc — not scanned.
 */
.steps { margin: .75rem 0 .5rem; padding-left: 1.25rem; }
.steps li { margin-bottom: .6rem; line-height: 1.55; }
.steps li:last-child { margin-bottom: 0; }

/* The guardian identification, above the signature pad on a minor's forms. */
.guardian-box { background: #FBF7EC; border: 1px solid var(--line-soft, #E5DFD2);
                border-radius: .5rem; padding: .9rem 1rem; margin: .75rem 0 1rem; }
.guardian-box .lead { margin-bottom: .75rem; }
.guardian-box .f { margin-bottom: .6rem; }

/* Screen-reader-only live region: present to assistive tech, absent from the layout. */
.sr-live { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
           overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.sig-typed { margin-top: .75rem; }

/* Consent cards: the expand control, the full-height mode, and the read gate. */
.doc-expand { background: none; border: 0; padding: 0; cursor: pointer; font: inherit;
              font-size: .82rem; color: var(--maroon); text-decoration: underline; }
.doc-expanded .doc-body, .doc-body-expanded { max-height: none !important; overflow: visible; }
.doc-end { height: 1px; }
.choice-disabled { opacity: .55; cursor: not-allowed; }
.doc-gate-hint { margin: -.35rem 0 0; }
/**
 * A GRID, because a wrapping flex row is what produced the gaps.
 *
 * These were flex items with basis widths and `flex-wrap: wrap`. On a wide screen they sat
 * flush; but the widget is embedded in a page column of somebody else's choosing, and as soon
 * as the row was narrower than the bases added up, one field dropped to the next line and left
 * the empty remainder of the line beside it — a gap after the street, after the apartment,
 * after the city, depending on where it broke. Reported three times, and each fix moved the
 * width at which it happened rather than removing it.
 *
 * A grid cannot wrap. The columns are proportional, so they stay flush at every width down to
 * the breakpoint where they deliberately stack. `minmax(0, …)` is what stops a long value from
 * pushing its column wider than its share.
 */
/* The wrapper had no rule, so the two rows of the address sat flush against each other. */
.addr { display: grid; gap: .6rem; }
.addr-row { display: grid; gap: .6rem; }
.addr-row:first-child  { grid-template-columns: minmax(0, 3fr) minmax(0, 1fr); }
.addr-row:nth-child(2) { grid-template-columns: minmax(0, 2fr) 5rem minmax(0, 1fr); }
.addr-part { display: flex; flex-direction: column; gap: .2rem; min-width: 0; }
/* The columns are declared on the rows above; the parts just sit in them. State keeps its own
   fixed column because two letters sized against a city name looks like a mistake. */
.q-sublabel { font-size: .82rem; color: var(--ink-2, #5a5148); }

/* ---- responsive pass (per J.S.'s review) --------------------------------- */
@media (max-width: 640px) {
  .actions { flex-wrap: wrap; gap: .5rem; }
  .actions .btn { flex: 1 1 auto; min-width: 9rem; }
  .choices.inline { flex-direction: column; }
  /* One column on a phone. `flex-direction` did this while the rows were flex; they are a grid
     now, so the same intent has to be said in the grid's own terms or the rule silently
     stopped applying — and State would sit in a 5rem column on a 360px screen. */
  .addr-row, .addr-row:first-child, .addr-row:nth-child(2) { grid-template-columns: 1fr; }
  .summary { grid-template-columns: 1fr; }
  .summary dd { margin-bottom: .6rem; }
  .doc-body { max-height: 40vh; }
}
.summary-sec { margin-bottom: 1.25rem; }
.summary-title { font-size: .95rem; margin: 1rem 0 .35rem; }

/**
 * The gate — a question whose answer changes what we can offer.
 *
 * Modal on purpose. A patient who has said their pain is from a car accident has to be told
 * what that means for the visit BEFORE they spend another ten minutes on the form, and a
 * notice they can scroll past is a notice they will scroll past.
 */
.gate-back {
  position: fixed; inset: 0; z-index: 60; display: flex; align-items: center;
  justify-content: center; padding: 1rem; background: rgba(30, 20, 24, .55);
}
.gate-card {
  background: var(--surface); border-radius: var(--r-card); box-shadow: var(--shadow);
  padding: clamp(1.25rem, 3vw, 2rem); max-width: 34rem; width: 100%;
  max-height: 90vh; overflow-y: auto;
}
.gate-card h3 { margin-bottom: .6rem; }
.gate-card p { margin-bottom: .8rem; }
.gate-acts { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: 1.2rem; }

/* ---- the checklist ------------------------------------------------------- */
/**
 * One card per errand, each listing what it covers. The card is the unit because one page
 * completes all of a module's items at once: three card photos are one visit to the cards
 * page, not three separate journeys.
 *
 * Completed cards stay, dimmed rather than removed. A list that shortens as somebody works
 * leaves them unsure whether they imagined the third item, and a patient returning to the link
 * wants to see that what they did on Tuesday is still done.
 */
.pl-group { display: flex; flex-direction: column; gap: .9rem; }
.pl-group.done { opacity: .62; }

.pl-list { list-style: none; margin: 0; padding: 0; display: flex;
           flex-direction: column; gap: .5rem; }
.pl-item { display: flex; align-items: baseline; gap: .6rem; }
.pl-mark { flex: 0 0 auto; width: 1rem; color: var(--ink-3); font-size: .95rem; }
.pl-item.done .pl-mark { color: var(--ok, #2e7d4f); }
.pl-label { flex: 1 1 auto; }
.pl-item.done .pl-label { text-decoration: line-through; text-decoration-thickness: 1px;
                          color: var(--ink-3); }
.pl-state { flex: 0 0 auto; font-size: var(--step--1); color: var(--ink-3); }

/* The button sits at the foot of its own card and takes only the width of its label, so a
   short errand does not get a button the width of the page. */
.pl-group .btn { align-self: flex-start; }

/**
 * Back to the checklist, on the masthead of each module page.
 *
 * On the masthead because every one of those pages renders by clearing its pane, so a link
 * placed inside would be destroyed by the first thing the patient did.
 */
.portal-back { display: inline-block; margin-top: .5rem; font-size: var(--step--1); }

/* Which appointment this card is, when the link carries more than one. */
.apptwhen { font-weight: 600; margin-bottom: .6rem; }


/**
 * The way out of the portal.
 *
 * Per J.S., 2026-08-16: the patient can ask us to stop engaging with them. Styled to be findable
 * and not pressable by accident: it sits below the help line at the foot of the page, in the
 * muted ink the help text uses, underlined so it is plainly a link. It is an offer, not one of
 * the actions the page is asking for, so it takes none of a button's weight.
 */
.portal-decline { margin-top: 1.25rem; }
.portal-decline .decline-link { color: var(--ink-3); text-decoration: underline; }
.portal-decline .decline-link:hover,
.portal-decline .decline-link:focus-visible { color: var(--maroon, #42212E); }

/* Two choices side by side on the confirmation step, wrapping on a narrow phone rather than
   squeezing, because the wrong press here closes somebody's file. */
.row { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1rem; }


/* The explanation that used to arrive by email, now beside the task it explains. Quieter than the
   item labels: it is context, and the list is the thing being read. */
.pl-group .pl-help { font-size: var(--step--1); color: var(--ink-2, #5A4A50);
                     margin: .35rem 0 0; line-height: 1.5; }
.pl-group .pl-help + .pl-help { margin-top: .2rem; }

/* ---- referring-provider type-ahead -------------------------------------
   The matches sit directly under the box they belong to and look like what they are: a short
   list of names to press, not a styled dropdown pretending to be a native select. */
.providerpick { position: relative; }
.provider-matches { display: flex; flex-direction: column; margin-top: .35rem; }
.provider-match {
  display: flex; flex-direction: column; align-items: flex-start; gap: .1rem;
  text-align: left; width: 100%; cursor: pointer;
  background: #fff; border: 1px solid var(--line, #DCD5C9); border-bottom: none;
  padding: .55rem .7rem; font: inherit;
}
.provider-match:first-child { border-radius: 8px 8px 0 0; }
.provider-match:last-child  { border-bottom: 1px solid var(--line, #DCD5C9); border-radius: 0 0 8px 8px; }
.provider-match:only-child  { border-radius: 8px; }
.provider-match:hover, .provider-match:focus-visible {
  background: #FCFAF6; border-color: var(--maroon, #6E2639);
}
.provider-match .pm-name { font-weight: 600; }
.provider-match .pm-meta { font-size: .85em; color: var(--ink-3, #7A7268); }

/* A signed document on the thank-you page: checked, and emphatically NOT struck through — see the
   note in public/js/forms.js. The check carries the meaning; the name stays readable. */
.pl-item.pl-signed .pl-mark { color: var(--ok, #2e7d4f); font-weight: 700; }
.pl-item.pl-signed .pl-label { text-decoration: none; color: var(--ink-1); }

/* ---- A linear rating scale -----------------------------------------------
   Per J.S., 2026-08-21: the pain score is linear. Eleven numbers on ONE LINE, ends anchored —
   a 0-10 rating means the same thing twice only if the whole range is visible while answering.

   Real radio inputs, visually hidden rather than display:none, so arrow keys still walk the
   scale and a screen reader still announces a radiogroup. display:none would take it out of
   the tab order and turn an accessible control into a row of decorations.

   It SCROLLS rather than wrapping on a narrow screen. A scale that wraps to two lines is no
   longer a line, and the reading "7 out of 10" depends on seeing where 7 falls. */
.scale-wrap { margin-top: .2rem; }
.scale { display: flex; gap: .25rem; overflow-x: auto; padding-bottom: .2rem; }
.scale-item { flex: 1 1 0; min-width: 2.25rem; }
.scale-item input {
  position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none;
}
.scale-num {
  display: block; text-align: center; padding: .6rem .2rem; cursor: pointer;
  border: 1px solid var(--line-soft); border-radius: var(--r-field);
  background: #fff; font-variant-numeric: tabular-nums; font-weight: 600;
}
.scale-item input:checked + .scale-num {
  background: var(--maroon); border-color: var(--maroon); color: #fff;
}
.scale-item input:focus-visible + .scale-num { outline: 2px solid var(--gold); outline-offset: 2px; }
.scale-ends {
  display: flex; justify-content: space-between;
  font-size: var(--step--1); color: var(--ink-3); margin-top: .25rem;
}
.scale.invalid .scale-num { border-color: var(--err); }

/* ---- A repeating list (medications) -------------------------------------- */
.rep { display: flex; flex-direction: column; gap: .6rem; }
.rep-row {
  display: grid; grid-template-columns: auto 1fr auto; gap: .5rem; align-items: start;
  border: 1px solid var(--line-soft); border-radius: var(--r-field); padding: .6rem .7rem;
  background: #fff;
}
.rep-n {
  font-variant-numeric: tabular-nums; font-weight: 700; color: var(--ink-3);
  padding-top: 1.3rem;
}
.rep-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: .5rem; }
.rep-f { display: flex; flex-direction: column; gap: .15rem; }
.rep-lab {
  font-size: var(--step--1); color: var(--ink-3); text-transform: uppercase;
  letter-spacing: .04em; font-weight: 700;
}
.rep-in { width: 100%; }
.rep-x {
  /* PINNED TO THE TOP RIGHT. Left to auto-placement it fell to a new grid row as soon as the
     provenance line was added below the fields, landing under the medication instead of beside
     it — a remove control that moves depending on where a row came from. */
  grid-column: 3; grid-row: 1;
  background: none; border: none; cursor: pointer; font-size: 1.3rem; line-height: 1;
  color: var(--ink-3); padding: .2rem .3rem;
}
.rep-x:hover, .rep-x:focus-visible { color: var(--err); }
.rep-add { align-self: flex-start; }

/* ---- Framing a card before it is sent -------------------------------------
   MOVED to css/framecard.css, so the staff New Patient screen can link the same rules
   without taking the whole patient stylesheet. A page that loads js/framecard.js loads
   that file too; tools/check-pages.js reports the script, and the offer is guarded, so
   neither the script nor the stylesheet going missing throws. */

/* A repeater row that was read off an uploaded document rather than typed. Tinted, not
   badged in color: it is a note about provenance, not a warning, and a row the patient
   still has to complete should not look like an error. */
.rep-row.rep-doc { background: var(--auto-wash); border-color: var(--auto); }
.rep-src {
  grid-column: 2; grid-row: 2; font-size: var(--step--1); color: var(--auto);
  font-weight: 600; margin: .1rem 0 0;
}

/* ---- A consent document's priced tables (js/docbody.js) -------------------
   The fee schedule had no styling at all: an unstyled four-column table, columns sized by
   content, the physician's fee sitting flush against the physician assistant's. The widths come
   from the document itself — the same fractions lib/pdf.js lays the signed copy out with — so
   what is read on screen and what is signed are the same shape. */
/* A PRICED TABLE SHOULD NEVER SCROLL SIDEWAYS NOW — js/docbody.js stacks each row instead, below
   the width at which that table's own columns fit, per J.S. on 2026-08-22. This stays as the
   fallback, because the width it stacks at is computed from an ESTIMATE of how wide a word is:
   if that estimate is ever a few pixels short, the choice is a table that pans or a price printed
   over the one beside it.

   The shadow appears at an edge ONLY while there is more table beyond it — the standard
   local/scroll background gradients, no JavaScript and no scroll listener. So on every table that
   fits, which should be all of them, nothing is drawn at all.

   The fade is `.doc`'s OWN background — `--doc-paper`, not white. A white fade over the card's
   warm paper leaves two pale grey bars down the edges of every priced table, and typing the hex
   a second time here is how the two drift apart the day one of them is adjusted. */
.doc-tablewrap {
  overflow-x: auto; margin: .5rem 0 1rem; -webkit-overflow-scrolling: touch;
  background:
    linear-gradient(to right, var(--doc-paper) 30%, transparent) left / 2rem 100% no-repeat local,
    linear-gradient(to left,  var(--doc-paper) 30%, transparent) right / 2rem 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%,   rgba(66, 33, 46, .18), rgba(66, 33, 46, 0)) left / .75rem 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, rgba(66, 33, 46, .18), rgba(66, 33, 46, 0)) right / .75rem 100% no-repeat scroll;
}
.doc-table {
  width: 100%; border-collapse: collapse; font-size: var(--step--1, .9rem);
  /* The colgroup decides the columns, not the content. Without this the browser ignores the
     widths the document specifies. */
  /* The minimum is set per table by js/docbody.js, computed from that table's own columns — a
     flat 20rem here gave a four-column priced table 35px for a $1,250 — and the same number is
     where the rows stack instead. This stays as the floor for anything drawn without it. */
  table-layout: fixed; min-width: 20rem;
}
.doc-table th, .doc-table td {
  padding: .45rem .5rem; text-align: left; vertical-align: top;
  border-bottom: 1px solid var(--line-soft, #e7e2dc);
  overflow-wrap: anywhere;            /* a long service name wraps rather than pushing prices off */
}
/* THE HEADER IS THE SIGNED COPY'S HEADER. lib/pdf.js draws it with `c.label` verbatim, bold, in
   maroon, at the SAME size as the rows — no capitals, no tracking, no grey. This drew it small,
   uppercase and letter-spaced instead, which is a third of the reason the table was hard to read
   and the whole reason it broke: "PHYSICIAN" needed 78px of the 74px that the document's own 16%
   column leaves at widget width, so `overflow-wrap: anywhere` split it as PHYSICIA / N. Mixed case
   at row size is 66px in the same 74px. The fractions are the document's and are not ours to
   change; the type is ours, and matching the PDF is what the widths were computed for. */
.doc-table th {
  font-size: inherit; color: var(--maroon, #42212E);
  border-bottom-width: 1.5px; font-weight: 700;
}
/* Money right-aligned and in tabular figures, so a column of prices can be compared down it —
   the same alignment lib/pdf.js gives them. */
.doc-table th.num, .doc-table td.num { text-align: right; font-variant-numeric: tabular-nums; }
/* NOWRAP IS FOR THE MONEY, NOT FOR THE WORD ABOVE IT. `$1,250` must never break; "Physician
   assistant" is two words in a 14%-wide column and needed 167px in the 112px it had — so it
   painted straight over "Time" in the next header. The header of a money column is prose and
   wraps like prose; the cells below it do not. */
.doc-table td.num { white-space: nowrap; }
.doc-table tbody tr:last-child td { border-bottom: none; }

/* ---- Continue, while a file is still going up (engine.js) -----------------
   Per J.S.: "brightness fluctuates until everything is ready". A slow pulse rather than a
   spinner — the button is not doing something separate from the page, it IS the thing that is
   not ready yet, and it says so in words as well.

   `prefers-reduced-motion` turns the pulse off and leaves the button plainly dimmed: a
   vestibular trigger is not a reasonable price for a progress hint, and the word "Uploading…"
   carries the meaning on its own. */
.btn.is-uploading {
  cursor: progress; opacity: .72;
  animation: mpm-uploading 1.6s ease-in-out infinite;
}
@keyframes mpm-uploading {
  0%, 100% { opacity: .55; }
  50%      { opacity: .92; }
}
@media (prefers-reduced-motion: reduce) {
  .btn.is-uploading { animation: none; opacity: .6; }
}
/* A disabled button still has to look like the practice's button, not the browser's. */
.btn[disabled] { pointer-events: none; }

/* A directory provider chosen inside a repeater row — the care team.
   The match list is positioned relative to the row's cell so it drops under the input it
   belongs to rather than under the whole card. */
.rep-provider { position: relative; }
.rep-matches { position: absolute; left: 0; right: 0; top: 100%; z-index: 5;
               background: #fff; border: 1px solid var(--line); border-radius: var(--r-field);
               box-shadow: var(--shadow); max-height: 14rem; overflow-y: auto; }
.rep-linked { display: block; font-size: var(--step--1); color: var(--ok); font-weight: 600;
              margin-top: .15rem; }
.rep-nomatch { font-size: var(--step--1); color: var(--ink-3); padding: .5rem .7rem; margin: 0; }
.rep-nomatch.rep-searchfail { color: var(--warn); font-weight: 600; }

/* The directory's specialty, after a matched provider's name.
   Per J.S., 2026-08-22: "we need to know their specialty after their name." A matched row hides
   the editable specialty box, because it is our confirmed record rather than something to retype
   — so this is the only place the answer appears, and a bare name does not say which doctor. */
.rep-spec, .provider-spec {
  font-size: var(--step--1);
  color: var(--ink-3);
  margin: .15rem 0 0;
}
.rep-spec { margin-left: .5rem; }

/* A sentence the practice is saying, not a question. Set apart from the questions around it so
   nobody looks for a control that is not there — added 2026-08-22 with the `note` field type,
   which replaced an "I understand…" check box in the imaging section. */
.f-note {
  border-left: 3px solid var(--gold-deep, #B5912C);
  padding: .1rem 0 .1rem .9rem;
  margin: .2rem 0 .6rem;
}
.f-note .note-say { margin: 0; font-weight: 600; }
.f-note .note-sub { margin: .25rem 0 0; color: var(--ink-3, #6E6167); font-size: .9375rem; }

/* ================= Responsive QA audit, 2026-08-23 — patient-facing ==================
   Sections 3, 4 and 7. Every selector below was confirmed to exist before a rule was written for
   it; the audit also names `.completion-actions`, which this codebase does not have — its
   equivalent is `.fail-actions`, and only the real one is styled. A rule for a class nobody emits
   is a rule nobody can find the effect of. */

@media (max-width: 30rem) {
  /* §3 — the masthead ate a third of a phone screen before the first question. */
  .masthead { padding: 1rem 1.1rem 1.15rem; }
  .masthead .eyebrow { margin-bottom: .2rem; }
  .masthead h1 { font-size: 1.5rem; line-height: 1.25; }

  /**
   * §3 — an uploaded file's row.
   *
   * Filename, status, document type, error and Remove were competing for one line, so a long
   * filename pushed Remove off the edge — the control a patient needs precisely WHEN something
   * has gone wrong with that file. Now the text stacks in one column and Remove keeps its own,
   * spanning the rows so it stays beside what it removes.
   */
  .file {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 2.75rem;
    align-items: center;
  }
  .file .name, .file .state, .file .doc-type, .file .file-err {
    grid-column: 1; min-width: 0; overflow-wrap: anywhere;
  }
  .file-remove { grid-column: 2; grid-row: 1 / span 4; align-self: center; }

  /* §4 — completion and failure actions, full width and stacked. Two buttons side by side on a
     narrow phone give each a target too small to hit accurately, and these are the last actions
     on the page. */
  .fail-actions { flex-direction: column; align-items: stretch; }
  .fail-actions .btn { width: 100%; justify-content: center; }

  /* §7 — a consent header and its signature tools. `.doc-meta` carries a document title that can
     be long and has no spaces to break at. */
  .doc-head, .sig-tools { flex-direction: column; align-items: flex-start; }
  .doc-meta { overflow-wrap: anywhere; }
  .sig-tools .btn { min-height: 44px; }

  /**
   * §7 — the checklist.
   *
   * The status ("Done", "Waiting on you") shared a row with the item name, so a long name pushed
   * the status out of view — and the status is the only reason a patient reads the list. It gets
   * its own row under the name, aligned past the tick.
   */
  .pl-item { display: grid; grid-template-columns: 1rem minmax(0, 1fr); align-items: start; }
  .pl-state { grid-column: 2; }
  .pl-group .btn { width: 100%; justify-content: center; }
}

/**
 * §3 — the processing card.
 *
 * It is shown while a submission is in flight, which is the worst moment for a patient to be
 * unable to read it. `dvh` rather than `vh` because a phone's address bar retracts during the
 * wait, and `overflow-y` because the card grows as steps report.
 */
.processing-card { width: 100%; max-height: calc(100dvh - 2rem); overflow-y: auto; }

/**
 * §4 — long provider and document text.
 *
 * A referring provider's practice name, an email address and a filename have no spaces to break
 * at. Without this one of them widens the whole page rather than wrapping, and the audit's rule
 * is to contain it at the component.
 */
.pm-name, .provider-match, .rep-spec, .provider-spec,
.doc-meta, .doc-mismatch-t, .f-note, .note-say, .note-sub,
.file .name, .file-err {
  min-width: 0; overflow-wrap: anywhere;
}

/* WHAT I GOT WRONG HERE, kept because the correction is the useful part. The audit names these
   in prose — "provider name and practice or specialty, provider email, referral notes, uploaded
   record filenames" — and I turned that prose straight into `.provider-name`, `.provider-email`,
   `.referral-notes` and three others. None of them is emitted by anything. Six rules that would
   have looked like coverage and done nothing, written directly beneath a comment saying not to do
   exactly that. The names above are the ones engine.js actually produces. */
