/* ==========================================================================
   TOKENS
   No web fonts. Amy's install makes no outbound calls at runtime, so the type
   comes from what Windows 11 already has: Segoe UI Variable ships in three
   optical cuts — Display for headings, Text for UI, Small for 12px meta — and
   using them by role is a real type system at zero network cost. Falls back to
   plain Segoe UI on Windows 10 and system-ui elsewhere. The explicit faces
   must lead the stack: ui-sans-serif resolves first on Windows and would
   silently defeat the optical sizing.

   Every contrast ratio below was computed, not eyeballed. Body text clears
   4.5:1 on both the page ground and white; control edges clear 3:1.
   Every colour in this file is a token, with one deliberate exception: the
   nine status tags are a self-contained semantic scale and keep their literal
   tint/ink pairs beside their measured ratios, where they can be read as a
   set rather than as eighteen more :root entries.
   ========================================================================== */
:root {
  /* ground + surfaces */
  --bg: #FAF9F7;            /* warm paper */
  --surface: #FFFFFF;
  --surface-2: #F6F4F1;     /* inset: table head, hover, code */

  /* ink */
  --text: #1C1B19;          /* 16.4:1 on --bg */
  --text-2: #6B6862;        /*  5.3:1 on --bg */
  --text-3: #767168;        /*  4.6:1 on --bg */
  --on-accent: #FFFFFF;     /*  9.1:1 on --accent */
  --on-brand-dim: rgba(255, 255, 255, 0.72);   /* 7.6:1 on --brand-navy */
  --good: #25612C;          /*  6.3:1 on --bg */

  /* edges */
  --border: #E7E3DD;        /* decorative hairlines */
  --border-2: #968D80;      /*  3.3:1 on white — control edges need 3:1 */

  /* accent */
  --accent: #0F4C75;        /*  8.6:1 on --bg */
  --accent-hover: #0C3E60;
  --accent-soft: rgba(15, 76, 117, 0.07);
  --focus: rgba(15, 76, 117, 0.18);
  --brand-navy: #0A3554;
  --brand-navy-hover: #072A43;  /* the lock screen's Sign in button, hovered */

  /* notice + danger */
  --notice-bg: #FDF3E2;
  --notice-border: #E3B87A; /* decorative hairline around the tint */
  --notice-edge: #B57C2A;   /*  3.3:1 on --notice-bg — the callout rule has to
                                 actually read, so it is not the hairline */
  --notice-text: #7A4E00;   /*  6.6:1 on --notice-bg */
  --danger: #9B2C22;        /*  7.2:1 on --bg */

  /* type */
  --font-display: "Segoe UI Variable Display", "Segoe UI", system-ui, sans-serif;
  --font-text: "Segoe UI Variable Text", "Segoe UI", system-ui, sans-serif;
  --font-small: "Segoe UI Variable Small", "Segoe UI", system-ui, sans-serif;

  /* space — 4px scale */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;

  /* widths — one centred container for the whole shell, and a narrower
     reading column for the public portal. --w-shell is deliberately wide:
     it centres the app on a large monitor without taking horizontal room
     away from Amy's 17-column case table at ordinary sizes. */
  --w-shell: 1600px;
  --w-content: 880px;

  /* shape */
  --r-control: 8px;
  --r-card: 12px;
  --shadow-raised: 0 1px 2px rgba(28, 27, 25, 0.04);
}

/* ==========================================================================
   BASE
   ========================================================================== */
* { box-sizing: border-box; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font-family: var(--font-text); font-size: 14px; line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4 {
  font-family: var(--font-display); line-height: 1.25; font-weight: 600;
}
h2 { font-size: 24px; letter-spacing: -0.012em; }
h3 { font-size: 20px; margin: var(--s5) 0 var(--s2); }
h4 { font-size: 16px; }
a { color: var(--accent); }
main { max-width: var(--w-shell); margin-inline: auto; padding: var(--s6); }

/* Focus. There is no focus style in the app today beyond the browser default;
   this is the single biggest accessibility win in the phase. */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn:focus-visible,
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--focus);
}

/* ==========================================================================
   SHELL — banner, header, nav, buttons, flash
   ========================================================================== */

/* The demo banner must stay the loudest thing on any page it appears on.
   Against the light header it reads louder than it did against the navy bar. */
