/* RareCare clinician workstation — design system.
   Light clinical surface; motion is quiet, fast, and always ease-out.
   Only transform + opacity are animated; every transition names its
   properties. */

:root {
  /* WHITE IS THE GROUND, not an off-white a shade below it. The page used
     #f7f6f4 with warm-stone neutrals on top, which reads as grey-beige next
     to the white cards sitting on it: the cards looked lit and the page
     looked dim. Separation is carried by hairlines and shadow instead of a
     tonal step, and the neutrals are cool rather than warm so nothing on the
     page pulls the white towards cream. */
  --bg: #ffffff;
  --surface: #ffffff;
  --surface-2: #f6f8fa;
  --ink: #16181b;
  --ink-2: #3c4046;
  --muted: #676c73;
  /* Still below the 3:1 WCAG minimum for a UI control and the 4.5:1 for
     text, on glyphs that WRITE EVIDENCE with one tap. Kept for genuinely
     decorative marks; --faint-text is the token for anything a clinician has
     to read or press in bright ward light. */
  --faint: #9ba1a8;             /* 2.8:1 — decorative marks only */
  --faint-text: #5f646b;        /* 6.0:1 on --surface */
  /* The only thing separating a white card from a white page, so it carries
     more weight here than it did over a tinted ground. */
  --line: #e4e7ec;
  --line-strong: #d3d7dd;
  --tick: #d3d7dd;      /* peer ticks on the candidate scale */

  --accent: #0f766e;
  --accent-ink: #ffffff;
  --accent-soft: #ccfbf1;
  --accent-text: #0d5d56;

  --ok: #047857;      --ok-soft: #d1fae5;
  --warn: #b45309;    --warn-soft: #fef3c7;
  --danger: #b91c1c;  --danger-soft: #fee2e2;
  --absent: #475569;  --absent-soft: #e2e8f0;

  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  /* ONE CONTROL HEIGHT. A text input, a date input, a select and a segmented
     control each derive their height differently and land 36-42px apart; the
     only way they stay a set is by being told. */
  --control-h: 42px;

  --r-sm: 7px;
  --r-md: 10px;
  --r-lg: 14px;

  /* HOW WIDE A PARAGRAPH IS ALLOWED TO GET.
     Measured, not guessed: the explanation on "What to do next" ran to 129
     characters a line on a 1920 monitor and the conditions lede to 103, over
     five and six lines. Past about 90 the eye loses the return sweep and
     re-reads the line it just left, which on a screen full of warnings about
     a child is the wrong thing to make somebody do.
     Applied to PROSE only — ledes, notices, explanations. Not to labels,
     rows or anything in a table: a heading that wraps early looks broken,
     and a column that stops short of its own card looks like a bug rather
     than a measure. The cards keep their width; the sentences inside them
     stop sooner. */
  --measure: 60ch;    /* ~78 rendered characters: `ch` is the width of "0",
                         which is wider than this face's average letter, so
                         the token reads about 1.3x what it renders. Set by
                         measuring, not by arithmetic. */
  --shadow-sm: 0 1px 2px rgba(17, 24, 39, 0.05);
  --shadow-md: 0 4px 16px -2px rgba(17, 24, 39, 0.09), 0 2px 4px rgba(17, 24, 39, 0.05);
  --shadow-lg: 0 12px 40px -8px rgba(17, 24, 39, 0.16), 0 4px 12px rgba(17, 24, 39, 0.06);

  /* The administrative palette. These screens are about accounts rather than
     care and should not look like a patient record, but the cool wash they
     used to carry is gone: the ground is white here like everywhere else.
     The distinction now lives in the LINE colour, which keeps its green cast,
     so an administrative card still does not read as a clinical one.
     Defined at :root rather than on .op-app since the organisation and
     oversight screens share the cards. */
  --op-bg: #ffffff;
  --op-line: #dfeae8;
  --op-line-soft: #eef4f3;
  --op-ink-soft: #5c6b68;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html { -webkit-text-size-adjust: 100%; }

body {
  overflow-x: hidden;          /* the shell owns its own scrolling regions */
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI",
    Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

::selection { background: var(--accent-soft); color: var(--accent-text); }

button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
input, select, textarea { font: inherit; color: inherit; }

:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

.num { font-variant-numeric: tabular-nums; }

/* ---------- buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 14px;
  /* A FLOOR, because padding alone does not give one. With a smaller font —
     the "Edit" button in the patient aside, which only renders from 1240px
     up — 7px of padding came to a 23px box, one pixel under the minimum this
     suite has used since it was written. A floor here catches every button
     at once rather than each one as it is noticed. */
  min-height: 24px;
  border-radius: var(--r-sm);
  font-weight: 500;
  white-space: nowrap;
  user-select: none;
  transition: transform 140ms var(--ease-out), background-color 120ms ease,
    border-color 120ms ease, color 120ms ease, opacity 120ms ease;
}
.btn:active { transform: scale(0.97); }
.btn[disabled] { opacity: 0.45; pointer-events: none; }

.btn-primary { background: var(--accent); color: var(--accent-ink); }
.btn-ghost { color: var(--ink-2); border: 1px solid var(--line-strong); background: var(--surface); }
.btn-subtle { color: var(--muted); }
.btn-danger-ghost { color: var(--danger); border: 1px solid var(--line-strong); background: var(--surface); }

@media (hover: hover) and (pointer: fine) {
  .btn-primary:hover { background: #0b5f59; }
  .btn-ghost:hover { background: var(--surface-2); border-color: var(--faint); }
  .btn-subtle:hover { color: var(--ink); background: var(--surface-2); }
  .btn-danger-ghost:hover { background: var(--danger-soft); border-color: var(--danger); }
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  border-radius: 6px;
  color: var(--faint);
  transition: transform 140ms var(--ease-out), background-color 120ms ease, color 120ms ease;
}
.icon-btn:active { transform: scale(0.94); }
.icon-btn[data-on="true"] { color: var(--accent-text); background: var(--accent-soft); }
@media (hover: hover) and (pointer: fine) {
  .icon-btn:hover { color: var(--ink-2); background: var(--surface-2); }
  .icon-btn[data-on="true"]:hover { color: var(--accent-text); background: var(--accent-soft); }
}

/* ---------- inputs ---------- */

/* ONE INPUT, EVERYWHERE. The modals were rebuilt with a 40px control on a
   10px radius; the caseload kept the original 7px box, so the two halves of
   the same product had two different text fields — and the one a clinician
   uses all day was the smaller, tighter one.

   The height is stated rather than inherited: a text input, a date input and
   a select derive their content height three different ways and land 38, 40
   and 36 pixels apart otherwise. */
.field {
  width: 100%;
  box-sizing: border-box;
  min-height: var(--control-h);
  padding: 9px 12px;
  line-height: 22px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  transition: border-color 130ms ease, box-shadow 130ms ease,
    background-color 130ms ease;
}
/* A FLOOR IS NOT ENOUGH FOR A DATE INPUT. Its calendar-picker chrome makes
   the intrinsic content taller than the min-height, so it came out 44 beside
   its neighbours' 42. Single-line controls get a stated height; a textarea
   keeps its own. */
input.field, select.field { height: var(--control-h); }
.field:hover:not(:disabled):not(:focus) { border-color: var(--tick); }
.field:focus-visible, .field:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(15, 118, 110, 0.14);
}
/* --faint is 2.42:1 on white. A placeholder is instructions for an empty
   field — the one moment the field has nothing else to say. */
.field::placeholder { color: var(--faint-text); opacity: 1; }
.field:disabled { background: var(--surface-2); color: var(--faint-text); cursor: not-allowed; }

textarea.field {
  resize: vertical; min-height: 132px; line-height: 1.6;
  padding: 12px 14px;
}

/* The icon wrapper, shared with the modals rather than reimplemented: same
   markup, same metrics, one place to change. */
.input-wrap { position: relative; display: block; }
.input-wrap .field { width: 100%; }
.input-wrap.has-icon .field { padding-left: 40px; }
.input-wrap-icon {
  position: absolute; left: 13px; top: 50%; transform: translateY(-50%);
  display: grid; place-items: center;
  color: var(--faint-text); pointer-events: none;
  transition: color 130ms ease;
}
.input-wrap-icon svg { width: 16px; height: 16px; }
.input-wrap:focus-within .input-wrap-icon { color: var(--accent); }

label.lbl {
  display: block;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 5px 1px;
}

/* ---------- login ---------- */
/* The first screen anyone sees, and the only one they see before trusting
   the thing with a child's record. It is reached roughly once a day, which
   under the frequency rule is exactly the band where an entrance animation
   earns its place: often enough to feel considered, rare enough that it
   never becomes a delay someone is waiting through. Everything here is
   transform + opacity, and the whole lot collapses under reduced motion. */

.login-wrap {
  position: relative;
  isolation: isolate;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 28px 24px;
  overflow: hidden;
  background: linear-gradient(180deg, #ffffff 0%, #ffffff 58%, #f5f7fa 100%);
}

/* A hairline grid, masked to a soft ellipse so it never reaches an edge and
   turns into a pattern. It reads as drafting paper: structure, not ornament. */
.login-wrap::before {
  content: '';
  position: absolute;
  inset: -10%;
  z-index: -2;
  background-image:
    linear-gradient(rgba(28, 25, 23, 0.03) 1px, transparent 1px),
    linear-gradient(90deg, rgba(28, 25, 23, 0.03) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: radial-gradient(ellipse 76% 62% at 50% 42%, #000 32%, transparent 78%);
  mask-image: radial-gradient(ellipse 76% 62% at 50% 42%, #000 32%, transparent 78%);
}

/* Two slow blooms in the product's own teal, with one warm counterweight so
   the field is not a single flat tint. 34s and barely any travel: at any one
   moment it is a still image, which is the point — atmosphere, not motion. */
.login-wrap::after {
  content: '';
  position: absolute;
  inset: -25%;
  z-index: -1;
  background:
    radial-gradient(38% 42% at 20% 24%, rgba(15, 118, 110, 0.14), transparent 68%),
    radial-gradient(34% 40% at 84% 72%, rgba(180, 83, 9, 0.07), transparent 66%),
    radial-gradient(30% 34% at 70% 12%, rgba(15, 118, 110, 0.07), transparent 70%);
  filter: blur(14px);
  animation: login-drift 34s ease-in-out infinite alternate;
  will-change: transform;
}
@keyframes login-drift {
  from { transform: translate3d(-1.4%, -1%, 0) scale(1); }
  to   { transform: translate3d(1.4%, 1.4%, 0) scale(1.06); }
}

.login-stage {
  width: min(1000px, 100%);
  display: grid;
  gap: 40px;
  grid-template-columns: minmax(0, 428px);
  justify-content: center;
  align-items: center;
}
@media (min-width: 960px) {
  .login-stage { grid-template-columns: 428px minmax(0, 1fr); gap: 68px; }
}

.login-card {
  position: relative;
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: 34px 32px 28px;
  /* three layers, not one: a contact shadow that keeps the edge crisp, a
     mid shadow for lift, and a wide soft one for depth. A single box-shadow
     always reads as either flat or muddy. */
  box-shadow:
    0 1px 2px rgba(28, 25, 23, 0.04),
    0 8px 24px -6px rgba(28, 25, 23, 0.08),
    0 28px 60px -18px rgba(28, 25, 23, 0.16);
}

/* .brand is shared with the shell topbar, so it lives here in full. Deleting
   it while restyling the login screen took the topbar's layout with it — the
   mark and the wordmark stacked instead of sitting side by side. */
.brand { display: flex; align-items: center; gap: 10px; }
/* SIZED BY CLASS, not by three different inline styles overriding this one.
   The mark was 30px here, 28px on the sign-in card and 24px in two topbars,
   each written at the call site, so it was impossible to see that they
   disagreed without opening four files. */
.brand-mark {
  width: 30px; height: 30px;
  border-radius: 9px;
  display: grid; place-items: center;
  color: #fff;
  background: linear-gradient(145deg, #15897f 0%, #0b5f59 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
/* THE GLYPH IS SIZED BY ITS TILE. `ICONS.brand` carries width="34"
   height="34" in the markup, and the tiles are 26, 30 and 38px — so
   everywhere except the login card a 34px drawing sat in a 30px box, hung
   over the edges and was clipped by the rounded corner. It read as a
   different, broken mark. 42% is the ratio the login card was already using
   (16 of 38) and the same one the app icon is generated at. */
.brand-mark svg { width: 42%; height: 42%; }
/* Only the login mark gets the lift; at 24px in a topbar it would just be
   a smudge. */
.login-card .brand-mark {
  width: 38px; height: 38px;
  border-radius: 11px;
  box-shadow:
    0 1px 2px rgba(11, 95, 89, 0.32),
    0 6px 16px -5px rgba(11, 95, 89, 0.42),
    inset 0 1px 0 rgba(255, 255, 255, 0.22);
}
/* (was `width: 16px` — 42% of 38 is 15.96, so the rule above covers it) */
.brand-name { font-size: 17px; font-weight: 650; letter-spacing: -0.012em; }
.brand-sub { color: var(--muted); font-size: 12.5px; margin-top: 2px; }

/* The pane's own heading. Without it every pane opened with a bare form and
   the person had to infer from the field labels which one they were on. */
.login-head { margin-top: 26px; }
.login-title {
  font-size: 21px; font-weight: 640;
  letter-spacing: -0.02em; line-height: 1.25;
  text-wrap: balance;
}
.login-lede {
  margin-top: 6px;
  font-size: 13px; line-height: 1.5;
  color: var(--muted);
  text-wrap: pretty;
}
.login-head + .login-form { margin-top: 20px; }

.login-users { display: grid; gap: 8px; margin-top: 22px; }
.user-card {
  display: flex; align-items: center; gap: 12px;
  text-align: left;
  padding: 11px 13px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  transition: transform 140ms var(--ease-out), border-color 120ms ease,
    background-color 120ms ease, box-shadow 140ms ease;
}
.user-card:active { transform: scale(0.98); }
@media (hover: hover) and (pointer: fine) {
  .user-card:hover {
    border-color: var(--line-strong);
    background: var(--surface-2);
    box-shadow: var(--shadow-sm);
  }
}
.avatar {
  width: 32px; height: 32px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 12px; font-weight: 650;
  background: var(--accent-soft); color: var(--accent-text);
  flex: none;
}
.user-card .u-name { font-weight: 550; }
.user-card .u-role { font-size: 12px; color: var(--muted); }

/* --faint is 2.42:1 on white. This is a sentence explaining how to get in,
   read in ward light, so it takes the token that is legible. */
.login-note {
  margin-top: 20px; padding-top: 16px;
  border-top: 1px solid var(--line);
  font-size: 12px; line-height: 1.5;
  color: var(--faint-text); text-align: center;
  text-wrap: pretty;
}

.login-form { display: grid; gap: 16px; margin-top: 24px; }
.login-field { display: grid; gap: 6px; }
.login-label {
  font-size: 12.5px; font-weight: 600; color: var(--ink-2);
  transition: color 140ms ease;
}
/* The label follows focus, so the eye is told where it is without a border
   colour being the only signal — which colour-blind users may not get. */
.login-field:focus-within .login-label { color: var(--accent-text); }
.login-field .field {
  padding: 10px 12px;
  font-size: 14.5px;
  border-radius: 9px;
}
.login-hint { font-size: 11.5px; color: var(--faint-text); line-height: 1.45; }

.login-submit {
  width: 100%; justify-content: center;
  margin-top: 4px;
  padding: 12px 16px;
  font-size: 14.5px; font-weight: 550;
  border-radius: 9px;
  background: linear-gradient(180deg, #12857c 0%, #0f766e 100%);
  box-shadow:
    0 1px 2px rgba(11, 95, 89, 0.26),
    0 8px 20px -8px rgba(11, 95, 89, 0.5);
}
@media (hover: hover) and (pointer: fine) {
  .btn-primary.login-submit:hover { background: linear-gradient(180deg, #0f766e 0%, #0b5f59 100%); }
}
.login-submit[disabled] { opacity: 0.7; }

/* Reserves no space until it has something to say, so the form does not
   jump the first time a sign-in is refused. */
.login-error {
  font-size: 12.5px; line-height: 1.45;
  padding: 10px 12px;
  border: 1px solid var(--danger);
  border-radius: 9px;
  background: var(--danger-soft);
  color: var(--danger);
}
.login-error:not([hidden]) { animation: login-error-in 220ms var(--ease-out); }
@keyframes login-error-in {
  from { opacity: 0; transform: translateY(-5px); }
}

.login-links {
  display: flex; flex-wrap: wrap; gap: 4px 16px;
  justify-content: center;
  margin-top: 4px;
}
.link-btn {
  background: none; border: 0; padding: 3px 2px;
  font: inherit; font-size: 12.5px;
  color: var(--accent-text); cursor: pointer;
  border-radius: 4px;
  transition: color 120ms ease;
}
.link-btn:hover { text-decoration: underline; }

/* The column beside the card. It is not a sales pitch: every line is a
   property the system actually has, phrased the way a clinician would check
   it. Hidden below the breakpoint rather than stacked — on a phone the only
   thing wanted is the form. */
.login-aside { display: none; }
@media (min-width: 960px) { .login-aside { display: block; } }
.login-aside-title {
  font-size: 28px; font-weight: 620;
  letter-spacing: -0.026em; line-height: 1.18;
  text-wrap: balance;
}
.login-aside-lede {
  margin-top: 12px;
  font-size: 14px; line-height: 1.6;
  color: var(--ink-2);
  max-width: 42ch;
  text-wrap: pretty;
}
.login-points { display: grid; gap: 18px; margin-top: 30px; }
.login-point { display: flex; gap: 13px; align-items: flex-start; }
.login-point-mark {
  flex: none;
  width: 26px; height: 26px; border-radius: 8px;
  display: grid; place-items: center;
  background: rgba(15, 118, 110, 0.1);
  color: var(--accent-text);
  box-shadow: inset 0 0 0 1px rgba(15, 118, 110, 0.14);
}
.login-point-mark svg { width: 14px; height: 14px; }
.login-point-title { font-size: 13.5px; font-weight: 600; letter-spacing: -0.005em; }
.login-point-body {
  margin-top: 2px;
  font-size: 12.5px; line-height: 1.55;
  color: var(--muted);
  max-width: 40ch;
  text-wrap: pretty;
}

/* ---------- shell ---------- */


.shell { display: grid; grid-template-rows: 52px 1fr; height: 100dvh;
  min-width: 0; }
/* GRID AND FLEX CHILDREN DEFAULT TO `min-width: auto`, so a child cannot
   shrink below its own content and the intrinsic width propagates back out
   to the page. Adding one nav tab was enough to push the caseload sideways
   on a 375px screen — the tab strip could not shrink, so the topbar could
   not, so `.main` could not. Declared for BOTH shells: it was scoped to the
   administrative one, which is why only that half was fixed. */
.shell > * { min-width: 0; }
.main { min-width: 0; }

.topbar {
  display: flex; align-items: center; gap: 14px;
  padding: 0 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.topbar .brand-name { font-size: 15px; }
/* Topbar account controls: label on a wide screen, icon on a phone. See
   topbarActionsHTML — the icon is hidden here rather than absent from the
   markup so both widths come from one template. */
.tb-action svg { display: none; width: 16px; height: 16px; flex: none; }
.tb-action { display: inline-flex; align-items: center; gap: 6px; }
/* The first-run call to action on Findings. Accent-tinted, not amber: it is
   the next step, not a warning, and it sits below the warnings it follows. */
.next-step-cue {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  margin: 12px 0; padding: 12px 14px;
  border-radius: var(--r-md, 12px);
  background: var(--accent-soft);
  border: 1px solid rgba(15, 118, 110, 0.18);
}
.next-step-cue p { margin: 0; color: var(--ink); font-size: 14px; }
.next-step-cue .btn { display: inline-flex; align-items: center; gap: 6px; }
.next-step-cue .btn svg { width: 15px; height: 15px; }
.topbar .org {
  font-size: 12.5px; color: var(--muted);
  padding-left: 14px; border-left: 1px solid var(--line);
}
/* A UTILITY THAT WORKED IN EXACTLY ONE PLACE. Ten flex rows render a
   `.spacer` to push what follows to the right; only `.topbar` had the rule
   that makes it do anything, so in the operator console the account name and
   Sign out sat hard against the wordmark, and every `.op-section-head`
   search box sat next to its heading instead of at the far end. */
.spacer { flex: 1 1 auto; min-width: 0; }
.role-pill {
  font-size: 11px; font-weight: 600; letter-spacing: 0.04em;
  padding: 3px 9px; border-radius: 99px;
  background: var(--accent-soft); color: var(--accent-text);
}

.main { display: grid; grid-template-columns: 244px 1fr; min-height: 0; }

/* ---------- case rail ---------- */

.rail {
  border-right: 1px solid var(--line);
  background: var(--surface);
  display: flex; flex-direction: column;
  min-height: 0;
}
.rail-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 14px 10px;
}
.rail-title { font-size: 12px; font-weight: 650; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted); }
.rail-list { overflow-y: auto; padding: 0 8px 12px; flex: 1; }

.case-item {
  display: block; width: 100%; text-align: left;
  padding: 9px 10px;
  border-radius: var(--r-sm);
  transition: background-color 120ms ease;
  position: relative;
}
@media (hover: hover) and (pointer: fine) {
  .case-item:hover { background: var(--surface-2); }
}
.case-item[aria-current="true"] { background: #eef4f3; }
.case-item[aria-current="true"]::before {
  content: ""; position: absolute; left: 0; top: 9px; bottom: 9px;
  width: 3px; border-radius: 3px; background: var(--accent);
}
.case-item .c-title { font-weight: 550; display: flex; align-items: center; gap: 7px; }
.case-item .c-meta { font-size: 12px; color: var(--muted); margin-top: 1px; }

.status-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
/* 7px non-text indicators need 3:1 against the surface. The old --faint
   (#a8a29e) measured 2.52:1 and --line-strong 1.49:1 — the two commonest
   states were effectively invisible on a bright ward screen. */
.status-dot[data-s="draft"] { background: #78716c; }
.status-dot[data-s="active"] { background: var(--accent); }
.status-dot[data-s="referred"] { background: var(--warn); }
.status-dot[data-s="resolved"] { background: var(--ok); }
.status-dot[data-s="archived"] { background: #8a8580; }

/* ---------- workspace ---------- */

.work { min-width: 0; display: flex; flex-direction: column; overflow: hidden; }

.case-head {
  padding: 18px 26px 0;
}
.case-head .row1 { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.case-title { font-size: 19px; font-weight: 650; letter-spacing: -0.01em; }
.case-sub { font-size: 12.5px; color: var(--muted); margin-top: 3px; }

.status-select {
  appearance: none;
  font-size: 12px; font-weight: 600;
  padding: 4px 24px 4px 10px;
  border-radius: 99px;
  border: 1px solid var(--line-strong);
  background: var(--surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%2378716c' stroke-width='3'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") no-repeat right 9px center;
  cursor: pointer;
  transition: border-color 120ms ease;
}

/* tabs */
.tabs { display: flex; gap: 2px; margin-top: 16px; position: relative; border-bottom: 1px solid var(--line); }
.tab {
  padding: 9px 14px 11px;
  font-weight: 550;
  color: var(--muted);
  display: inline-flex; align-items: center; gap: 7px;
  /* A tab label does not wrap. On a phone "Possible conditions" broke onto
     two lines and doubled the height of the tab row, in a strip that already
     scrolls sideways precisely so it never has to. */
  white-space: nowrap;
  transition: color 140ms ease;
  position: relative;
}
.tab[aria-selected="true"] { color: var(--ink); }
@media (hover: hover) and (pointer: fine) { .tab:hover { color: var(--ink-2); } }
.tab .count {
  font-size: 11px; font-weight: 650;
  min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 99px;
  display: inline-grid; place-items: center;
  background: var(--line); color: var(--ink-2);
  transition: background-color 140ms ease, color 140ms ease;
}
/* A tab that HAS something but counts nothing: a dot, not a number, so it
   cannot be misread as a count that failed to arrive. */
.tab .count[data-dot="true"] {
  min-width: 6px; width: 6px; height: 6px; padding: 0;
  background: var(--faint);
}
.tab[aria-selected="true"] .count[data-dot="true"] { background: var(--accent); }
.tab .count[data-warn="true"] { background: var(--warn-soft); color: var(--warn); }
.tab[aria-selected="true"] .count { background: var(--accent-soft); color: var(--accent-text); }
.tab-ink {
  position: absolute; bottom: -1px; left: 0; height: 2px; width: 60px;
  background: var(--accent); border-radius: 2px;
  transition: transform 200ms var(--ease-out), width 200ms var(--ease-out);
}

.panel-scroll { overflow-y: auto; flex: 1; min-height: 0; }
.panel { padding: 20px 26px 48px; max-width: 880px; }
/* 880px is a READING measure, and right for every stage that is mostly
   prose. The Why tab is not prose: it is three constraints side by side, a
   five-column comparison, and two panels that only work beside each other.
   Capping it at a paragraph's width squeezed all of that into two-thirds of
   the space the screen was offering. */
.panel[data-stage="why"],
.panel[data-stage="summary"] { max-width: 1000px; }

/* ---------- cards & sections ---------- */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
}
.section-title {
  font-size: 12px; font-weight: 650; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--muted);
  margin: 26px 0 10px;
  display: flex; align-items: center; gap: 8px;
}
.section-title:first-child { margin-top: 0; }

.empty {
  text-align: center;
  color: var(--muted);
  padding: 54px 20px;
}
.empty .e-glyph { color: var(--line-strong); margin-bottom: 12px; }
.empty .e-title { font-weight: 600; color: var(--ink-2); margin-bottom: 4px; }
.empty .e-sub { font-size: 13px; max-width: 380px; margin: 0 auto; }

/* ---------- provenance / chips ---------- */

.pill {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; font-weight: 600;
  padding: 2px 8px; border-radius: 99px;
  white-space: nowrap;
}
.pill::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
.pill[data-k="suggested"] { background: var(--warn-soft); color: var(--warn); }
.pill[data-k="confirmed"] { background: var(--ok-soft); color: var(--ok); }
.pill[data-k="specialist"] { background: var(--accent-soft); color: var(--accent-text); }
.pill[data-k="absent"] { background: var(--absent-soft); color: var(--absent); }
.pill[data-k="rejected"] { background: var(--line); color: var(--muted); }
.pill[data-k="unknown"] { background: var(--line); color: var(--muted); }
.pill[data-k="danger"] { background: var(--danger-soft); color: var(--danger); }
.pill[data-k="plain"] { background: var(--line); color: var(--ink-2); }
.pill[data-k="plain"]::before, .pill[data-k="none"]::before { display: none; }

.hpo-code { font-size: 11px; color: var(--faint); font-variant-numeric: tabular-nums; }

/* ---------- capture stage ---------- */

.note-block { padding: 16px; }
.note-actions {
  display: flex; align-items: center; gap: 10px; margin-top: 12px;
  /* On a phone the button and this sentence could not share a line, and the
     row did not wrap, so the sentence was crushed into a 70px column seven
     lines tall beside the button. It is the sentence that says where a
     child's history goes; it drops to its own line instead. */
  flex-wrap: wrap;
}
/* the padlock is the point of the sentence: it says where the note goes */
.note-hint {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12px; color: var(--faint-text);
  /* prefers a line of its own over a sliver beside the button */
  flex: 1 1 220px;
}
.note-hint svg { flex: none; width: 14px; height: 14px; color: var(--faint); }

.note-preview {
  padding: 14px 16px;
  font-size: 13.5px; line-height: 1.7;
  color: var(--ink-2);
  border-top: 1px solid var(--line);
  background: var(--surface-2);
  border-radius: 0 0 var(--r-md) var(--r-md);
  white-space: pre-wrap;
}
mark.span {
  background: var(--warn-soft);
  color: inherit;
  border-radius: 3px;
  padding: 1px 2px;
  transition: background-color 140ms ease;
}
mark.span[data-kind="explicitly_absent"] { background: var(--absent-soft); }
mark.span[data-kind="family_history"] { background: var(--accent-soft); }
/* a hedged phrase the extractor was unsure about must not look identical to a
   confident positive match */
mark.span[data-kind="unknown"],
mark.span[data-kind="not_assessed"] {
  background: transparent;
  box-shadow: inset 0 -2px 0 var(--faint);
  border-radius: 0;
}
mark.span.hl { background: var(--warn); color: #fff; }
mark.span[data-kind="explicitly_absent"].hl { background: var(--absent); color: #fff; }

/* suggestion cards */
.sug-list { display: grid; gap: 8px; }
/* The button matching what the extractor read from the note is OUTLINED, not
   filled: it marks the suggestion without pre-deciding it. Nothing reaches
   the analysis until a clinician taps, which is the promise the capture
   screen makes — but the tap that is one thumb-width away must not silently
   be the wrong one. */
/* THE DECISION MUST BE LOUDER THAN THE GUESS.
   The suggested ring was 4.36:1 and the SELECTED state a white fill at
   1.26:1 — and the ring was removed exactly when the clinician AGREED with
   the extractor, so the strongest mark on the card was only ever drawn on a
   button the clinician had NOT picked. Whenever they overrode the extractor
   — the case the card exists for — the loudest thing on screen sat on the
   rejected reading. Selected is now a filled, high-contrast state; suggested
   is a quiet dashed hint that yields to it. */
.seg button[data-suggested="true"] {
  box-shadow: inset 0 0 0 1px var(--line-strong);
  color: var(--faint-text);
}
.seg button[aria-pressed="true"] {
  background: var(--accent); color: var(--accent-ink);
  box-shadow: none; font-weight: 700;
}
.seg button[data-suggested="true"][aria-pressed="true"] {
  background: var(--accent); color: var(--accent-ink);
}

.sug {
  display: flex; align-items: center; gap: 12px;
  /* A GRID ITEM'S min-width IS auto, so the card could not shrink below its
     own content — and its content includes the quoted sentence, which is
     `white-space: nowrap`. On a real ward note that quote is a full clause,
     so each card grew to the width of the sentence: 575px inside a 360px
     Android, with "Unsure" and "Reject" off the right edge and the panel
     panning sideways under the thumb on every card.
     The earlier fix made the BUTTONS shrinkable, which could not help while
     the card around them would not. With this the sentence ellipsises as it
     was always meant to. */
  min-width: 0;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  transition: border-color 140ms ease, opacity 200ms ease;
}
.sug[data-decision="reject"] { opacity: 0.55; }
.sug .s-main { flex: 1; min-width: 0; }
.sug .s-label { font-weight: 550; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.sug .s-sentence {
  font-size: 12px; color: var(--muted);
  margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* `flex: none` plus four non-shrinking buttons gave the suggestion card a
   338px floor, so the whole Findings panel panned sideways under the thumb on
   a 360px Android — the commonest width in the target market, on the screen
   where a clinician works down a column of decisions one-handed. The segment
   may shrink now, and its buttons may shrink within it. */
.seg { display: inline-flex; background: var(--line); border-radius: var(--r-sm);
       padding: 2px; gap: 2px; flex: 0 1 auto; min-width: 0; max-width: 100%; }
.seg button {
  font-size: 12px; font-weight: 600;
  padding: 4px 10px; border-radius: 5px;
  color: var(--muted);
  transition: background-color 140ms ease, color 140ms ease, transform 140ms var(--ease-out);
}
.seg button:active { transform: scale(0.96); }
.seg button[aria-pressed="true"] { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-sm); }
.seg button[data-v="explicitly_absent"][aria-pressed="true"] { color: var(--absent); }
.seg button[data-v="reject"][aria-pressed="true"] { color: var(--danger); }

.confirm-bar {
  position: sticky; bottom: 0;
  display: flex; align-items: center; gap: 12px;
  margin-top: 12px;
  padding: 10px 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-md);
}
.confirm-bar .cb-note { font-size: 12.5px; color: var(--muted); flex: 1; }

/* evidence rows */
.evi-list { display: grid; gap: 6px; }
.evi {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}
.evi .e-label { font-weight: 550; }
.evi .e-src { font-size: 11.5px; color: var(--faint); }
.evi .e-grow { flex: 1; }
.evi .e-actions { display: flex; gap: 2px; opacity: 0; transition: opacity 140ms ease; }
.evi:focus-within .e-actions { opacity: 1; }
@media (hover: hover) and (pointer: fine) { .evi:hover .e-actions { opacity: 1; } }
@media (hover: none) { .evi .e-actions { opacity: 1; } }

/* HPO search */
.hpo-search { position: relative; }
.hpo-pop {
  position: absolute; top: calc(100% + 5px); left: 0; right: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  max-height: 280px; overflow-y: auto;
  z-index: 30;
  padding: 4px;
  /* frequent while typing: opacity only, very fast */
  transition: opacity 80ms ease;
}
.hpo-pop[hidden] { display: none; }
.hpo-opt {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; text-align: left;
  padding: 7px 10px; border-radius: 6px;
  transition: background-color 80ms ease;
}
.hpo-opt[data-active="true"] { background: var(--surface-2); }
.hpo-opt .o-label { font-weight: 500; }

/* THE SEGMENTED CONTROL SITS BESIDE THE SEARCH FIELD and has to measure the
   same. It was 31px against the field's 42 and five pixels lower — the two
   controls that make up one action, visibly not a pair. */
.assert-picker {
  display: inline-flex; align-items: center;
  box-sizing: border-box; min-height: var(--control-h);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 3px; gap: 2px;
}
.assert-picker button {
  font-size: 12.5px; font-weight: 600; padding: 6px 13px;
  border-radius: 7px; color: var(--muted);
  transition: background-color 140ms ease, color 140ms ease,
    box-shadow 140ms ease;
}
.assert-picker button:hover { color: var(--ink-2); }
.assert-picker button[aria-pressed="true"] {
  background: var(--surface); color: var(--ink); box-shadow: var(--shadow-sm);
}

/* family history */
.fam-list { display: grid; gap: 6px; }
.fam {
  display: flex; gap: 10px; align-items: baseline;
  font-size: 13px; color: var(--ink-2);
  padding: 8px 12px;
  background: var(--accent-soft);
  border-radius: var(--r-sm);
}

/* ---------- candidates stage ---------- */

.notice {
  display: flex; gap: 10px; align-items: flex-start;
  font-size: 12.5px; color: var(--muted);
  padding: 10px 14px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  margin-bottom: 14px;
}
.notice svg { flex: none; margin-top: 1px; color: var(--faint); }
.notice-warn { border-color: #fcd34d; background: var(--warn-soft); color: var(--warn); }
.notice-warn svg { color: currentColor; }
/* Why the sign-in screen came back — a revoked membership, a suspended
   hospital. Deliberately the calm variant and not `.notice-warn`: being
   taken off a hospital's records is an ordinary administrative act, and an
   alarm here would read as a fault in the application, which is the wrong
   thing to conclude before ringing whoever did it. */
.notice-info { border-color: var(--line); background: var(--surface-2); }
.login-why { margin-bottom: 16px; text-align: left; }

.cand-list {
  display: grid; gap: 8px;
  /* ONE template, shared by the axis header and by every row, so the end
     labels sit exactly above the dots they label */
  --cols: 30px minmax(0, 1fr) 160px 20px;
  --tw: 1px;                       /* half-width of a peer tick */
}

/* the run's provenance, compressed from a full notice into one strip */
.runline {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 0 2px 10px; font-size: 12px; color: var(--muted);
}
.runline .rl-note { flex-basis: 100%; color: var(--warn); }
.runline .rl-btn { margin-left: auto; padding: 3px 10px; font-size: 12px; }
.notice .rl-btn { margin-left: auto; padding: 3px 10px; font-size: 12px; }
.cand {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
}
.cand-row, .strip-head {
  display: grid;
  /* minmax(0, 1fr) inside --cols: an auto-min track refuses to shrink,
     letting long disease names overflow into the columns beside them */
  grid-template-columns: var(--cols);
  align-items: center; gap: 14px;
}
.cand-row {
  width: 100%; text-align: left;
  padding: 11px 14px;
  transition: background-color 120ms ease;
}
@media (hover: hover) and (pointer: fine) { .cand-row:hover { background: var(--surface-2); } }
.cand .rank { font-size: 13px; font-weight: 650; color: var(--faint-text); font-variant-numeric: tabular-nums; }
.cand .d-cell { min-width: 0; }
/* block-level: text-overflow does not clip an inline box */
.cand .d-label { display: block; font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Indented to sit under the disease name: 14px row padding + 30px rank
   column + 14px gap. A pill may wrap its own words if a future one outgrows
   the card, which is ugly but never hides a fact. */
.cand .d-flags {
  display: flex; flex-wrap: wrap; gap: 5px;
  padding: 0 14px 11px 58px; margin-top: -4px;
}
.cand .d-flags .pill { white-space: normal; max-width: 100%; text-align: left; }
/* The percentage is a DIFFERENT quantity from the dot, so it is stated in
   words on the line describing the condition and never placed beside the
   scale. It sits next to the feature count deliberately: across a run those
   two move against each other, and a reader who can see both can see why a
   thinly described condition explains a larger share. */
.cand .d-meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 1px 10px; min-width: 0; }
.cand .d-id { font-size: 11px; color: var(--faint-text); font-variant-numeric: tabular-nums; white-space: nowrap; }
.cand .score { font-size: 11px; font-weight: 550; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---------- where a candidate sits: a dot on a shared scale --------------
   Replaces the fill bar. A bar fills from an origin, so it reads as
   "percentage complete" — the one metaphor a comparison between conditions
   must never suggest, and the leader's bar was full every time regardless of
   how poor the match was. This mark has no origin and nothing fills: it is a
   POSITION on a scale whose two ends are set by this list and nothing else,
   and every row draws the whole field of candidates behind its own dot, so a
   dot is never read alone. No number is printed for it. */
.pip { position: relative; display: block; height: 22px; }
/* Two background layers on one pseudo-element: the peer field, then the
   hairline. --peers is inherited from .cand-list, so every row shares one
   string. If it is absent this degrades to a bare hairline rather than to a
   wrong picture. The dot is a real child, so it paints above both. */
.pip::before {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  height: 9px; transform: translateY(-50%);
  background-image: var(--peers, none), linear-gradient(var(--line), var(--line));
  background-repeat: no-repeat, no-repeat;
  background-size: 100% 100%, 100% 1px;
  background-position: 0 0, 0 50%;
}
.pip-dot {
  position: absolute; top: 50%; left: var(--at, 50%);
  width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px;
  border-radius: 50%; background: var(--ink);
  /* a ring in the surface colour keeps the dot legible when it lands inside
     a dense cluster of ticks */
  box-shadow: 0 0 0 2.5px var(--surface);
}
@media (hover: hover) and (pointer: fine) {
  .cand-row:hover .pip-dot { box-shadow: 0 0 0 2.5px var(--surface-2); }
}

/* the axis header: five dots at uneven positions. The legend it replaces
   drew a bar filled to 62% six words from the text "explains 62%", which
   taught exactly the association it existed to break. */
.strip-head { padding: 2px 15px 10px; }
.sh-title { grid-column: 2; font-size: 12px; line-height: 1.45; color: var(--muted); }
.sh-title b { color: var(--ink-2); font-weight: 600; }
.sh-axis { grid-column: 3; }
.sh-rule {
  position: relative; display: block; height: 9px;
  background: linear-gradient(var(--line), var(--line)) no-repeat 0 50% / 100% 1px;
}
.sh-rule i {
  position: absolute; top: 50%; left: var(--at);
  width: 7px; height: 7px; margin: -3.5px 0 0 -3.5px;
  border-radius: 50%; background: var(--faint);
}
.sh-ends { display: flex; justify-content: space-between; margin-top: 5px;
           font-size: 10.5px; color: var(--faint-text); }
.cand .chev { color: var(--faint); transition: transform 200ms var(--ease-out); }
.cand[data-open="true"] .chev { transform: rotate(180deg); }

.bar { height: 5px; border-radius: 3px; background: var(--line); overflow: hidden; }
.bar > i {
  display: block; height: 100%; border-radius: 3px;
  background: var(--accent);
  transform-origin: left center;
  transform: scaleX(0);
  transition: transform 500ms var(--ease-out);
}

.cand-body {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows 220ms var(--ease-out);
}
.cand[data-open="true"] .cand-body { grid-template-rows: 1fr; }
/* visibility:hidden removes the collapsed detail from the tab order AND the
   accessibility tree — clipping to 0fr alone left 126 invisible tab stops
   across a 15-row differential. `transition: visibility` flips it late on
   close and early on open, so neither direction flashes. */
.cand-body > div {
  overflow: hidden;
  visibility: hidden;
  /* delay the flip to hidden until the collapse finishes, but become visible
     immediately on open — a plain duration flips it at the wrong moment */
  transition: visibility 0s linear 220ms;
}
.cand[data-open="true"] .cand-body > div {
  visibility: visible;
  transition: visibility 0s linear 0s;
}
.cand-detail {
  padding: 4px 14px 16px 56px;
  display: grid; gap: 14px;
  border-top: 1px solid var(--line);
  padding-top: 12px;
}
.trace-h { font-size: 11px; font-weight: 650; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted); margin-bottom: 6px; }
.trace-row {
  display: flex; align-items: baseline; gap: 8px;
  font-size: 13px; padding: 3px 0;
}
.trace-row .t-share { font-size: 11.5px; color: var(--faint); font-variant-numeric: tabular-nums; margin-left: auto; padding-left: 12px; flex: none; }
.trace-row.contra { color: var(--danger); }
.unassessed-chip {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12px; font-weight: 500;
  padding: 3px 5px 3px 10px;
  background: var(--surface-2);
  border: 1px dashed var(--line-strong);
  border-radius: 99px;
  margin: 0 6px 6px 0;
}
/* These two record a finding as present or as looked-for-and-absent, so a
   mistap writes the wrong assertion into the case. 24px is the WCAG 2.5.8
   minimum; the visible disc stays 20px, drawn by a pseudo-element, so the
   chip does not grow into something clumsy. */
/* These two glyphs WRITE EVIDENCE with one tap, no confirmation and no undo
   — and the second one writes `explicitly_absent`, the only assertion that
   counts against a condition. They were --faint (2.42:1) set-theory symbols
   four pixels apart, with their meaning carried only by `title`, which does
   not exist on a touch screen. They now carry their meaning in colour that
   reads in bright light, and the chip is labelled once above the list. */
.unassessed-chip .uc-btn {
  position: relative;
  min-width: 24px; width: 24px; height: 24px; border-radius: 50%;
  display: inline-grid; place-items: center;
  font-size: 12px; font-weight: 700;
  color: var(--faint-text);
  transition: color 120ms ease, transform 140ms var(--ease-out);
}
.unassessed-chip .uc-btn.yes { color: var(--ok); }
.unassessed-chip .uc-btn.no  { color: var(--absent); }
.unassessed-chip .uc-btn::before { border: 1px solid var(--line-strong); }
.unassessed-chip .uc-btn::before {
  content: ""; position: absolute; inset: 2px; z-index: -1;
  border-radius: 50%;
  transition: background-color 120ms ease;
}
.unassessed-chip .uc-btn:active { transform: scale(0.9); }
@media (hover: hover) and (pointer: fine) {
  .unassessed-chip .uc-btn.yes:hover::before { background: var(--ok-soft); }
  .unassessed-chip .uc-btn.yes:hover { color: var(--ok); }
  .unassessed-chip .uc-btn.no:hover::before { background: var(--absent-soft); }
  .unassessed-chip .uc-btn.no:hover { color: var(--absent); }
}

.versions { font-size: 11.5px; color: var(--faint); margin-top: 16px; }

/* ---------- next actions ---------- */

/* the clickable pointer to the tab that carries the instruction */
.esc-link { cursor: pointer; }
.esc-link:focus-visible { outline: 2px solid var(--danger); outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .esc-link:hover { filter: brightness(0.985); }
}

.escalation {
  display: flex; gap: 12px; align-items: flex-start;
  background: var(--danger-soft);
  border: 1px solid #fca5a5;
  border-radius: var(--r-md);
  padding: 14px 16px;
  margin-bottom: 14px;
}
.escalation .esc-title { font-weight: 650; color: var(--danger); }
.escalation .esc-reason { font-size: 13px; color: #7f1d1d; margin-top: 3px; }

.act-list { display: grid; gap: 8px; }
.act {
  display: grid; grid-template-columns: 30px 1fr; gap: 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 12px 14px;
}
.act .a-pri {
  font-size: 13px; font-weight: 650; color: var(--faint);
  font-variant-numeric: tabular-nums; padding-top: 1px;
}
.act .a-title { font-weight: 550; }
.act .a-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 6px; }
.meta-item { font-size: 12px; color: var(--muted); display: inline-flex; align-items: center; gap: 5px; }
.meta-item .unknown { color: var(--faint); font-style: italic; }
/* The label "how much this would tell you" sat on all twelve cards in the
   same words; it is one column header now. */
.act-head {
  display: flex; align-items: center; flex-wrap: wrap;
  font-size: 12px; color: var(--muted); margin: 0 2px 8px;
}
.eig-wrap { display: flex; align-items: center; gap: 8px; margin-top: 8px; max-width: 320px; }
.eig-wrap .bar { flex: 1; }
.act .a-reason { font-size: 12.5px; color: var(--muted); margin-top: 7px; line-height: 1.5; }

/* the excluded list is a native <details> now — see disclosureHTML */
#excl { margin-top: 18px; }
#excl .disclosure-body { display: grid; gap: 6px; }
.excluded-item {
  font-size: 12.5px; color: var(--muted);
  padding: 8px 12px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}
.excluded-item b { color: var(--ink-2); font-weight: 550; }

/* ---------- summary ---------- */

.sum-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.sum-card { padding: 18px; margin-top: 12px; }
.sum-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.sum-head .sh-title { font-weight: 650; flex: 1; }
.sum-body { font-size: 13.5px; line-height: 1.6; color: var(--ink-2); display: grid; gap: 12px; }
.sum-body h4 {
  font-size: 11px; font-weight: 650; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--muted);
  margin-bottom: 4px;
}
.sum-body table { border-collapse: collapse; width: 100%; }
.sum-body td, .sum-body th {
  text-align: left; padding: 5px 10px 5px 0;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
}
.sum-body th { font-weight: 600; color: var(--muted); font-size: 12px; }
.sum-note { font-size: 12px; color: var(--faint); font-style: italic; }

/* ---------- modal ---------- */

dialog.modal {
  border: 0;
  border-radius: 20px;
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  padding: 0;
  /* the global reset zeroes margin, which also kills the UA stylesheet's
     `margin: auto` on <dialog> — every modal rendered jammed into the
     top-left corner with its heading clipped by the viewport edge */
  margin: auto;
  max-height: calc(100vh - 40px);
  /* NOT overflow-y: auto. The BODY scrolls, via the grid on .modal-inner, so
     the header and the footer buttons stay on screen. Scrolling the dialog
     itself pushed Save and Close below the fold on anything tall. */
  overflow: hidden;
  width: min(660px, calc(100vw - 32px));
  /* modal: transform-origin stays center */
  opacity: 1; transform: scale(1);
  transition: opacity 180ms var(--ease-out), transform 180ms var(--ease-out),
    overlay 180ms allow-discrete, display 180ms allow-discrete;
}
dialog.modal::backdrop {
  background: rgba(28, 25, 23, 0.32);
  transition: opacity 180ms ease, overlay 180ms allow-discrete, display 180ms allow-discrete;
  opacity: 1;
}
@starting-style {
  dialog.modal[open] { opacity: 0; transform: scale(0.96); }
  dialog.modal[open]::backdrop { opacity: 0; }
}
/* --- the modal shell ------------------------------------------------------
   Every dialog in the application is this shape: a header that names the
   thing and says what it is for, a body that scrolls, and a footer whose
   buttons never leave the screen.

   THE GRID IS WHAT KEEPS THE FOOTER PUT. With the dialog scrolling instead of
   its middle row, the patient dialog — which carries a whole case thread —
   pushed Save and Close below the fold, and on a laptop there was no visible
   way to accept or dismiss it. `min-height: 0` on the body is the part that
   is easy to leave out and silently disables the whole arrangement. */
dialog.modal.is-wide { width: min(860px, calc(100vw - 32px)); }
.modal-inner {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  max-height: calc(100vh - 64px);
}

.m-head {
  display: flex; align-items: flex-start; gap: 16px;
  padding: 28px 30px 18px;
}
.m-head-words { flex: 1; min-width: 0; }
.m-title {
  font-size: 30px; font-weight: 660; letter-spacing: -0.035em; line-height: 1.08;
  text-wrap: balance;
}
.m-lede {
  margin-top: 7px; max-width: 62ch;
  font-size: 14.5px; line-height: 1.5; color: var(--op-ink-soft);
  text-wrap: pretty;
}
.m-close {
  flex: none;
  display: grid; place-items: center;
  width: 34px; height: 34px;
  border: 0; border-radius: 50%;
  background: transparent; color: var(--muted);
  cursor: pointer;
  transition: background 140ms ease, color 140ms ease,
    transform 150ms var(--ease-out);
}
.m-close:hover { background: var(--surface-2); color: var(--ink); }
.m-close:active { transform: scale(0.92); }

.m-body {
  min-height: 0; overflow-y: auto;
  padding: 0 30px 4px;
  display: grid; gap: 18px; align-content: start;
}
.m-foot {
  display: flex; align-items: center; justify-content: flex-end; gap: 10px;
  padding: 18px 30px 24px;
}
.m-foot .m-status { margin-right: auto; }
.m-rule { border: 0; border-top: 1px solid var(--line); margin: 0; }

/* --- a section inside a modal --------------------------------------------- */
.m-section { display: grid; gap: 14px; }
.m-section-head { display: flex; align-items: flex-start; gap: 14px; }
.m-section-words { min-width: 0; flex: 1; }
.m-section-title {
  font-size: 19px; font-weight: 640; letter-spacing: -0.02em; line-height: 1.25;
}
.m-section-sub {
  margin-top: 3px; font-size: 13.5px; line-height: 1.5; color: var(--op-ink-soft);
  text-wrap: pretty;
}
.m-section-body { display: grid; gap: 14px; }

.m-medallion {
  display: grid; place-items: center;
  width: 46px; height: 46px; flex: none;
  border-radius: 50%;
  background: var(--accent-soft); color: var(--accent-text);
}
.m-medallion svg { width: 21px; height: 21px; }
.m-medallion.is-sm { width: 40px; height: 40px; }
.m-medallion.is-sm svg { width: 18px; height: 18px; }

/* --- the tinted panel: something to know, not something to do ------------- */
.m-panel {
  display: flex; align-items: flex-start; gap: 14px;
  padding: 17px 18px;
  border-radius: 14px;
  background: #eefaf6;
  border: 1px solid #d7ece6;
}
.m-panel-words { min-width: 0; flex: 1; display: grid; gap: 6px; }
.m-panel-title {
  font-size: 15px; font-weight: 630; letter-spacing: -0.012em;
  color: var(--accent-text);
}
.m-panel-text { font-size: 13.5px; line-height: 1.5; color: #37665e; text-wrap: pretty; }
.m-panel.is-warn { background: #fffaf1; border-color: #f0dcb6; }
.m-panel.is-warn .m-medallion { background: #fdebc8; color: #92400e; }
.m-panel.is-warn .m-panel-title { color: #92400e; }
.m-panel.is-warn .m-panel-text { color: #8a5a1c; }

/* --- fields ---------------------------------------------------------------- */
.m-field { display: grid; gap: 6px; min-width: 0; }
.m-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 620px) { .m-row { grid-template-columns: 1fr; } }

/* The wrapper itself is `.input-wrap`, shared with the caseload. Only the
   parts a modal adds — a password reveal, a select chevron — live here. */
.m-input.has-reveal .field { padding-right: 42px; }
.m-reveal {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  display: grid; place-items: center;
  width: 30px; height: 30px;
  border: 0; border-radius: 8px;
  background: transparent; color: var(--faint-text);
  cursor: pointer;
  transition: background 130ms ease, color 130ms ease;
}
.m-reveal:hover { background: var(--surface-2); color: var(--ink-2); }
.m-reveal[aria-pressed="true"] { color: var(--accent-text); }

/* A SELECT IS THE SAME CONTROL AS AN INPUT, and has to measure the same. The
   modal selects used to be `.op-select`, borrowed from the operator console:
   12.5px type against the field's inherited size, a 9px radius against 7, and
   a lighter border. Beside a date input in a two-column row that produced a
   control four pixels shorter, sitting thirty-seven pixels lower than its
   neighbour — nobody can name it and everybody can see it. */
/* AN EXPLICIT BOX, not an intrinsic one. A text input, a date input and a
   select with identical padding and font still measure 38, 40 and 36 pixels,
   because each derives its content height its own way — a line-height alone
   does not settle it. Two pixels is invisible alone and unmistakable in a
   two-column row, so the height is stated rather than inherited. */
.m-input.is-select .field {
  appearance: none; -webkit-appearance: none;
  padding-right: 36px;
  font: inherit;
  cursor: pointer;
}
.m-input-chevron {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  display: grid; place-items: center;
  color: var(--faint-text); pointer-events: none;
}
.m-input-chevron svg { width: 13px; height: 13px; }
.m-input.is-select.has-icon .field { padding-left: 40px; }

/* THE ROW ALIGNS ON ITS CONTROLS, not on its text. A hint under one field
   used to push the next row's label down; with the field boxes as the grid
   items, a hint of any length leaves the controls beside it level. */
.m-row > .m-field { align-content: start; }
.m-field > .lbl { display: block; min-height: 1.2em; }

.modal .m-grid { display: grid; gap: 13px; }

@media (max-width: 560px) {
  .m-head { padding: 22px 20px 14px; }
  .m-title { font-size: 25px; }
  .m-body { padding: 0 20px 4px; }
  .m-foot { padding: 16px 20px 20px; flex-wrap: wrap; }
}

/* ---------- toasts ---------- */

.toasts {
  position: fixed; bottom: 18px; right: 18px;
  display: flex; flex-direction: column; gap: 8px;
  z-index: 100;
  pointer-events: none;
}
.toast {
  display: flex; align-items: center; gap: 9px;
  background: var(--ink);
  color: #fafaf9;
  font-size: 13px; font-weight: 500;
  padding: 10px 14px;
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  pointer-events: auto;
  max-width: 380px;
  opacity: 1; transform: translateY(0);
  transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out);
}
@starting-style { .toast { opacity: 0; transform: translateY(12px); } }
.toast[data-closing] { opacity: 0; transform: translateY(12px); transition-duration: 150ms; }
.toast[data-kind="error"] { background: #7f1d1d; }
.toast[data-kind="ok"] svg { color: #6ee7b7; }

/* ---------- loading ---------- */

.spinner {
  width: 15px; height: 15px;
  border: 2px solid rgba(15, 118, 110, 0.2);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 600ms linear infinite;
  flex: none;
}
.btn-primary .spinner { border-color: rgba(255,255,255,0.35); border-top-color: #fff; }
@keyframes spin { to { transform: rotate(360deg); } }

.skel { display: grid; gap: 8px; }
.skel > i {
  display: block; height: 42px;
  border-radius: var(--r-md);
  background: var(--line);
  animation: pulse 1.1s ease-in-out infinite alternate;
}
.skel > i:nth-child(2) { animation-delay: 120ms; }
.skel > i:nth-child(3) { animation-delay: 240ms; }
@keyframes pulse { from { opacity: 0.55; } to { opacity: 1; } }

.pending-line {
  display: flex; align-items: center; gap: 10px;
  font-size: 13px; color: var(--muted);
  padding: 12px 2px;
}

/* ---------- narrow screens (ward round on a tablet or phone) ---------- */

.rail-toggle { display: none; }
.rail-scrim { display: none; }

@media (max-width: 900px) {
  .main { grid-template-columns: 1fr; }

  .rail-toggle {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 5px 10px; border-radius: var(--r-sm);
    border: 1px solid var(--line-strong);
    font-size: 13px; font-weight: 550;
    transition: transform 140ms var(--ease-out), background-color 120ms ease;
  }
  .rail-toggle:active { transform: scale(0.97); }

  /* off-canvas: transform only, so it composites */
  .rail {
    position: fixed; z-index: 60;
    top: 52px; bottom: 0; left: 0; width: 272px;
    transform: translateX(-100%);
    box-shadow: var(--shadow-lg);
    transition: transform 220ms var(--ease-out);
  }
  .rail[data-open="true"] { transform: translateX(0); }

  .rail-scrim {
    display: block;
    position: fixed; inset: 52px 0 0 0; z-index: 55;
    background: rgba(28, 25, 23, 0.3);
    opacity: 0; pointer-events: none;
    transition: opacity 200ms ease;
  }
  .rail-scrim[data-open="true"] { opacity: 1; pointer-events: auto; }

  .topbar .org, .topbar .role-pill { display: none; }
  /* The NAME goes on a phone; the SWITCHER stays, because a clinician who
     works at two hospitals needs it there as much as anywhere. Without a
     floor it collapsed to a bare chevron — a control showing nothing, which
     is worse than either the label or no control at all. */
  .topbar .org-switch select { min-width: 108px; max-width: 44vw; }
  .topbar .user-name { display: none; }
  /* The wordmark goes, the mark stays, and the controls get compact — rather
     than dropping People or Account, which are exactly what an administrator
     reaches for on a phone when somebody has just left. */
  .topbar .brand-name { display: none; }
  .topbar .btn { padding: 5px 9px; font-size: 12px; }

  .case-head { padding: 14px 16px 0; }
  .panel { padding: 16px 16px 40px; }
  .case-title { font-size: 17px; }

  .tabs { overflow-x: auto; scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }

  /* What survives in the third column is the SCALE, not the percentage.
     Dropping the mark that explains the order — as the bar used to be dropped
     here — left a phone showing only the number that does NOT order the list,
     so rank 4 at 89% sitting under rank 3 at 57% read as a mis-sort with
     nothing on screen to account for it. The percentage moves onto the
     condition's own line, where it wraps. */
  .cand-list { --cols: 24px minmax(0, 1fr) 64px 18px; --tw: 0.75px; }
  .cand-row { gap: 10px; }
  /* nowrap here printed the identifier straight through the scale: the meta
     text is wider than the 161px name cell at this width, and flex-wrap wraps
     ITEMS, not the text inside one. Wrapping the words keeps the feature
     count beside the percentage, which is the pairing that explains why a
     thinly described condition shows a high one. */
  .cand .d-id { white-space: normal; }
  .cand .score-tail { display: none; }     /* back to the shorter wording */
  .cand .d-flags { padding-left: 48px; }   /* 14 + 24 rank + 10 gap */

  /* The caption spans the row; the AXIS stays in column 3, over the dots it
     labels. Making the whole header `display:block` put "weakest here"
     entirely over the disease-name column and "strongest here" 31px to the
     LEFT of the rank-1 dot — so a reader mapping the caption onto the rows
     read the leader as sitting beyond the strongest anchor, on the only
     device this is used on, for the mark that orders the whole list. */
  .strip-head { padding: 2px 15px 12px; row-gap: 8px; }
  .strip-head .sh-title { grid-column: 1 / -1; }
  .strip-head .sh-axis { grid-column: 3; }
  .sh-ends { font-size: 10px; }
  .sh-ends span:first-child { transform: translateX(-4px); }
  .sh-ends span:last-child { transform: translateX(4px); }
  .cand-detail { padding-left: 16px; }

  .confirm-bar { flex-wrap: wrap; }
  .modal .m-row { grid-template-columns: 1fr; }
}


/* THE TOPBAR ON A PHONE. At 375px its contents measured 454px: Cases, the
   mark, the hospital switcher, and two 66px text buttons, with 14px between
   every item including the ones already collapsed to nothing. The overflow
   widened the whole page, so dialogs centred in the wider box and opened
   half off the right edge — the New case form among them, which is the first
   thing a paediatrician does — and the area navigation got zero width, which
   made "Second opinions" unreachable.

   Every control stays. The account buttons become icons with their labels
   clipped rather than removed, the gap tightens, and what that frees goes to
   the area navigation, which scrolls sideways inside itself rather than
   pushing the page. */
@media (max-width: 620px) {
  .topbar { gap: 6px; padding: 0 10px; }
  .tb-action svg { display: block; }
  .tb-action .tb-label {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .topbar .tb-action { padding: 7px; }
  .topbar .area-nav { flex: 1 1 auto; min-width: 72px; margin-left: 0; }
  .topbar .spacer { display: none; }
  .topbar .rail-toggle { padding: 7px; }
}

/* THE WORD GOES WHEREVER THE DRAWER IS, which is up to 900px and not up to
   620. The drawer button and the area navigation both say "Cases", side by
   side; this was fixed once at phone width and the band above it kept the
   duplication — on a tablet the bar read "☰ Cases   Cases". 900px is where
   `RAIL_DRAWER_QUERY` in app.js turns the case list into a drawer, so the
   two now describe the same thing. The button keeps its menu mark and its
   aria-label ("Show cases"), so nothing is lost to a screen reader. */
@media (max-width: 900px) {
  .rail-toggle .rail-label {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
}

/* Phone-width only: a tablet at 800px still has room for single-line rows. */
@media (max-width: 620px) {
  .evi { flex-wrap: wrap; row-gap: 4px; }
  .evi .e-grow { flex-basis: 100%; height: 0; }   /* force the tail to a 2nd line */
  .evi .e-label { flex-basis: 100%; }

  .sug { flex-wrap: wrap; }
  .sug .seg { width: 100%; justify-content: space-between; }
  /* min-width: 0 is what lets them actually shrink; without it each button
     held an 82px floor and the card ran 60px past a 320px screen */
  .sug .seg button { flex: 1 1 0; min-width: 0; text-align: center;
                     padding: 4px 6px; }

  /* Condition names were ellipsised to a 177px cell, and three PAIRS of
     genuinely different candidates rendered as identical words — the full
     name lived only in a `title`, which does not exist on touch. Two lines
     of wrapped name costs less than a clinician acting on the wrong one. */
  .cand .d-label { white-space: normal; overflow: visible;
                   display: -webkit-box; -webkit-line-clamp: 2;
                   -webkit-box-orient: vertical; overflow: hidden; }
}

@media (max-width: 900px) and (prefers-reduced-motion: reduce) {
  .rail { transition: none; }
}

/* ---------- reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 1ms !important; animation-duration: 1ms !important; }
  .spinner { animation-duration: 600ms !important; } /* keep progress signal */
  .skel > i { animation-duration: 1.1s !important; }
  .btn:active, .icon-btn:active, .user-card:active, .seg button:active { transform: none; }
  .bar > i { transition: none; }
  /* The blanket 1ms above is WRONG for an infinite alternating animation: it
     does not stop the drift, it runs it at 500 cycles a second. The one
     ambient animation in the app therefore has to be turned off by name. */
  .login-wrap::after { animation: none !important; }
  .login-error:not([hidden]) { animation: none !important; }
  /* Holding still confirms, but the 1.4s fill is motion nobody asked for;
     wireHoldToSuspend shortens the hold to 350ms to match. */
  .op-hold.is-holding .op-hold-fill { transition-duration: 350ms !important; }
}

/* ------------------------------------------------ case management ------- */
/* The rail is the screen a clinician lives in: it must answer "where is that
   case" and "which of these needs me" without opening anything. */

.rail-tools {
  display: flex; flex-direction: column; gap: 8px;
  padding: 0 12px 10px; border-bottom: 1px solid var(--line);
}
.rail-search { font-size: 13px; }
.rail-filters { display: flex; gap: 4px; flex-wrap: wrap; }
.chip {
  /* the four of them are one control — Open / Closed / Archived / All — so
     they belong on one line at the rail's width, not three-and-a-wrap */
  font-size: 11.5px; padding: 4px 8px; border-radius: 999px;
  border: 1px solid var(--line-strong); color: var(--muted);
  background: var(--surface); cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}
.chip[aria-pressed="true"] {
  background: var(--accent-soft); color: var(--accent-text);
  border-color: transparent; font-weight: 600;
}
@media (hover: hover) and (pointer: fine) {
  .chip:hover { background: var(--surface-2); }
  .chip[aria-pressed="true"]:hover { background: var(--accent-soft); }
}

.case-item .c-name {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.case-item .c-ref { font-variant-numeric: tabular-nums; font-weight: 550; }
.case-item .c-needs { display: flex; gap: 5px; flex-wrap: wrap; margin-top: 5px; }
.case-item .c-needs:empty { display: none; }
.need {
  font-size: 11px; padding: 2px 7px; border-radius: 999px;
  background: var(--surface-2); color: var(--muted); white-space: nowrap;
}
.need[data-k="review"] { background: #fef3c7; color: #92400e; }
.need[data-k="draft"] { background: var(--accent-soft); color: var(--accent-text); }

.rail-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; padding: 8px 12px; border-top: 1px solid var(--line);
  font-size: 12px; color: var(--muted); min-height: 38px;
}
.rail-count { font-variant-numeric: tabular-nums; }

.case-title[role="button"] { cursor: text; border-radius: var(--r-sm); }
@media (hover: hover) and (pointer: fine) {
  .case-title[role="button"]:hover { background: var(--surface-2); }
}

.hint { font-size: 12px; color: var(--muted); margin-top: 4px; line-height: 1.45; }
.m-status { font-size: 12px; color: var(--muted); margin-right: auto; }

.hist { display: flex; flex-direction: column; gap: 4px; max-height: 190px;
        overflow-y: auto; }
.hist-row {
  display: flex; justify-content: space-between; gap: 12px; font-size: 12.5px;
  padding: 5px 0; border-bottom: 1px solid var(--line);
}
.hist-row:last-child { border-bottom: none; }
.hist-when { color: var(--muted); white-space: nowrap; font-size: 11.5px; }

/* Supporting-evidence strength, as a word rather than a unit nobody reads. */
.t-strength {
  font-size: 11.5px; padding: 2px 8px; border-radius: 999px;
  background: var(--surface-2); color: var(--muted); white-space: nowrap;
}
.t-strength[data-s="strong"] { background: var(--accent-soft); color: var(--accent-text); font-weight: 600; }
.t-strength[data-s="moderate"] { background: #eef4f3; color: var(--accent-text); }
.t-strength:empty { display: none; }

.toast-x {
  background: none; border: 0; color: inherit; cursor: pointer;
  font-size: 17px; line-height: 1; padding: 0 2px; margin-left: 6px;
  opacity: 0.7;
}
.toast-x:hover { opacity: 1; }

/* Notes already saved to a case — the source of the recorded findings. */
.saved-notes { border-top: 1px solid var(--line); padding: 0 14px 12px; }
.saved-note {
  display: flex; justify-content: space-between; align-items: center;
  gap: 12px; width: 100%; text-align: left; padding: 7px 8px;
  border-radius: var(--r-sm); font-size: 13px; cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .saved-note:hover { background: var(--surface-2); }
}
.note-read {
  white-space: pre-wrap; font-size: 13.5px; line-height: 1.55;
  max-height: 55vh; overflow-y: auto; padding: 4px 2px;
}

/* The workflow tabs overflow on a phone; the last one (Letters) is the
   deliverable, so its edge must be visibly cut rather than simply absent. */
@media (max-width: 480px) {
  .tabs {
    -webkit-mask-image: linear-gradient(to right, #000 88%, transparent 100%);
    mask-image: linear-gradient(to right, #000 88%, transparent 100%);
  }
}

.status-reason { color: var(--muted); font-style: italic; }

/* ------------------------------------------- tappable explanations ------ */
/* A title= tooltip does not exist on a touch screen, and the bedside device
   is a phone. Anything a clinician needs in order to read a number
   correctly is a real button. */
/* The HIT AREA is 24px — the WCAG 2.5.8 minimum — while the visible ring
   stays small enough to sit inline in a sentence. These exist so that an
   explanation is reachable on a phone; at 15px square they were too small
   to tap reliably on the device they were built for. The circle is drawn by
   a pseudo-element so the button's own box can be bigger than it looks. */
.info-btn {
  position: relative; display: inline-flex;
  align-items: center; justify-content: center;
  width: 24px; height: 24px; margin-left: 2px; padding: 0;
  border: 0; background: none; color: var(--muted);
  font: 600 10px/1 ui-sans-serif, system-ui, sans-serif;
  cursor: pointer; vertical-align: middle; flex: none;
}
.info-btn::before {
  content: ""; position: absolute; inset: 4px; z-index: -1;
  border-radius: 50%; border: 1px solid var(--line-strong);
  background: var(--surface);
}
.info-btn:hover::before, .info-btn[aria-expanded="true"]::before {
  background: var(--accent-soft); border-color: transparent;
}
.info-btn:hover, .info-btn[aria-expanded="true"] { color: var(--accent-text); }
.info-pop {
  position: fixed; z-index: 60;
  background: var(--ink); color: #fff;
  padding: 10px 12px; border-radius: var(--r-sm);
  font-size: 12.5px; line-height: 1.5;
  box-shadow: var(--shadow-lg);
}

/* The bar orders the list; the percentage is a different quantity. Saying so
   once, visibly, stops the third row's higher percentage reading as a
   contradiction of its position. */
.cand-legend {
  padding: 0 15px 12px; font-size: 12px; line-height: 1.45; color: var(--muted);
}
.cand-legend b { color: var(--ink-2); font-weight: 600; }

/* A destructive confirm must not look like the ordinary primary action. */
.btn-danger { background: var(--danger); color: #fff; }
@media (hover: hover) and (pointer: fine) {
  .btn-danger:hover { filter: brightness(0.94); }
}

/* Two identical bars imply a measured difference that is not there. Where
   steps genuinely carry the same information, the interface says so and
   points at what the choice between them actually turns on. */
.tie-note {
  font-size: 11.5px; color: var(--muted); margin-top: 4px;
  display: flex; align-items: baseline; gap: 4px; flex-wrap: wrap;
}

/* Connection state, said before work is lost rather than after. */
.conn-bar {
  background: var(--warn-soft); color: var(--warn);
  border-bottom: 1px solid #fcd34d;
  padding: 8px 16px; font-size: 12.5px; line-height: 1.45;
}

/* Treatment given — a record of what the clinician wrote, never a suggestion. */
.tx-form {
  display: grid; gap: 8px; margin-bottom: 8px;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  align-items: center;
}
.tx-dose {
  font-family: ui-monospace, monospace; font-size: 12px;
  color: var(--ink-2); background: var(--surface-2);
  padding: 1px 7px; border-radius: 999px;
}
.tx-response {
  font-size: 12.5px; color: var(--muted); padding: 0 4px 4px 14px;
  border-left: 2px solid var(--line); margin-left: 8px;
}

/* ---------------------------------------- evidence comparison grid ------ */
/* The ranked list says which condition leads; this says why, by putting the
   candidates against the same findings. Collapsed by default: it answers a
   question the clinician asks second, after reading the list. */
.disclosure, .grid-wrap, .conf-wrap {
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface); margin: 0 0 12px;
}
.disclosure > summary, .grid-wrap > summary, .conf-wrap > summary {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding: 11px 14px; cursor: pointer; list-style: none;
  font-size: 13px;
  min-height: 26px;                 /* tappable */
}
.disclosure > summary::-webkit-details-marker,
.grid-wrap > summary::-webkit-details-marker,
.conf-wrap > summary::-webkit-details-marker { display: none; }
.gw-title { font-weight: 600; }
.gw-sub { color: var(--muted); font-size: 12.5px; }
.disclosure > summary .chev, .grid-wrap > summary .chev, .conf-wrap > summary .chev {
  margin-left: auto; transition: transform 160ms ease;
}
.disclosure[open] > summary .chev, .grid-wrap[open] > summary .chev,
.conf-wrap[open] > summary .chev { transform: rotate(180deg); }
.disclosure-body { padding: 2px 14px 14px; }
@media (max-width: 560px) {
  /* the sub wrapped onto its own line and pushed the chevron to a third,
     leaving a summary three lines tall with a lone arrow on the last */
  .disclosure > summary .gw-sub, .grid-wrap > summary .gw-sub,
  .conf-wrap > summary .gw-sub { flex-basis: 100%; order: 3; }
}

/* wide content scrolls inside its own container, never the page body */
/* POSITIONED, SO THAT WHAT IS INSIDE IT STAYS INSIDE IT.
   `.sr-only` is absolutely positioned and 1px wide, and with no positioned
   ancestor its containing block is the document — so its static position,
   deep inside a 474px comparison grid, stretched the PAGE to 474px at 360px
   wide and let a clinician scroll the whole workspace 114px sideways. The
   grid is meant to scroll; the page is not. (The operator console had the
   same bug, in its audit table, with the same one-line cause.) */
.grid-scroll { overflow-x: auto; padding: 0 14px; position: relative; }
.ev-grid { border-collapse: collapse; font-size: 12.5px; }
.ev-grid th, .ev-grid td { padding: 5px 6px; }
.gh-find, .gr-find {
  text-align: left; font-weight: 500; white-space: nowrap;
  position: sticky; left: 0; background: var(--surface);
  padding-right: 12px !important;
}
.gh-find { color: var(--muted); font-weight: 600; font-size: 11.5px;
           text-transform: uppercase; letter-spacing: .04em; }
.gh-cand { width: 62px; vertical-align: bottom; }
.gh-rank {
  display: block; font-weight: 700; font-size: 13px; text-align: center;
}
.gh-name {
  display: block; width: 62px; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; color: var(--muted); font-size: 10.5px;
  font-weight: 400; text-align: center;
}
.ev-grid tbody tr { border-top: 1px solid var(--line); }
.ev-grid tr.disc .gr-find { font-weight: 650; }
.disc-tag {
  display: inline-block; margin-left: 7px; font-size: 10.5px; font-weight: 500;
  color: var(--accent-text); background: var(--accent-soft);
  padding: 1px 6px; border-radius: 999px; text-transform: none;
  letter-spacing: 0;
}
.gc { text-align: center; }
/* strength is carried by SIZE as well as colour — a photocopy, a
   colour-blind reader and a bright ward screen all have to work */
.gc-mark {
  display: inline-block; border-radius: 3px; background: var(--accent);
  width: 22px; height: 13px; vertical-align: middle;
}
.gc-mark[data-k="strong"], .gc[data-k="strong"] .gc-mark { opacity: 1; height: 15px; }
.gc-mark[data-k="moderate"], .gc[data-k="moderate"] .gc-mark { opacity: .62; height: 10px; }
.gc-mark[data-k="slight"], .gc[data-k="slight"] .gc-mark { opacity: .34; height: 6px; }
.gc-mark[data-k="no"], .gc[data-k="no"] .gc-mark {
  background: none; color: var(--muted); font-size: 14px; line-height: 13px;
  width: 22px; height: 13px; text-align: center;
}
.gc[data-k="none"] .gc-mark { background: none; }
.grid-key {
  display: flex; gap: 14px; flex-wrap: wrap; align-items: center;
  padding: 9px 14px 12px; font-size: 11.5px; color: var(--muted);
}
.grid-key span { display: inline-flex; align-items: center; gap: 5px; }
.grid-key i { flex: none; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* On a phone the finding labels were so wide that only ONE candidate column
   fitted — which defeats a view whose whole purpose is comparison. Cap the
   label, let it ellipsise (the full text stays in the title and for screen
   readers), and shrink the discriminator tag to a mark so at least three
   candidates are visible side by side before any scrolling. */
@media (max-width: 620px) {
  .gr-find, .gh-find {
    max-width: 138px; overflow: hidden; text-overflow: ellipsis;
    padding-right: 8px !important;
  }
  .disc-tag {
    font-size: 0; padding: 0; margin-left: 5px;
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--accent); vertical-align: middle;
  }
  .gh-cand, .gh-name { width: 48px; }
  .gc-mark { width: 18px; }
  .grid-key { font-size: 11px; gap: 10px; }
}

/* ------------------------------------------- calibrated confidence ------ */
/* The bar the clinician sees is min-max, so the leader always renders full
   however poor the fit. These are the two things that actually predict
   whether the leader is right, on the measured scales, with this case marked
   on them — and the shape of the segments says "further right is better"
   without anyone reading a number. */
/* the frame is the shared .disclosure ruleset; only the body differs */
.conf-body { padding: 2px 14px 14px; display: flex; flex-direction: column; gap: 14px; }

.cal { display: flex; flex-direction: column; gap: 6px; }
.cal-track {
  position: relative; display: flex; gap: 3px; height: 34px;
  align-items: flex-end;
}
.cal-seg {
  display: flex; align-items: flex-end; height: 100%;
  background: var(--surface-2); border-radius: 3px; overflow: hidden;
}
.cal-seg i { display: block; width: 100%; background: var(--accent); opacity: .45; }
/* the marker is a shape, not a colour: it has to survive a photocopy */
.cal-you {
  position: absolute; top: -3px; bottom: -3px; width: 2px;
  background: var(--ink); border-radius: 2px;
}
.cal-you::before {
  content: ""; position: absolute; top: -4px; left: -4px;
  border-left: 5px solid transparent; border-right: 5px solid transparent;
  border-top: 6px solid var(--ink);
}
.cal-cap { font-size: 12.5px; color: var(--muted); line-height: 1.5; }
.cal-cap b, .conf-line b { color: var(--ink-2); font-weight: 600; }
.conf-line { font-size: 12.5px; color: var(--muted); line-height: 1.5; }
.conf-caveat {
  display: flex; gap: 10px; align-items: flex-start;
  font-size: 11.5px; line-height: 1.55; color: var(--muted);
  margin-top: 12px; padding: 11px 13px;
  background: var(--op-bg);
  border: 1px solid var(--op-line);
  border-radius: var(--r-md);
}
.conf-caveat svg { flex: none; margin-top: 1px; color: var(--accent-text); }

/* ------------------------------------------------------ case thread ----- */
/* Five separate records — findings, tests, treatments, laboratory results,
   rankings — told as one story, because reconstructing it by hand is what a
   clinician does when they pick up a case they have not seen for weeks. */
.thread { list-style: none; margin: 0; padding: 0 0 0 4px; }
.th-day {
  font-size: 11px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted);
  margin: 12px 0 6px; padding-left: 26px;
}
.th-day:first-child { margin-top: 2px; }
.th-item {
  position: relative; display: grid; gap: 0 10px;
  grid-template-columns: 62px 19px minmax(0, 1fr);
  padding: 5px 0; align-items: start;
}
/* the date column: shown when the day changes, held open when it does not,
   so the spine and the words stay in one line down the card */
.th-when {
  grid-column: 1; font-size: 11px; line-height: 1.5; color: var(--faint-text);
  font-variant-numeric: tabular-nums; visibility: hidden;
}
.th-item[data-newday] .th-when { visibility: visible; }
.th-dot { grid-column: 2; }
.th-body { grid-column: 3; }
/* the spine */
.th-item::before {
  content: ""; position: absolute; left: 81px; top: 0; bottom: -6px;
  width: 1px; background: var(--line);
}
.th-item:last-child::before { bottom: 50%; }
@media (max-width: 460px) {
  .th-item { grid-template-columns: 19px minmax(0, 1fr); }
  .th-when { grid-column: 1 / -1; visibility: visible; margin-bottom: 2px; }
  .th-item:not([data-newday]) .th-when { display: none; }
  .th-dot { grid-column: 1; }
  .th-body { grid-column: 2; }
  .th-item::before { left: 9px; }
}
.th-dot {
  position: relative; z-index: 1; flex: none;
  width: 19px; height: 19px; border-radius: 50%;
  background: var(--surface-2); border: 1px solid var(--line);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px; color: var(--muted); line-height: 1;
}
/* each kind of event is a different GLYPH as well as a different tint —
   colour alone would not survive a photocopy or a colour-blind reader */
.th-item[data-kind="analysis"] .th-dot {
  background: var(--accent-soft); color: var(--accent-text); border-color: transparent;
}
.th-item[data-kind="treatment"] .th-dot { background: #fef3c7; color: #92400e; border-color: transparent; }
.th-item[data-kind="genetics"] .th-dot,
.th-item[data-kind="investigation"] .th-dot { background: var(--surface-2); }
.th-body { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.th-kind {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); font-weight: 600;
}
.th-text { font-size: 13px; font-weight: 550; }
.th-detail { font-size: 12px; color: var(--muted); }
.th-span {
  display: inline-block; margin-top: 2px; font-size: 11px;
  color: #92400e; background: #fef3c7; border-radius: 999px; padding: 1px 8px;
  align-self: flex-start;
}

/* The arithmetic said out loud. A finding every candidate explains places the
   family, not the diagnosis — which is the thing a ranked list never says. */
.grid-headline {
  margin: 0; padding: 0 14px 10px; font-size: 12.5px; line-height: 1.55;
  color: var(--muted); max-width: 66ch;
}
.grid-headline b { color: var(--ink-2); font-weight: 650; }

/* The discriminator marker must survive the label being ellipsised — it was
   being clipped along with the text, which hid the one thing the row is
   sorted for. Flex keeps the marker outside the truncating box. */
.gr-find { display: flex; align-items: center; gap: 0; }
.gr-find > .disc-tag { flex: none; order: 2; }
.ev-grid .gr-find { white-space: nowrap; }
@media (max-width: 620px) {
  .gr-find {
    max-width: 150px;
  }
  /* the text truncates; the marker does not */
  .gr-find::before { content: none; }
}
.gr-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }

/* ================================================== the Why tab ========= */
.why-intro {
  font-size: 12.5px; color: var(--muted); line-height: 1.6;
  max-width: 70ch; margin: 0 0 14px;
}
.why-pick {
  font-size: 12.5px; padding: 4px 8px; max-width: 260px; margin-left: auto;
  font-weight: 400; text-transform: none; letter-spacing: 0;
}
.why-limits {
  display: flex; gap: 9px; align-items: flex-start; margin-top: 16px;
  font-size: 11.5px; line-height: 1.6; color: var(--muted);
  border-top: 1px solid var(--line); padding-top: 12px; max-width: 74ch;
}
.why-limits svg { flex: none; margin-top: 2px; }
.why-limits b { color: var(--ink-2); }

/* ---- what moved the score: the model is additive, so this is exact ----- */
.force-head {
  display: flex; align-items: baseline; gap: 9px; margin-bottom: 8px;
}
.f-rank {
  font-weight: 700; font-size: 13px; color: var(--muted);
  min-width: 18px; text-align: center;
}
.f-name { font-weight: 600; font-size: 14px; }
.f-fit { margin-left: auto; font-size: 12px; color: var(--muted); }
.force-bal { display: flex; gap: 3px; height: 18px; margin-bottom: 12px; }
.fb-seg {
  display: flex; align-items: center; justify-content: center;
  font-size: 10.5px; border-radius: 4px; white-space: nowrap;
  overflow: hidden; padding: 0 6px;
}
.fb-seg[data-k="for"] { background: var(--accent-soft); color: var(--accent-text); }
.fb-seg[data-k="against"] { background: var(--danger-soft); color: var(--danger); }

.force-rows { list-style: none; margin: 0; padding: 0;
              display: flex; flex-direction: column; gap: 5px; }
.fr { display: grid; grid-template-columns: minmax(90px,1.1fr) minmax(120px,1.4fr) minmax(0,1.2fr);
      gap: 10px; align-items: center; font-size: 12.5px; }
.fr-label { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fr-track { position: relative; height: 15px; background: var(--surface-2); border-radius: 3px; }
.fr-axis { position: absolute; left: 50%; top: -2px; bottom: -2px;
           width: 1px; background: var(--line-strong); }
.fr-bar { position: absolute; top: 2px; bottom: 2px; border-radius: 2px; }
/* direction is carried by SIDE as well as colour, so it survives a photocopy */
.fr-bar[data-k="for"] { background: var(--accent); }
.fr-bar[data-k="against"] { background: var(--danger); }
.fr-why { color: var(--muted); font-size: 11.5px;
          overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.force-key { display: flex; gap: 14px; align-items: center; flex-wrap: wrap;
             margin-top: 11px; font-size: 11.5px; color: var(--muted); }
.force-key i.fk { display: inline-block; width: 16px; height: 8px;
                  border-radius: 2px; margin-right: 5px; vertical-align: middle; }
.fk[data-k="for"] { background: var(--accent); }
.fk[data-k="against"] { background: var(--danger); }

/* ---- the reasoning path ------------------------------------------------ */
.path-title { font-size: 12px; font-weight: 650; color: var(--muted);
              text-transform: uppercase; letter-spacing: .05em; margin-bottom: 8px; }
.path-scroll { overflow-x: auto; position: relative; }
.p-edge { fill: none; stroke: var(--line-strong); stroke-width: 1.2; }
.p-edge[data-k="strong"] { stroke: var(--accent); stroke-width: 2; }
.p-edge[data-k="moderate"] { stroke: var(--accent); stroke-width: 1.4; opacity: .7; }
.p-edge[data-k="slight"] { stroke: var(--line-strong); stroke-width: 1; }
.p-node rect { fill: var(--surface-2); stroke: var(--line); }
.p-node text { font: 11px ui-sans-serif, system-ui, sans-serif; fill: var(--ink); }
.p-node .p-sub { font-size: 9.5px; fill: var(--muted); }
.p-node[data-k="condition"] rect { fill: var(--accent-soft); stroke: transparent; }
.p-node[data-k="condition"] text { fill: var(--accent-text); font-weight: 600; }
.p-node[data-k="gene"] rect { fill: #eef4f3; stroke: var(--line); }
.p-node[data-k="gene"] text { font-family: ui-monospace, monospace; font-weight: 600; }
.p-node[data-k="variant"] rect { fill: #fef3c7; stroke: transparent; }
.p-node[data-k="variant"] text { fill: #92400e; }
.p-node[data-k="none"] rect { fill: none; stroke-dasharray: 3 3; }
.p-node[data-k="none"] text { fill: var(--muted); }
.path-key { font-size: 11px; color: var(--muted); margin-top: 8px; }

/* At 375px the three-column force row squeezed the finding name — the most
   important part of it — down to "Lower limb h..." and the reason to
   "a known feat...". Stack instead: the name gets the full width, the bar
   gets the full width under it, and the reason sits below in small text.
   Nothing is truncated and the bar is longer, not shorter, than before. */
@media (max-width: 560px) {
  .fr {
    display: block; padding: 6px 0;
    border-bottom: 1px solid var(--line);
  }
  .fr:last-child { border-bottom: none; }
  .fr-label { display: block; white-space: normal; margin-bottom: 4px; }
  .fr-track { display: block; width: 100%; }
  .fr-why {
    display: block; white-space: normal; margin-top: 3px; font-size: 11px;
  }
  .force-head { flex-wrap: wrap; }
  .f-fit { margin-left: 26px; }
  .why-pick { max-width: 100%; margin: 6px 0 0; }
  .section-title { flex-wrap: wrap; }
}

/* Stopping a treatment is a record of a clinical decision — it needs a
   target you can hit on a ward round, not a 21px sliver. */
.tx-stop { padding: 4px 10px; font-size: 12px; min-height: 26px; }


/* ---------- people ---------- */

.m-rule { border: 0; border-top: 1px solid var(--line); margin: 2px 0; }
.member-list { display: grid; gap: 2px; max-height: 220px; overflow-y: auto; }
.member {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 2px;
  border-bottom: 1px solid var(--line);
}
.member:last-child { border-bottom: 0; }
.member-who { flex: 1; min-width: 0; display: grid; gap: 1px; }
.member-name { font-weight: 550; font-size: 13px; }
.member-sub { font-size: 11.5px; color: var(--muted); }
/* Somebody whose access was taken away stays visible and legible — a removed
   colleague who vanishes from the list looks like a mistake, and an
   administrator needs to see that the removal actually happened. */
.member[data-gone="true"] .member-name::after {
  content: ' — no access';
  font-weight: 450; color: var(--danger);
}
.member-note { font-size: 11.5px; color: var(--faint); }
.member-act { padding: 4px 10px; font-size: 12px; }

/* ---------- your account ---------- */

.mfa-state { margin-top: 8px; display: grid; gap: 6px; }
.mfa-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.mfa-say { flex: 1; min-width: 200px; font-size: 12.5px; color: var(--muted); }
.mfa-act { padding: 5px 11px; font-size: 12.5px; }
.hint-warn { color: var(--danger); }

.mfa-setup { display: grid; gap: 10px; }
.mfa-steps {
  margin: 0; padding-left: 20px;
  display: grid; gap: 6px;
  font-size: 12.5px; color: var(--text);
}
/* The key is typed into a phone by hand, so it gets the space and the letter
   spacing that makes a wrong character obvious. */
.mfa-secret {
  display: block; margin-top: 5px; padding: 8px 10px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-md);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 14px; letter-spacing: 0.08em;
  user-select: all;
}
.mfa-confirm { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.mfa-confirm .field { max-width: 150px; }
.mfa-codes {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 6px;
  padding: 10px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.mfa-codes code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px; letter-spacing: 0.04em;
  user-select: all;
}


/* ---------- looking up a condition outside the shown list ---------- */

.rank-lookup { margin: 10px 0 4px; display: grid; gap: 6px; }
.rank-lookup-row { display: flex; gap: 8px; align-items: center; }
.rank-lookup-row .field { flex: 1; min-width: 0; }
.rank-out { display: grid; gap: 4px; margin-top: 4px; }
.rank-hit {
  display: grid; grid-template-columns: auto 1fr auto;
  gap: 10px; align-items: baseline;
  padding: 6px 8px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
  font-size: 12.5px;
}
/* The position is the answer to the question, so it leads and does not wrap. */
.rank-hit-pos { font-weight: 650; font-variant-numeric: tabular-nums; white-space: nowrap; }
.rank-hit-name { min-width: 0; }
.rank-hit-fit { color: var(--muted); white-space: nowrap; }
@media (max-width: 560px) {
  .rank-hit { grid-template-columns: auto 1fr; }
  .rank-hit-fit { grid-column: 2; }
}


/* ---------- second factor: making a typed key survivable ---------- */

.mfa-key-row {
  display: flex; align-items: center; gap: 8px;
  flex-wrap: wrap; margin-top: 4px;
}
/* The key must break between groups, never mid-group: a four-character
   group split across two lines is exactly where a mistyped key comes from. */
.mfa-secret {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px; letter-spacing: 0.04em;
  padding: 5px 8px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm, 6px);
  background: var(--surface-2);
  word-spacing: 0.35em;
  overflow-wrap: normal;
  user-select: all;
}
.mfa-copy { padding: 4px 10px; font-size: 12px; flex: none; }
.mfa-codes-acts {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  margin-top: 10px;
}

/* ---------- operator console ---------- */
/* A DIFFERENT GROUND FROM THE CLINICAL APP, on purpose. The caseload sits on
   warm stone; this sits on a cool one. An operator moves between a screen
   where they administer tenancy and a screen where somebody reads a child's
   record, and those two should never be mistaken for each other at a glance.
   Type, spacing and components are shared; the ground is not.

   It is a tool: scanned and operated rather than read, so the craft is
   information design — state before detail, status carried in form as well as
   in words, and depth used to say which surface you are meant to work on. */

.op-app {
  display: grid;
  grid-template-rows: 60px 1fr;
  height: 100dvh;
  background: var(--op-bg);
}

/* --- topbar -------------------------------------------------------------- */
.op-topbar {
  display: flex; align-items: center; gap: 14px;
  padding: 0 20px;
  background: var(--surface);
  border-bottom: 1px solid var(--op-line);
}
.op-topbar .brand-name { font-size: 17px; font-weight: 660; letter-spacing: -0.02em; }
/* THE SAME PHONE FIX THE CLINICAL TOPBAR ALREADY HAD, which had never
   reached this one. At 360px the operator's bar measured 453px: 329px of
   content, six 14px gaps and 40px of padding — so the whole console laid out
   453 wide and the PAGE scrolled sideways, taking Knowledge, Branding,
   Settings and Sign out off the right edge. The arithmetic is the whole bug;
   the gaps and the padding are most of it. */
@media (max-width: 620px) {
  .op-topbar { gap: 6px; padding: 0 12px; }
  .op-topbar .brand-name { font-size: 15px; }
  /* Kept for a screen reader, dropped from the layout: the console is
     unmistakably the operator's, and the name beside it is still on screen. */
  .op-topbar .op-topbar-role {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  .op-topbar .op-topbar-sep { display: none; }
  .op-topbar .op-whoami { min-width: 0; }
}
.op-topbar-sep { width: 1px; height: 22px; background: var(--op-line); flex: none; }
.op-topbar-role { font-size: 13px; color: var(--op-ink-soft); }
.op-whoami { display: flex; align-items: center; gap: 9px; }
.op-whoami .avatar { width: 30px; height: 30px; font-size: 11.5px; }
.op-whoami-name { font-size: 13.5px; font-weight: 570; }
.op-signout { gap: 7px; color: var(--op-ink-soft); }
.op-signout svg { width: 15px; height: 15px; }

/* --- the rail ------------------------------------------------------------ */
.op-body {
  display: grid; grid-template-rows: auto minmax(0, 1fr);
  grid-template-columns: 1fr; min-height: 0;
}
@media (min-width: 940px) {
  .op-body { grid-template-rows: minmax(0, 1fr); grid-template-columns: 216px minmax(0, 1fr); }
}
/* NARROW DOES NOT MEAN GONE. Hiding the rail below the breakpoint made
   Knowledge and Settings unreachable on a phone — navigation that disappears
   rather than adapting. It becomes a scrolling strip instead, and only the
   help card drops, because that one has somewhere else to live. */
.op-rail {
  display: flex;
  flex-direction: row;
  gap: 4px;
  padding: 10px 14px;
  overflow-x: auto;
  background: var(--surface);
  border-bottom: 1px solid var(--op-line);
}
.op-rail::-webkit-scrollbar { display: none; }
.op-rail { scrollbar-width: none; }
@media (min-width: 940px) {
  .op-rail {
    flex-direction: column;
    padding: 16px 14px;
    overflow-x: visible;
    border-bottom: 0;
    border-right: 1px solid var(--op-line);
  }
}
.op-nav { display: flex; gap: 4px; }
@media (min-width: 940px) { .op-nav { display: grid; gap: 3px; } }
.op-nav-item { white-space: nowrap; }
.op-nav-item {
  display: flex; align-items: center; gap: 11px;
  width: 100%; text-align: left;
  padding: 10px 12px;
  border-radius: 10px;
  font: inherit; font-size: 13.5px; font-weight: 550;
  color: var(--op-ink-soft);
  background: transparent; border: 0; cursor: pointer;
  transition: color 130ms ease, background-color 130ms ease,
    transform 140ms var(--ease-out);
}
.op-nav-item:active { transform: scale(0.985); }
.op-nav-icon { display: inline-flex; color: currentColor; }
.op-nav-icon svg { width: 18px; height: 18px; }
@media (hover: hover) and (pointer: fine) {
  .op-nav-item:hover { background: var(--op-line-soft); color: var(--ink); }
}
.op-nav-item[aria-current="page"] {
  background: var(--accent-soft);
  color: var(--accent-text);
  font-weight: 620;
}

.op-help {
  display: none;
  margin-top: auto;
  display: flex; gap: 11px; align-items: flex-start;
  padding: 13px;
  border: 1px solid var(--op-line);
  border-radius: 12px;
  background: linear-gradient(180deg, #ffffff, #f7fbfa);
  text-decoration: none;
  transition: border-color 130ms ease, box-shadow 140ms ease;
}
@media (min-width: 940px) { .op-help { display: flex; } }
@media (hover: hover) and (pointer: fine) {
  .op-help:hover { border-color: #cfe3de; box-shadow: var(--shadow-sm); }
}
.op-help-icon { color: var(--accent-text); display: inline-flex; }
.op-help-icon svg { width: 18px; height: 18px; }
.op-help-title { display: block; font-size: 12.5px; font-weight: 620; color: var(--ink); }
.op-help-link {
  display: inline-flex; align-items: center; gap: 5px; margin-top: 2px;
  font-size: 12px; color: var(--op-ink-soft);
}
.op-help-link svg { width: 12px; height: 12px; }

/* --- the page ------------------------------------------------------------ */
.op-main { overflow-y: auto; padding: 24px 22px 56px; }
@media (min-width: 940px) { .op-main { padding: 28px 32px 60px; } }
.op-inner {
  width: min(1180px, 100%);
  margin: 0 auto;
  display: grid; gap: 18px; align-content: start;
  /* THE COLUMN HOLDS ITS WIDTH; THE CONTENT SCROLLS INSIDE IT.
     A grid item's min-width is `auto`, and the implicit column here was
     therefore sized to the widest min-content among the panels — which is
     the knowledge release, `hp-releases-2026-09-01+obo:…`, a 391px line with
     nowhere to break. At 360px .op-inner measured 316 and the card inside it
     427, so the hero, the stat cards and the org list all hung off the right
     of a panel that then scrolled. Naming the track lets the card be narrower
     than its own text, which is what `overflow-x: auto` on the value was
     always for. */
  grid-template-columns: minmax(0, 1fr);
}

.op-hero {
  display: grid; gap: 20px;
  grid-template-columns: minmax(0, 1fr);
  align-items: center;
}
@media (min-width: 1040px) {
  .op-hero { grid-template-columns: minmax(0, 1fr) auto; gap: 32px; }
}
.op-eyebrow {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.11em;
  text-transform: uppercase; color: var(--op-ink-soft);
}
.op-hero-title {
  margin-top: 8px;
  font-size: 33px; font-weight: 650; letter-spacing: -0.032em; line-height: 1.1;
  text-wrap: balance;
}
.op-hero-lede {
  margin-top: 8px; max-width: 60ch;
  font-size: 14px; line-height: 1.5; color: var(--op-ink-soft);
  text-wrap: pretty;
}
.op-hero-side { display: none; align-items: flex-end; gap: 18px; }
@media (min-width: 1040px) { .op-hero-side { display: flex; } }
.op-hero-art { width: 300px; height: 150px; flex: none; }
.op-hero-tag {
  display: grid; gap: 1px;
  font-size: 13px; line-height: 1.45; color: var(--ink-2);
  padding-bottom: 8px;
}
.op-hero-rule {
  width: 34px; height: 3px; border-radius: 2px;
  background: var(--accent); margin-top: 9px;
}

/* --- stat cards ---------------------------------------------------------- */
.op-stats {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(238px, 1fr));
}
.op-stat {
  display: flex; align-items: center; gap: 14px;
  width: 100%; text-align: left;
  padding: 17px 16px;
  border: 1px solid var(--op-line);
  border-radius: 14px;
  background: var(--surface);
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(28, 25, 23, 0.03);
  transition: transform 140ms var(--ease-out), border-color 130ms ease,
    box-shadow 150ms ease;
}
.op-stat:active { transform: scale(0.99); }
@media (hover: hover) and (pointer: fine) {
  .op-stat:hover {
    border-color: #cfe3de;
    box-shadow: 0 1px 2px rgba(28, 25, 23, 0.04),
                0 8px 22px -10px rgba(28, 25, 23, 0.16);
  }
  .op-stat:hover .op-stat-go { transform: translateX(2px); color: var(--accent-text); }
}
/* Tinted badges, one hue per kind of fact. Three hues is a set; five is a
   fruit salad, so semantic colour (warn, bad) stays separate from these. */
.op-stat-badge {
  flex: none; width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center;
}
.op-stat-badge svg { width: 21px; height: 21px; }
.op-stat-badge.is-teal { background: #d8efe9; color: #0d5d56; }
.op-stat-badge.is-blue { background: #dde9f7; color: #1e4e8c; }
.op-stat-badge.is-violet { background: #e6e2f6; color: #4c3f96; }
.op-stat-badge.is-amber { background: #fbeacf; color: #92500b; }
.op-stat-body { display: grid; gap: 1px; min-width: 0; }
.op-stat-label { font-size: 12.5px; color: var(--op-ink-soft); }
.op-stat-value {
  font-size: 27px; font-weight: 640; letter-spacing: -0.03em; line-height: 1.15;
}
.op-stat-sub { font-size: 12px; color: var(--faint-text); }
.op-stat-sub.is-warn { color: var(--warn); }
.op-stat-sub.is-bad { color: var(--danger); }
.op-stat-go {
  margin-left: auto; color: var(--faint); display: inline-flex;
  transition: transform 150ms var(--ease-out), color 130ms ease;
}
.op-stat-go svg { width: 16px; height: 16px; }

/* --- the knowledge band -------------------------------------------------- */
.op-band {
  display: flex; align-items: center; gap: 13px; flex-wrap: wrap;
  width: 100%; text-align: left;
  padding: 14px 17px;
  border: 1px solid #d9eae6;
  border-radius: 14px;
  background: linear-gradient(180deg, #f4fbf9 0%, #edf7f5 100%);
  cursor: pointer;
  transition: border-color 130ms ease, box-shadow 150ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .op-band:hover { border-color: #b9dbd3; box-shadow: var(--shadow-sm); }
}
.op-band-icon { color: var(--accent-text); display: inline-flex; }
.op-band-icon svg { width: 19px; height: 19px; }
.op-band-label {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--accent-text);
}
.op-band-value {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px; color: var(--ink-2);
  background: var(--surface); border: 1px solid #d9eae6;
  border-radius: 7px; padding: 4px 10px;
  overflow-x: auto; white-space: nowrap; max-width: 100%;
}
.op-band-sep { width: 1px; height: 20px; background: #cfe3de; }
.op-band-note { font-size: 13px; color: var(--op-ink-soft); }

/* --- panes --------------------------------------------------------------- */
.op-panes { display: grid; gap: 18px; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 1040px) {
  .op-panes { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; }
}
.op-surface {
  background: var(--surface);
  border: 1px solid var(--op-line);
  border-radius: 16px;
  box-shadow: 0 1px 2px rgba(28, 25, 23, 0.03),
              0 10px 30px -18px rgba(28, 25, 23, 0.12);
}
.op-pane { padding: 20px; min-width: 0; }
.op-pane-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
}
.op-pane-title { display: flex; align-items: center; gap: 10px; }
.op-pane-badge {
  width: 34px; height: 34px; border-radius: 10px;
  display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent-text); flex: none;
}
.op-pane-badge svg { width: 17px; height: 17px; }
.op-title { font-size: 18px; font-weight: 650; letter-spacing: -0.02em; }
.op-subtitle { font-size: 14px; font-weight: 630; letter-spacing: -0.01em; }
.op-lede {
  margin-top: 9px; max-width: 66ch;
  font-size: 13px; line-height: 1.6; color: var(--op-ink-soft);
  text-wrap: pretty;
}
.op-count {
  font-size: 12px; font-weight: 620; color: var(--accent-text);
  background: var(--accent-soft); border-radius: 999px; padding: 2px 9px;
}
.op-new { gap: 6px; padding: 9px 15px; border-radius: 10px; }

.op-search { position: relative; margin-top: 16px; }
.op-search-icon {
  position: absolute; left: 13px; top: 50%; transform: translateY(-50%);
  color: var(--faint); pointer-events: none; display: inline-flex;
}
.op-search-icon svg { width: 16px; height: 16px; }
.op-search .field {
  width: 100%; padding: 11px 13px 11px 38px; border-radius: 10px;
  border-color: var(--op-line); font-size: 13.5px;
}
.op-list { display: grid; margin-top: 6px; }

/* --- a hospital in the list ---------------------------------------------- */
.op-org {
  display: flex; align-items: center; gap: 13px;
  width: 100%; text-align: left;
  padding: 14px 6px;
  border: 0; border-bottom: 1px solid var(--op-line-soft);
  background: transparent; cursor: pointer;
  transition: background-color 130ms ease;
}
.op-org:last-child { border-bottom: 0; }
@media (hover: hover) and (pointer: fine) {
  .op-org:hover { background: #f7fbfa; }
  .op-org:hover .op-org-go { transform: translateX(2px); color: var(--accent-text); }
}
.op-org.is-open { background: #f2f9f7; }
.op-org.is-open .op-org-badge { background: var(--accent); color: #fff; }
.op-org-badge {
  flex: none; width: 42px; height: 42px; border-radius: 12px;
  display: grid; place-items: center;
  background: #eef5f3; color: var(--accent-text);
  transition: background-color 140ms ease, color 140ms ease;
}
.op-org-badge svg { width: 19px; height: 19px; }
.op-org-main { min-width: 0; display: grid; gap: 1px; flex: 1; }
.op-org-name { font-weight: 590; font-size: 14px; }
.op-org-meta {
  font-size: 11.5px; color: var(--faint-text);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.op-admin { font-size: 12px; color: var(--op-ink-soft); display: block; }
.op-org-nobody { font-size: 12px; color: var(--danger); }
/* A HOSPITAL ROW IS SCANNED, NOT READ. `.op-org-main` already carried
   min-width: 0, but it is a GRID, and its implicit column was sized to the
   widest thing in it — an administrator's address, one unbreakable token.
   Every row was therefore as wide as the longest email in the list (355px at
   360px), so the list hung off the right of its panel and the panel scrolled.
   Truncated instead: the whole value is on the hospital's own screen, one
   tap away, which is where you go when you want to read it rather than find
   it. */
.op-org-main { grid-template-columns: minmax(0, 1fr); }
.op-org-name, .op-org-meta, .op-admin, .op-org-nobody {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.op-org-go { color: var(--faint); display: inline-flex; flex: none;
             transition: transform 150ms var(--ease-out), color 130ms ease; }
.op-org-go svg { width: 15px; height: 15px; }
.op-empty {
  padding: 26px; text-align: center;
  color: var(--faint-text); font-size: 13px;
  border: 1px dashed var(--op-line); border-radius: 12px; margin-top: 10px;
}

/* --- pills --------------------------------------------------------------- */
.pill {
  font-size: 11px; font-weight: 620; letter-spacing: 0.01em;
  padding: 4px 10px; border-radius: 999px; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 6px;
}
/* A dot as well as a colour: colour alone is not a signal everybody receives. */
.pill::before { content: ''; width: 6px; height: 6px; border-radius: 50%;
                background: currentColor; }
.pill-ok { background: #dcf3e7; color: #0b6b45; }
.pill-accent { background: var(--accent-soft); color: var(--accent-text); }
.pill-danger { background: var(--danger-soft); color: var(--danger); }
/* "We could not establish this" — distinct from both yes and no. Without it
   a failed check had to borrow one of the other two and assert something. */
.pill-warn { background: var(--warn-soft); color: var(--warn); }
.pill-muted { background: #f1f5f4; color: var(--faint-text); }
/* The sentence that explains an unknown, so the state is readable and not
   just a colour. */
.op-lede-warn { color: var(--warn); }

/* --- the detail / add pane ----------------------------------------------- */
.op-detail-head { display: grid; gap: 6px; }
.op-detail-title { display: flex; align-items: center; gap: 11px; flex-wrap: wrap; }
.op-hero2 { font-size: 22px; font-weight: 640; letter-spacing: -0.026em; }
.op-detail-actions { display: flex; gap: 9px; flex-wrap: wrap; margin-top: 12px; }
.op-section { margin-top: 24px; }
.op-section-head {
  display: flex; align-items: center; gap: 10px;
  padding-bottom: 10px; border-bottom: 1px solid var(--op-line);
}
.op-form { margin-top: 18px; }
.op-form .login-field { gap: 7px; }
.op-form .login-label { font-size: 13px; font-weight: 600; color: var(--ink-2); }
/* Fields carry a leading icon: it names the kind of thing without a second
   line of label, and it is what makes a form look considered rather than
   generated. */
.op-field { position: relative; }
.op-field-icon {
  position: absolute; left: 13px; top: 50%; transform: translateY(-50%);
  color: var(--faint); pointer-events: none; display: inline-flex;
}
.op-field-icon svg { width: 16px; height: 16px; }
.op-field .field {
  width: 100%; padding: 12px 13px 12px 40px; border-radius: 10px;
  border-color: var(--op-line); font-size: 14px;
}
.op-field .field::placeholder { color: #a9b5b2; }
.op-form .login-submit {
  margin-top: 18px; gap: 8px; padding: 14px 18px; border-radius: 11px;
  font-size: 14.5px;
}
.op-members { display: grid; gap: 8px; margin-top: 14px; }
.op-member {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  padding: 13px 14px;
  border: 1px solid var(--op-line); border-radius: 12px;
  background: var(--surface);
}
.op-member.is-revoked { background: #f7f9f9; }
.op-member-who { display: flex; align-items: center; gap: 12px; min-width: 0; }
.op-member-who .avatar { width: 36px; height: 36px; font-size: 12.5px; }
.op-member-name {
  font-weight: 580; font-size: 14px;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.op-member-email { font-size: 12.5px; color: var(--op-ink-soft); margin-top: 1px; }
.op-member-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.op-member-actions .btn { padding: 7px 12px; font-size: 12.5px; border-radius: 9px; }
.op-select { position: relative; display: inline-flex; align-items: center; }
.op-select select {
  appearance: none; -webkit-appearance: none;
  padding: 7px 32px 7px 11px;
  font: inherit; font-size: 12.5px;
  border-radius: 9px; border: 1px solid var(--op-line);
  background: var(--surface); cursor: pointer;
}
.op-select svg {
  position: absolute; right: 10px; pointer-events: none;
  color: var(--muted); width: 13px; height: 13px;
}
.op-select select:disabled { opacity: 0.5; cursor: default; }

.op-status {
  margin-top: 14px; font-size: 13px; line-height: 1.55;
  color: var(--accent-text);
  max-height: 0; opacity: 0; overflow: hidden;
  transition: opacity 180ms var(--ease-out), max-height 180ms var(--ease-out);
}
.op-status.is-shown { max-height: 8em; opacity: 1; }
.op-status.is-bad { color: var(--danger); }

.op-add { margin-top: 22px; border-top: 1px solid var(--op-line); padding-top: 16px; }
.op-add summary {
  font-size: 13px; font-weight: 620; color: var(--accent-text);
  cursor: pointer; list-style: none; width: fit-content;
}
.op-add summary::-webkit-details-marker { display: none; }
.op-add summary::before { content: '+ '; }
.op-add[open] summary::before { content: '\2013  '; }

.op-loading { padding: 40px; text-align: center; color: var(--faint-text); font-size: 13px; }
/* One thing has gone wrong and it is worth reading: an alert, not a chip. */
.op-alert {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 15px 17px;
  border: 1px solid var(--warn);
  border-radius: 14px;
  background: var(--warn-soft);
  color: #7a4408;
  font-size: 13px; line-height: 1.55;
}
.op-alert b { font-weight: 650; }
.op-alert-icon { color: var(--warn); display: inline-flex; flex: none; margin-top: 1px; }
.op-alert-icon svg { width: 18px; height: 18px; }
.au-org { font-size: 12.5px; color: var(--op-ink-soft); }
.au-act { text-align: right; white-space: nowrap; }
.au-act .btn { padding: 5px 11px; font-size: 12px; border-radius: 8px; }
.au-rowerr { color: var(--danger); font-size: 12.5px; padding-top: 0 !important;
              line-height: 1.5; max-width: 70ch; }
.au-wait { font-size: 12px; color: var(--faint-text); white-space: nowrap; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
/* WHO ADMINISTERS THE HOSPITAL, as a control rather than an assumption.
   Every account this console created used to be an administrator; the flag
   now has a visible switch on the add form and on each member row. */
.op-check {
  display: flex; align-items: flex-start; gap: 9px; cursor: pointer;
  font-size: 13px; line-height: 1.5; color: var(--op-ink-soft);
  margin: 2px 0 14px; max-width: 46ch;
}
.op-check input { margin: 2px 0 0; accent-color: var(--accent); flex: none; }
.op-check-inline {
  margin: 0; align-items: center; white-space: nowrap; max-width: none;
  font-size: 12.5px;
}
.op-check-inline input { margin: 0; }
.op-check-inline input:disabled + span { opacity: 0.5; }

.op-checklist { margin-top: 14px; display: grid; gap: 10px; padding-left: 18px; }
.op-checklist li {
  font-size: 13px; line-height: 1.6; color: var(--op-ink-soft); max-width: 72ch;
}
.op-checklist b { color: var(--ink); font-weight: 620; }
.op-kv-head { display: flex; align-items: center; gap: 13px; }
.op-kv {
  display: inline-block; margin-top: 4px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px; color: var(--ink-2);
  background: #f4f8f7; border: 1px solid var(--op-line);
  border-radius: 8px; padding: 5px 11px;
  overflow-x: auto; white-space: nowrap; max-width: 100%;
}

/* --- hold to suspend ------------------------------------------------------ */
/* The only destructive act here, and the only one with friction. A click is
   the wrong affordance: the same gesture as "open this hospital", one row
   away, and a confirm dialog is something people learn to dismiss without
   reading. Its COMPLETION is the trigger (transitionend), so the bar cannot
   disagree with the action. */
.op-hold { position: relative; overflow: hidden; isolation: isolate; }
.op-hold-fill {
  position: absolute; inset: 0;
  background: var(--danger);
  clip-path: inset(0 100% 0 0);
  transition: clip-path 200ms var(--ease-out);
  z-index: -1;
}
.op-hold.is-holding .op-hold-fill {
  clip-path: inset(0 0 0 0);
  transition: clip-path 1400ms linear;
}
.op-hold-label { position: relative; transition: color 200ms ease; }
.op-hold.is-holding .op-hold-label { color: #fff; }
.op-hold.is-holding { border-color: var(--danger); }

.op-handover {
  margin-top: 18px;
  padding: 17px 18px;
  border: 1px solid #b9dbd3;
  border-radius: 14px;
  background: linear-gradient(180deg, #f2fbf8 0%, #e7f5f1 100%);
  color: var(--accent-text);
}
.op-handover-head { font-weight: 650; font-size: 14.5px; }
.op-handover p { margin-top: 6px; font-size: 13px; line-height: 1.55; text-wrap: pretty; }
.op-secret-row { display: flex; gap: 9px; align-items: center; margin-top: 13px; }
.op-secret {
  flex: 1; min-width: 0;
  padding: 11px 13px;
  background: var(--surface);
  border: 1px solid #cfe3de; border-radius: 9px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13.5px; color: var(--ink);
  overflow-x: auto; white-space: nowrap;
}
.op-invite {
  margin-top: 0; background: var(--surface);
  border: 1px solid var(--op-line); border-radius: 16px;
  padding: 20px 22px 22px; max-width: none;
}

/* ---------- areas: the topbar nav, oversight, organisation ---------- */
/* Two of the four roles had no screen at all. These are those screens, sharing
   the console's surface recipe so the product reads as one thing. */

/* THE ADMIN SHELL DID NOT FIT A PHONE, ON ANY OF ITS THREE SCREENS.
   A flex item's `min-width` is `auto`, so the tab strip could not shrink
   below its own content: the topbar measured 516px inside a 375px viewport
   and Organisation, Oversight and Services all scrolled sideways. The tabs
   are how you reach the other two screens, so they scroll rather than being
   dropped or wrapped — and the scrollbar is hidden because a 3px trough
   under four tabs reads as damage. */
.area-nav {
  display: flex; gap: 2px; margin-left: 6px;
  min-width: 0; overflow-x: auto;
  scrollbar-width: none; -ms-overflow-style: none;
  -webkit-overflow-scrolling: touch;
}
.area-nav::-webkit-scrollbar { display: none; }
/* THE ONLY SIGN THAT THERE IS MORE. The strip hides its scrollbar, so on a
   phone a clinician who also administers — which is what signing a hospital
   up makes you — saw "Cases Organisation Ser…" in 199px with Oversight and
   Second opinions past the edge and nothing to say so. A fade on whichever
   side has more is the affordance; it is applied only when the strip really
   overflows, or it would dim the last tab on a bar with room to spare. */
.area-nav.has-more-right, .op-rail.has-more-right {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent);
}
.area-nav.has-more-left, .op-rail.has-more-left {
  -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 26px), transparent);
  mask-image: linear-gradient(to left, #000 calc(100% - 26px), transparent);
}
.area-nav.has-more-left.has-more-right,
.op-rail.has-more-left.has-more-right {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 26px,
    #000 calc(100% - 26px), transparent);
  mask-image: linear-gradient(to right, transparent, #000 26px,
    #000 calc(100% - 26px), transparent);
}
.area-nav > * { flex: none; }
.area-tab {
  font: inherit; font-size: 12.5px; font-weight: 550;
  color: var(--muted);
  padding: 5px 11px; border-radius: 999px;
  border: 1px solid transparent; background: transparent;
  cursor: pointer;
  transition: color 130ms ease, background-color 130ms ease,
    border-color 130ms ease, transform 140ms var(--ease-out);
}
.area-tab:active { transform: scale(0.97); }
@media (hover: hover) and (pointer: fine) {
  .area-tab:hover { color: var(--ink); background: var(--surface-2); }
}
.area-tab[aria-current="page"] {
  color: var(--accent-text);
  background: var(--accent-soft);
  border-color: rgba(15, 118, 110, 0.16);
}

.area-shell { grid-template-rows: 52px 1fr; min-width: 0; }
/* Grid and flex children default to `min-width: auto` too, so without these
   the topbar's intrinsic width propagated back out to the shell and the
   scroll appeared on the document instead. */
.area-shell > .topbar, .area-shell > .area-main { min-width: 0; }
.area-main {
  overflow-y: auto;
  padding: 26px 22px 48px;
  /* A COOL WASH, not the caseload's warm stone. These screens administer
     accounts; the warm ground belongs to the record of a child's care, and
     using it here made "who can sign in" look like a clinical document. */
  background:
    radial-gradient(1100px 340px at 78% -8%, #eaf5f7 0%, rgba(234, 245, 247, 0) 70%),
    linear-gradient(180deg, #ffffff 0%, var(--op-bg) 55%, #f4f8f8 100%);
}
.area-inner {
  width: min(1080px, 100%);
  margin: 0 auto;
  display: grid;
  gap: 20px;
  align-content: start;
}
.area-inner .op-section {
  margin-top: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 20px 22px 22px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    0 1px 2px rgba(28, 25, 23, 0.04),
    0 6px 18px -6px rgba(28, 25, 23, 0.07);
}
.au-head { display: flex; align-items: flex-start; justify-content: space-between;
           gap: 24px; flex-wrap: wrap; }

/* --- the chain verdict --------------------------------------------------- */
/* The headline, not a footnote. An append-only hash-chained trail whose entire
   value is the word "intact" is worth nothing if nobody is ever shown it. */
.au-chain {
  padding: 13px 16px;
  border-radius: var(--r-md);
  background: var(--accent-soft);
  border: 1px solid rgba(15, 118, 110, 0.2);
  color: var(--accent-text);
  min-width: 250px;
}
.au-chain-verdict {
  font-size: 14px; font-weight: 650; letter-spacing: -0.01em;
  display: flex; align-items: center; gap: 7px;
}
.au-chain-verdict::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%;
  background: currentColor;
}
.au-chain-detail { margin-top: 4px; font-size: 12px; line-height: 1.5; }
.au-chain.is-broken {
  background: var(--danger-soft);
  border-color: var(--danger);
  color: var(--danger);
}
.au-chain.is-broken .au-chain-verdict { letter-spacing: 0.02em; }

.au-filters { display: flex; gap: 6px; flex-wrap: wrap; }
.au-warn {
  margin-top: 14px; font-size: 12.5px; line-height: 1.5;
  color: var(--warn); max-width: 66ch;
}

/* --- the trail ----------------------------------------------------------- */
.au-table-wrap {
  overflow-x: auto;
  /* POSITIONED SO THAT WHAT IS INSIDE IT STAYS INSIDE IT. The last column's
     header is a `.visually-hidden` span — absolutely positioned, 1px wide,
     for a screen reader. With no positioned ancestor its containing block
     was the document, and its static position is the far end of a 585px
     table, so a 1px span for a screen reader stretched the PAGE to 461px at
     360px wide. The table scrolls here; everything in it should too. */
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 16px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    0 1px 2px rgba(28, 25, 23, 0.04),
    0 6px 18px -6px rgba(28, 25, 23, 0.07);
}
.au-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.au-table th {
  text-align: left; font-size: 10.5px; font-weight: 650; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--muted);
  padding: 12px 16px 9px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.au-row td { padding: 10px 16px; border-bottom: 1px solid var(--line); vertical-align: top; }
.au-row:last-child td { border-bottom: 0; }
/* An event that changed WHO CAN REACH RECORDS is the one a reviewer is looking
   for, so it is the one with a mark against it. */
.au-row.is-notable td:first-child { box-shadow: inset 2px 0 0 var(--accent); }
.au-when { white-space: nowrap; width: 1%; }
.au-time { font-weight: 600; }
.au-date { display: block; font-size: 11px; color: var(--faint-text); margin-top: 1px; }
.au-label { font-weight: 550; }
.au-meta { display: block; font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.au-what .pill { margin-left: 7px; }
.au-restype { font-size: 12px; color: var(--muted); }
.au-resid {
  display: block; margin-top: 2px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px; color: var(--faint-text);
}
.op-invite {
  margin-top: 0;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: 16px;
  padding: 20px 22px 22px; max-width: none;
  box-shadow: 0 1px 2px rgba(28, 25, 23, 0.04),
              0 6px 18px -6px rgba(28, 25, 23, 0.07);
}
.op-invite .op-subtitle { margin-bottom: 4px; }

/* ==================== organisation & oversight ==========================
   The org admin's two screens. They share the operator console's cards and
   palette — same product, same job of administering access — but sit on the
   area shell rather than the console's sidebar, because an administrator here
   is one hospital looking at itself rather than the platform looking down.

   Layout is a working column and a rail: the task on the left, the standing
   context on the right. The rail drops BELOW the main column rather than
   disappearing under 1080px, because "Add another admin" lives in it and a
   control that vanishes on a laptop is a control nobody uses. */

.area-shell { background: var(--op-bg); }
.area-inner { width: min(1180px, 100%); }

.area-cols { display: grid; gap: 18px; align-items: start; }
@media (min-width: 1080px) {
  .area-cols { grid-template-columns: minmax(0, 1fr) 340px; }
}
.area-col-main { display: grid; gap: 18px; align-content: start; min-width: 0; }
.oc-rail { display: grid; gap: 14px; align-content: start; min-width: 0; }

/* --- the working card ---------------------------------------------------- */
.oc-card {
  background: var(--surface);
  border: 1px solid var(--op-line);
  border-radius: 16px;
  box-shadow: 0 1px 2px rgba(28, 25, 23, 0.03);
  overflow: hidden;
}
.oc-card-head {
  display: flex; align-items: flex-start; gap: 13px;
  padding: 18px 18px 14px;
}
.oc-card-icon {
  display: grid; place-items: center;
  width: 34px; height: 34px; flex: none;
  border-radius: 10px;
  background: var(--accent-soft); color: var(--accent-text);
}
.oc-card-icon svg { width: 18px; height: 18px; }
.oc-card-words { min-width: 0; flex: 1; }
.oc-card-title {
  font-size: 17px; font-weight: 640; letter-spacing: -0.015em; line-height: 1.2;
}
.oc-card-sub {
  margin-top: 4px; font-size: 13px; line-height: 1.45; color: var(--op-ink-soft);
  text-wrap: pretty;
}
.oc-card-head .btn { flex: none; align-self: center; }
.oc-card-body { padding: 0 18px 18px; display: grid; gap: 14px; }
.oc-card-foot {
  padding: 12px 18px;
  border-top: 1px solid var(--op-line-soft);
  background: var(--surface-2);
  display: flex; align-items: center; gap: 12px;
}
.oc-count { font-size: 12.5px; color: var(--op-ink-soft); }

/* --- search -------------------------------------------------------------- */
.oc-search { position: relative; }
.oc-search-icon {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  display: grid; place-items: center;
  color: var(--faint-text); pointer-events: none;
}
.oc-search-icon svg { width: 16px; height: 16px; }
.oc-search .field { width: 100%; padding-left: 36px; }

/* --- people and invitation tables ---------------------------------------- */
/* Both tables scroll inside their own box. The page body must never scroll
   sideways — an email address is unpredictably long and a role select has a
   floor width, so this table WILL overflow on a phone. */
.oc-table-wrap { overflow-x: auto; }
.oc-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.oc-table th {
  text-align: left; font-size: 11px; font-weight: 650;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--op-ink-soft);
  padding: 9px 10px; border-bottom: 1px solid var(--op-line);
  white-space: nowrap;
}
.oc-th-actions { text-align: right; }
.oc-table td { padding: 11px 10px; border-bottom: 1px solid var(--op-line-soft); }
.oc-table tr:last-child td { border-bottom: 0; }
.oc-row.is-revoked { opacity: 0.62; }
.oc-person { display: flex; align-items: center; gap: 11px; min-width: 210px; }
.oc-person-words { display: grid; min-width: 0; }
.oc-person-name { font-weight: 570; letter-spacing: -0.01em; }
.oc-person-email {
  font-size: 12px; color: var(--op-ink-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.avatar.is-ghost {
  background: var(--surface-2); color: var(--faint-text);
  border: 1px dashed var(--op-line);
}
.avatar.is-ghost svg { width: 15px; height: 15px; }
.oc-role { min-width: 160px; }
.oc-plain { color: var(--ink-2); }
.oc-status { display: flex; flex-wrap: wrap; gap: 5px; min-width: 120px; }
.oc-actions { position: relative; text-align: right; white-space: nowrap; }
.oc-nomenu { display: inline-block; width: 30px; }
.oc-when { font-size: 12.5px; color: var(--op-ink-soft); }

/* --- the row menu -------------------------------------------------------- */
.oc-menu {
  position: absolute; right: 8px; top: calc(100% - 6px); z-index: 30;
  min-width: 208px;
  display: grid; gap: 2px; padding: 5px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  box-shadow: var(--shadow-lg);
  text-align: left;
  /* Nothing in the real world appears from nothing: it scales from ALMOST
     its full size, and from the top-right where the kebab that opened it is. */
  transform-origin: top right;
  animation: ocMenuIn 150ms var(--ease-out) both;
}
@keyframes ocMenuIn {
  from { opacity: 0; transform: scale(0.96) translateY(-3px); }
  to   { opacity: 1; transform: none; }
}
.oc-menu-item {
  display: flex; align-items: center; gap: 9px;
  width: 100%; padding: 8px 10px;
  border: 0; border-radius: 8px; background: none;
  font: inherit; font-size: 13px; color: var(--ink);
  text-align: left; cursor: pointer;
  transition: background 120ms ease;
}
.oc-menu-item:hover, .oc-menu-item:focus-visible { background: var(--surface-2); }
.oc-menu-item.is-danger { color: var(--danger); }
.oc-menu-item.is-danger:hover { background: var(--danger-soft); }
.oc-menu-item svg { flex: none; opacity: 0.75; }

/* --- the amber banner ---------------------------------------------------- */
/* A state that needs a decision, sitting inside the card it is about rather
   than at the top of the page where it would be read once and scrolled past. */
.oc-banner {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 14px;
  border: 1px solid #f6dfb4;
  border-radius: 12px;
  background: linear-gradient(180deg, #fffbf3 0%, #fef6e9 100%);
}
.oc-banner-icon { color: var(--warn); display: grid; place-items: center; flex: none; }
.oc-banner-words { display: grid; gap: 2px; font-size: 13px; min-width: 0; flex: 1; }
.oc-banner-words strong { color: #92400e; font-weight: 630; }
.oc-banner-words span { color: #9a5b12; line-height: 1.45; }
.btn-warn-ghost {
  border: 1px solid #e3b878; background: var(--surface); color: #92400e;
  flex: none;
}
.btn-warn-ghost:hover { background: #fffaf1; border-color: #d9a355; }

/* --- the rail ------------------------------------------------------------ */
.oc-rcard {
  background: var(--surface);
  border: 1px solid var(--op-line);
  border-radius: 14px;
  padding: 15px 15px 16px;
  display: grid; gap: 11px;
  box-shadow: 0 1px 2px rgba(28, 25, 23, 0.03);
}
.oc-rcard.is-warn {
  border-color: #f0d5a8;
  background: linear-gradient(180deg, #fffdf8 0%, #fef8ee 100%);
}
.oc-rcard-head { display: flex; align-items: center; gap: 10px; }
.oc-rcard-icon {
  display: grid; place-items: center;
  width: 28px; height: 28px; flex: none;
  border-radius: 9px;
  background: var(--accent-soft); color: var(--accent-text);
}
.oc-rcard.is-warn .oc-rcard-icon { background: #fdebc8; color: #92400e; }
.oc-rcard-icon svg { width: 16px; height: 16px; }
.oc-rcard-title { font-size: 14.5px; font-weight: 630; letter-spacing: -0.012em; }
.oc-rcard.is-warn .oc-rcard-title { color: #92400e; }
.oc-rtext { font-size: 13px; line-height: 1.5; color: var(--op-ink-soft); text-wrap: pretty; }
.oc-rcard.is-warn .oc-rtext { color: #8a5a1c; }
.oc-rnote {
  display: flex; gap: 7px; align-items: flex-start;
  font-size: 12px; line-height: 1.45; color: var(--faint-text);
}
.oc-rnote svg { flex: none; width: 14px; height: 14px; margin-top: 1px; }

.oc-note {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 11px 12px; border-radius: 11px;
  background: #eefaf6; border: 1px solid #cdeae2;
}
.oc-note-icon { color: var(--accent-text); display: grid; place-items: center; flex: none; }
.oc-note-icon svg { width: 16px; height: 16px; }
.oc-note div { display: grid; gap: 2px; font-size: 12.5px; line-height: 1.45; }
.oc-note strong { color: var(--accent-text); font-weight: 620; }
.oc-note span { color: #37665e; }

.oc-tips { display: grid; gap: 7px; }
.oc-tips-head {
  display: flex; align-items: center; gap: 7px;
  font-size: 12.5px; font-weight: 620; color: var(--ink-2);
}
.oc-tips-head svg { color: var(--warn); }
.oc-tips ul, .oc-bullets { display: grid; gap: 5px; padding-left: 17px; margin: 0; }
.oc-tips li, .oc-bullets li {
  font-size: 12.5px; line-height: 1.45; color: var(--op-ink-soft);
}
.oc-tips li::marker, .oc-bullets li::marker { color: var(--faint); }

.oc-kv { display: grid; gap: 9px; margin: 0; }
.oc-kv dt {
  font-size: 11px; font-weight: 650; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--faint-text);
}
.oc-kv dd { margin: 0 0 2px; font-size: 13.5px; color: var(--ink); }
.oc-kv code { font-size: 12.5px; }

/* --- oversight: the chain verdict and the trail -------------------------- */
.au-chain {
  display: flex; align-items: flex-start; gap: 12px;
  max-width: 520px; padding: 15px 16px;
  border-radius: 14px;
  border: 1px solid #cdeae2;
  background: linear-gradient(180deg, #f2fbf8 0%, #e6f6f1 100%);
}
.au-chain-icon { color: var(--accent-text); display: grid; place-items: center; flex: none; }
.au-chain-icon svg { width: 22px; height: 22px; }
.au-chain-verdict {
  font-size: 16px; font-weight: 650; letter-spacing: -0.015em; color: var(--accent-text);
}
.au-chain-detail { margin-top: 3px; font-size: 12.5px; line-height: 1.45; color: #37665e; }
.au-chain.is-broken { border-color: #f3c2c2; background: linear-gradient(180deg, #fff5f5 0%, #fee9e9 100%); }
.au-chain.is-broken .au-chain-icon, .au-chain.is-broken .au-chain-verdict { color: var(--danger); }
.au-chain.is-broken .au-chain-detail { color: #9b2c2c; }

.au-what-line { display: flex; align-items: center; gap: 8px; }
.au-what-icon {
  display: grid; place-items: center;
  width: 24px; height: 24px; flex: none;
  border-radius: 7px; background: var(--surface-2); color: var(--op-ink-soft);
  border: 1px solid var(--op-line-soft);
}
.au-what-icon svg { width: 13px; height: 13px; }
.au-by { font-size: 13px; color: var(--ink-2); white-space: nowrap; }
.au-integrity { white-space: nowrap; }
.au-integrity .pill { display: inline-flex; align-items: center; gap: 4px; }

/* The rail must not vanish on a laptop — it holds "Add another admin". */
@media (max-width: 1079px) {
  .oc-rail { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
}

/* Who the actor is TO YOU, beside their name. A platform operator acting on
   your hospital is a different fact from one of your own administrators
   doing it, and no name alone conveys that. */
.au-actor-kind { margin-left: 6px; vertical-align: middle; }
.au-by { white-space: normal; }

/* The specialist's attestation, in the confirm bar beside the action it
   qualifies — not in a settings panel somewhere, because it is a decision
   about THESE findings and nothing else. */
.cb-attest {
  display: flex; align-items: center; gap: 8px;
  font-size: 12.5px; color: var(--ink-2);
  cursor: pointer; user-select: none;
  padding: 6px 10px; border-radius: 999px;
  border: 1px solid var(--accent-soft); background: #f3fbf8;
}
.cb-attest input { accent-color: var(--accent); cursor: pointer; }
.cb-attest b { font-weight: 620; color: var(--accent-text); }

/* ===================== the case aside ==================================
   Standing context beside the work: who this child is, how far the case has
   got, and what this tool does not do.

   THE AGE AND SEX WERE BEHIND A BUTTON. They decide which safety warnings
   apply and get checked constantly, and the answer to "how old is this child
   again" was three clicks and a modal covering the findings you were
   checking it against. */

/* SCOPED, because this block sits after the phone rule that collapses .main
   to one column. Written unconditionally it won a same-specificity cascade
   at every width — including 375px, where the rail then took 264 of the 375
   and the work column had 111 to render a differential in. Nothing errored;
   the text simply overlapped, and two layout tests caught it. */
@media (min-width: 901px) {
  .main { grid-template-columns: 244px minmax(0, 1fr); }
}
@media (min-width: 1240px) {
  .main { grid-template-columns: 244px minmax(0, 1fr) 320px; }
}
.case-aside {
  display: none;
  min-width: 0;
  overflow-y: auto;
  padding: 18px 20px 40px;
  border-left: 1px solid var(--line);
  background: linear-gradient(180deg, #ffffff 0%, var(--op-bg) 60%);
  gap: 14px;
  align-content: start;
  /* EACH CARD IS AS TALL AS ITS OWN CONTENTS. Without this the three rows
     came out exactly equal — 247px each, dividing the column's height between
     them — and the Patient details card, whose contents need 310, had its
     last row clipped by the card's own `overflow: hidden`. The current stage
     simply ended mid-sentence, and nothing about it looked like a bug. */
  grid-auto-rows: min-content;
}
@media (min-width: 1240px) { .case-aside { display: grid; } }

.case-aside .oc-card-head { padding: 15px 15px 11px; gap: 11px; }
.case-aside .oc-card-icon { width: 30px; height: 30px; border-radius: 9px; }
.case-aside .oc-card-icon svg { width: 16px; height: 16px; }
.case-aside .oc-card-title { font-size: 15px; }
.case-aside .oc-card-body { padding: 0 15px 15px; gap: 11px; }
.case-aside .oc-card-head .btn { padding: 3px 10px; font-size: 12px; }

/* --- patient details ----------------------------------------------------- */
.pd-list { display: grid; gap: 0; margin: 0; }
.pd-row {
  display: grid; grid-template-columns: 110px minmax(0, 1fr);
  gap: 10px; align-items: baseline;
  padding: 8px 0;
  border-bottom: 1px solid var(--op-line-soft);
}
.pd-row:last-child { border-bottom: 0; }
.pd-row dt { font-size: 12.5px; color: var(--op-ink-soft); }
.pd-row dd { margin: 0; font-size: 13px; font-weight: 550; color: var(--ink); }
.pd-row code { font-size: 12.5px; font-weight: 500; }
.pd-none { font-weight: 400; color: var(--faint-text); font-style: italic; }
.pd-stage { display: block; }
.pd-stage-sub {
  display: block; margin-top: 3px;
  font-size: 12px; font-weight: 400; line-height: 1.4; color: var(--op-ink-soft);
}

/* --- the stepper --------------------------------------------------------- */
/* Every step is a BUTTON. It shows where you are, so it should also take you
   there — a progress indicator you cannot click is a picture of navigation
   sitting next to the thing it is describing. */
.cs-steps { display: grid; gap: 2px; }
.cs-step {
  display: flex; align-items: flex-start; gap: 11px;
  width: 100%; padding: 8px; text-align: left;
  border: 0; border-radius: 10px; background: none;
  font: inherit; cursor: pointer;
  transition: background 130ms ease;
}
.cs-step:hover { background: var(--surface-2); }
.cs-num {
  display: grid; place-items: center;
  width: 24px; height: 24px; flex: none;
  border-radius: 50%;
  font-size: 12px; font-weight: 620;
  background: var(--surface-2); color: var(--op-ink-soft);
  border: 1px solid var(--op-line);
}
.cs-num svg { width: 12px; height: 12px; }
.cs-step.is-done .cs-num {
  background: var(--accent-soft); color: var(--accent-text);
  border-color: transparent;
}
.cs-step.is-now .cs-num {
  background: var(--accent); color: var(--accent-ink); border-color: transparent;
  box-shadow: 0 0 0 3px rgba(15, 118, 110, 0.14);
}
.cs-words { display: grid; gap: 2px; min-width: 0; }
.cs-title { font-size: 13px; font-weight: 570; color: var(--ink-2); }
.cs-step.is-now .cs-title { color: var(--ink); font-weight: 640; }
.cs-sub { font-size: 11.5px; line-height: 1.4; color: var(--op-ink-soft); }

/* --- guidance ------------------------------------------------------------ */
.oc-card.is-guidance {
  border-color: #cdeae2;
  background: linear-gradient(180deg, #f4fbf9 0%, #eef8f5 100%);
}
.oc-card.is-guidance .oc-card-icon { background: #ddf3ec; color: var(--accent-text); }
.cg-list { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.cg-list li {
  display: flex; gap: 8px; align-items: flex-start;
  font-size: 12.5px; line-height: 1.45; color: #33645c;
}
.cg-list svg { flex: none; margin-top: 2px; color: var(--accent); }

/* The heading of the primary object on the primary tab. It was a
   `.section-title` — 12px uppercase grey — which is the right treatment for a
   divider between groups and the wrong one for the name of the thing you came
   here to look at. */
.panel-heading {
  display: flex; align-items: center; gap: 11px;
  margin: 0 0 12px;
}
.panel-heading h2 {
  font-size: 17px; font-weight: 640; letter-spacing: -0.015em;
}
.panel-heading-icon {
  display: grid; place-items: center;
  width: 32px; height: 32px; flex: none;
  border-radius: 10px;
  background: var(--accent-soft); color: var(--accent-text);
}
.panel-heading-icon svg { width: 17px; height: 17px; }

/* ================== the case workspace, as cards ========================
   The capture panel was a heading, then controls, then an empty state, all
   sitting directly on the page. Each block is a separate thing you do, so
   each gets its own surface — which is also what makes the empty state read
   as "this card has nothing in it yet" rather than "this page is broken". */

.work-card {
  background: var(--surface);
  border: 1px solid var(--op-line);
  border-radius: 16px;
  padding: 18px;
  margin-bottom: 14px;
  box-shadow: 0 1px 2px rgba(28, 25, 23, 0.03);
}
.work-card .panel-heading { margin-bottom: 14px; }
.work-card .hpo-search { margin-bottom: 0; }

/* --- the collapsible cards ---------------------------------------------- */
.disclosure {
  border-radius: 14px;
  border-color: var(--op-line);
  box-shadow: 0 1px 2px rgba(28, 25, 23, 0.03);
  transition: border-color 140ms ease, box-shadow 140ms ease;
}
.disclosure:hover { border-color: var(--line-strong); }
.disclosure > summary { padding: 14px 16px; align-items: center; gap: 13px; }
.disclosure.has-icon > summary { padding: 13px 16px; }
.disc-icon {
  display: grid; place-items: center;
  width: 34px; height: 34px; flex: none;
  border-radius: 11px;
  background: var(--accent-soft); color: var(--accent-text);
}
.disc-icon svg { width: 17px; height: 17px; }
.disc-words {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  min-width: 0; flex: 1;
}
.disclosure .gw-title { font-size: 14.5px; font-weight: 620; letter-spacing: -0.012em; }
.disclosure .gw-sub { color: var(--op-ink-soft); }
.disclosure-body { padding: 4px 16px 16px; }
.disclosure.has-icon .disclosure-body { padding-left: 63px; }
@media (max-width: 640px) {
  .disclosure.has-icon .disclosure-body { padding-left: 16px; }
}

/* --- the empty state, as part of the card ------------------------------- */
.work-card .empty {
  padding: 40px 20px;
  border-radius: 12px;
  background: linear-gradient(180deg, #fafdfc 0%, #f2faf7 100%);
  border: 1px solid var(--op-line-soft);
  margin-top: 14px;
}
.work-card .empty .e-glyph {
  display: grid; place-items: center;
  width: 56px; height: 56px; margin: 0 auto 14px;
  border-radius: 50%;
  background: var(--surface); color: var(--accent-text);
  border: 1px solid #d7ece6;
}
.work-card .empty .e-glyph svg { width: 24px; height: 24px; }
.work-card .empty .e-title { font-size: 15.5px; font-weight: 640; color: var(--ink); }
.work-card .empty .e-sub { line-height: 1.55; max-width: 46ch; margin: 6px auto 0; }

/* --- the case title ------------------------------------------------------ */
/* It is the name of the child's case and the first thing read on the screen;
   19px put it level with a section label. */
.case-title { font-size: 26px; font-weight: 660; letter-spacing: -0.03em; }
.case-head { padding: 22px 26px 0; }
/* THE PHONE SIZES ABOVE WERE DEAD. The 900px block sets .case-title to 17px
   and .case-head to 16px sides, and these two rules — same specificity,
   later in the file — silently overrode both when the title was enlarged for
   desktop. On a 375px phone the title rendered at 26px and wrapped to two
   lines, so the header took 263px before the case's own content began. 20px
   keeps it the most prominent thing on the screen, which is why it was
   enlarged, without spending a second line on it. Declared here, after the
   rule it corrects, because that ordering is what broke it. */
@media (max-width: 900px) {
  .case-title { font-size: 20px; }
  .case-head { padding: 14px 16px 0; }
}

/* A statistic with nowhere to go: same surface, no pointer, no chevron. */
.op-stat.is-static { cursor: default; }
.op-stat.is-static:hover { border-color: var(--op-line); box-shadow: 0 1px 2px rgba(28, 25, 23, 0.03); }
.op-stat.is-static:active { transform: none; }

/* The help block is informational now, not a link. */
.op-help-note { display: block; font-size: 11.5px; line-height: 1.45; color: var(--op-ink-soft); margin-top: 2px; }


/* ================= Possible conditions ==================================
   The stage a clinician spends longest on, so it carries the most weight in
   how trustworthy the whole application feels. The shape is: a stack of
   notes that qualify the list, then the list, then the provenance.

   Every note is a TILE + WORDS. The tile makes the note's kind readable
   before the sentence is, and separating the first sentence from the rest
   means the point survives a skim — the failure mode for a caution is not
   being disbelieved, it is not being read. */
.pc-note {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 13px 15px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  margin-bottom: 10px;
  box-shadow: var(--shadow-sm);
}
.pc-note-body { min-width: 0; flex: 1; }
.pc-note-body p { margin: 0; font-size: 12.5px; line-height: 1.55; color: var(--muted); }
.pc-note-body p b { color: var(--ink-2); font-weight: 600; }
.pc-note-title {
  font-size: 13px; font-weight: 600; color: var(--ink);
  margin-bottom: 3px;
}
.pc-tile {
  flex: none; display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: 9px;
  background: var(--op-bg); color: var(--accent-text);
  border: 1px solid var(--op-line);
}
.pc-tile svg { width: 16px; height: 16px; }
.pc-note-warn { border-color: #f6d98a; background: var(--warn-soft); }
.pc-note-warn .pc-note-body p { color: var(--warn); }
.pc-note-warn .pc-note-body p b { color: #92400e; }
.pc-note-warn .pc-tile {
  background: rgba(255, 255, 255, 0.68); border-color: #f0cf82; color: var(--warn);
}
/* The one place on this screen that asks the clinician a question, so it is
   the one panel that is tinted. It answers the fear the list creates —
   "what if the thing I am worried about is not here" — and that is worth
   looking like an offer rather than a footnote. */
.pc-lookup {
  display: grid; gap: 10px;
  grid-template-columns: 30px minmax(0, 1fr);
  padding: 15px;
  margin: 14px 0 18px;
  border: 1px solid var(--op-line);
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, var(--op-bg), var(--surface) 140%);
}
.pc-lookup-tile {
  grid-row: 1; display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent-text);
}
.pc-lookup-tile svg { width: 15px; height: 15px; }
.pc-lookup-words { grid-column: 2; }
.pc-lookup-words h3 {
  margin: 0; font-size: 13.5px; font-weight: 600; color: var(--ink);
}
.pc-lookup-words p { margin: 2px 0 0; font-size: 12px; color: var(--muted); }
.pc-lookup-row {
  grid-column: 2; display: flex; gap: 9px; align-items: center;
}
.pc-search { position: relative; flex: 1; min-width: 0; display: block; }
.pc-search svg {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  width: 15px; height: 15px; color: var(--faint); pointer-events: none;
}
.pc-search .field { width: 100%; padding-left: 34px; background: var(--surface); }
.pc-lookup-note, .pc-lookup .rank-out { grid-column: 2; }
.pc-lookup-note { font-size: 11.5px; line-height: 1.5; color: var(--muted); }
@media (max-width: 640px) {
  .pc-lookup { grid-template-columns: minmax(0, 1fr); }
  .pc-lookup-tile { display: none; }
  .pc-lookup-words, .pc-lookup-row, .pc-lookup-note, .pc-lookup .rank-out { grid-column: 1; }
  .pc-lookup-row { flex-wrap: wrap; }
  .pc-lookup-row .btn { width: 100%; }
}

/* The scale legend sits beside the count it describes rather than above the
   list, so the sentence and the picture are read as one line. */
.strip-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 20px; padding: 2px 4px 6px;
}
.sh-showing { margin: 0; font-size: 12px; color: var(--muted); }
.sh-axis { flex: none; }
.sh-cap {
  display: block; font-size: 11px; line-height: 1.4; white-space: nowrap;
  color: var(--muted); text-align: right; margin-bottom: 6px;
}
/* the scale itself stays the width of the dot column it describes */
.sh-rule, .sh-ends { width: 190px; margin-left: auto; }
.sh-cap-q { color: var(--faint-text); }
.sh-ends { color: var(--faint-text); }
@media (max-width: 720px) {
  .strip-head { flex-direction: column; align-items: stretch; gap: 10px; }
  .sh-cap { text-align: left; white-space: normal; }
  .sh-rule, .sh-ends { width: auto; margin-left: 0; }
}

/* A numeral alone reads as body text at the start of a line. In a tile it
   reads as a rank, which is what it is. */
.cand .rank {
  display: grid; place-items: center;
  width: 26px; height: 26px; border-radius: 8px;
  background: var(--surface-2); border: 1px solid var(--line);
  font-size: 12px; font-weight: 600; color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.cand[data-open="true"] .rank,
.cand-row:hover .rank { border-color: var(--line-strong); }
.cand-row { padding: 13px 15px; }
.cand .d-label { font-size: 13.5px; letter-spacing: -0.005em; }
.cand .d-meta { margin-top: 3px; gap: 1px 6px; }
.cand .d-sep { font-size: 11px; color: var(--faint); }
.cand .d-flags { padding-left: 55px; }

/* The header's patient button and the aside's Edit open the same editor.
   Where the aside is on screen, one of them is noise.
   THE BREAKPOINT MUST MATCH the one that shows .case-aside above, exactly.
   At 1180px it did not, and between 1180 and 1240 the button was hidden
   while the aside was still hidden too — sixty pixels of window in which
   nothing could open the patient editor at all. */
@media (min-width: 1240px) { .case-head #case-details { display: none; } }

/* ---------- Re-run -------------------------------------------------------
   The only control on the provenance strip, and the one that costs real
   work when pressed, so it should look like something you decide to press
   rather than a link you might brush past. It was a 12px ghost button with
   3px of padding.

   It states what it does with a mark and a word, presses in (scale, not
   colour — the surface is already pale), and spins its own icon while the
   run is in flight, which is where the feedback belongs: the strip sits at
   the end of the list, far from any progress the panel shows. */
.btn-rerun {
  display: inline-flex; align-items: center; gap: 7px;
  margin-left: auto; padding: 0 13px; height: 32px;
  font: inherit; font-size: 12.5px; font-weight: 550;
  color: var(--ink-2); cursor: pointer;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 99px;
  box-shadow: var(--shadow-sm);
  /* named properties, never `all`: `all` would animate the box-shadow swap
     and the icon's rotation together and fight the spin below */
  transition: transform 160ms var(--ease-out),
              border-color 160ms ease, background-color 160ms ease,
              box-shadow 160ms ease;
}
.btn-rerun svg { width: 14px; height: 14px; color: var(--accent); flex: none; }
@media (hover: hover) and (pointer: fine) {
  .btn-rerun:hover {
    background: var(--surface);
    border-color: var(--accent);
    box-shadow: 0 2px 8px -2px rgba(15, 118, 110, 0.22), var(--shadow-sm);
    transform: translateY(-1px);
  }
}
.btn-rerun:active { transform: translateY(0) scale(0.97); }
.btn-rerun:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.btn-rerun[data-busy="true"] {
  pointer-events: none; color: var(--muted); border-color: var(--line);
}
.btn-rerun[data-busy="true"] svg { animation: rerun-spin 900ms linear infinite; }
@keyframes rerun-spin { to { transform: rotate(360deg); } }
/* A spinner is decoration; a person who has asked for less motion still
   needs to know the button was heard, so the label carries it instead. */
@media (prefers-reduced-motion: reduce) {
  .btn-rerun { transition: none; }
  .btn-rerun[data-busy="true"] svg { animation: none; }
}
.rl-prov { color: var(--muted); }

/* ================= the Why tab =========================================
   The page that shows the working. Every section here used to be a
   COLLAPSED strip, which is the wrong default for exactly this page: a
   clinician deciding whether to believe a ranking had to open four things
   first, and what nobody opens may as well not have been computed. Open,
   with a chevron to put it away, is the other way round. */
.why-intro {
  font-size: 12.5px; line-height: 1.6; color: var(--muted);
  /* 78ch here was already a measure; it just was not a tight enough one —
     `ch` is the width of "0", so 78 of them rendered about 101 characters.
     The token is the same intent with a value that was measured. */
  margin: 0 2px 14px; max-width: var(--measure);
}
.wcard {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  margin-bottom: 12px;
  overflow: hidden;
}
.wcard-head {
  display: flex; align-items: center; gap: 12px;
  padding: 15px 18px; cursor: pointer;
  list-style: none;
  transition: background-color 140ms ease;
}
.wcard-head::-webkit-details-marker { display: none; }
.wcard[open] .wcard-head { border-bottom: 1px solid var(--op-line-soft); }
@media (hover: hover) and (pointer: fine) {
  .wcard-head:hover { background: var(--surface-2); }
}
.wcard-head:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.wcard-title {
  margin: 0; font-size: 14.5px; font-weight: 600; color: var(--ink);
  letter-spacing: -0.01em;
}
.wcard-pill {
  display: inline-flex; align-items: center;
  font-size: 11.5px; font-weight: 550;
  color: var(--accent-text); background: var(--accent-soft);
  padding: 3px 10px; border-radius: 99px;
}
/* the picker rides in the header, so it must not look like the pill */
.wcard-pill:has(.why-pick), .wcard-head .why-pick { background: none; padding: 0; }
.wcard-head .why-pick {
  max-width: 340px; height: 30px; font-size: 12px;
  cursor: pointer;
}
.wcard-chev { margin-left: auto; display: grid; place-items: center; color: var(--faint); }
.wcard-chev svg { transition: transform 220ms var(--ease-out); }
.wcard[open] .wcard-chev svg { transform: rotate(180deg); }
.wcard-body { padding: 16px 18px 18px; }

/* --- the three measured constraints ------------------------------------ */
.wm-row {
  display: grid; gap: 12px;
  /* 196px, not 230: the three constraints are read together — the ranking is
     only as good as the WORST of them — so they belong on one row wherever
     one will hold them. At 230 the main column fell four pixels short and
     the third dropped to a line of its own, reading as an afterthought. */
  grid-template-columns: repeat(auto-fit, minmax(196px, 1fr));
}
.wm {
  display: flex; flex-direction: column;
  padding: 13px 13px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
}
.wm .wm-cap { margin-top: auto; padding-top: 9px; }
.wm-head { display: flex; align-items: flex-start; gap: 5px; margin-bottom: 10px; }
/* 11px and a tighter affordance, measured: at 11.5px with a 24px info button
   the longest of the three titles — "Leader explains 47% of what you
   recorded" — overran its tile by 17px and dropped onto a second line, which
   left the three headers on different baselines. */
.wm-title { font-size: 11px; font-weight: 600; color: var(--ink-2);
             line-height: 1.45; letter-spacing: 0; }
/* Tighter ONLY where the squeeze exists AND a mouse is doing the pointing.
   Three tiles share a row from 900px up, and there the 24px affordance
   pushed the longest title onto a second line; below that each tile is full
   width and has room to spare.
   `(pointer: fine)` as well as the width, because width was standing in for
   "this is a desktop" and it is not: an iPad in landscape is 1024px and
   entirely touch, so the tablet a ward round is most likely to carry got
   16px info buttons — under the minimum, on exactly the device the original
   note here said to protect. The rule now asks what it means. */
@media (min-width: 900px) and (pointer: fine) {
  .wm-head .info-btn { width: 16px; height: 16px; font-size: 10px; flex: none; }
}
.wm-viz { display: flex; align-items: center; gap: 12px; }
.wm-fig {
  font-size: 19px; font-weight: 650; color: var(--ink);
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em; flex: none;
}
/* One flat track divided into its bands, with a marker for where this case
   falls. Drawing the segments at heights proportional to their measured share
   put a second quantity on the chart with nothing naming it. */
.wm-band {
  position: relative; flex: 1; min-width: 0;
  display: flex; align-items: stretch; gap: 2px; height: 12px;
}
.wm-band i { flex: 1; background: var(--accent-soft); border-radius: 2px; }
.wm-band .wm-you {
  position: absolute; top: -4px; bottom: -4px; width: 2px;
  background: var(--ink); border-radius: 2px;
}
.wm-fill {
  flex: 1; min-width: 0; height: 10px; border-radius: 99px;
  background: var(--line); overflow: hidden;
}
.wm-fill i { display: block; height: 100%; background: var(--accent); border-radius: 99px; }
.wm-dots { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.wm-dots i {
  width: 10px; height: 10px; border-radius: 50%;
  border: 1.5px solid var(--line-strong); background: none;
}
.wm-dots i[data-on] { background: var(--accent); border-color: var(--accent); }
.wm-cap { margin: 9px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--muted); }

/* --- what moved the score ---------------------------------------------- */
.force-head { display: flex; align-items: flex-start; gap: 11px; margin-bottom: 12px; }
.force-head .f-rank {
  display: grid; place-items: center; flex: none;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--op-bg); border: 1px solid var(--op-line);
  font-size: 12px; font-weight: 600; color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.force-head .f-cell { min-width: 0; flex: 1; }
.force-head .f-name {
  display: block; font-size: 13px; font-weight: 600; color: var(--ink);
  line-height: 1.35;
}
.force-head .f-meta {
  display: block; margin-top: 2px; font-size: 11px; color: var(--faint-text);
}
.force-head .f-tally {
  flex: none; max-width: 190px; text-align: right;
  font-size: 11.5px; font-weight: 550; line-height: 1.35;
  color: var(--accent-text); background: var(--accent-soft);
  padding: 4px 11px; border-radius: 99px;
}

/* --- the two closing panels, side by side ------------------------------ */
.why-pair { display: grid; gap: 12px; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 900px) {
  /* not 50/50: the map needs the room to lay findings, condition and variant
     out left-to-right, and the thread beside it is a list that does not */
  .why-pair { grid-template-columns: minmax(0, 1.16fr) minmax(0, 1fr); }
  .why-pair .wcard { margin-bottom: 0; }
}
@media (max-width: 620px) {
  .force-head { flex-wrap: wrap; }
  .force-head .f-tally { max-width: none; text-align: left; }
  .wcard-head .why-pick { max-width: 100%; }
}

/* ================= What to do next ======================================
   A plan, read top-down: how many steps there are and in which tier, how the
   ordering was arrived at, the one step to take first in full, then the rest
   as a list that opens. */
.ns-intro { margin: 0 2px 16px; max-width: 84ch; }
.ns-intro p { margin: 0 0 3px; font-size: 12.5px; line-height: 1.6; color: var(--muted); }
.ns-intro p:last-child { margin-bottom: 0; }

.ns-how {
  display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap;
  padding: 11px 14px; margin-bottom: 16px;
  font-size: 12px; line-height: 1.55; color: var(--muted);
  background: var(--op-bg);
  border: 1px solid var(--op-line);
  border-radius: var(--r-md);
}
.ns-how b { color: var(--ink-2); font-weight: 600; flex: none; }
/* `.ns-how > span` once, which also matched the icon's own span — a type
   selector beats the class on it, so the 26px mark was being stretched to a
   220px flex item and the row opened a hole where the icon should be. It
   names the element it was written for. */
.ns-how .ns-how-text { flex: 1; min-width: 220px; }

/* --- the one step to take first --------------------------------------- */
.ns-best {
  position: relative;
  margin: 18px 0 22px;
  padding: 18px 18px 18px;
  background: linear-gradient(180deg, #f3fbfa, var(--surface) 70%);
  border: 1px solid var(--accent-soft);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
}
.ns-best-tag {
  position: absolute; top: -13px; left: 18px;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px; border-radius: 99px;
  font-size: 11.5px; font-weight: 600;
  background: var(--accent); color: var(--accent-ink);
  box-shadow: var(--shadow-sm);
}
.ns-best-tag svg { width: 12px; height: 12px; }
.ns-best-grid { display: grid; gap: 18px; grid-template-columns: minmax(0, 1fr); margin-top: 8px; }
@media (min-width: 820px) {
  .ns-best-grid { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); }
  .ns-best-side { border-left: 1px solid var(--op-line); padding-left: 18px; }
}
.ns-best-head { display: flex; gap: 12px; align-items: flex-start; margin-bottom: 12px; }
.ns-rank {
  flex: none; display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent-text);
  font-size: 13px; font-weight: 650; font-variant-numeric: tabular-nums;
}
.ns-best-title { margin: 0; font-size: 16px; font-weight: 650; color: var(--ink); letter-spacing: -0.015em; }
.ns-best-kind { margin: 2px 0 0; font-size: 12px; color: var(--muted); }
.ns-why { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }
.ns-why li { display: flex; gap: 9px; align-items: flex-start; font-size: 12.5px;
             line-height: 1.5; color: var(--ink-2); }
.ns-why li svg { flex: none; width: 14px; height: 14px; margin-top: 3px; color: var(--accent); }
.ns-best-acts { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 16px; }
.ns-best-acts .btn { display: inline-flex; align-items: center; gap: 7px; }
.ns-best-acts .btn svg { width: 14px; height: 14px; }
.ns-flag {
  display: inline-flex; align-items: center; gap: 6px; float: right;
  padding: 4px 10px; border-radius: 99px; margin-bottom: 10px;
  font-size: 11px; font-weight: 600;
  background: var(--accent-soft); color: var(--accent-text);
}
.ns-flag svg { width: 11px; height: 11px; }
.ns-side-use { clear: both; margin-bottom: 14px; }
.ns-side-k { display: block; font-size: 12px; color: var(--muted); margin-bottom: 6px; }
.ns-use { display: flex; align-items: center; gap: 10px; }
.ns-use .bar { flex: 1; min-width: 60px; }
.ns-use b { font-size: 15px; font-weight: 650; color: var(--ink);
            font-variant-numeric: tabular-nums; }
.ns-facts { margin: 0; display: grid; gap: 0; }
.ns-fact {
  display: grid; grid-template-columns: 150px minmax(0, 1fr); gap: 12px;
  padding: 9px 0; border-bottom: 1px solid var(--op-line-soft);
  align-items: baseline;
}
.ns-fact:last-child { border-bottom: 0; }
.ns-fact dt { display: flex; gap: 8px; align-items: center; font-size: 12px; color: var(--muted); }
.ns-fact dt svg { width: 14px; height: 14px; flex: none; color: var(--faint); }
.ns-fact dd { margin: 0; font-size: 12.5px; font-weight: 550; color: var(--ink); }
.ns-fact-wide dd { font-weight: 400; line-height: 1.5; color: var(--ink-2); }

/* --- the rest of the plan ---------------------------------------------- */
.ns-others-head {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin: 0 2px 10px;
}
.ns-others-head h3 {
  margin: 0; font-size: 14.5px; font-weight: 600; color: var(--ink);
  display: flex; align-items: center; gap: 8px;
}
.ns-count {
  font-size: 11.5px; font-weight: 600; padding: 2px 9px; border-radius: 99px;
  background: var(--accent-soft); color: var(--accent-text);
}
.ns-sort {
  margin-left: auto; display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--muted); white-space: nowrap;
}
.ns-sort .field { height: 32px; font-size: 12px; }
.ns-list { display: grid; gap: 8px; }
.ns-row {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); overflow: hidden;
}
.ns-row-head {
  display: grid; align-items: center; gap: 14px; width: 100%; text-align: left;
  grid-template-columns: 30px minmax(0, 1fr) auto auto 20px;
  padding: 12px 14px; background: none; border: 0; cursor: pointer; font: inherit;
  transition: background-color 120ms ease;
}
@media (hover: hover) and (pointer: fine) { .ns-row-head:hover { background: var(--surface-2); } }
.ns-row-cell { min-width: 0; }
.ns-row-title {
  display: block; font-size: 13px; font-weight: 550; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ns-row-kind { display: block; margin-top: 2px; font-size: 11px; color: var(--faint-text); }
.ns-row-chips { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.ns-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: 99px;
  font-size: 11px; color: var(--muted);
  background: var(--surface-2); border: 1px solid var(--line);
  white-space: nowrap;
}
.ns-chip svg { width: 11px; height: 11px; flex: none; color: var(--faint); }
.ns-row .chev { color: var(--faint); transition: transform 200ms var(--ease-out); }
.ns-row[data-open="true"] .chev { transform: rotate(180deg); }
.ns-row-body { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 240ms var(--ease-out); }
.ns-row[data-open="true"] .ns-row-body { grid-template-rows: 1fr; }
.ns-row-body > div { overflow: hidden; }
.ns-row[data-open="true"] .ns-row-body > div { padding: 0 14px 14px 58px; }
.ns-tie { margin: 10px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--muted); }
@media (max-width: 720px) {
  .ns-row-head { grid-template-columns: 30px minmax(0, 1fr) 20px; }
  .ns-row-chips, .ns-use { grid-column: 2 / -1; justify-content: flex-start; }
  .ns-row[data-open="true"] .ns-row-body > div { padding-left: 14px; }
  .ns-fact { grid-template-columns: minmax(0, 1fr); gap: 2px; }
}
.ns-chip.ns-planned {
  background: var(--accent-soft); border-color: transparent; color: var(--accent-text);
  font-weight: 600;
}
.ns-chip.ns-planned svg { color: currentColor; }

/* the strip that says how the order was arrived at */
.ns-how { align-items: center; }
.ns-how-mark {
  flex: none; display: grid; place-items: center;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--surface); border: 1px solid var(--op-line);
  color: var(--accent-text);
}
.ns-how-mark svg { width: 14px; height: 14px; }
.ns-how-text { flex: 1; min-width: 220px; }
.ns-learn {
  flex: none; display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 2px; border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 12px; font-weight: 550; color: var(--accent-text);
  text-decoration: underline; text-underline-offset: 3px;
}
.ns-learn svg { width: 12px; height: 12px; }
.ns-learn:hover { color: var(--accent); }
.ns-learn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

/* the sentence the card leads with */
.ns-best-lede {
  margin: 0 0 14px; font-size: 13px; line-height: 1.6; color: var(--ink-2);
  max-width: 62ch;
}

/* the counts carry this section, so give them the weight the design does */

/* the empty state's mark, as a disc rather than a loose glyph */
.empty .e-glyph {
  display: grid; place-items: center; margin: 0 auto 14px;
  width: 62px; height: 62px; border-radius: 50%;
  background: var(--op-bg); border: 1px solid var(--op-line);
  color: var(--accent-text);
}
.empty .e-glyph svg { width: 26px; height: 26px; }
.empty .e-title { font-size: 15px; }

/* the rail names what it lists, in words rather than small caps */
.rail-title {
  font-size: 15px; font-weight: 600; letter-spacing: -0.01em;
  text-transform: none; color: var(--ink);
}
.rail-head .field, .rail-search .field { border-radius: 999px; }
.case-item .need {
  font-size: 10.5px; padding: 2.5px 8px; margin-top: 5px;
  display: inline-block; border: 1px solid var(--line);
}
.case-item[aria-current="true"] .need { background: var(--surface); }

/* "learn more", and what it opens */
.cg-more {
  display: inline-flex; align-items: center; gap: 7px;
  margin-top: 12px; padding: 0; border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 12px; font-weight: 550; color: var(--accent-text);
  /* 12px type in a zero-padding box is a 17px target. It is already
     inline-flex and centred, so a floor grows the box without moving the
     words. */
  min-height: 24px;
}
.cg-more svg { width: 13px; height: 13px; transition: transform 160ms var(--ease-out); }
.cg-more:hover svg { transform: translateX(2px); }
.cg-more:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
.about-points { display: grid; gap: 14px; }
.about-point { display: flex; gap: 12px; align-items: flex-start; }
.about-point b { display: block; font-size: 13px; color: var(--ink); margin-bottom: 2px; }
.about-point p { margin: 0; font-size: 12.5px; line-height: 1.55; color: var(--muted); }
.about-mark {
  flex: none; display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: 9px;
  background: var(--op-bg); border: 1px solid var(--op-line); color: var(--accent-text);
}
.about-mark svg { width: 15px; height: 15px; }

/* ================= Letters =============================================
   The last screen before a ranking becomes paper. It is laid out as: what
   this is for, what exists already, what you can make, where a draft lands,
   and what to check before it leaves. */
.lt-intro {
  display: flex; gap: 11px; align-items: flex-start;
  padding: 13px 15px; margin-bottom: 14px;
  font-size: 12.5px; line-height: 1.6; color: var(--muted);
  background: var(--op-bg); border: 1px solid var(--op-line);
  border-radius: var(--r-lg);
}
.lt-intro svg { flex: none; margin-top: 2px; color: var(--accent-text); }

.lt-create {
  display: grid; gap: 0; grid-template-columns: minmax(0, 1fr);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-sm);
  margin-bottom: 14px; overflow: hidden;
}
@media (min-width: 900px) {
  .lt-create { grid-template-columns: minmax(0, 1fr) 250px; }
  .lt-included { border-left: 1px solid var(--op-line); border-top: 0 !important; }
}
.lt-create-main { padding: 17px 18px 18px; }
.lt-h { margin: 0; font-size: 15px; font-weight: 600; color: var(--ink); letter-spacing: -0.01em; }
.lt-sub { margin: 3px 0 0; font-size: 12.5px; line-height: 1.55; color: var(--muted); }
.lt-templates {
  display: grid; gap: 12px; margin-top: 15px;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
.lt-card {
  display: flex; flex-direction: column;
  padding: 15px; border: 1px solid var(--op-line); border-radius: var(--r-md);
  background: var(--op-bg);
}
.lt-card-mark {
  display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: 10px; background: var(--surface);
  border: 1px solid var(--op-line); color: var(--accent-text); margin-bottom: 11px;
}
.lt-card-mark svg { width: 17px; height: 17px; }
.lt-card h3 { margin: 0 0 5px; font-size: 13.5px; font-weight: 600; color: var(--ink); }
.lt-card p { margin: 0 0 14px; font-size: 12px; line-height: 1.5; color: var(--muted); }
.lt-card .btn {
  margin-top: auto; width: 100%; display: inline-flex;
  align-items: center; justify-content: center; gap: 7px;
}
.lt-card .btn svg { width: 13px; height: 13px; }
.lt-needs-run { margin-top: 14px; }
.lt-included { padding: 17px 18px; background: var(--surface-2); border-top: 1px solid var(--op-line); }
.lt-included-head { display: flex; gap: 8px; align-items: center; margin-bottom: 7px; }
.lt-included-head svg { flex: none; color: var(--accent-text); }
.lt-included-head b { font-size: 13px; color: var(--ink); }
.lt-included p { margin: 0 0 10px; font-size: 12px; line-height: 1.5; color: var(--muted); }

.lt-workspace .panel-heading { align-items: flex-start; }
.lt-workspace .panel-heading h2 { margin: 0; }
.lt-empty {
  text-align: center; color: var(--muted);
  padding: 40px 20px; margin: 4px 0 2px;
  border: 1px dashed var(--line-strong); border-radius: var(--r-md);
  background: var(--surface-2);
}
.lt-empty .e-glyph { margin-bottom: 12px; }
.lt-empty .e-title { font-weight: 600; color: var(--ink-2); margin-bottom: 4px; font-size: 15px; }
.lt-empty .e-sub { font-size: 12.5px; max-width: 340px; margin: 0 auto; line-height: 1.55; }

.lt-before {
  padding: 16px 18px 18px; margin-top: 14px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-sm);
}
.lt-before-head { display: flex; gap: 12px; align-items: flex-start; margin-bottom: 13px; }
.lt-before-mark {
  flex: none; display: grid; place-items: center; width: 32px; height: 32px;
  border-radius: 10px; background: var(--op-bg);
  border: 1px solid var(--op-line); color: var(--accent-text);
}
.lt-before-mark svg { width: 16px; height: 16px; }
.lt-before-head b { font-size: 14px; color: var(--ink); }
.lt-before-head p { margin: 2px 0 0; font-size: 12.5px; color: var(--muted); }
.lt-checks {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 9px 24px;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.lt-checks li {
  display: flex; gap: 9px; align-items: flex-start;
  font-size: 12.5px; line-height: 1.5; color: var(--ink-2);
}
.lt-checks li svg { flex: none; width: 14px; height: 14px; margin-top: 3px; color: var(--accent); }

/* The case tabs sit inside a narrower column than the organisation and
   oversight screens, so the same stat card is packed a little tighter there.
   Same component, same marks, same type — only the gutters differ. */
.op-stats-tight { gap: 12px; grid-template-columns: repeat(auto-fit, minmax(196px, 1fr)); }
.op-stats-tight .op-stat { padding: 14px 15px; gap: 12px; }

/* the audit filter: one control, not a wall of chips that grows with the
   vocabulary of the system */
.au-filters {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 10px 0 4px;
}
.au-filter-label { font-size: 12.5px; color: var(--op-ink-soft); }
.au-filters .op-select { flex: 1 1 260px; max-width: 340px; }
.au-filters .field { width: 100%; height: 38px; }

.brand-mark.is-sm { width: 26px; height: 26px; border-radius: 8px; }
.brand-mark.is-md { width: 30px; height: 30px; border-radius: 9px; }
.brand-mark.is-lg { width: 38px; height: 38px; border-radius: 11px; }
/* An operator's logo replaces the mark, so it loses the gradient plate it
   was drawn to sit on and is contained rather than cropped — a wordmark and
   a glyph both have to survive this box. */
.brand-mark.has-img { background: none; box-shadow: none; padding: 0; }
.brand-img { width: 100%; height: 100%; object-fit: contain; display: block; }

/* the branding screen shows the thing itself, which is the point of it */
.brand-preview {
  display: flex; align-items: center; gap: 14px;
  padding: 18px; margin-bottom: 18px;
  background: var(--op-bg); border: 1px solid var(--op-line);
  border-radius: var(--r-lg);
}
.op-field { margin-bottom: 16px; max-width: 520px; }
.op-field label {
  display: block; font-size: 12.5px; font-weight: 600;
  color: var(--ink-2); margin-bottom: 6px;
}
.op-hint { margin: 6px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--muted); }
.op-status[data-bad="true"] { color: var(--danger); }


/* Not recognised in your note — the other half of the extraction record.
   Styled as a quiet list, NOT as a warning: nothing in it is wrong, and most
   of it is ordinary prose. An amber block here would teach a clinician to
   skip the one place a missed cardinal feature shows up. */
.unmapped-list { display: grid; gap: 8px; }
/* A BUTTON NOW, not a div: tapping one searches the findings list for it.
   A button defaults to centred inline-block text, so the row has to be told
   to stay a full-width left-aligned block or the phrase moves when it becomes
   actionable. */
.unmapped-row {
  display: block; width: 100%; text-align: left;
  padding: 9px 12px; border: 1px solid var(--op-line-soft);
  border-radius: 9px; background: var(--op-bg); font-size: 13.5px;
  cursor: pointer;
  transition: border-color 140ms var(--ease-out),
              background 140ms var(--ease-out);
}
.unmapped-row:hover { border-color: var(--accent-soft); background: #f7fbfb; }
.unmapped-row:active { transform: scale(0.995); }
.unmapped-row:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.unmapped-row b { font-weight: 600; }
.unmapped-ctx {
  margin-top: 3px; color: var(--op-ink-soft); font-size: 12.5px;
  font-style: italic; overflow-wrap: anywhere;
}
#unmapped-card > summary { list-style: none; }
#unmapped-card > summary::-webkit-details-marker { display: none; }
#unmapped-card[open] > summary .wcard-chev { transform: rotate(180deg); }


/* Date bounds on the audit filter bar. Narrow, because they sit beside a
   select and a label in one row and a full-width date input would push the
   clear button onto a second line at 1280px. */
.au-date {
  width: auto; min-width: 138px; padding: 7px 10px;
  font-size: 13px; height: var(--control-h);
}

/* A concern in the oversight rail. Bordered rather than tinted: the state
   pill carries the status, and colouring the whole block would make an
   answered concern shout as loudly as an open one. */
.oc-concern {
  padding: 9px 10px; margin-top: 8px;
  border: 1px solid var(--op-line-soft); border-radius: 9px;
  font-size: 12.5px;
}
.oc-concern b { display: block; margin: 4px 0 2px; }

/* The services table's numeric inputs. Narrow, right-aligned and tabular so
   a column of costs can be compared down the page rather than read across. */
.svc-in { padding: 6px 9px; font-size: 13px; }
.svc-num { width: 88px; text-align: right; font-variant-numeric: tabular-nums; }
.svc-status { display: block; font-size: 11.5px; margin-top: 3px; }

/* ---------------------------------------------------------------- services --
   The catalogue was a 63-row form: four inputs and a Save on every line, all
   of them the same weight, with the field that decides what a child can be
   offered here rendered as the smallest control on the row. These styles
   spend the page's emphasis on the two things that carry meaning — how much
   of the work is done, and which answer each step has — and take the rest
   down to a quiet grid. Every colour, radius and easing is a token that was
   already here. */

/* --- readiness -------------------------------------------------------- */
.svc-ready {
  display: flex; align-items: center; gap: 26px;
  padding: 22px 26px;
  margin-bottom: 18px;
  border: 1px solid var(--op-line); border-radius: 18px;
  background:
    radial-gradient(120% 140% at 0% 0%, #ffffff 0%, #f8fbfb 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9),
              0 1px 2px rgba(28, 25, 23, 0.04),
              0 8px 24px -10px rgba(28, 25, 23, 0.10);
}
.svc-ready-fig { flex: none; }
/* CENTRED AS A PAIR, not one each. `display: grid` with two children makes
   two implicit rows and centres each child inside its own row — so the
   number sat at a quarter of the height and "of 63" at three quarters, both
   pressed against the ring instead of sitting together in the middle. */
.svc-meter {
  position: relative; width: 84px; height: 84px;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
}
.svc-meter svg { position: absolute; inset: 0; transform: rotate(-90deg); }
.svc-meter circle { fill: none; stroke-width: 7; }
.svc-meter-track { stroke: var(--op-line); }
.svc-meter-fill {
  stroke: var(--accent); stroke-linecap: round;
  /* 2πr for r=36 */
  stroke-dasharray: 226.19;
  stroke-dashoffset: calc(226.19 - (226.19 * var(--p) / 100));
  transition: stroke-dashoffset 620ms var(--ease-out);
}
.svc-meter-num { font-size: 23px; font-weight: 660; letter-spacing: -0.02em;
  line-height: 1; font-variant-numeric: tabular-nums; }
.svc-meter-of { font-size: 10.5px; line-height: 1; color: var(--muted);
  margin-top: 3px; font-variant-numeric: tabular-nums; }
.svc-ready-words { min-width: 0; }
.svc-ready-title { font-size: 17.5px; font-weight: 620; letter-spacing: -0.015em;
  text-wrap: balance; }
.svc-ready-lede { margin-top: 5px; color: var(--op-ink-soft); font-size: 13.5px;
  line-height: 1.5; max-width: 62ch; }
.svc-split { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 13px; }
.svc-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px 4px 8px;
  border: 1px solid var(--op-line); border-radius: 999px;
  background: var(--surface);
  font-size: 12px; color: var(--op-ink-soft);
  font-variant-numeric: tabular-nums;
}
.svc-chip b { color: var(--ink); font-weight: 640; }
.svc-chip i { width: 7px; height: 7px; border-radius: 50%; background: var(--tick); }
.svc-chip[data-tone="ok"] i { background: var(--ok); }
.svc-chip[data-tone="info"] i { background: var(--accent); }
.svc-chip[data-tone="off"] i { background: var(--absent); }
.svc-chip[data-tone="warn"] i { background: var(--warn); }

/* --- the list --------------------------------------------------------- */
.svc-list {
  border: 1px solid var(--line); border-radius: 16px;
  background: var(--surface);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9),
              0 1px 2px rgba(28, 25, 23, 0.04),
              0 6px 18px -6px rgba(28, 25, 23, 0.07);
  overflow: hidden;
}
.svc-head, .svc-row {
  display: grid;
  /* The availability column is sized to its LONGEST option, not to a round
     number. "Only by referral elsewhere" is 159px at 13px and had 114px to
     live in, so it truncated on every row a hospital had answered that way —
     and it is the one answer that says "we cannot do this, but we can send
     the child somewhere that can", which is not a thing to leave half
     written. The two flexible columns give up the 52px. */
  grid-template-columns:
    minmax(190px, 1.35fr) minmax(140px, 0.9fr) 230px 122px 104px 86px;
  gap: 12px; align-items: center;
}
.svc-head {
  padding: 11px 18px 9px;
  font-size: 10.5px; font-weight: 650; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--muted);
  border-bottom: 1px solid var(--line);
}
.svc-group + .svc-group { border-top: 1px solid var(--line); }
.svc-group-head {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 18px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}
/* NOT sticky. `.svc-list` clips to its own rounded corners, and an ancestor
   with `overflow` other than visible is a scroll container that a sticky
   descendant sticks INSIDE — so `position: sticky` here did nothing at all,
   which is worse than not claiming it. Keeping the corners and losing the
   stick is the right way round: the header divides the work either way. */
.svc-group-name {
  font-size: 11px; font-weight: 660; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--ink-2);
}
.svc-group-count { font-size: 11.5px; color: var(--muted);
  font-variant-numeric: tabular-nums; }
.svc-group-bar {
  flex: 1; max-width: 132px; height: 4px; border-radius: 999px;
  background: var(--line); overflow: hidden;
}
.svc-group-bar i {
  display: block; height: 100%; width: var(--p, 0%);
  border-radius: inherit; background: var(--accent);
  transition: width 520ms var(--ease-out);
}
.svc-row { padding: 9px 18px; border-bottom: 1px solid var(--line); }
.svc-group:last-child .svc-row:last-child { border-bottom: 0; }
.svc-row:hover { background: rgba(15, 118, 110, 0.022); }

/* THE ONE MARK THAT SAYS WHERE THE WORK IS. Unanswered rows carry an amber
   dot; the eye finds the remaining ones without reading a word. */
/* Declared BEFORE .svc-step overrides it. With .svc-cell last, `display:
   block` won on equal specificity, the step cell never became a flex
   container, and the status dot collapsed to zero width — the one mark on
   the row that says where the remaining work is. */
.svc-cell { display: block; min-width: 0; }
.svc-step { display: flex; align-items: center; gap: 10px; min-width: 0; }
.svc-dot { flex: none; width: 7px; height: 7px; border-radius: 50%;
  background: var(--tick); }
.svc-row[data-state="unconfigured"] .svc-dot,
.svc-row[data-state="unknown"] .svc-dot { background: var(--warn); }
.svc-row[data-state="available"] .svc-dot { background: var(--ok); }
.svc-row[data-state="external_referral"] .svc-dot { background: var(--accent); }
.svc-row[data-state="unavailable"] .svc-dot { background: var(--absent); }
.svc-step-words { min-width: 0; }
/* Two lines is the ceiling. A title allowed to wrap freely made rows 128px
   tall beside 61px neighbours, and a list whose rows are all different
   heights cannot be scanned down a column. */
.svc-title {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden;
  font-size: 13.5px; font-weight: 550; line-height: 1.35; color: var(--ink);
}
/* The ordering guidance the title carries inline. It belongs to the clinician
   choosing the test, not to the administrator answering "can we do it"; kept
   to one line here, in full on hover and in the record. */
.svc-note {
  display: block; margin-top: 2px;
  font-size: 11.5px; line-height: 1.4; color: var(--faint-text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  cursor: help;
}

.svc-lab { display: none; }
.svc-cell .field {
  width: 100%;
  font-size: 13px; min-height: 38px; padding: 7px 11px;
}
.svc-cell .field::placeholder { color: var(--faint); }

/* Availability is the answer a child gets, so it is the one control on the
   row that carries colour. */
.svc-avail { display: block; width: 100%; }
/* `.svc-cell .field` is two classes and beat `.svc-avail select`, so the
   select kept its 11px inset and the status dot landed on top of the word.
   Matched at three classes deliberately, rather than nudged with !important. */
.svc-cell .svc-avail select {
  width: 100%; font-size: 13px;
  padding: 7px 32px 7px 30px;
  border-color: var(--line-strong); border-radius: var(--r-md);
  cursor: pointer;
}
.svc-avail::before {
  content: ""; position: absolute; left: 12px; top: 50%;
  width: 7px; height: 7px; margin-top: -3.5px; border-radius: 50%;
  background: var(--warn); pointer-events: none; z-index: 1;
}
.svc-avail[data-v="available"]::before { background: var(--ok); }
.svc-avail[data-v="external_referral"]::before { background: var(--accent); }
.svc-avail[data-v="unavailable"]::before { background: var(--absent); }

/* Units belong in the field, not in a column header the eye has left behind
   by row forty. */
/* The unit is positioned against THIS box, so the input has to fill it.
   Left to its intrinsic 88px inside a 255px cell on a phone, the number sat
   in a small box on the left and the word "days" floated at the far right of
   the row, attached to nothing. */
.svc-adorn { position: relative; display: block; }
.svc-adorn .field { width: 100%; }
.svc-adorn::before, .svc-adorn::after {
  position: absolute; top: 50%; transform: translateY(-50%);
  font-size: 11px; color: var(--faint-text); pointer-events: none;
}
.svc-adorn[data-pre]::before { content: attr(data-pre); left: 11px; }
.svc-adorn[data-post]::after { content: attr(data-post); right: 11px; }
.svc-adorn[data-pre] .field { padding-left: 40px; }
.svc-adorn[data-post] .field { padding-right: 40px; }
.svc-num { text-align: right; font-variant-numeric: tabular-nums; }

/* SAVE ARRIVES WHEN THERE IS SOMETHING TO SAVE. Sixty-three permanent
   buttons made the page read as a form to be filled rather than a record to
   be corrected; the row still saves exactly as it did. */
.svc-act { display: flex; align-items: center; justify-content: flex-end;
  gap: 8px; }
.svc-save {
  opacity: 0; transform: scale(0.94); pointer-events: none;
  padding: 6px 13px; font-size: 12.5px; min-height: 32px;
  transition: opacity 150ms var(--ease-out), transform 150ms var(--ease-out);
}
.svc-row[data-dirty="true"] .svc-save { opacity: 1; transform: none;
  pointer-events: auto; }
.svc-save:active { transform: scale(0.97); }
.svc-row[data-dirty="true"] { background: rgba(180, 83, 9, 0.035); }
.svc-row[data-saved="true"] { background: rgba(4, 120, 87, 0.07); }
.svc-status { font-size: 11.5px; color: var(--muted); }
.svc-status[data-bad="true"] { color: var(--danger); }
.svc-none { margin: 0; }

/* --- the unsaved bar --------------------------------------------------- */
.svc-bar {
  position: sticky; bottom: 14px; z-index: 5;
  display: flex; align-items: center; gap: 10px;
  margin: 14px 0 0; padding: 10px 12px 10px 16px;
  border: 1px solid var(--op-line); border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  animation: svc-bar-in 200ms var(--ease-out);
}
/* `display:flex` above beats the [hidden] attribute, so the bar announced
   "0 steps changed" on a page nobody had touched. */
.svc-bar[hidden] { display: none; }
.svc-bar-n { font-size: 13px; font-weight: 560; font-variant-numeric: tabular-nums; }
/* Room for the bar to sit over, so it never covers the last row it would be
   saving. */
.svc-pane { padding-bottom: 8px; }
@keyframes svc-bar-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

@media (max-width: 1080px) {
  .svc-head { display: none; }
  .svc-row {
    grid-template-columns: 1fr 1fr;
    align-items: end;
    gap: 10px 12px;
    padding: 13px 16px;
  }
  .svc-step { grid-column: 1 / -1; }
  .svc-cell .svc-lab {
    display: block; font-size: 10.5px; font-weight: 620;
    letter-spacing: 0.06em; text-transform: uppercase;
    color: var(--muted); margin-bottom: 4px;
  }
  .svc-act { grid-column: 1 / -1; justify-content: flex-start; }
  .svc-note { white-space: normal; display: -webkit-box;
    -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
  .svc-save { opacity: 1; transform: none; pointer-events: auto; }
  .svc-row:not([data-dirty="true"]) .svc-save { display: none; }
}
@media (max-width: 720px) {
  .svc-ready { flex-direction: column; align-items: flex-start; gap: 16px; }
  .svc-row { grid-template-columns: 1fr; }
  /* Held on one line, the heading wrapped to three and squeezed the search
     box to "Search st". */
  .svc-pane .op-section-head { flex-wrap: wrap; row-gap: 10px; }
  .svc-pane .op-section-head .op-subtitle { flex: 1 0 auto; }
  .svc-pane .op-section-head .spacer { display: none; }
  .svc-pane .op-section-head .oc-search,
  .svc-pane .op-section-head .op-search { flex: 1 0 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .svc-meter-fill, .svc-group-bar i, .svc-save { transition: none; }
  .svc-bar { animation: none; }
}

/* ------------------------------------------------------- second opinions --
   The queue a specialist works and the sent list a clinician reads are the
   same rows with different verbs on them. */
.rv-list { display: grid; gap: 10px; }
.rv-row {
  display: flex; gap: 16px; align-items: flex-start;
  padding: 14px 16px;
  border: 1px solid var(--line); border-radius: 14px;
  background: var(--surface);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9),
              0 1px 2px rgba(28, 25, 23, 0.04);
}
/* An unclaimed question is the one thing on this page that is waiting on
   somebody, so it is the one thing with a mark against it. */
.rv-row[data-state="requested"] { box-shadow: inset 3px 0 0 var(--warn),
  inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 1px 2px rgba(28, 25, 23, 0.04); }
.rv-row[data-state="answered"] { box-shadow: inset 3px 0 0 var(--ok),
  inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 1px 2px rgba(28, 25, 23, 0.04); }
.rv-main { flex: 1; min-width: 0; }
.rv-q { font-size: 14px; line-height: 1.5; color: var(--ink); text-wrap: pretty; }
/* SAID, NOT BLANK. A governance reader is shown the shape of the queue and
   not the clinical text, and an empty line where a question should be reads
   as a question nobody wrote. It says which it is, in the muted voice the
   rest of the interface uses for what is deliberately absent. */
.rv-withheld { color: var(--faint-text); font-style: italic; }
.rv-meta { margin-top: 4px; font-size: 12px; color: var(--muted); }
.rv-answer {
  margin-top: 10px; padding: 10px 12px;
  border-left: 2px solid var(--ok); border-radius: 0 8px 8px 0;
  background: var(--surface-2);
}
.rv-answer b { font-size: 12.5px; color: var(--ok); }
.rv-answer p { margin-top: 4px; font-size: 13px; line-height: 1.55;
  color: var(--ink-2); }
/* `align-content: start` because the grid otherwise stretched its rows to the
   height of the question beside it, and a two-line question left the three
   decisions floating apart down a tall empty column. */
.rv-side { flex: none; display: grid; gap: 7px; justify-items: stretch;
  align-content: start; min-width: 168px; }
.rv-side .btn { justify-content: center; padding: 6px 12px; font-size: 12.5px;
  min-height: 34px; }
/* THE LABEL IS THE TARGET, and it was 18px tall. The checkbox inside it is
   13px — the browser's own size — and a native checkbox cannot be made
   bigger without redrawing it, so the thing a thumb actually has to hit is
   the label. WCAG 2.5.8 puts the minimum at 24px and this suite has used 24
   since it was written; a ward round is not a careful pointing
   environment. */
.rv-only { display: inline-flex; align-items: center; gap: 7px;
  min-height: 24px; padding: 3px 2px; cursor: pointer;
  font-size: 12.5px; color: var(--op-ink-soft); white-space: nowrap; }
@media (max-width: 720px) {
  .rv-row { flex-direction: column; }
  .rv-side { min-width: 0; width: 100%; }
}

/* ------------------------------------------------- status and error pages --
   Reached with the workspace already gone, so the message has to BE the
   screen. Built from the sign-in card's family, because that is the other
   page a clinician meets with nothing behind it. */
.st-wrap {
  min-height: 100dvh;
  display: grid; place-items: center;
  padding: 32px 20px;
  background:
    radial-gradient(1100px 340px at 78% -8%, #eaf5f7 0%, rgba(234, 245, 247, 0) 70%),
    linear-gradient(180deg, #ffffff 0%, var(--op-bg) 55%, #f4f8f8 100%);
}
.st-card {
  width: min(520px, 100%);
  padding: 34px 34px 30px;
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--op-line);
  border-radius: 18px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9), var(--shadow-lg);
}
.st-mark {
  width: 44px; height: 44px; margin: 0 auto 18px;
  border-radius: 13px;
  display: grid; place-items: center;
  color: #fff;
  background: linear-gradient(145deg, #15897f 0%, #0b5f59 100%);
  box-shadow: 0 1px 2px rgba(11, 95, 89, 0.32),
              0 6px 16px -5px rgba(11, 95, 89, 0.42),
              inset 0 1px 0 rgba(255, 255, 255, 0.22);
}
.st-mark svg { width: 42%; height: 42%; }
/* Large, quiet, and behind the sentence — the number is for orientation, not
   for the clinician to act on. */
.st-code {
  font-size: 13px; font-weight: 650; letter-spacing: 0.14em;
  color: var(--faint-text);
  font-variant-numeric: tabular-nums;
}
.st-title {
  margin-top: 8px;
  font-size: 22px; font-weight: 640; letter-spacing: -0.02em;
  line-height: 1.25; text-wrap: balance;
}
.st-body {
  margin-top: 10px;
  font-size: 14px; line-height: 1.6; color: var(--op-ink-soft);
  text-wrap: pretty;
}
.st-detail { margin-top: 14px; text-align: left; }
.st-detail summary {
  cursor: pointer; font-size: 12.5px; color: var(--muted);
  list-style: none;
}
.st-detail summary::-webkit-details-marker { display: none; }
.st-detail summary::before { content: "▸ "; }
.st-detail[open] summary::before { content: "▾ "; }
.st-detail pre {
  margin-top: 8px; padding: 10px 12px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 8px;
  font-size: 11.5px; line-height: 1.5; color: var(--ink-2);
  white-space: pre-wrap; word-break: break-word;
  max-height: 190px; overflow: auto;
}
.st-actions {
  margin-top: 22px;
  display: flex; gap: 9px; justify-content: center; flex-wrap: wrap;
}
.st-actions .btn { min-height: 40px; padding: 9px 18px; }
@media (max-width: 480px) {
  .st-card { padding: 26px 20px 22px; }
  .st-actions .btn { flex: 1 1 100%; justify-content: center; }
}

/* ------------------------------------------------- dismissible notices ---- */
/* A standing note about a PROCESS gets a way out. One that qualifies a
   clinical answer — the scope statement, a stale ranking, an unreviewed
   red-flag rule — deliberately does not: see wireNotices() for why. */
.has-notice-x { position: relative; }
.notice-x {
  position: absolute; top: 6px; right: 6px;
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border-radius: 7px; border: 0; background: transparent;
  color: var(--faint-text); cursor: pointer;
  opacity: 0.55;
  transition: opacity 130ms var(--ease-out), background-color 130ms ease,
    transform 130ms var(--ease-out);
}
.notice-x svg { width: 14px; height: 14px; }
.notice-x:hover { opacity: 1; background: rgba(28, 25, 23, 0.06); }
.notice-x:active { transform: scale(0.92); }
.notice-x:focus-visible { opacity: 1; outline: 2px solid var(--accent);
  outline-offset: 1px; }
/* Room for the control, so it never sits on top of the words it closes. */
.has-notice-x { padding-right: 34px; }
p.has-notice-x { padding-right: 36px; }
@media (prefers-reduced-motion: reduce) { .notice-x { transition: none; } }

/* ------------------------------------------------------------------ prose */
/* The paragraphs a clinician actually reads, held to a measure. See
   --measure. Measured at 1920 before any of this: 129ch on the next-steps
   explanation, 119ch on its ledes, 104ch on the urgent-check warning, 103ch
   on the conditions lede, 100ch on the letters lede, 95ch on the Why intro.

   TWO SHAPES, AND WHICH ONE DEPENDS ON WHETHER THERE IS A BOX. The ledes
   below sit on the page itself, so capping the text leaves nothing behind
   them — white space beside a paragraph is just white space. Anything inside
   a card that PAINTS is capped as a card instead, further down; `.why-intro`
   already had a measure of its own and keeps it, at a value that was
   measured rather than guessed. */
.ns-intro p {
  max-width: var(--measure);
}
/* THE CARD, NOT THE TEXT INSIDE IT. Capping the span first left the amber
   and grey blocks at full width with their right half empty — dead colour,
   which reads as a rendering fault rather than as a measure. A notice that
   is narrower than the column looks deliberate; a wide one half-filled does
   not. The extra over --measure is the icon, the gap and the padding, so the
   SENTENCES land on the measure rather than the box. */
.notice,
.pc-note,
.lt-intro {
  max-width: calc(var(--measure) + 6rem);
}