.demo-banner {
  position: sticky; top: 0; z-index: 100;
  background: var(--notice-bg); color: var(--notice-text);
  border-bottom: 1px solid var(--notice-border);
  text-align: center; padding: 7px var(--s4);
  font-weight: 600; font-size: 13px;
}

/* Full-bleed bar, contained contents: the background and hairline run the
   whole width, but the wordmark and nav line up with the content column
   underneath. The padding resolves to --s6 at any width below --w-shell and
   grows past it, which is the same edge <main> computes from its auto
   margins. */
header {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s4);
  background: var(--surface); color: var(--text);
  border-bottom: 1px solid var(--border);
  padding-block: var(--s3);
  padding-inline: max(var(--s6), calc((100% - var(--w-shell)) / 2 + var(--s6)));
}
header h1 { margin: 0; font-size: 17px; letter-spacing: -0.01em; }
header h1 a { color: var(--text); text-decoration: none; }
header h1 a:hover { color: var(--accent); }
nav { display: flex; gap: var(--s2); align-items: center; }
.whoami {
  font-family: var(--font-small); font-size: 12px; color: var(--text-3);
  margin: 0 var(--s2);
}

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  height: 34px; padding: 0 14px;
  border: 1px solid var(--border-2); border-radius: var(--r-control);
  background: var(--surface); color: var(--text);
  font: inherit; font-size: 14px; font-weight: 500;
  text-decoration: none; cursor: pointer; white-space: nowrap;
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.btn:hover { background: var(--surface-2); }
.btn-primary {
  background: var(--accent); border-color: var(--accent); color: var(--on-accent);
}
.btn-primary:hover {
  background: var(--accent-hover); border-color: var(--accent-hover);
}
.btn-danger { background: var(--surface); border-color: var(--border-2); color: var(--danger); }
.btn-danger:hover { background: var(--surface-2); border-color: var(--danger); }

/* Nav links go quiet; the log-out button sits inside a form, so it keeps the
   ordinary bordered treatment and stays the one deliberate control up there. */
nav > .btn { border-color: transparent; background: transparent; color: var(--text-2); }
nav > .btn:hover { background: var(--surface-2); color: var(--text); }

/* Every flash the app sends looks the same today, including "Wrong name or
   PIN". A neutral ink notice is honest for all of them; adding real severity
   means categorising the flash() calls in app.py, which is a behaviour change
   (see todo.md). */
/* The flash sits outside <main>, so it needs main's box repeated to line up
   with the content underneath it once the shell is centred. */
.flash {
  max-width: calc(var(--w-shell) - (2 * var(--s6)));
  margin: var(--s4) auto 0;
  padding: 10px var(--s4);
  background: var(--surface-2);
  border: 1px solid var(--border-2);
  border-radius: var(--r-control);
  color: var(--text);
}

/* ==========================================================================
   FILTERS + CASE TABLE
   table.js reads #cases, tbody.rows, .filters select, #search, #row-count,
   th[data-sort], th.cellIndex and the sorted-asc/desc classes, and toggles
   row.style.display. So the table stays a real <table>, rows keep their
   default display, and column order and count are untouched. No CSS grid on
   rows, however tempting.
   ========================================================================== */
.filters {
  display: flex; flex-wrap: wrap; gap: var(--s2); align-items: center;
  margin-bottom: var(--s4);
}
.filters input[type="search"] { flex: 1 1 240px; }
.filters input, .filters select {
  height: 34px; padding: 0 10px;
  border: 1px solid var(--border-2); border-radius: var(--r-control);
  background: var(--surface); color: var(--text);
  font: inherit; font-size: 14px; font-weight: 400;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.row-count {
  margin-left: auto; color: var(--text-2);
  font-family: var(--font-small); font-size: 12px;
  font-variant-numeric: tabular-nums;
}

.table-wrap {
  overflow-x: auto; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r-card);
}
table {
  border-collapse: collapse; width: 100%; font-size: 13px;
  font-variant-numeric: tabular-nums;   /* dates and money line up in column */
}
th, td { padding: 0 12px; text-align: left; white-space: nowrap; }
th {
  height: 34px;
  background: var(--surface-2); color: var(--text-2); font-weight: 600;
  cursor: pointer; user-select: none;
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 1;   /* opaque, so rows pass underneath */
}
th.sorted-asc::after { content: " ▲"; font-size: 0.7em; color: var(--accent); }
th.sorted-desc::after { content: " ▼"; font-size: 0.7em; color: var(--accent); }

/* Hairline separators, not zebra stripes. nth-child(even) counts rows the
   search has hidden, so today's stripes scramble after a filter. */
tbody td { height: 40px; border-top: 1px solid var(--border); }
tbody tr:hover { background: var(--accent-soft); }
td.num, th.num { text-align: right; }
td.notes { max-width: 220px; overflow: hidden; text-overflow: ellipsis; }
.redo-cell { color: var(--danger); font-weight: 600; }
.submitter { color: var(--text-3); font-size: 0.85em; }

/* Row actions stay quiet until the row is hovered. The :not(.btn) matters —
   the referrer case list puts real buttons in this same cell, and they must
   keep their button treatment. */
.row-actions { white-space: nowrap; }
.row-actions a:not(.btn), .row-actions .linklike {
  margin-right: 10px; color: var(--text-3); text-decoration: none;
  font-family: var(--font-small); font-size: 12px;
}
tbody tr:hover .row-actions a:not(.btn),
tbody tr:hover .row-actions .linklike {
  color: var(--accent); text-decoration: underline;
}

/* ==========================================================================
   STATUS TAGS
   Nine meanings, seven hues, one construction: a pale tint carrying its own
   hue's ink. Report status and payment status sit in different columns, so
   received/invoiced and sent/paid can share a hue without ambiguity. Every
   pairing clears 4.5:1.
   ========================================================================== */
.tag {
  display: inline-block; padding: 2px 9px; border-radius: 999px;
  font-family: var(--font-small); font-size: 12px; font-weight: 500;
  white-space: nowrap;
}
.tag-received { background: #FBF0DC; color: #7A4E00; }   /* 6.4:1 */
.tag-assigned { background: #F0EBFA; color: #553094; }   /* 8.0:1 */
.tag-draft    { background: #E4EDF7; color: #14507F; }   /* 7.2:1 */
.tag-review   { background: #FAF3D6; color: #6B5400; }   /* 6.5:1 */
.tag-final    { background: #DFF0EF; color: #14615E; }   /* 6.2:1 */
.tag-sent     { background: #E2F0E1; color: #25612C; }   /* 6.3:1 */
.tag-unpaid   { background: #FAE4E1; color: #96261F; }   /* 6.7:1 */
.tag-invoiced { background: #FBF0DC; color: #7A4E00; }   /* 6.4:1 */
.tag-paid     { background: #E2F0E1; color: #25612C; }   /* 6.3:1 */

/* ==========================================================================
   SUMMARY
   ========================================================================== */
.summary-totals {
  display: flex; gap: var(--s3); flex-wrap: wrap; margin: var(--s2) 0 var(--s5);
}
.stat {
  min-width: 132px; padding: var(--s3) var(--s4);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-control);
  font-family: var(--font-small); font-size: 12px; color: var(--text-2);
}
.stat-n {
  display: block; font-family: var(--font-display); font-size: 24px;
  font-weight: 600; color: var(--text); letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.summary-table { max-width: 720px; }
.summary-controls input[type="date"] { background: var(--surface); }
.fee-label {
  display: inline-flex; flex-direction: column; gap: var(--s1);
  font-family: var(--font-small); font-size: 12px; color: var(--text-2);
}
.case-tools { align-items: center; flex-wrap: wrap; }
.linklike {
  background: none; border: none; padding: 0; color: var(--accent);
  text-decoration: underline; cursor: pointer; font: inherit;
}

.home-actions {
  display: flex; gap: var(--s3); flex-wrap: wrap; margin-bottom: var(--s5);
}
.big-action {
  flex: 1 1 0; max-width: 340px; padding: var(--s4) var(--s5);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-card); text-decoration: none;
  display: flex; flex-direction: column; gap: var(--s1);
  font-family: var(--font-small); font-size: 12px; color: var(--text-2);
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.big-action:hover { border-color: var(--accent); box-shadow: var(--shadow-raised); }
.big-action-title {
  font-family: var(--font-display); font-size: 17px; font-weight: 600;
  color: var(--accent);
}
.inline-form { display: inline-flex; gap: var(--s1); align-items: center; }
.inline-form input {
  padding: 0.35rem 0.5rem; border: 1px solid var(--border-2);
  border-radius: var(--r-control);
}
/* ==========================================================================
   AUTH PAGES — the local /login and the Settings PIN stages
   (the cloud lock screen is SIGN-IN, below)
   ========================================================================== */
/* Centred horizontally, and sat in the upper third rather than against the
   header — the top margin scales with the viewport so it holds that position
   on a laptop and a large monitor alike, and collapses on a short window. */
.login-box {
  max-width: 400px; padding: var(--s5);
  margin: clamp(var(--s5), 12vh, 128px) auto var(--s8);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-card); box-shadow: var(--shadow-raised);
  text-align: center;
}
/* Everything in the card centres except the form itself: a label reads as a
   left edge for the field under it, and centred labels over full-width inputs
   are hard to scan. */
.login-box label { text-align: left; }
.login-box input, .login-box select { text-align: left; }
.login-box .actions { justify-content: center; }
/* dxr_logo.jpg is a JPEG with a hard white background, which reads as a white
   box against the warm ground. Multiply drops the white into the page without
   needing a second asset — the mark itself is dark navy and is unaffected. */
.auth-logo {
  display: block; width: 168px; max-width: 100%; height: auto;
  margin: 0 auto var(--s5); mix-blend-mode: multiply;
}
.login-box h2 { margin: 0 0 var(--s5); font-size: 20px; }
.login-box label {
  display: flex; flex-direction: column; gap: 6px; margin-bottom: var(--s4);
  font-size: 13px; font-weight: 500; color: var(--text-2);
}
.login-box input, .login-box select {
  height: 36px; padding: 0 10px;
  border: 1px solid var(--border-2); border-radius: var(--r-control);
  background: var(--surface); color: var(--text);
  font: inherit; font-size: 14px; font-weight: 400;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.login-box .actions { margin-top: var(--s5); }
.edit-meta {
  color: var(--text-2); font-family: var(--font-small); font-size: 12px;
  font-weight: 400;
}
.settings-table { max-width: 640px; margin-bottom: var(--s4); }
.about {
  max-width: 760px; background: var(--surface); padding: var(--s5);
  border-radius: var(--r-card); border: 1px solid var(--border);
}
/* The About table is a key/value list, not a data grid — it opts out of the
   sticky header, the row height and the nowrap. */
.kv th {
  height: auto; padding: 6px var(--s4) 6px 0; white-space: nowrap;
  background: none; border: none; position: static; cursor: default;
  vertical-align: top; color: var(--text-2);
}
.kv td { height: auto; padding: 6px 0; white-space: normal; word-break: break-all; }
.kv code {
  background: var(--surface-2); padding: 1px 5px; border-radius: 4px;
  font-size: 12px;
}

/* ==========================================================================
   CASE FORM
   Field order and attribute order are untouched: smoke_phase14 matches
   name="patient_age" and name="date_of_birth" with regexes that depend on
   attribute order inside the tag.
   ========================================================================== */
.case-form {
  max-width: 860px; background: var(--surface); padding: var(--s5);
  border-radius: var(--r-card); border: 1px solid var(--border);
}
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s4); }
.case-form label {
  display: flex; flex-direction: column; gap: 6px;
  font-size: 13px; font-weight: 500; color: var(--text-2);
}
.case-form input, .case-form select, .case-form textarea {
  height: 36px; padding: 0 10px;
  border: 1px solid var(--border-2); border-radius: var(--r-control);
  background: var(--surface); color: var(--text);
  font: inherit; font-size: 14px; font-weight: 400;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}
.case-form textarea {
  height: auto; padding: 8px 10px; resize: vertical; line-height: 1.5;
}
.case-form input[type="file"] { height: auto; padding: 7px 10px; font-size: 13px; }
.case-form > label { margin-top: var(--s4); }
.actions {
  margin-top: var(--s5); display: flex; gap: var(--s2);
  align-items: center; flex-wrap: wrap;
}
.delete-form { margin-top: var(--s5); }

@media (max-width: 860px) { .grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px) {
  .grid { grid-template-columns: 1fr; }
  main { padding: var(--s4); }
  .flash { margin: var(--s3) var(--s4) 0; }
  header { padding: var(--s3) var(--s4); }
}

/* ==========================================================================
   LANDING PAGE
   Centre-aligned. The hero, the section heading, each step, and the CTA strip
   all centre their contents; the two panels keep their text ranged left,
   because a bulleted list is read rather than announced, while the pair of
   them still sits centred as a block.
   ========================================================================== */
.btn-lg { height: 42px; padding: 0 22px; font-size: 15px; }

/* The column is centred in the viewport; the rules below centre the contents
   inside it. Blocks with their own max-width need auto side margins as well —
   text-align alone does not move a constrained block. */
.hero, .steps, .panels, .cta-strip, .site-foot {
  max-width: var(--w-content);
  margin-inline: auto;
}

.hero { margin-block: var(--s6) var(--s7); text-align: center; }
.hero-logo {
  display: block; width: 260px; max-width: 100%; height: auto;
  margin: 0 auto var(--s5); mix-blend-mode: multiply;   /* see .auth-logo */
}
.hero h2 {
  max-width: 620px; margin: 0 auto var(--s4);
  font-size: 36px; line-height: 1.15; letter-spacing: -0.018em;
  text-wrap: balance;
}
.hero-lead {
  max-width: 60ch; margin: 0 auto var(--s5);
  font-size: 17px; line-height: 1.55; color: var(--text-2);
}
.hero-actions {
  display: flex; gap: var(--s3); flex-wrap: wrap; justify-content: center;
}
.hero-sub {
  margin: var(--s4) 0 0; color: var(--text-3);
  font-family: var(--font-small); font-size: 12px;
}

.section-title { margin: 0 0 var(--s5); font-size: 20px; text-align: center; }
.steps { margin-block: 0 var(--s7); }
.step-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s5); }
/* The three steps are a real sequence, so the numbering earns its place — but
   the numeral carries it, set large and light, instead of a filled badge. */
.step { background: none; border: none; padding: 0; text-align: center; }
.step-n {
  display: block; margin-bottom: var(--s2);
  font-family: var(--font-display); font-size: 34px; font-weight: 300;
  line-height: 1; color: var(--accent); font-variant-numeric: tabular-nums;
}
.step h4 { margin: 0 0 var(--s1); font-size: 16px; }
.step p { margin: 0; color: var(--text-2); line-height: 1.55; font-size: 14px; }

.panels {
  margin-block: 0 var(--s7);
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4);
}
.panel {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-card); padding: var(--s5);
}
.panel h4 { margin: 0 0 var(--s3); font-size: 16px; }
.panel ul { margin: 0; padding-left: 18px; color: var(--text-2); line-height: 1.7; }

/* The navy strip is the one place brand colour carries a whole block, so the
   button inverts to white — the accent on navy would be unreadable. */
.cta-strip {
  margin-block: 0 var(--s6); padding: var(--s6);
  background: var(--brand-navy); color: var(--on-accent);
  border-radius: var(--r-card); text-align: center;
}
.cta-strip h3 { margin: 0 0 var(--s1); font-size: 24px; color: var(--on-accent); }
.cta-strip p { margin: 0 0 var(--s5); color: var(--on-brand-dim); }
.cta-strip .btn-primary {
  background: var(--on-accent); border-color: var(--on-accent);
  color: var(--brand-navy);
}
.cta-strip .btn-primary:hover {
  background: var(--surface-2); border-color: var(--surface-2);
}

.site-foot {
  padding: var(--s5) 0 var(--s7);
  border-top: 1px solid var(--border);
  color: var(--text-2); font-size: 13px; line-height: 1.6;
}
.foot-contact { color: var(--text-3); }

@media (max-width: 800px) {
  .step-grid, .panels { grid-template-columns: 1fr; }
  .hero h2 { font-size: 28px; }
  .cta-strip { padding: var(--s5); }
}

/* Phase 14: anonymized-scan warnings on the case form. A heavier left edge so
   it reads as a callout rather than another card, and it keeps the notice
   amber so it stays as loud as the DEMO banner's family. */
.case-warning {
  max-width: 860px; margin-bottom: var(--s4); padding: 10px var(--s4);
  background: var(--notice-bg); color: var(--notice-text);
  border: 1px solid var(--notice-border);
  border-left: 3px solid var(--notice-edge);
  border-radius: var(--r-control);
}
.case-warning ul { margin: 6px 0 0; padding-left: 18px; }
.case-warning li { margin: 2px 0; }

/* Phase 13C / 16: admin view of portal accounts */
.wide-settings-table { max-width: 900px; }

/* ==========================================================================
   REFERRER CASE LIST + DETAIL
   ========================================================================== */
/* Both referrer pages centre their column. The heading and the table are
   siblings in <main>, so the sibling combinator carries the width across
   without needing a wrapper — this phase changes no markup. */
.my-cases-head,
.my-cases-head ~ .table-wrap,
.my-cases-head ~ .edit-meta {
  max-width: var(--w-content); margin-inline: auto;
}
.my-cases-head {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--s3); margin-bottom: var(--s4);
}
.my-cases-head h2 { margin: 0; }
.pstatus {
  display: inline-block; padding: 2px 9px; border-radius: 999px;
  font-family: var(--font-small); font-size: 12px; font-weight: 600;
  white-space: nowrap;
}
.pstatus-progress { background: #E4EDF7; color: #14507F; }   /* 7.2:1 */
.pstatus-ready    { background: #E2F0E1; color: #25612C; }   /* 6.3:1 */

/* An empty case list is an invitation to act, so the action is the loudest
   thing in it. */
.empty-state {
  max-width: 560px; margin: var(--s6) auto; padding: var(--s8) var(--s5);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-card); text-align: center;
}
.empty-state p { margin: 0 0 var(--s5); color: var(--text-2); }

/* The "← All your cases" link is a direct child of <main>, above the card, so
   it is matched by what the page contains rather than by a class base.html
   does not carry. Without this the link floats at the far left of a centred
   card. */
main:has(.case-detail) > .edit-meta { max-width: 720px; margin-inline: auto; }
.case-detail {
  max-width: 720px; margin-inline: auto; padding: var(--s5);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-card);
}
.case-detail-head {
  display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap;
}
.case-detail-head h2 { margin: 0; }
/* These read as field labels, not headings, so they take the UI face. */
.case-detail h3 {
  margin: var(--s5) 0 var(--s1);
  font-family: var(--font-text); font-size: 13px; font-weight: 600;
  color: var(--text-2);
}
.ready-note { margin-bottom: var(--s3); color: var(--good); font-weight: 600; }

/* ==========================================================================
   SUBMISSION PORTAL
   ========================================================================== */
.portal-note {
  padding: 10px var(--s4); border-radius: var(--r-control);
  background: var(--notice-bg); color: var(--notice-text);
  border: 1px solid var(--notice-border);
  border-left: 3px solid var(--notice-edge);
}
/* /submit is a portal page, so it sits in the portal's centred column rather
   than left-aligned the way the internal case form does. */
.submit-form { max-width: var(--w-content); margin-inline: auto; }
/* The four numbered parts get a rule under each heading, so a busy front desk
   can see where one part ends and the next begins. */
.submit-form h3 {
  margin: var(--s6) 0 var(--s3); padding-bottom: var(--s2);
  font-size: 16px; border-bottom: 1px solid var(--border);
}
.reason-row {
  display: flex; align-items: center; gap: var(--s3); margin: var(--s1) 0;
}
.reason-check {
  flex-direction: row !important; align-items: center; gap: var(--s2);
  font-size: 14px !important; font-weight: 400 !important;
  color: var(--text) !important;
}
.reason-row input[type="text"], .reason-row input:not([type]) {
  flex: 1 1 220px; max-width: 320px;
}
.hp-field { position: absolute; left: -9999px; top: -9999px; }

.confirm-box { text-align: center; }
/* The one place a monospace face earns its keep: this is the number the
   office quotes back to the clinic, so the digits have to be unambiguous. */
.ref-number {
  font-family: Consolas, "Cascadia Mono", monospace;
  font-size: 24px; font-weight: 700; letter-spacing: 0.05em;
  color: var(--accent);
}

.referral-info {
  max-width: 860px; margin-top: var(--s4); padding: var(--s4) var(--s5);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-card);
}
.referral-info h3 { margin: 0 0 var(--s2); font-size: 16px; }

/* ==========================================================================
   Motion is hover and focus only, and never required to understand a page.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ==========================================================================
   SIGN-IN — the cloud lock screen (Phase 16, templates/signin.html)
   One centred card and nothing else on the page.
   ========================================================================== */
.signin-main {
  min-height: 100vh; min-height: 100dvh;
  display: grid; place-items: center;
  padding: var(--s5) var(--s4);
}
.signin-card {
  width: 100%; max-width: 380px; padding: var(--s6) var(--s5) var(--s5);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-card); box-shadow: var(--shadow-raised);
  text-align: center;
}
/* The tooth mark only. dxr_logo.jpg is the full lockup — tooth plus the words
   DENTAL X-RAY REPORTS — and the wordmark is set in text underneath, so the box
   is cut to the tooth's proportions (about 660 x 826 of the 1280 x 826 file)
   and the image is anchored left. One asset, no derived copy to keep in step.
   The card is pure white, the JPEG's ground, so no blend mode is needed. */
.signin-mark {
  width: 76px; aspect-ratio: 660 / 826; margin: 0 auto var(--s4);
  overflow: hidden;
}
.signin-mark img {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: left center;
}
.signin-wordmark {
  margin: 0 0 var(--s5); font-family: var(--font-display);
  font-size: 22px; font-weight: 600; letter-spacing: -0.01em;
  color: var(--text);
}
.signin-message {
  margin: 0 0 var(--s4); padding: var(--s2) var(--s3);
  border-radius: var(--r-control); background: var(--notice-bg);
  color: var(--notice-text); font-size: 13px; text-align: left;
}
.signin-form { text-align: left; }
.signin-form label {
  display: flex; flex-direction: column; gap: 6px; margin-bottom: var(--s4);
  font-size: 13px; font-weight: 500; color: var(--text-2);
}
.signin-form input {
  height: 40px; padding: 0 12px;
  border: 1px solid var(--border-2); border-radius: var(--r-control);
  background: var(--surface); color: var(--text);
  font: inherit; font-size: 15px; font-weight: 400;
}
.signin-form input:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--focus);
}
.signin-button {
  display: block; width: 100%; height: 42px; margin-top: var(--s2);
  border: 0; border-radius: var(--r-control);
  background: var(--brand-navy); color: var(--on-accent);
  font: inherit; font-size: 15px; font-weight: 600; cursor: pointer;
  transition: background 120ms ease;
}
.signin-button:hover { background: var(--brand-navy-hover); }
.signin-button:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
.signin-note {
  margin: var(--s3) 0 0; font-family: var(--font-small); font-size: 12px;
  color: var(--text-3);
}
.signin-note:first-of-type { margin-top: var(--s5); }

/* --- Phase 17: the chunked scan uploader -----------------------------------
   Existing tokens only, so the contrast audit's pair list is unchanged. The
   panel is the one place the page tells the user the tab must stay open, so it
   reads as a notice rather than as decoration. */
.scan-upload {
  margin-top: var(--s3); padding: var(--s3) var(--s4);
  border: 1px solid var(--notice-border); border-left: 3px solid var(--notice-edge);
  border-radius: var(--r-control); background: var(--notice-bg);
}
.scan-upload-say { margin: 0; color: var(--notice-text); font-size: 14px; }
.scan-upload-done { margin: 0; color: var(--good); font-size: 14px; }
.scan-upload-error {
  margin: 0 0 var(--s2); color: var(--danger); font-size: 14px; font-weight: 600;
}
.scan-upload-file {
  margin: var(--s2) 0 0; font-family: var(--font-small); font-size: 13px;
  color: var(--text-2);
}
.scan-upload-track {
  height: 8px; margin-top: var(--s2); overflow: hidden;
  border-radius: 4px; background: var(--surface-2);
}
.scan-upload-bar {
  width: 0; height: 100%; background: var(--accent);
  transition: width 200ms ease;
}
.scan-upload-meta {
  margin: var(--s2) 0 0; font-family: var(--font-small); font-size: 12px;
  color: var(--text-2);
}
/* A completed upload is a different state, not a full bar — the operator
   ruling of 2026-09-21 asks for it to be visibly distinct. */
.scan-upload:has([data-upload="uploaded"]:not([hidden])) {
  border-color: var(--border); border-left-color: var(--good);
  background: var(--surface-2);
}
