/* CRP Provider Portal — design system (2026-07-16 redesign).
 *
 * Derived from the CRP Design System (design-system/colors_and_type.css):
 * navy #072061 · blue #1843AD · cyan #A2DCEB · orange #FF9933 (the SINGLE
 * accent) · cool borders #c8d6e8 · cool shadows rgba(7,32,97,…) · stepped
 * radii · Area Normal — the DS brand face, self-hosted via the deploy-time
 * /assets/ds copy (colors_and_type.css + Area_*.otf) and KEPT DELIBERATELY
 * per owner decision 2026-07-19 — with a system-stack digital fallback.
 * (CSP style-src 'self' forbids third-party font stylesheets, and it also
 * forbids inline style="" attributes — the 2026-07-15 "sloppy UI" report was
 * partly 12 dead inline styles the browser silently dropped. EVERYTHING
 * lives in classes here.)
 *
 * Aesthetic: a physician's instrument, not a marketing page. The board reads
 * like a lab report — ruled rows, tabular figures, a "generated" timestamp —
 * because charts and reports are the visual vernacular referring physicians
 * live in. One signature: the chart-tab orange underline on the active nav
 * item. Everything else stays quiet.
 */

/* Tokens DERIVE from the CRP design system (design-system/colors_and_type.css,
   served as /assets/ds/colors_and_type.css — a deploy-time copy, linked by
   every page BEFORE this file). Every var() below resolves to the DS token
   when present and falls back to the same literal value the DS defines, so
   a local boot without the copy still renders on-brand. Per the standing
   doctrine: standalone HTML surfaces MUST run on the design system — do not
   introduce a color/typography literal here that diverges from the DS. */
/* ── Typeface ────────────────────────────────────────────────────────────
   Inter, SELF-HOSTED. The dashboard and joinresearchstudies.com both render
   in Inter (loaded there from the Google Fonts CDN); this portal was the one
   surface still on Area Normal, which is why it read as a different product.
   CSP here is `style-src 'self'`, so a third-party font STYLESHEET is blocked
   outright -- the files are served from our own origin instead, which
   `font-src 'self'` already allows and which also removes a third-party
   dependency from an authenticated PHI surface. Supersedes the 2026-07-19
   "keep Area Normal" decision (owner, 2026-07-20). */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/assets/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/assets/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --navy: var(--crp-navy, #072061);
  --blue: var(--crp-blue, #1843AD);
  --cyan: var(--crp-cyan, #A2DCEB);
  --orange: var(--crp-orange, #FF9933);
  --border: #c8d6e8;       /* same value as the DS --border (name collision, kept literal) */
  --border-soft: #dde7f2;
  --ink: var(--fg-1, #072061);
  --ink-2: var(--fg-2, #3d5373);   /* DS muted body — darker than slate for readability */
  --ink-3: var(--fg-3, #5e7694);
  --paper: var(--surface-2, #edf2f8);
  --card: var(--surface, #ffffff);
  --wash: var(--blue-bg, #E8EEFF); /* DS soft blue tint for chips/wells */
  --ok: #0f7a4d;
  --ok-bg: var(--success-bg, #ecfdf5);
  --warn: #b45309;
  --warn-bg: var(--warning-bg, #fff8f0);
  --err: #b3261e;
  --err-bg: var(--danger-bg, #fef2f2);
  --shadow-1: 0 1px 2px rgba(7, 32, 97, 0.06), 0 2px 8px rgba(7, 32, 97, 0.05);
  --shadow-2: 0 4px 18px rgba(7, 32, 97, 0.09);
  --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
  /* ONE column and ONE gutter for every band on the page. Previously the
     app bar ran to 1200px while the hero, content and footer ran to 920px,
     so the brand sat at x=60 and the page title at x=204 -- nothing lined
     up vertically. 1080 is wide enough for the full nav row (the reason the
     bar was widened) while keeping the tables at a readable measure. */
  --container: 1080px;
  --gutter: 24px;
  /* Join-aligned type scale (joinresearchstudies.com index.html + refer.html:
     16px/1.5 body, 15px inputs, 16px buttons). The portal inherited the
     dashboard's dense 14px scale, which the owner read as "too small, hard to
     read" for a physician often on a phone. ONE source of truth going forward
     -- the base + these tokens are locked by the type-scale test. Genuine
     uppercase, letter-spaced eyebrows stay ~11-12px (that is how the join site
     treats them) so they never wrap. */
  --fs-base: 1rem;      /* body base */
  --fs-body: 1rem;      /* comfortable body copy / lede */
  --fs-sm: 0.9375rem;        /* dense body, table cells, meta */
  --fs-label: 0.875rem;     /* labels, fine meta */
  --fs-xs: 0.75rem;        /* fine print */
  --fs-eyebrow: 0.75rem;   /* uppercase letter-spaced eyebrows ONLY */
  --fs-input: 1rem;     /* inputs / selects / textarea */
  --fs-btn: 1rem;       /* primary buttons */
  --fs-h2: 1.375rem;
  --fs-h1: 2rem;
  --lh: 1.5;            /* base line-height */
  /* Radii: controls / cards / pills. Nothing else.
     Join-parity (owner 2026-08-10, joinresearchstudies.com/refer): controls
     round at 10px and cards at 16px — the refer page's --radius — so the
     portal reads as the same product as the public screener. */
  --r-control: 10px;
  /* Card inner padding == table cell padding. These disagreed (26 vs 20),
     so the search box sat 6px inboard of the column it filters. */
  --pad-card: 24px;
  --r-card: 16px;
  --r-pill: 999px;
  --mono: var(--font-mono, ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace);
  /* Back-compat token aliases (older markup references these) */
  --shadow-sm: 0 1px 3px rgba(7, 32, 97, 0.08);
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-base);
  line-height: var(--lh);
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

/* ── Hero band (site parity: joinresearchstudies.com) ───────────────
   One 135° navy→blue gradient per page (DS rule) carrying the app bar AND
   the page title; content cards float up into it (.page overlap). */
.hero-band {
  background: linear-gradient(135deg, var(--navy) 0%, var(--blue) 100%);
  color: #fff;
  padding-bottom: 46px;
}
.page-hero {
  max-width: var(--container);
  margin: 0 auto;
  padding: 28px var(--gutter) 0;
}
.page-hero .page-title {
  color: #fff;
  font-size: var(--fs-h1);
  margin: 0 0 8px;
}
.page-hero .page-lede {
  color: rgba(255, 255, 255, 0.85);
  font-size: 16px;
  max-width: 66ch;
}
/* ── App bar (every authenticated page) ────────────────────────────── */
.appbar {
  background: transparent;
  color: #fff;
  border-bottom: 1px solid rgba(255, 255, 255, 0.14);
}
.appbar-inner {
  /* Wider than the 920px content column: 4 nav items + the staff admin
     switcher + Sign out need the room (Sign out was clipping at 1440px).
     flex-wrap is the safety net at mid widths — the bar grows a second
     row rather than ever clipping controls off-screen. */
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 0 12px;
  min-height: 58px;
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 8px 0;
  color: #fff;
  text-decoration: none;
  flex-shrink: 0;
}
.brand-logo { height: 30px; width: auto; display: block; flex-shrink: 0; }
.brand-text { display: flex; flex-direction: column; justify-content: center; gap: 1px; }
.auth-brand .brand-logo { height: 76px; margin: 0 auto 12px; } /* refer header logo weight */
.brand-eyebrow {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--cyan);
}
.brand-name {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.appbar-nav {
  display: flex;
  align-items: stretch;
  gap: 4px;
  margin-left: auto;
}
.appbar-nav a {
  display: flex;
  align-items: center;
  padding: 0 11px;
  color: rgba(255, 255, 255, 0.82);
  text-decoration: none;
  font-size: var(--fs-sm);
  font-weight: 600;
  border-bottom: 3px solid transparent;
  border-top: 3px solid transparent; /* keeps the label optically centered */
}
.appbar-nav a:hover { color: #fff; }
.appbar-nav a.active {
  color: #fff;
  border-bottom-color: var(--orange); /* the signature: chart-tab underline */
}
.appbar-signout {
  display: flex;
  align-items: center;
  margin-left: 8px;
}
.appbar-signout button {
  font: inherit;
  font-size:var(--btn-fs-sm);
  font-weight: 600;
  color: rgba(255, 255, 255, 0.85);
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius:var(--r-control);
  padding:var(--btn-pad-sm);min-height:var(--btn-h-sm);
  cursor: pointer;
}
.appbar-signout button:hover { background: rgba(255, 255, 255, 0.16); color: #fff; }
/* Persistent "Refer a patient" CTA on every authenticated page → /studies#refer
   (owner decision 2026-07-19, C3). Deliberately the app bar's QUIET button
   treatment — the signout pill — never a second orange: one accent per page,
   and the page's payoff CTAs keep it. */
.appbar-cta {
  align-self: center;
  margin-left: 8px;
  font-size: var(--fs-label);
  font-weight: 600;
  color: rgba(255, 255, 255, 0.85);
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 8px;
  padding: 6px 14px;
  text-decoration: none;
}
.appbar-cta:hover { background: rgba(255, 255, 255, 0.16); color: #fff; }

/* ── Page scaffold ──────────────────────────────────────────────────── */
.page {
  max-width: var(--container);
  margin: -28px auto 0;
  padding: 0 var(--gutter) 64px;
}
.page-head { margin: 4px 0 20px; }
.page-title {
  /* Owner 2026-08-10: "text across the board too small" — page titles get
     the full H1 token (32px, the 7/31 calibration), not the H2 hand-me-down. */
  margin: 0 0 6px;
  font-size: var(--fs-h1);
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--navy);
}
.page-lede {
  margin: 0;
  max-width: 62ch;
  font-size: var(--fs-body);
  color: var(--ink-2);
}

/* ── Cards ──────────────────────────────────────────────────────────── */
.panel {
  background: var(--card);
  border: 1px solid var(--border);
  /* Join-parity card: 16px radius + the refer page's exact shadow. */
  border-radius: var(--r-card);
  box-shadow: 0 4px 16px rgba(7, 32, 97, 0.10);
  overflow: hidden;
}
.panel + .panel { margin-top: 18px; }
.panel-pad { padding: 24px var(--pad-card); }
.panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 18px var(--pad-card) 12px;
}
.panel-title {
  /* Join-parity (owner 2026-08-10): the refer page heads every card with a
     real sentence-case bold-navy heading, not a tiny all-caps eyebrow — a
     big part of why it reads cleaner. 20px sits inside the owner's H2 band
     (20-28, 2026-07-31 calibration) nearest the refer card h2. */
  margin: 0;
  font-size: var(--fs-h2); /* 22px — bumped from 20 (owner 2026-08-10: too small) */
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--navy);
}

/* ── The report table (patients board, results) ────────────────────── */
/* Wide content scrolls inside its own container — .panel clips at its
   rounded corners, so without this the status column truncates and the
   Upload/Download columns are unreachable on phones (UX review 2026-07-18). */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table-scroll .report-table { min-width: 520px; }
/* A9 (round-2): 39% of the board hid off-screen at 390px with zero hint.
   Two affordances: (1) a right-edge fade that appears only while there IS
   more content (scrolling-shadow technique: the "cover" layers scroll with
   the content via background-attachment:local and hide the edge shadows at
   the extremes); (2) the sticky Patient column below. Cool-tinted shadow
   per the DS (never pure black). */
.table-scroll {
  background-image:
    linear-gradient(to right, var(--card) 45%, rgba(255, 255, 255, 0)),
    linear-gradient(to left, var(--card) 45%, rgba(255, 255, 255, 0)),
    linear-gradient(to right, rgba(7, 32, 97, 0.14), rgba(7, 32, 97, 0)),
    linear-gradient(to left, rgba(7, 32, 97, 0.14), rgba(7, 32, 97, 0));
  background-position: left center, right center, left center, right center;
  background-size: 36px 100%, 36px 100%, 14px 100%, 14px 100%;
  background-repeat: no-repeat;
  background-attachment: local, local, scroll, scroll;
}
/* Sticky first column (Patient). border-collapse:separate — collapsed-border
   tables leave cell borders behind while the sticky cell moves (Chrome). The
   separate/border-spacing pair lives ON THE BASE .report-table rule below:
   a duplicate `.report-table` rule here is DEAD — same specificity, and the
   base rule comes later in the file, so its value wins the cascade (review
   round-2 fix). The per-cell borders reproduce the exact same ruling. */
.table-scroll .report-table th:first-child,
.table-scroll .report-table td:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--card);
}
.table-scroll .report-table th:first-child { background: var(--paper); z-index: 2; }
/* Edge cue on the sticky column ONLY while content is actually beneath it
   (patients.js toggles .table-scroll-x on scrollLeft > 0). */
.table-scroll .report-table th:first-child::after,
.table-scroll .report-table td:first-child::after {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 12px;
  transform: translateX(100%);
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(to right, rgba(7, 32, 97, 0.12), rgba(7, 32, 97, 0));
  transition: opacity 0.15s ease;
}
.table-scroll.table-scroll-x .report-table th:first-child::after,
.table-scroll.table-scroll-x .report-table td:first-child::after { opacity: 1; }
.table-scroll.table-scroll-x .report-table th:first-child,
.table-scroll.table-scroll-x .report-table td:first-child {
  border-right: 1px solid var(--border-soft);
}
.report-meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding: 0 20px 8px;
  font-size: var(--fs-label);
  color: var(--ink-3);
}
.report-table {
  width: 100%;
  /* separate + spacing 0, NOT collapse — the A9 sticky Patient column needs
     it (collapsed borders stay behind while the sticky cell moves, Chrome).
     Cell borders are one-sided (th top/bottom, td bottom-only) so the ruling
     is identical to collapse. */
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--fs-sm);
}
.report-table th {
  text-align: left;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-2);
  padding: 10px 20px;
  border-top: 1px solid var(--border-soft);
  border-bottom: 1px solid var(--border);
  background: var(--paper);
}
.report-table td {
  padding: 12px 20px;
  border-bottom: 1px solid var(--border-soft);
  vertical-align: middle;
}
.report-table tr:last-child td { border-bottom: 0; }
.report-table .t-name { font-weight: 600; color: var(--ink); }
.report-table .t-dim { color: var(--ink-2); }
.report-num { font-family: var(--mono); font-size: var(--fs-label); color: var(--ink-3); }

/* ── Pills (stage / verdict) — informational only, never alarm ─────── */
.pill,
.stage-pill {
  display: inline-block;
  font-size: var(--fs-label);
  font-weight: 700;
  line-height: 1;
  padding: 5px 10px;
  border-radius: 999px;
  white-space: nowrap;
}
.pill-neutral, .stage-pill-neutral { background: var(--wash); color: var(--ink-2); }
.pill-progress, .stage-pill-progress { background: #e8effc; color: var(--blue); }
.pill-done, .stage-pill-done { background: var(--ok-bg); color: var(--ok); }
.pill-review { background: var(--warn-bg); color: var(--warn); }

/* ── Buttons ────────────────────────────────────────────────────────── */
/* ── THE BUTTON SCALE (2026-08-18) ──────────────────────────────────────
   An audit of this file found 33 button rules using 4 heights (36/40/44/48),
   FOURTEEN distinct padding pairs, 5 font sizes, and the radius spelled four
   different ways (8px, var(--r-control), and two spacings of
   var(--r-control,8px)). Buttons that differ by 2px read as carelessness even
   when nobody can name what is wrong.

   `.btn` below is the canonical control and is already test-locked at
   var(--fs-btn)/44px. These tokens express it as a SCALE so every other
   control can conform instead of inventing its own:

     sm  36px — DENSE controls inside a table row, where a 44px pair would
                double the row height of a 407-row board. Deliberate, and the
                only tier allowed below the touch target.
     md  44px — the default, and the touch-target floor.
     lg  48px — page-level submit / primary CTA.

   Radius, weight and gap are single-valued on purpose: a control may pick a
   SIZE, never its own shape. */
:root{
  --btn-h-sm:36px;  --btn-pad-sm:8px 14px;   --btn-fs-sm:var(--fs-label);
  --btn-h-md:44px;  --btn-pad-md:11px 18px;  --btn-fs-md:var(--fs-sm);
  --btn-h-lg:48px;  --btn-pad-lg:14px 22px;  --btn-fs-lg:var(--fs-btn);
  --btn-gap:8px;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font: inherit;
  font-size: var(--fs-btn);
  font-weight: 700;
  border-radius: var(--r-control); /* 10px — the refer .btn radius */
  padding: 11px 22px;
  cursor: pointer;
  border: 1px solid transparent;
  text-decoration: none;
  /* Join-style touch target — a busy physician is often on a phone. */
  min-height: 44px;
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
.btn:disabled { opacity: 0.55; cursor: default; }
/* Site parity: orange CTA lifts on hover with the orange glow the public
   site uses. Text is NAVY on the orange (owner decision 2026-07-19, C1):
   #072061 on #FF9933 measures 7.10:1 (AA/AAA) where the site's white text
   measured 2.16:1. DS doctrine note: orange stays the SINGLE accent — this
   changes only the label color ON the accent, not the accent itself. Hover
   #f28a1f keeps navy at 6.07:1 (AA). Locked by the uxc-decisions test
   (CTA contrast hex-pair lock). */
.btn-primary { background: var(--orange), #FF9933; background: var(--orange); color: var(--navy); }
.btn-primary:hover:not(:disabled) {
  background: #f28a1f;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(255, 153, 51, 0.3);
}
.btn-navy { background: var(--navy); color: #fff; }
.btn-navy:hover:not(:disabled) {
  background: #0a2b7e;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(7, 32, 97, 0.25);
}
.btn-quiet {
  background: var(--card);
  color: var(--blue);
  border-color: var(--border);
}
.btn-quiet:hover:not(:disabled) { background: var(--wash); }
.btn-sm { font-size:var(--btn-fs-sm); padding:var(--btn-pad-sm);min-height:var(--btn-h-sm); border-radius:var(--r-control); }

/* DS collision reset: ds/colors_and_type.css defines its own .btn box
   (height 36px, min-width 96px, nowrap) at equal specificity, loaded first.
   The portal's buttons are padding-sized, so the DS height clipped them and
   the DS hover rules (no :not(:disabled)) recolored in-flight disabled
   buttons mid-action. Neutralize the box + pin the disabled state.
   (UX review 2026-07-18) */
.btn, .btn-sm { height: auto; min-width: 0; line-height: normal; }
.btn-primary:disabled, .btn-primary:disabled:hover {
  background: var(--orange); color: var(--navy); border-color: transparent;
  box-shadow: none; transform: none;
}
.btn-navy:disabled, .btn-navy:disabled:hover {
  background: var(--navy); color: #fff; border-color: transparent;
  box-shadow: none; transform: none;
}
.btn-quiet:disabled, .btn-quiet:disabled:hover {
  background: var(--card); color: var(--blue); border-color: var(--border);
  box-shadow: none; transform: none;
}

/* ── Status + empty states ──────────────────────────────────────────── */
.status { font-size: var(--fs-sm); color: var(--ink-2); margin: 10px 0; min-height: 1em; }

/* An EMPTY status line still reserved min-height + margins. Three of them sit
   above the fold on some pages, so ~99px of the first screen was held for
   messages that were not there — read as a hole between the banner and the
   first card. The reservation exists to avoid a layout shift when a message
   arrives; collapsing only while genuinely empty keeps that benefit for the
   one that fills and returns the space for the ones that never do. */
.status:empty { display: none; }
/* .page overlaps the hero band by 28px, so a bare top-of-page status line
   ("Loading…") painted straight onto the navy gradient. Non-empty status
   text gets a card chip so it's readable wherever it lands.
   (UX review 2026-07-18) */
.status:not(:empty) {
  display: inline-block;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 13px;
  box-shadow: 0 2px 10px rgba(7, 32, 97, 0.06);
}
.status.err {
  color: var(--err);
  background: var(--err-bg);
  border: 1px solid #f1c7c4;
  border-radius: 8px;
  padding: 10px 14px;
}
.empty,
.board-empty {
  padding: 36px 20px;
  text-align: center;
  color: var(--ink-2);
  font-size: var(--fs-body);
}
.empty-title { font-weight: 700; color: var(--ink); margin: 0 0 4px; font-size: var(--fs-body); }

/* An empty state used as a PAGE-LEVEL band (candidates has one) was a lone
   paragraph on the page background, indented 20px off the shared column by the
   in-card padding it inherited — so it read as unfinished next to every other
   surface, which shows a card. In-card empties (.panel .empty, .board-empty)
   are unaffected. */
.page > .empty {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-1);
  padding: 36px var(--pad-card);
}

/* ── Login / single-card pages (login, callback, agreement, maintenance) ── */
.auth-body,
body.card-page {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  padding: 0 24px 40px;
  background: var(--paper);
}
/* The site's hero band, rendered as a fixed-height backdrop the card floats
   into (one 135° gradient per page, DS rule). */
body.card-page::before {
  content: '';
  display: block;
  align-self: stretch;
  margin: 0 -24px;
  height: 210px;
  background: linear-gradient(135deg, var(--navy) 0%, var(--blue) 100%);
}
.card {
  width: 100%;
  max-width: 460px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 8px 32px rgba(7, 32, 97, 0.16);
  padding: 36px 34px 30px;
  margin-top: -130px;
}
.auth-brand { margin-bottom: 20px; display: flex; flex-direction: column; gap: 1px; }
.auth-brand .brand-eyebrow { color: var(--blue); }
.auth-brand .brand-name { color: var(--navy); font-size: 16px; font-weight: 700; letter-spacing: -0.01em; }
.card h1 {
  margin: 0 0 8px;
  font-size: var(--fs-h2);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--navy);
}
.card .lede { margin: 0 0 18px; font-size: var(--fs-body); color: var(--ink-2); }
.card label {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-2);
  margin: 0 0 6px;
}
.card input[type="email"],
.field input, .field select {
  width: 100%;
  font: inherit;
  font-size: 16px;
  color: var(--ink);
  padding: 12px 14px;
  border: 1.5px solid var(--border);
  border-radius: var(--r-control); /* join-parity: refer inputs round at 10px */
  background: #fff;
  transition: border 0.2s, box-shadow 0.2s;
}
.card input[type="email"]:focus, .field input:focus, .field select:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(24, 67, 173, 0.25);
}
.card input[type="email"]:focus, .field input:focus, .field select:focus,
.btn:focus-visible, .appbar-nav a:focus-visible, .appbar-signout button:focus-visible,
.tc-slot:focus-visible, .tc-q-opt:focus-visible, .tc-refer-btn:focus-visible,
.result-download-btn:focus-visible, .tc-more:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}
/* A3 (round-2): the blue ring measured 1.0–1.76:1 against the navy→blue app
   bar gradient — invisible to a keyboard user. Everything focusable in the
   bar gets a WHITE ring (8.6:1 on the navy end) and drops the DS box-shadow
   ring so there is exactly one indicator. */
.appbar a:focus-visible,
.appbar button:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
  box-shadow: none;
}
/* A15 (round-2): the DS utility (button:focus-visible in ds/colors_and_type
   .css) adds ITS ring via box-shadow AND snaps border-radius to
   var(--radius-sm) — so portal buttons showed a double ring and a radius
   jump on focus. Keep the portal outline as the single ring and pin each
   button's own radius. */
.btn:focus-visible { box-shadow: none; border-radius: var(--r-control); }
.btn-sm:focus-visible { border-radius: var(--r-control); }
.tc-slot:focus-visible, .tc-refer-btn:focus-visible, .tc-more:focus-visible,
.result-download-btn:focus-visible, .why-more:focus-visible,
.ref-dettoggle:focus-visible, .btn-row-upl:focus-visible,
.row-result-chip:focus-visible, .results-jump:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
  box-shadow: none;
}
.tc-q-opt:focus-visible { box-shadow: none; border-radius: 999px; }
.card button[type="submit"]:not(.btn) {
  width: 100%;
  margin-top: 14px;
  font: inherit;
  font-size:var(--btn-fs-lg);
  font-weight: 600;
  border-radius:var(--r-control);
  padding:var(--btn-pad-lg);
  min-height:var(--btn-h-lg);
  cursor: pointer;
  border: none;
  background: var(--orange);
  color: var(--navy); /* C1 owner decision 2026-07-19 — same orange-CTA treatment as .btn-primary (7.10:1) */
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
.card button[type="submit"]:not(.btn):hover:not(:disabled) {
  background: #f28a1f;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(255, 153, 51, 0.3);
}
.card button[type="submit"]:not(.btn):disabled { opacity: 0.55; cursor: default; }
.fine, .auth-fine { margin-top: 16px; font-size: var(--fs-label); color: var(--ink-3); }
.fine a, .auth-fine a { color: var(--blue); }

/* ── "Continue with Google" SSO button + divider (2026-08-01) ──────────
   Official-style NEUTRAL Google button: white surface, cool border, dark
   text. Google's sign-in branding must not be re-colored, so this button
   deliberately does NOT take the orange CTA treatment — orange stays the
   single accent on the email-link submit. Hidden (with its divider) until
   login.js proves the google.com IdP is live (graceful degradation). */
.btn-google {
  width: 100%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font: inherit;
  font-size: var(--fs-btn);
  font-weight: 600;
  border-radius: 8px;
  padding: 13px 18px;
  min-height: 48px;
  cursor: pointer;
  background: #fff;
  color: var(--ink);
  border: 1px solid var(--border);
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
.btn-google:hover:not(:disabled) {
  background: var(--wash);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(7, 32, 97, 0.08);
}
.btn-google:disabled { opacity: 0.55; cursor: default; }
.btn-google .g-mark { width: 18px; height: 18px; flex: 0 0 auto; }
.auth-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 18px 0 14px;
  color: var(--ink-3);
  font-size: var(--fs-label);
}
.auth-divider::before,
.auth-divider::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--border);
}

/* ── Six-digit code sign-in (2026-09-04) ───────────────────────────────
   The code box is a MONOSPACE, letter-spaced, centred field. Not
   decoration: a proportional font makes 1/7 and 6/8 hard to tell apart at
   a glance, and the whole point of this path is that a provider reads six
   characters off a phone and retypes them correctly the first time.
   16px minimum like every other input here — anything smaller makes iOS
   zoom the page on focus and the field jumps out from under the thumb.

   type="text" (not "number"): a number input drops leading zeros, and
   "012345" is one in ten codes. inputmode="numeric" still brings up the
   number pad on a phone, which is the part that actually matters. */
.card input[type="text"].otp-input {
  width: 100%;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 26px;
  font-weight: 600;
  letter-spacing: 0.32em;
  text-indent: 0.32em; /* offsets the trailing letter-space so digits sit centred */
  text-align: center;
  color: var(--ink);
  padding: 12px 14px;
  border: 1.5px solid var(--border);
  border-radius: var(--r-control);
  background: #fff;
  transition: border 0.2s, box-shadow 0.2s;
}
.card input[type="text"].otp-input:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(24, 67, 173, 0.25);
}
/* The alternate-path row. A button, never an <a href="#">: it performs an
   action rather than going anywhere, and a screen reader should hear a
   button. Styled as a link so it reads as the quiet second choice beside
   the orange CTA — but it takes its geometry from the SIZE SCALE like
   every other control (md, so it keeps the 44px touch floor: it sits
   between two full-width buttons, where a mis-tap is expensive). */
.auth-alt { margin: 12px 0 0; text-align: center; font-size: var(--fs-label); }
.auth-alt-sep { color: var(--ink-3); margin: 0 6px; }
.btn-textlink {
  font: inherit;
  font-size: var(--btn-fs-sm);
  background: none;
  border: none;
  padding: var(--btn-pad-md);
  min-height: var(--btn-h-md);
  border-radius: var(--r-control);
  color: var(--blue);
  text-decoration: underline;
  cursor: pointer;
}
.btn-textlink:hover:not(:disabled) { color: var(--navy); }
.btn-textlink:disabled { opacity: 0.55; cursor: default; text-decoration: none; }
.btn-textlink:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; border-radius: var(--r-control); }

/* ── Results section on the board page ─────────────────────────────── */
.result-new { margin-left: 8px; }
.download-note,
.board-fine {
  padding: 10px 20px 16px;
  font-size: var(--fs-label);
  color: var(--ink-3);
  margin: 0;
}
.board-updated { font-size: var(--fs-label); color: var(--ink-3); margin: 4px 0 0; }
/* C4 (empathy review 2026-07-28): the "As of …" freshness line + Refresh button. */
#updated-at { display: flex; align-items: center; gap: 10px; }
.board-updated-age { font-size: var(--fs-label); color: var(--ink-3); }
.board-refresh {
  font: inherit; font-size: var(--fs-label); font-weight: 600; cursor: pointer;
  border: 1px solid var(--border); background: var(--card); color: var(--blue);
  border-radius: 8px; padding: 4px 12px;
}
.board-refresh:hover:not(:disabled) { background: var(--wash); border-color: var(--blue); }
.board-refresh:disabled { opacity: .6; cursor: default; }
.board-subhead { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: var(--navy); margin: 0; }
.result-download-btn {
  font: inherit; font-size:var(--btn-fs-sm); font-weight: 700; padding:var(--btn-pad-sm);min-height:var(--btn-h-sm);
  background: var(--card); color: var(--blue); border: 1px solid var(--border);
  border-radius:var(--r-control); cursor: pointer;
}
.result-download-btn:hover { background: var(--wash); }
.result-download-btn:disabled { opacity: 0.55; cursor: default; }

/* ── Trial candidates ───────────────────────────────────────────────── */
.tc-controls {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 0 0 14px;
  font-size: var(--fs-sm);
  color: var(--ink-2);
}
.tc-controls label { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; font-weight: 600; color: var(--ink); margin: 0; font-size: var(--fs-sm); text-transform: none; letter-spacing: 0; }
.tc-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  box-shadow: 0 4px 16px rgba(7, 32, 97, 0.10);
  margin: 0 0 18px;
  overflow: hidden;
}
.tc-card-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--border-soft);
  /* Join-parity: refer study tiles are clean white end-to-end — the gray
     header band made every card read as a boxy internal tool. */
  background: var(--card);
}
.tc-proto {
  margin: 0;
  font-size: var(--fs-body);
  font-weight: 700;
  letter-spacing: -0.005em;
  color: var(--navy);
}
.tc-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.tc-list { padding: 0 20px; }
.tc-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  padding: 13px 0;
  border-top: 1px solid var(--border-soft);
}
.tc-list .tc-row:first-child { border-top: 0; }
.tc-row-main { min-width: 0; }
.tc-name { font-size: var(--fs-body); color: var(--ink); }
.tc-name strong { font-weight: 700; }
.tc-meta { font-size: var(--fs-label); color: var(--ink-3); }
.tc-detail { font-size: var(--fs-label); color: var(--ink-2); margin-top: 3px; }
/* Eligibility match cards put .tc-detail lines directly under .tc-card
   (no .tc-list/.tc-row wrapper), so they need the card's own gutter. */
.tc-card > .tc-detail { padding: 0 20px; }
.tc-card > .tc-detail:first-of-type { margin-top: 12px; }
.tc-card > .tc-detail:last-of-type { margin-bottom: 14px; }
/* B6 payoff CTA must FIT the card: the DS .btn keeps white-space:nowrap
   (the portal reset at the Buttons section neutralizes height/min-width
   but not nowrap), so the long Lp(a) label rendered as one unbreakable
   line and poked ~35px past the card edge at 390px, clipping mid-word.
   Let the match-card CTA wrap inside the card. (UX round 2, 2026-07-18) */
.tc-card > .tc-detail .btn {
  max-width: 100%;
  white-space: normal;
  text-align: center;
}
.result-new { margin-left: 8px; }
.tc-row-side {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-shrink: 0;
  padding-top: 2px;
}
.tc-refer-btn {
  font: inherit; font-size:var(--btn-fs-md); font-weight: 700; padding:var(--btn-pad-md);min-height:var(--btn-h-md);
  background: var(--navy); color: #fff; border: none; border-radius:var(--r-control); cursor: pointer;
}
.tc-refer-btn:hover:not(:disabled) { background: #0a2b7e; }
.tc-refer-btn:disabled { opacity: 0.55; cursor: default; }
.tc-referred {
  font: inherit; font-size: var(--fs-label); font-weight: 700; padding: 8px 16px;
  background: var(--ok-bg); color: var(--ok); border: 1px solid #bfe6d4;
  border-radius: 8px; cursor: default;
}
.tc-more {
  display: block;
  width: calc(100% - 40px);
  margin: 0 20px 16px;
  font: inherit; font-size: var(--fs-label); font-weight: 700; padding: 8px 14px;
  background: var(--wash); color: var(--blue); border: 1px solid var(--border);
  border-radius: 8px; cursor: pointer;
}
.tc-more:hover { background: #e2edf9; }

/* Refer panel — slot picker + mini-pre-screener */
.tc-panel {
  margin: 0 0 13px;
  padding: 14px 16px 16px;
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.tc-panel-head {
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--navy);
  margin: 12px 0 8px;
}
.tc-panel-head:first-child { margin-top: 0; }
.tc-slots { display: flex; flex-wrap: wrap; gap: 7px; }
.tc-slot {
  font: inherit; font-size: var(--fs-sm); font-weight: 600; padding: 10px 14px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--card); color: var(--ink-2); cursor: pointer;
}
.tc-slot:hover { border-color: var(--blue); color: var(--blue); }
.tc-slot-on {
  border-color: var(--blue) !important;
  background: #e8effc !important;
  color: var(--blue) !important;
  font-weight: 700;
}
.tc-q {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 8px 0;
  border-bottom: 1px dashed var(--border-soft);
}
.tc-q:last-of-type { border-bottom: 0; }
.tc-q-text { font-size: var(--fs-sm); color: var(--ink); }
.tc-q-opts { display: flex; gap: 5px; flex-shrink: 0; }
.tc-q-opt {
  font: inherit; font-size: var(--fs-sm); font-weight: 600; padding: 8px 14px;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--card); color: var(--ink-2); cursor: pointer;
  text-transform: capitalize;
}
.tc-besttime {
  width: 100%;
  margin-top: 12px;
  font: inherit; font-size: var(--fs-input); padding: 8px 12px;
  border: 1px solid var(--border); border-radius: 8px; background: #fff;
}
.tc-panel-actions { display: flex; gap: 10px; margin-top: 14px; }
.tc-panel-actions .tc-refer-btn { flex: 0 0 auto; }
.tc-panel-actions .tc-more { width: auto; margin: 0; padding: 8px 18px; }

/* ── Eligibility checker ────────────────────────────────────────────── */
.elig-form { max-width: 664px; } /* refer form measure (720 card − 2×28 pad) */
/* Prose ran flush into the first field label — measured 0px between the
   "nothing you type here is stored" line and the AGE label, which is most of
   why the form read as squeezed. One gap between explanatory text and the
   controls it explains. */
.panel-pad > p + form,
.panel-pad > p + .elig-grid,
.panel-pad > p + .field,
.panel > p + form { margin-top: 16px; }
.elig-form .field { margin: 0 0 14px; }
.elig-form label,
.elig-form .elig-group-label {
  /* Join-parity (owner 2026-08-10): refer form labels are sentence-case
     semibold ink ("Patient first name"), not all-caps eyebrows. The
     .elig-group-label variant heads the medication-chip GROUP (a div +
     aria-labelledby, not an orphan <label> — Chrome a11y issue). */
  display: block;
  font-size: var(--fs-label);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 6px;
}
/* Same treatment for the refer-a-patient panel labels (studies.js
   labeledField reuses .sf-label, which stays an eyebrow elsewhere). */
.rp-field .sf-label {
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
}
.elig-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.elig-form .btn { margin-top: 4px; }

/* ── Footer ─────────────────────────────────────────────────────────── */
/* Site-parity footer: centered color logo + fine print. */
.portal-foot {
  max-width: var(--container);
  margin: 0 auto;
  padding: 10px var(--gutter) 44px;
  font-size: var(--fs-label);
  /* A8 (round-2): --ink-3 on --paper measured 4.15:1 — an AA fail on the
     line carrying the escalation phone number. --ink-2 clears AA. */
  color: var(--ink-2);
  display: flex;
  flex-direction: column;
  /* flex-start, not center: text-align alone cannot move flex children, so
     the footer kept rendering centred under a left-aligned page. */
  align-items: flex-start;
  gap: 6px;
  text-align: left;
  line-height: 1.6;
}
.portal-foot a { color: var(--blue); text-decoration: none; font-weight: 500; }
.foot-logo { height: 64px; width: auto; opacity: 0.9; margin-bottom: 6px; }

/* ── Responsive ─────────────────────────────────────────────────────── */
@media (max-width: 640px) {
  /* C6 (owner decision 2026-07-19): the band measured 328px at 390×844 —
     38.9% of a phone viewport before any content. Target ~25%: compact the
     brand row (so Sign out shares it instead of wrapping to its own row),
     put the Refer CTA in the tab-strip row, and trim hero/lede padding +
     type. The 135° navy→blue gradient rules are untouched. Measured after:
     ~215px ≈ 25% (CDP probe, 390×844). */
  .appbar-inner { padding: 0 12px; gap: 6px 10px; flex-wrap: wrap; min-height: 0; }
  /* Force the wrap instead of hoping for it. The strip relied on
     flex-basis:180px being "too big to fit beside the brand" — true at 375px,
     false by ~500px, where the nav squeezed onto the brand row and clipped
     "Trial candidates" mid-word while Sign out rendered to its LEFT. A
     zero-height 100% flex item between the order-0 items and the order-3 nav
     breaks the row deterministically at every width in this range. */
  .appbar-inner::before {
    content: '';
    flex: 0 0 100%;
    order: 2;
    height: 0;
    margin: 0;
  }
  .brand { gap: 8px; padding: 6px 0; }
  .brand-logo { height: 26px; }
  .brand-text { line-height: 1.25; }
  .brand-name { font-size: var(--fs-sm); }
  .page-hero { padding: 10px 16px 0; }
  .page-hero .page-title { font-size: var(--fs-h2); margin-bottom: 4px; }
  .page-hero .page-lede { font-size: var(--fs-sm); line-height: 1.45; }
  .hero-band { padding-bottom: 24px; }
  .card { margin-top: -110px; }
  /* Tabs are nowrap links in a flex row — at 375px the third tab clipped
     mid-word. Scroll the strip instead (UX review 2026-07-18). flex-basis
     180px (not 0 / not 100%): small enough that the strip never squeezes
     onto the brand row, large enough that it wraps to its own row and the
     Refer CTA (order 4) fits BESIDE it down to 360px-wide phones. */
  .appbar-nav {
    margin-left: 0; flex: 1 1 auto; min-width: 0; order: 3;
    border-top: 1px solid rgba(255,255,255,0.14);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .appbar-nav::-webkit-scrollbar { display: none; }
  .appbar-nav a { padding: 8px 12px; }
  .appbar-signout { margin-left: auto; }
  .appbar-signout button { padding:var(--btn-pad-sm);min-height:var(--btn-h-sm); }
  /* The Refer CTA joins the tab-strip row, pinned right of the scrolling
     tabs (stays visible while they scroll) and rendered in the strip's own
     link treatment — the pill chrome reads as a 4th control the bar has no
     room for at phone widths. */
  .appbar-cta {
    order: 4;
    margin-left: 0;
    align-self: stretch;
    display: inline-flex;
    align-items: center;
    background: none;
    border: 0;
    border-top: 1px solid rgba(255,255,255,0.14);
    border-radius: 0;
    padding: 10px 12px;
    min-height: 44px;
    font-size: var(--fs-sm);
  }
  .page { padding: 20px 14px 48px; margin-top: -18px; }
  .report-table th, .report-table td { padding-left: 14px; padding-right: 14px; }
  .tc-row { flex-direction: column; gap: 8px; }
  .tc-row-side { padding-top: 0; }
  .elig-grid { grid-template-columns: 1fr; }
  /* A6 (round-2): every text control under 16px triggers iOS Safari's
     auto-zoom on focus (login 15px, refer fields 14px, tc-besttime 13px,
     sf-select 13.5px). 16px at the phone breakpoint kills the zoom. */
  input[type="text"], input[type="tel"], input[type="email"], input[type="file"],
  select, textarea { font-size: 16px; }
  /* A6 specificity repair (review round-2): the bare-element rule above
     LOSES to the portal's classed controls — .card input[type="email"]
     (0,2,1 — login email 15px), .field select (0,1,1 — eligibility selects
     15px), and the (0,1,0) class rules that appear AFTER this media block
     in the file and so win a same-specificity tie: .sf-select 13.5px,
     .upl-field 14px, .viewas-select 13px. Repeat the declaration
     ELEMENT-QUALIFIED so it wins on specificity, not source order. */
  .card input[type="email"],
  .field input, .field select,
  select.sf-select, select.viewas-select,
  input.upl-field, select.upl-field { font-size: 16px; }
  /* A7 (round-2): residual sub-44px touch targets — Download 33px,
     Refer/Confirm 33px, Sign out ~31px, row Upload ~38px. */
  .result-download-btn, .tc-refer-btn, .btn-row-upl, .appbar-signout button,
  .why-more { min-height: 44px; }
  .ref-dettoggle { padding: 10px 8px; margin: 0 0 0 -8px; }
  .portal-foot a { display: inline-block; padding: 8px 4px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

.appbar-nav a, .appbar-signout button, .appbar-cta { white-space: nowrap; }

/* ── Staff admin view switcher + banner (2026-07-15) ──────────────────
   Rendered by admin-view.js ONLY for portal_providers docs with
   role='admin'. Neutral styling per the no-persistent-alarm doctrine —
   this is an informational mode indicator, not a warning. */
/* The switcher lives IN the banner strip (2026-07-17 header-stability fix:
   the app bar is identical for providers and admins). */
.viewas-select {
  max-width: 340px;
  min-width: 180px;
  padding: 8px 10px;
  font: inherit;
  font-size: var(--fs-input);
  color: var(--ink);
  background: var(--card);
  border: 1.5px solid var(--border);
  border-radius: 8px;
}
.viewas-select:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
.viewas-banner {
  padding: 8px 24px;
  font-size: var(--fs-sm);
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  flex-wrap: wrap;
  color: var(--navy);
  background: var(--wash);
  border-bottom: 1px solid var(--border);
  position: relative;
  z-index: 2;
  /* Align content to the shared column while the tint stays full-bleed. */
  padding-left: max(var(--gutter), calc((100% - var(--container)) / 2 + var(--gutter)));
  padding-right: max(var(--gutter), calc((100% - var(--container)) / 2 + var(--gutter)));
}
.viewas-text { white-space: nowrap; }
/* Read-only staff previews (2026-08-01): the reviewer queue refuses every
   decision server-side, and /notifications is permanently SELF-scoped — both
   need a banner that reads differently from ordinary provider view-as. A calm
   cyan left rule + a heavier bottom border, never alarm styling (a staff
   preview is a normal ops state — no-persistent-alarm doctrine). */
.viewas-banner-readonly {
  border-left: 4px solid var(--cyan);
  border-bottom-color: var(--blue);
}
/* These two carry a full explanatory sentence, so the copy WRAPS instead of
   pushing the switcher off the row. */
.viewas-banner-readonly .viewas-text,
.viewas-banner-note .viewas-text { white-space: normal; }
/* The banner sits between the band and the overlapping content column —
   push the column back down so cards never cover it. */
.viewas-banner + main.page { margin-top: 24px; }
.viewas-banner strong { font-weight: 700; }
.report-table th.col-practice, .report-table td.col-practice { color: var(--ink-2); }
@media (max-width: 640px) {
  .viewas-select { max-width: 220px; }
}

/* ── Studies & reference page (2026-07-16) ────────────────────────────── */
.page-head-mid { margin-top: 34px; }
.page-subtitle {
  margin: 0 0 6px;
  font-size: var(--fs-h2);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--navy);
}
.stage-flow { margin: 0; padding: 0 0 0 18px; }
.stage-flow li { margin: 0 0 12px; }
.stage-flow .stage-note { display: block; margin: 4px 0 0; font-size: var(--fs-sm); color: var(--ink-2); }
.ref-fine { font-size: var(--fs-label); color: var(--ink-3); margin: 10px 0 0; }
.ref-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 20px; }
.ref-block-title { margin: 0 0 6px; font-size: var(--fs-body); font-weight: 700; color: var(--navy); }
.ref-block p { margin: 0 0 8px; font-size: var(--fs-sm); color: var(--ink-2); }
.ref-site-head { margin: 22px 0 12px; }
.ref-site-title { margin: 0; font-size: 16px; font-weight: 700; color: var(--navy); }
/* A8 (round-2): --ink-3 fails AA on the paper background — these two carry
   real reference content (site address line, study phase/visit meta). */
.ref-site-sub { margin: 2px 0 0; font-size: var(--fs-label); color: var(--ink-2); }
.ref-title-wrap { min-width: 0; }
.ref-study-meta { margin-top: 3px; font-size: var(--fs-label); color: var(--ink-2); }
.ref-study-body { padding: 12px 20px 14px; }
.ref-detrow { font-size: var(--fs-sm); color: var(--ink-2); margin: 0 0 5px; }
.ref-detrow strong { color: var(--ink); font-weight: 600; }
.ref-dettoggle {
  margin-top: 8px;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--blue);
  cursor: pointer;
}
.ref-dettoggle:hover { text-decoration: underline; }
.ref-critcols { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; margin-top: 10px; }
.ref-crit-title { font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); margin: 0 0 5px; }
.ref-crit-list { margin: 0; padding-left: 18px; }
.ref-crit-list li { font-size: var(--fs-sm); color: var(--ink-2); margin: 0 0 3px; }

/* Pre-screen criteria on the Studies page — open by default, checklist
   glyphs (✓/✗ per DS rules: unicode status glyphs, no emoji). */
.ref-prescreen-head {
  margin: 10px 0 4px;
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--navy);
}
.ref-crit-list { list-style: none; padding-left: 2px; }
.ref-crit-list li { position: relative; padding-left: 20px; font-size: var(--fs-sm); color: var(--ink); margin: 0 0 4px; }
.ref-crit-inc li::before { content: '✓'; position: absolute; left: 0; color: var(--ok); font-weight: 700; }
.ref-crit-exc li::before { content: '✗'; position: absolute; left: 0; color: var(--warn); font-weight: 700; }

/* ── Approved pre-screening checklist panel (spec §4.3, 2026-07-19) ────
   Compact collapsible reference shown on the Trial candidates study card
   and at the top of the refer flow. Deliberately quiet: neutral wash,
   design-system tokens only, ✓/✗ glyphs reused from .ref-crit-* above, and
   NO alarm colors — an exclusion is normal clinical information, not an
   act-now signal. The checklist is SHORT by design (§4.1 targets 5–10
   items), so there is no inner scroller and no height cap to trap content. */
.pc-panel {
  margin: 10px 0 4px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--paper);
}
.pc-summary {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 8px 12px;
  cursor: pointer;
  list-style: none;
  color: var(--navy);
}
.pc-summary::-webkit-details-marker { display: none; }
.pc-summary::before {
  content: '▾';
  font-size: var(--fs-xs);
  color: var(--ink-3);
  transform: rotate(-90deg);
  transition: transform 0.15s;
}
.pc-panel[open] > .pc-summary::before { transform: rotate(0deg); }
.pc-summary:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
  border-radius: 8px;
}
.pc-summary-text { font-size: var(--fs-sm); font-weight: 700; }
.pc-count { font-size: var(--fs-label); color: var(--ink-3); font-weight: 400; }
.pc-body { padding: 2px 12px 12px; }
.pc-meds { margin-top: 12px; }
.pc-pills { display: flex; flex-wrap: wrap; gap: 6px; }
.pc-foot { margin: 12px 0 0; font-size: var(--fs-label); color: var(--ink-3); }

@media (prefers-reduced-motion: reduce) {
  .pc-summary::before { transition: none; }
}

/* ── Staff upload panel (admin view-as only, 2026-07-16) ──────────────── */
.upl-open { margin-left: auto; }
.panel-head .upl-open { flex-shrink: 0; }
.upl-panel[hidden] { display: none; } /* display:flex below would defeat [hidden] (Settings create-partner starts collapsed) */
.upl-panel {
  margin: 0 20px 16px;
  padding: 14px 16px;
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  gap: 9px;
  max-width: 560px;
}
.upl-title { font-size: var(--fs-sm); font-weight: 700; color: var(--navy); }
.upl-note { margin: 0; font-size: var(--fs-label); color: var(--ink-2); }
.upl-field {
  font: inherit;
  font-size: var(--fs-body);
  color: var(--ink);
  background: var(--card);
  border: 1.5px solid var(--border);
  border-radius: var(--r-control);
  padding: 12px 14px; /* join-parity input box */
  transition: border 0.2s, box-shadow 0.2s;
}
.upl-field:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(24, 67, 173, 0.25);
}

/* ── Agreements acceptance page (PR-E, 2026-07-16) ────────────────────── */
.agr-body {
  padding: 14px 20px;
  max-height: 340px;
  overflow-y: auto;
  border-bottom: 1px solid var(--border-soft);
}
.agr-body p { margin: 0 0 10px; font-size: var(--fs-sm); color: var(--ink); line-height: 1.6; }
.agr-accept { padding: 12px 20px; background: var(--paper); }
.agr-check { display: flex; gap: 9px; align-items: flex-start; font-size: var(--fs-sm); font-weight: 600; color: var(--ink); cursor: pointer; }
/* A7 (round-2): the native checkbox rendered ~13px — undersized for the
   one legally load-bearing control on the page. */
.agr-check input { margin-top: 2px; flex-shrink: 0; width: 18px; height: 18px; }
.agr-signpad { display: flex; flex-direction: column; gap: 10px; max-width: 560px; }

/* Study-aware board rows (2026-07-17)
   Type floor: the status-why line is the clinically load-bearing text for a
   60+ audience — keep it at or above 13px (UX review 2026-07-18). */
.t-study { font-weight: 600; color: var(--ink); }
.t-prog-sub { font-size: var(--fs-sm); color: var(--ink-3); margin-top: 1px; }
/* §4 expansion #3 (2026-07-22): the CRP-history line — do-not-contact chip +
   last-contact date. Wraps on narrow viewports; the chip stays neutral (never
   an alarm color) per the no-persistent-alarm doctrine. */
.t-contact-info { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin-top: 4px; font-size: var(--fs-label); }
.t-contact-info .t-dim { color: var(--ink-3); }
.stage-pill.t-dnc { text-transform: none; letter-spacing: 0; }
.t-status-why { font-size: var(--fs-sm); color: var(--ink-2); margin-top: 3px; max-width: 340px; line-height: 1.45; }
/* B4 (round-2): rows averaged 164px tall — clamp the why-line to 2 lines;
   patients.js adds a More/Less toggle to rows that actually overflow.
   -webkit-box + line-clamp is the interoperable pair (Firefox implements
   the -webkit- form); max-height is the belt for anything else. */
.t-status-why {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  max-height: calc(2 * 1.45 * 14px + 1px);
}
.t-status-why.t-status-why-open {
  -webkit-line-clamp: unset;
  line-clamp: unset;
  display: block;
  max-height: none;
}
.why-more {
  display: inline-block;
  margin-top: 2px;
  padding: 2px 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--blue);
  cursor: pointer;
}
.why-more:hover { text-decoration: underline; }

/* B1 (round-2): stage group headers + the name filter. Group header rows are
   NON-patient rows by contract — my-upload.js/admin-view.js append a
   td.col-upl to every #patients-body row, so it is hidden here instead of
   patching their iteration. */
.report-table tr[data-group-header] td.col-upl { display: none; }
.report-table .group-row > td {
  background: var(--paper);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border-soft);
  padding-top: 8px;
  padding-bottom: 8px;
}
.group-label {
  /* Stays readable while the board is scrolled sideways (the cell spans the
     full table width; the label pins to the scrollport's left edge). */
  position: sticky;
  left: 20px;
  display: inline-block;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--navy);
}
.group-count {
  /* Lives INSIDE .group-label so the pair pins together during sideways
     scroll (two independent sticky spans would overlap). */
  display: inline-block;
  margin-left: 8px;
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-2);
  background: var(--wash);
  border-radius: 999px;
  padding: 2px 8px;
}
.board-tools { padding: 0 var(--pad-card) 12px; }
.board-search {
  width: 100%;
  max-width: 320px;
  font: inherit;
  font-size: var(--fs-body);
  color: var(--ink);
  background: var(--card);
  border: 1.5px solid var(--border);
  border-radius: 8px;
  padding: 8px 12px;
}
.board-search:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(24, 67, 173, 0.25);
}
.empty p { margin: 0 0 6px; }
.empty a { color: var(--blue); font-weight: 600; }
/* C1 (empathy review 2026-07-28): the first-run "what you can do" card. */
.empty-do { margin: 8px 0 14px; padding-left: 20px; text-align: left; display: inline-block; }
.empty-do li { margin: 0 0 6px; font-size: var(--fs-sm); color: var(--ink-2); line-height: 1.5; }
.empty-cta { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
.empty-cta a { font-weight: 600; }

/* B2 (round-2): results linkage from the board. */
.panel-head-side {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-left: auto;
  flex-wrap: wrap;
}
.results-jump[hidden] { display: none; } /* display below would defeat [hidden] */
.results-jump {
  display: inline-block;
  font-size: var(--fs-label);
  font-weight: 700;
  color: var(--blue);
  background: var(--wash);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 4px 11px;
  text-decoration: none;
  white-space: nowrap;
}
.results-jump:hover { background: #e2edf9; }
.row-result-chip {
  display: inline-block;
  margin-left: 8px;
  font-size: var(--fs-label);
  font-weight: 700;
  color: var(--blue);
  text-decoration: none;
  white-space: nowrap;
}
.row-result-chip:hover { text-decoration: underline; }
.result-upd { margin-left: 8px; }
.col-upl { width: 1%; white-space: nowrap; }
.btn-row-upl {
  font: inherit;
  font-size:var(--btn-fs-md);
  font-weight: 600;
  color: var(--blue);
  background: var(--card);
  border: 1.5px solid var(--border);
  border-radius:var(--r-control);
  padding:var(--btn-pad-md);min-height:var(--btn-h-md);
  cursor: pointer;
  transition: border 0.15s, background 0.15s;
}
.btn-row-upl:hover { border-color: var(--blue); background: var(--wash); }

/* Enrolling-studies filters (Site + Therapeutic area, 2026-07-17) */
.studies-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin: 12px 0 4px;
}
.sf-field { display: inline-flex; flex-direction: column; gap: 4px; }
.sf-label {
  /* A8 (round-2): was 10.5px --ink-3 — tiny AND under-contrast. */
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.sf-select {
  font: inherit;
  font-size: var(--fs-body);
  color: var(--ink);
  background: var(--card);
  border: 1.5px solid var(--border);
  border-radius: var(--r-control);
  padding: 8px 12px;
  min-width: 190px;
}
.sf-select:focus { outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px rgba(24, 67, 173, 0.25); }

/* Join-parity condition pills (joinresearchstudies.com/refer .cpill —
   owner 2026-08-10): the Studies-page site + therapeutic-area filters
   render as tappable pills instead of labeled <select>s. Sized one step
   up from the refer 12px original per the portal readability floor. */
.cpill-row { display: flex; flex-wrap: wrap; gap: 8px; }
.cpill-row + .cpill-row { margin-top: 10px; }
.cpill {
  font: inherit;
  font-size: var(--fs-label);
  font-weight: 600;
  color: var(--ink);
  background: var(--card);
  border: 1.5px solid var(--border);
  border-radius: var(--r-pill);
  padding: 8px 16px;
  cursor: pointer;
  transition: border 0.15s, background 0.15s, color 0.15s;
}
.cpill:hover { border-color: var(--blue); color: var(--blue); }
.cpill.active { background: var(--blue); border-color: var(--blue); color: #fff; }
.cpill:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }

/* ── Consent-to-contact + canonical flow (spec §6a/§6b, 2026-07-19) ─────
   Quiet, informational treatment throughout — these are normal ops
   affordances, never alarm surfaces (no-persistent-alarm doctrine). */

/* Board row actions (Mark contacted / Patient interested / Ask). */
.row-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
}
.row-actions .btn-quiet { white-space: nowrap; }
.row-act-note { font-size: var(--fs-sm); color: var(--ink-2); }
.row-act-note.err { color: var(--err); }

/* Ask-about-this-patient panel row (rides the upl-panel look). */
.ask-field { resize: vertical; min-height: 64px; }
.ask-count { text-align: right; }
.ask-actions { display: flex; gap: 10px; align-items: center; }

/* Trial-candidates study-scope grant strip (inside a tc-card, under the head). */
.tc-grant {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 0 20px 12px;
}
.tc-grant .tc-panel { flex-basis: 100%; }

/* Studies-page contact permissions (grants.js). */
.grant-posture { margin: 0 0 12px; font-size: var(--fs-body); color: var(--ink); }
.grant-list { display: flex; flex-direction: column; gap: 8px; margin: 0 0 14px; }
.grant-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  padding: 10px 14px;
  background: var(--card);
}
.grant-row-label { font-size: var(--fs-body); font-weight: 600; color: var(--navy); }
.grant-row-meta { font-size: var(--fs-sm); color: var(--ink-2); }
.grant-row-side { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.grant-note { font-size: var(--fs-sm); color: var(--ink-2); max-width: 420px; }
.grant-note.err { color: var(--err); }
.grant-all { margin-top: 6px; display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.grant-all .upl-panel { flex-basis: 100%; }
.grant-all-panel { margin: 0; max-width: 560px; }
.grant-ack {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: var(--fs-sm);
  color: var(--ink);
  cursor: pointer;
}
.grant-ack input { margin-top: 2px; }
.grant-all-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

/* ── Identified group (combined My patients board, IA redesign 2026-07-21) ──
   Patients CRP found in the provider's records, awaiting a contact decision.
   Renders as a .report-table so it shares the "Referred & in a study" board's
   grid EXACTLY — same cell padding, sticky Patient column, row height — and the
   two sections read as one continuous board. Reuses tokens; no new colors. */
.ident-count{background:var(--wash);color:var(--blue);font-size: var(--fs-label);font-weight:700;
  border-radius:var(--r-pill,999px);padding:1px 9px;margin-left:8px;vertical-align:middle}
/* Full-width study-group separator row inside the table body. */
#identified-table .ident-grp td{padding:10px var(--pad-card,20px);font-size: var(--fs-xs);
  letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3);font-weight:700;
  background:var(--paper);border-bottom:1px solid var(--border-soft);
  /* STICKY: with the per-row study name removed, this is the only thing
     naming the study. A 250-row group must not scroll its own header away. */
  position:sticky;top:0;z-index:2}
/* Dim second line under the name (age·sex·masked phone). */
#identified-table .ident-sub{color:var(--ink-3);font-size: var(--fs-label);margin-top:2px;
  /* "age 51 · male · •••• 3824" was breaking after the dots and stranding the
     last four digits on their own line. The line is short and its parts are
     one fact — keep it whole. */
  white-space:nowrap}
/* The eligibility verdict, now the whole cell (the study lives in the sticky
   group header above, not repeated on every row). */
#identified-table .t-verdict{color:var(--ink-2);font-weight:600}
#identified-table td.ident-action{text-align:right;white-space:nowrap}
/* nowrap, so the two decisions sit on ONE line instead of stacking and
   doubling the row height. */
.ident-controls{display:inline-flex;gap:8px;flex-wrap:nowrap}
.ident-controls .cbtn{border:1.5px solid var(--border);background:var(--card);color:var(--ink-2);
  font:inherit;font-weight:600;font-size:var(--btn-fs-sm);padding:var(--btn-pad-sm);border-radius:var(--r-control);
  cursor:pointer;white-space:nowrap;min-height:var(--btn-h-sm)}
.ident-controls .cbtn:hover{border-color:var(--blue)}
.ident-controls .cbtn:disabled{opacity:.55;cursor:default}
.ident-controls .cbtn.on-yes{background:var(--ok-bg);border-color:var(--ok);color:var(--ok)}
.ident-controls .cbtn.on-no{background:var(--err-bg);border-color:var(--err);color:var(--err)}
/* B1 (empathy review 2026-07-28): the inline "patient agreed?" confirm on the
   Identified ✓ — a speed bump before the grant fires. */
/* The inline confirm adds a question + two buttons — that one DOES need to
   wrap. Scoped to the confirm state so the resting row stays one line. */
.ident-controls:has(.cbtn-confirm){flex-wrap:wrap}
.cbtn-confirm-q{font-size: var(--fs-label);color:var(--ink-2);align-self:center;margin-right:2px}
.ident-controls .cbtn.cbtn-confirm{background:var(--blue);border-color:var(--blue);color:#fff}
.ident-controls .cbtn.cbtn-confirm:hover{background:var(--navy);border-color:var(--navy)}
@media(max-width:640px){
  #identified-table td.ident-action{white-space:normal}
  .ident-controls{display:flex}
  .ident-controls .cbtn{flex:1}
}

/* ── PI Review (2026-07-24, Dr. Leventhal rheumatology) ──
   Reuses the Identified decision language: two outlined buttons that fill
   with the ok/err tint when chosen. No new colors. */
.pi-decision-cell { white-space: nowrap; }
.pi-actions { display: inline-flex; gap: 8px; }
.pi-btn { border: 1.5px solid var(--border); background: var(--card); color: var(--ink-2);
  font: inherit; font-weight: 600; font-size:var(--btn-fs-sm); padding:var(--btn-pad-sm); border-radius:var(--r-control);
  cursor: pointer; white-space: nowrap; min-height:var(--btn-h-sm); }
.pi-btn:hover { border-color: var(--blue); }
.pi-btn:disabled { opacity: .55; cursor: default; }
/* Differentiate the binary choice so the affirmative primary and the quiet
   secondary are not visually identical — a same-styled pair on a consequential
   decision invites mis-clicks (UX review 2026-07-25). "Confirm eligible" reads
   as the affirmative (green outline, echoing the Eligible verdict pill);
   "Not eligible" is the quieter alternative. The .is-current fill states below
   are more specific and still win once a decision is recorded. */
.pi-btn-yes { border-color: var(--ok); color: var(--ok); }
.pi-btn-no { color: var(--ink-3); }
.pi-btn-yes.is-current { background: var(--ok-bg); border-color: var(--ok); color: var(--ok); }
.pi-btn-no.is-current { background: var(--err-bg); border-color: var(--err); color: var(--err); }
.pi-decided { display: inline-flex; align-items: center; gap: 10px; }
.pi-verdict { font-size: var(--fs-label); font-weight: 700; padding: 3px 10px; border-radius: var(--r-pill, 999px); }
.pi-verdict-eligible { background: var(--ok-bg); color: var(--ok); }
.pi-verdict-not { background: var(--err-bg); color: var(--err); }
.pi-change { border: 0; background: transparent; color: var(--ink-3); font: inherit; font-size: var(--fs-label);
  text-decoration: underline; cursor: pointer; padding: 0; }
.pi-change:hover { color: var(--blue); }
/* Records affordance (PR 11) — a large, plain, senior-physician-friendly link
   button. Blue outline reads as a navigational CTA (open the record), distinct
   from the green/quiet decision pair above. */
.pi-records-cell { white-space: nowrap; }
.pi-records-none { color: var(--ink-3); font-size: var(--fs-label); }
.pi-records-btn { border: 1.5px solid var(--blue); background: var(--card); color: var(--blue);
  font: inherit; font-weight: 600; font-size:var(--btn-fs-sm); padding:var(--btn-pad-sm); border-radius:var(--r-control);
  cursor: pointer; white-space: nowrap; min-height:var(--btn-h-sm); }
.pi-records-btn:hover { background: var(--paper, #f6f9ff); }
.pi-records-btn:disabled { opacity: .55; cursor: default; }
.pi-records-btn:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.pi-records-list { display: inline-flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.pi-records-doc { text-align: left; }
@media(max-width:640px){
  .pi-decision-cell{white-space:normal}
  .pi-actions{display:flex}
  .pi-btn{flex:1}
  /* Stacked-card reflow for ACTION-bearing tables so the primary / destructive
     control never clips off the right edge on a phone (UX review 2026-07-25).
     The fixed multi-column table + the .table-scroll min-width:520px pushed the
     decision / Remove column off-screen behind a faint scroll shadow — the PI
     could not see "Not eligible", and the admins "Remove" was unreachable.
     Opt-in via .stack-mobile so read-only tables keep the horizontal-scroll
     pattern. Each row becomes a card; cells stack; the first cell is the title;
     action buttons sit full-width beneath. */
  .table-scroll .report-table.stack-mobile{min-width:0}
  .report-table.stack-mobile thead{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);border:0}
  .report-table.stack-mobile tbody tr{display:block;border:1px solid var(--border);border-radius:12px;padding:12px 14px;margin-bottom:12px}
  .report-table.stack-mobile tbody tr:last-child{margin-bottom:0}
  .report-table.stack-mobile tbody td{display:block;border:0;padding:3px 0;white-space:normal;position:static}
  .report-table.stack-mobile tbody td:first-child{font-weight:700;font-size: 16px;color:var(--ink);margin-bottom:2px}
  .report-table.stack-mobile tbody td.col-practice{color:var(--ink-2)}
  .report-table.stack-mobile tbody td.pi-decision-cell{margin-top:10px}
  .report-table.stack-mobile .pi-decided{display:flex;justify-content:space-between;align-items:center}
  .report-table.stack-mobile tbody td:empty{display:none}
}

/* ── Senior-friendly review tables (PR 13b) ────────────────────────────────
   Live beta feedback from the actual PI (an older, deliberately non-technical
   physician): larger row text + bigger click targets on the review surface
   ONLY. Scoped to body.pi-review-page so the referring-provider board keeps its
   dense sizing. Reuses existing tokens — no new colours. */
.pi-review-page .report-table th { font-size: var(--fs-sm); }
.pi-review-page .report-table td { font-size: 16px; padding-top: 13px; padding-bottom: 13px; }
.pi-review-page .report-table .t-name { font-size: 16px; }
.pi-review-page .pi-btn { font-size: var(--btn-fs-lg); padding: var(--btn-pad-md); min-height: var(--btn-h-md); }
.pi-review-page .pi-verdict { font-size: var(--fs-body); padding: 4px 12px; }
.pi-review-page .pi-records-btn { font-size: var(--btn-fs-lg); min-height: var(--btn-h-md); padding: var(--btn-pad-md); }
.pi-review-page .pi-change { font-size: var(--fs-body); }
.pi-review-page .page-lede { font-size: 16px; }
/* Group-header rows on the All patients overview stay quiet — a practice label,
   not a data row. */
.pi-review-page .report-table .group-row > td { font-size: var(--fs-sm); font-weight: 700; color: var(--ink-2); }

/* ── PI-review clinical upgrade — controls + note + clinical context ────────
   Rationale note (item 4), study filter + bulk confirm + reviewed search
   (item 8), and the per-row clinical-context expander (item 5). Senior-friendly
   sizing, large targets; reuses existing tokens — no new colours, no emoji. */
.pi-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 16px 24px;
  padding: 12px 2px 14px; }
.pi-filter { display: inline-flex; align-items: center; gap: 8px; }
.pi-filter-label { font-size: var(--fs-sm); font-weight: 700; color: var(--ink-2); }
.pi-select, .pi-search-input { font: inherit; font-size: 16px; padding: 9px 12px; min-height: 42px;
  border: 1.5px solid var(--border); border-radius: var(--r-control); background: var(--card); color: var(--ink); }
.pi-select:focus-visible, .pi-search-input:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
.pi-bulk { display: inline-flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.pi-selectall { display: inline-flex; align-items: center; gap: 8px; font-size: var(--fs-body); font-weight: 600;
  color: var(--ink-2); cursor: pointer; }
.pi-selectall-check, .pi-row-check { width: 20px; height: 20px; cursor: pointer; }
.pi-bulk-confirm { border: 1.5px solid var(--ok); background: var(--ok-bg); color: var(--ok);
  font: inherit; font-weight: 700; font-size: 16px; padding: 11px 18px; border-radius: var(--r-control);
  cursor: pointer; min-height: 44px; }
.pi-bulk-confirm:hover:not(:disabled) { filter: brightness(0.97); }
.pi-bulk-confirm:disabled { opacity: .5; cursor: default; border-color: var(--border); background: var(--card); color: var(--ink-3); }
.pi-bulk-confirm:focus-visible { outline: 2px solid var(--ok); outline-offset: 2px; }
.pi-sel-count { font-size: var(--fs-sm); color: var(--ink-3); }
.pi-search { display: inline-flex; align-items: center; gap: 8px; }
.pi-search-input { min-width: 240px; }
.pi-check-cell, .pi-check-col { width: 34px; text-align: center; }
/* The decision control — a stacked note + verdict buttons. */
.pi-decision { display: flex; flex-direction: column; gap: 8px; align-items: stretch; min-width: 220px; }
.pi-note { font: inherit; font-size: var(--fs-body); padding: 8px 10px; border: 1.5px solid var(--border);
  border-radius: var(--r-control); background: var(--card); color: var(--ink); resize: vertical; min-height: 40px; }
.pi-note:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
.pi-note-hint { margin: 0; font-size: var(--fs-label); color: var(--ink-3); }
/* Clinical context expander — a quiet blue toggle; the grid renders in the
   panel below (reusing the d-* study/criteria styles). */
.pi-clinical-cell { min-width: 150px; }
.pi-clinical-btn { border: 1.5px solid var(--blue); background: var(--card); color: var(--blue);
  font: inherit; font-weight: 600; font-size:var(--btn-fs-md); padding:var(--btn-pad-md); border-radius:var(--r-control);
  cursor: pointer; min-height:var(--btn-h-md); white-space: nowrap; }
.pi-clinical-btn:hover { background: var(--paper, #f6f9ff); }
.pi-clinical-btn:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.pi-clinical-panel { margin-top: 10px; padding: 12px 14px; border: 1px solid var(--border);
  border-radius: 12px; background: var(--paper, #f6f9ff); max-width: 460px; }
.pi-review-page .pi-clinical-btn { font-size: var(--btn-fs-lg); min-height: var(--btn-h-md); }

/* ══════════════════════════════════════════════════════════════════════
   Three-pane app shell (2026-07-22 — the "revised visual language")
   navy left nav rail · patient list in the centre · patient detail pane on
   the right. Applies ONLY to body.portal-app (the My Patients surface); the
   other pages keep the top hero-band/appbar. Reuses the existing tokens —
   no new colors.
   ══════════════════════════════════════════════════════════════════════ */
body.portal-app { background: var(--card); }
.app-shell { display: grid; grid-template-columns: 240px minmax(0, 1fr); min-height: 100vh; }

/* — Left rail — */
.prail { background: var(--navy); color: #dbe6ff; padding: 20px 14px; display: flex;
  flex-direction: column; gap: 4px; position: sticky; top: 0; height: 100vh; }
.prail-brand { padding: 2px 8px 16px; border-bottom: 1px solid rgba(255,255,255,.12); margin-bottom: 10px; }
.prail-logo { display: inline-block; margin-bottom: 12px; }
/* Join-parity brand weight (owner 2026-08-10: "logos are too small") — the
   refer page's header logo renders at 72px; the rail carries it at 60px
   (the rail column is narrower than refer's white header band). */
/* Owner 2026-08-10: the rail logo + text were "hardly readable" — the
   stacked lockup needs real height for its wordmark to resolve. */
.prail-logo img { height: 78px; width: auto; max-width: 100%; }
.prail-eyebrow { font-size: var(--fs-xs); letter-spacing: .09em; text-transform: uppercase; color: #9fb4e6; }
.prail-org { font-weight: 700; font-size: var(--fs-body); color: #fff; margin-top: 2px; line-height: 1.3; }
.prail-who { font-size: var(--fs-sm); color: #9fb4e6; margin-top: 8px; line-height: 1.4; }
.prail-nav { display: flex; flex-direction: column; gap: 2px; margin-top: 2px; }
.prail-nav a { display: flex; align-items: center; gap: 10px; padding: 10px 11px;
  border-radius: var(--r-control); color: #c7d6f5; text-decoration: none; font-weight: 500; font-size: var(--fs-body); }
.prail-nav a:hover { background: rgba(255,255,255,.07); color: #fff; }
.prail-nav a.active { background: var(--orange); color: #241200; font-weight: 700; }
.prail-ic { width: 16px; text-align: center; opacity: .85; }
.prail-foot { margin-top: auto; padding-top: 14px; border-top: 1px solid rgba(255,255,255,.12);
  display: flex; flex-direction: column; gap: 10px; }
.prail-refer { display: inline-block; text-align: center; background: rgba(255,255,255,.10); color: #fff;
  text-decoration: none; font-weight: 600; font-size: var(--fs-body); padding: 9px 12px; border-radius: var(--r-control); }
.prail-refer:hover { background: rgba(255,255,255,.16); }
.prail-call { font-size: var(--fs-label); color: #9fb4e6; }
.prail-signout button { width: 100%; background: transparent; border: 1px solid rgba(255,255,255,.22);
  color: #c7d6f5; font: inherit; font-size:var(--btn-fs-md); font-weight: 600; padding:var(--btn-pad-md);min-height:var(--btn-h-md); border-radius:var(--r-control); cursor: pointer; }
.prail-signout button:hover { background: rgba(255,255,255,.08); color: #fff; }

/* — Main = list + detail — */
/* --pdetail-w is drag-set by the pane divider (owner 2026-07-23: expand the
   right block to view the full grid); the 384px default is unchanged. */
.pmain { display: grid; grid-template-columns: minmax(0, 1fr) var(--pdetail-w, 384px); min-height: 100vh; }
.list-col { padding: 30px 30px 24px; min-width: 0; }
body.portal-app .list-head .page-title { margin: 0 0 4px; }
body.portal-app .list-head .page-lede { margin: 0 0 6px; max-width: 64ch; }

/* Refer-page hero band (join-refer parity, 2026-08-10): the guided flow
   opens under the same 135° navy→blue banner the public wizard uses.
   The rail is solid navy, so this is the page's one gradient (DS rule). */
body.portal-app .list-head.refer-hero {
  background: linear-gradient(135deg, var(--crp-navy, #072061) 0%, var(--crp-blue, #1843AD) 100%);
  color: #fff;
  border-radius: var(--r-card, 16px);
  padding: 26px 28px 24px;
  margin-bottom: 18px;
  box-shadow: 0 4px 16px rgba(7, 32, 97, 0.10);
}
body.portal-app .list-head.refer-hero .page-title { color: #fff; }
body.portal-app .list-head.refer-hero .page-lede { color: rgba(255, 255, 255, 0.88); }
body.portal-app .list-head.refer-hero .page-lede a {
  color: #fff;
  text-decoration: underline;
}
.list-foot { margin-top: 34px; }

/* study filter alongside the name search */
.board-study-filter { font: inherit; font-size: var(--fs-input); padding: 8px 12px; border-radius: var(--r-control);
  border: 1px solid var(--border); background: var(--card); color: var(--ink); cursor: pointer; }

/* D4: source-bucket filter segments (Identified / Referred / In a study) */
.board-segs { display: inline-flex; flex-wrap: wrap; gap: 4px; background: var(--card);
  border: 1px solid var(--border); border-radius: 999px; padding: 4px; margin: 0 0 12px; }
/* RAIL_TABS=true keeps the segment bar permanently hidden; the `.board-segs`
   display:inline-flex above overrides the `hidden` attribute, leaving an empty
   rounded pill (the "stray bullet"). Respect hidden. */
.board-segs[hidden] { display: none; }
.board-segs .seg { border: 0; background: transparent; color: var(--ink-2); font: inherit;
  font-size: var(--fs-label); font-weight: 600; padding: 6px 14px; border-radius: 999px; cursor: pointer; white-space: nowrap; }
.board-segs .seg:hover { color: var(--ink); }
.board-segs .seg.on { background: var(--navy); color: #fff; }
.board-segs .seg-ct { opacity: .7; font-weight: 700; margin-left: 4px; font-variant-numeric: tabular-nums; }
.board-segs .seg.on .seg-ct { opacity: .9; }
/* ── Action rail (2026-08-06: "make them more prominent in the portal") ──
   The two movable cohorts as slim banners above the filter chips — amber for
   investigator-approved-awaiting-OK (the one thing that needs the eye), calm
   blue for records-matched re-review (same tone split the row dots use;
   no-persistent-alarm doctrine: amber, never red). */
.action-rail { display: grid; gap: 8px; margin: 0 0 16px; }
.ar-item { display: flex; align-items: center; gap: 14px; padding: 12px 16px;
  border: 1px solid var(--border); border-radius: 10px; background: var(--card); }
.ar-item.ar-needs { border-color: #f3d9b0; background: #fffaf1; border-left: 4px solid var(--warn); }
.ar-item.ar-review { border-color: #c7d5f2; background: #f6f9ff; border-left: 4px solid var(--blue); }
.ar-count { flex: none; min-width: 30px; height: 30px; border-radius: 999px; display: inline-flex;
  align-items: center; justify-content: center; color: #fff; font-weight: 800;
  font-size: var(--fs-sm); font-variant-numeric: tabular-nums; padding: 0 8px; }
.ar-needs .ar-count { background: var(--warn); }
.ar-review .ar-count { background: var(--blue); }
.ar-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ar-line { font-size: var(--fs-base); font-weight: 600; color: var(--ink); line-height: 1.5; }
.ar-studies { font-size: var(--fs-sm); color: var(--ink-2); font-weight: 600; }
.ar-btn { flex: none; border: 0; font: inherit; font-size:var(--btn-fs-md); font-weight: 700;
  padding:var(--btn-pad-md);min-height:var(--btn-h-md); border-radius: 999px; cursor: pointer; color: #fff; white-space: nowrap; }
.ar-needs .ar-btn { background: var(--warn); }
.ar-review .ar-btn { background: var(--blue); }
.ar-btn:hover { filter: brightness(1.08); }
.ar-btn:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; }
@media (max-width: 640px) {
  .ar-item { flex-wrap: wrap; }
  .ar-btn { margin-left: 44px; }
}

/* Status filter (2026-07-24 redesign): the "Needs action" count badge — calm
   amber, never alarm-red (no-persistent-alarm doctrine). */
.board-segs.board-status-filter { margin-bottom: 16px; }
.board-segs .seg-need { background: var(--warn); color: #fff; border-radius: 999px; font-size: var(--fs-xs); font-weight: 800;
  min-width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center; padding: 0 5px;
  margin-left: 5px; font-variant-numeric: tabular-nums; }
.board-segs .seg.on .seg-need { background: #fff; color: var(--warn); }

/* Patient names never wrap mid-name ("Constance / P." read as two lines on
   every row — 2026-07-22 owner UX). The sticky first column widens to fit;
   any width overflow scrolls inside .table-scroll per the A9 pattern. */
.board-list td.t-name { white-space: nowrap; }
/* clickable board rows + selected state */
.board-list tbody tr:not([data-group-header]) { cursor: pointer; }
.board-list tbody tr:not([data-group-header]):hover { background: var(--wash); }
.board-list tbody tr.pt-sel { background: var(--wash); box-shadow: inset 3px 0 0 var(--blue); }
/* The sticky Patient cell carries its own background (var(--card)) so content
   can slide beneath it — on hovered/selected rows it must take the row tint
   or the first cell reads as a white hole in the highlight (2026-07-22 QA). */
.board-list tbody tr:not([data-group-header]):hover td:first-child,
.board-list tbody tr.pt-sel td:first-child { background: var(--wash); }
/* D1 (2026-07-22): the "records not needed" marker where the upload button
   would be, for records-closed (DNQ / screen-fail / terminal) patients. */
.upl-closed { font-size: var(--fs-label); color: var(--ink-3); font-style: italic; white-space: nowrap; }

/* — Right detail pane — */
.pdetail { border-left: 1px solid var(--border); background: var(--card); padding: 28px 24px;
  min-width: 0; position: sticky; top: 0; align-self: start; max-height: 100vh; overflow-y: auto; }
.pdetail-empty { color: var(--ink-3); font-size: var(--fs-sm); text-align: center; margin-top: 76px; padding: 0 10px; }
.pdetail-empty-mark { font-size: 2.125rem; opacity: .3; margin-bottom: 12px; }
.d-eyebrow { font-size: var(--fs-xs); letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3); font-weight: 700; }
.d-name { font-size: var(--fs-h2); font-weight: 800; letter-spacing: -.01em; margin: 4px 0 2px; color: var(--ink); }
.d-meta { color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.5; }
.d-pill-row { margin-top: 12px; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.d-sec { margin-top: 22px; }
.d-sec h4 { font-size: var(--fs-xs); letter-spacing: .05em; text-transform: uppercase; color: var(--ink-3); margin: 0 0 10px; }
.d-kv { list-style: none; margin: 0; padding: 0; font-size: var(--fs-sm); }
.d-kv li { display: flex; justify-content: space-between; gap: 12px; padding: 8px 0; border-top: 1px solid var(--border-soft); }
.d-kv li:first-child { border-top: 0; }
.d-kv .k { color: var(--ink-3); }
.d-kv .v { font-weight: 600; text-align: right; color: var(--ink); }
.d-kv .v.stop { color: var(--err); }
.d-kv .v.good { color: var(--ok); }
/* The "why" note (screen-fail reason / tracker note) — visually separated
   from the status list above it, quote-style (2026-07-22 owner UX pass). */
/* ── The SHARED eligibility record (2026-08-03) ─────────────────────────
   Dr. Leventhal: "there should also be a box stating clearly why they are not
   eligible. Both recruiting team and I should add to that box."
   Append-only entries, oldest first, each with a byline. DS tokens only; no
   alarm colours — a decline is a finding, not an alarm. */
.d-elig-notes .d-notelist { list-style: none; margin: 4px 0 0; padding: 0; }
.d-noteitem { padding: 10px 0; border-top: 1px solid var(--border-soft); }
.d-noteitem:first-child { border-top: 0; padding-top: 2px; }
.d-noteby { font-size: var(--fs-label); color: var(--ink-3); text-transform: none; }
.d-noteauthor { color: var(--ink-3); }
.d-notebody { font-size: var(--fs-sm); color: var(--ink); margin-top: 3px; white-space: pre-wrap;
  overflow-wrap: anywhere; }
.d-noteadd { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.d-noteinput { width: 100%; box-sizing: border-box; font: inherit; font-size: var(--fs-sm);
  color: var(--ink); padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface); resize: vertical; }
.d-noteinput:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
.d-noteadd .btn { align-self: flex-start; }

.d-actions { display: flex; flex-direction: column; gap: 8px; }
.d-actions .btn-quiet { text-align: center; }
.d-result-link { display: inline-flex; align-items: center; gap: 8px; font-weight: 700; color: var(--blue);
  text-decoration: none; font-size: var(--fs-sm); }
/* Owner UX 2026-07-22: matches show met criteria; results download in-pane. */
.d-match { padding: 10px 0; border-top: 1px solid var(--border-soft); }
.d-match:first-of-type { border-top: 0; padding-top: 2px; }
.d-match-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.d-match-name { font-weight: 700; font-size: var(--fs-sm); color: var(--ink); }
.d-match-ind { font-size: var(--fs-label); color: var(--ink-3); margin-top: 1px; }
.d-match-crit { font-size: var(--fs-label); color: var(--ink-2); margin-top: 4px; line-height: 1.4; }
/* (.d-result-row / -meta / -title / -date REMOVED 2026-08-01, owner: "we dont
   need another button for medical records in the bottom when we have it up
   top." The pane's per-document Download list duplicated the header's
   "Download records (N)"; the header affordance is the one that stays, so
   these rules had no renderer left. .d-result-link above SURVIVES — it styles
   the honest degrade shown when the results list did not load at all. */
.d-note { font-size: var(--fs-label); color: var(--ink-3); margin-top: 8px; line-height: 1.45; }
.d-note.err { color: var(--err); }
.d-note.ok { color: var(--ok); }
/* A1 (empathy review 2026-07-28): "What to tell your patient" card — a quiet
   cyan-wash panel so the visit commitment + compensation read as a talk-track,
   set apart from the CRP-status list. B4: the Actions section sits near the top. */
.d-tell { background: var(--wash); border: 1px solid var(--border-soft); border-radius: 10px; padding: 12px 14px; }
.d-tell h4 { margin-top: 0; }
.d-tell .d-kv .v { text-align: right; }

/* responsive */
@media (max-width: 1120px) { .pmain { grid-template-columns: minmax(0, 1fr) var(--pdetail-w, 320px); } }
@media (max-width: 900px) {
  .app-shell { grid-template-columns: 1fr; }
  /* Owner 2026-08-01: "The mobile version is not usable — can't read it. Very
     confusing." Two root causes, both fixed here.
     (1) GRID MIN-CONTENT TRAP: grid items default to min-width:auto, so the
     patients table's intrinsic width (~1200px) propagated up through
     .list-col → .pmain → .app-shell and stretched the WHOLE PAGE into
     horizontal scroll — .table-scroll's own overflow-x never got to act.
     min-width:0 at every grid level lets the scroll container do its job. */
  .prail, .pmain, .pmain > *, .list-col, .pdetail { min-width: 0; }
  /* (2) NAV JUMBLE: flex-wrap on .prail-nav stacked 7 links + brand + foot
     into a full-first-screen two-column navy jumble. The rail is now a
     compact header — condensed brand line, then ONE horizontal swipeable
     chip strip (44px touch targets, never wrapped), so patients — not
     navigation — are the first screen. */
  .prail { position: static; height: auto; flex-direction: row; flex-wrap: wrap; align-items: center; padding: 10px 12px 6px; gap: 4px; }
  .prail-brand { border: 0; margin: 0; padding: 0; flex: 1 1 100%; }
  .prail-logo { display: none; }
  /* The 32px desktop H1 eats a phone line — step down to the H2 token. */
  .page-title { font-size: var(--fs-h2); }
  .prail-eyebrow { display: none; }
  .prail-org { font-size: var(--fs-label); }
  .prail-who { font-size: var(--fs-xs); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; margin-top: 2px; }
  .prail-nav { flex-direction: row; flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; justify-content: flex-start; gap: 6px; flex: 1 1 100%; margin: 4px -12px 0; padding: 0 12px 4px; }
  .prail-nav::-webkit-scrollbar { display: none; }
  /* Scroll hint (UX polish 2026-08-10): with the scrollbar hidden, a
     half-clipped item was the ONLY sign the row scrolls. prail-nav.js tags
     an actually-overflowing row `is-scrollable`; the edge fade signals the
     off-screen items. Cosmetic — an unfaded row still scrolls fine. */
  .prail-nav.is-scrollable {
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 14px, #000 calc(100% - 26px), transparent 100%);
    mask-image: linear-gradient(90deg, transparent 0, #000 14px, #000 calc(100% - 26px), transparent 100%);
  }
  .prail-nav a { flex: 0 0 auto; white-space: nowrap; min-height: 44px; display: inline-flex; align-items: center; padding: 10px 12px; }
  .prail-foot { margin: 0; padding: 0; border: 0; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 6px 10px; flex: 1 1 100%; }
  /* C2 (empathy review 2026-07-28): "Refer a patient" + the CRP phone number
     must stay reachable on mobile — they used to disappear at 900px, so a
     phone user lost the fastest path to refer AND the number to call. Keep
     them visible + tappable in the wrapped foot row. */
  .prail-refer { display: inline-block; padding: 8px 12px; }
  .prail-call { display: inline; font-size: var(--fs-label); }
  .prail-signout { margin-left: auto; }
  .prail-signout button { width: auto; padding:var(--btn-pad-md); font-size:var(--btn-fs-md); min-height:var(--btn-h-md); }
  .pmain { grid-template-columns: 1fr; }
  .list-col { padding: 18px 14px; }
  .pdetail { position: static; max-height: none; border-left: 0; border-top: 1px solid var(--border); }
}


/* ══ UI/UX audit batch (2026-07-22 late) ═══════════════════════════════ */
/* #1 (HIGH): the DS focus ring is 1.76:1 on the navy rail and outline is
   suppressed — keyboard users had NO visible focus on the primary nav.
   White outline, DS blue ring off (the A3/A15 appbar pattern, rail-scoped). */
.prail a:focus-visible, .prail button:focus-visible {
  outline: 2px solid #fff; outline-offset: 2px; box-shadow: none;
}
/* #6: small-text contrast — solid colors, no opacity tricks. */
.board-segs .seg-ct { opacity: 1; color: var(--ink-2); }
.board-segs .seg.on .seg-ct { opacity: 1; color: #dbe6ff; }
.upl-closed { color: var(--ink-2); }
/* #10: long unbroken result titles wrap inside their cell. */
.report-table td.rtitle { overflow-wrap: anywhere; }
/* #11: the study filter can never clip out of the panel. */
.board-study-filter { max-width: 100%; min-width: 0; }
/* #13: the selected-row accent paints on the sticky cell (the tr's inset
   shadow was hidden beneath the cell's own background), and selection reads
   darker than hover. */
.board-list tbody tr.pt-sel td:first-child { box-shadow: inset 3px 0 0 var(--blue); }
.board-list tbody tr.pt-sel,
.board-list tbody tr.pt-sel td:first-child { background: #dde6fb; }
/* #12: the Identified decision buttons wrap INSIDE the shell's narrower list
   column well before the old 640px phone breakpoint. */
@media (max-width: 1150px) {
  body.portal-app #identified-table td.ident-action { white-space: normal; }
  body.portal-app .ident-controls { display: flex; flex-wrap: wrap; }
}


/* ── Rail shell on ALL authed pages (owner 2026-07-23: "the navigation pane
   goes away" when leaving My patients). Non-board pages use the single-column
   main; their legacy main.page spacing is neutralized inside the shell. ── */
.pmain-single { grid-template-columns: 1fr; }
body.portal-app .list-col main.page { max-width: none; padding: 0; margin: 0; }
/* Join-parity measure (owner 2026-08-10 side-by-side vs /refer): the refer
   page centers a focused 720px column; the single-column portal pages let
   cards sprawl to ~1140px, which read as the biggest remaining divergence.
   880px is the refer measure scaled for the portal's larger type + the
   two-column criteria grid. Board/detail (two-column .pmain) is untouched. */
/* 2026-08-19, owner: raised 880 → 1200. The 880 measure above was set for
   parity with the public /refer page, but /refer is a marketing page read
   once and Studies & eligibility is a reference a physician works from. Side
   by side with My patients (1296px content) it read as narrow, with ~460px of
   dead space to its right on a 1920 screen. 1200 keeps a focused, centred
   column while sitting close enough to the board that moving between the two
   no longer feels like changing products. */
.pmain-single .list-col { max-width: 1200px; margin-inline: auto; width: 100%; }


/* ── Specialty eligibility grid in the detail pane (owner 2026-07-23) ── */
.d-grid-scroll { overflow-x: auto; margin-top: 4px; }
.d-grid { border-collapse: collapse; font-size: var(--fs-label); min-width: 100%; }
.d-grid th, .d-grid td { border: 1px solid var(--border-soft); padding: 6px 8px; text-align: center; vertical-align: middle; }
.d-grid th { background: var(--paper); font-weight: 700; }
.d-grid-study { min-width: 96px; }
.d-grid-study-name { font-size: var(--fs-label); line-height: 1.25; margin-bottom: 4px; }
/* min-width keeps criterion text readable — the .d-grid-scroll wrapper
   handles the overflow; without it the study columns crush this column
   into one-word-per-line stacks (2026-07-23 preview). */
.d-grid-crit { text-align: left; font-size: var(--fs-label); color: var(--ink-2); min-width: 150px; max-width: 190px; }
.d-grid-type { display: inline-block; font-size: var(--fs-eyebrow); font-weight: 800; color: var(--ink-3);
  border: 1px solid var(--border); border-radius: 4px; padding: 0 4px; margin-right: 2px; }
.d-grid-cell.ok { color: var(--ok); font-weight: 700; background: var(--ok-bg); }
.d-grid-cell.bad { color: var(--err); font-weight: 700; background: var(--err-bg); }
.d-grid-cell.warn { color: var(--warn); font-weight: 600; background: var(--warn-bg); font-size: var(--fs-xs); text-align: left; }
.d-grid-meds td { border-top: 2px solid var(--border); }

/* ── Rail tab count badges (2026-07-23 rail-tabs IA) ── */
.prail-ct {
  display: inline-block;
  min-width: 18px;
  padding: 0 5px;
  margin-left: 4px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.16);
  font-size: var(--fs-xs);
  line-height: 17px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.prail-nav a.active .prail-ct { background: rgba(255, 255, 255, 0.28); }

/* ── Refer-CTA landing highlight (/studies#refer) ── */
@keyframes refer-here-pulse {
  0% { box-shadow: 0 0 0 0 rgba(24, 67, 173, 0.45); }
  100% { box-shadow: 0 0 0 10px rgba(24, 67, 173, 0); }
}
.panel.refer-here { animation: refer-here-pulse 0.9s ease-out 2; }
.panel.refer-here,
.panel.refer-here-static { outline: 2px solid var(--crp-blue, #1843AD); outline-offset: 2px; }
.d-grid-cell.na { color: var(--ink-3); font-size: var(--fs-eyebrow); letter-spacing: 0.02em; }


/* ── Pane divider (drag to widen the detail pane, 2026-07-23) ── */
.pmain { position: relative; }
.pdetail-divider {
  position: absolute;
  right: calc(var(--pdetail-w, 384px) - 5px);
  top: 0; bottom: 0;
  width: 10px;
  cursor: col-resize;
  z-index: 5;
  touch-action: none;
}
.pdetail-divider::after {
  content: '';
  position: absolute;
  left: 4px; top: 0; bottom: 0;
  width: 2px;
  background: transparent;
  transition: background .15s;
}
.pdetail-divider:hover::after,
.pdetail-divider.dragging::after { background: var(--crp-blue, #1843AD); }
@media (max-width: 900px) { .pdetail-divider { display: none; } }

/* Staff-only CRIO deep link in the pane */
.d-crio-link { font-size: var(--fs-label); font-weight: 600; }

/* ── STAFF-ONLY contact strip, directly under the patient name ──────────
   2026-08-02, owner annotation #9: "Need to list their phone number below so
   easy to contact and their CRIO profile". The phone and the CRIO link used to
   sit far apart and far down the pane; ONE row now carries both, where the
   reader is already looking. Neutral, no alarm colour; tap-to-call.
   STAFF ONLY — an external provider never reaches this element (see
   renderStaffIdentStrip); the board doc has no phone field at all. */
.d-ident-strip {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin: 2px 0 6px;
}
.d-ident-phone { display: inline-flex; align-items: center; }
.d-phone-link { font-size: var(--fs-sm); font-weight: 700; color: var(--crp-blue, #1843AD); text-decoration: none; }
.d-phone-link:hover { text-decoration: underline; }
/* Honest about ABSENCE — a missing phone/CRIO record is a DATA gap, and
   saying so beats a silently empty strip that reads as a broken UI. */
.d-ident-none { font-size: var(--fs-label); color: var(--ink-3, #94a3b8); font-style: italic; }

/* Per-study eligibility detail (grid dropdown) */
.d-grid-picker { width: 100%; margin: 4px 0 8px; padding: 7px 10px; font-size: var(--fs-input);
  border: 1px solid var(--border); border-radius: 8px; background: var(--card); color: var(--ink); }
.d-sdetail-head { font-size: var(--fs-xs); font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
  color: var(--ink-3); margin: 12px 0 4px; }
.d-sdetail-line { font-size: var(--fs-label); line-height: 1.45; padding: 3px 0; color: var(--ink-2); }
.d-sdetail-line.ok { color: var(--ok); }
.d-sdetail-line.bad { color: var(--err); }

/* ── Eligibility checker: condition-specific medication chips (2026-07-23) ── */
.elig-med-hint { font-weight: 400; color: var(--ink-3); font-size: var(--fs-label); }
.elig-med-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 10px; }
.elig-med-chip {
  padding: 7px 13px;
  border: 1.5px solid var(--border);
  border-radius: 999px;
  background: var(--card);
  cursor: pointer;
  font-size: var(--fs-label);
  font-weight: 600;
  color: var(--ink);
  font-family: inherit;
  transition: background .15s, border-color .15s, color .15s;
}
.elig-med-chip:hover { border-color: var(--crp-blue, #1843AD); color: var(--crp-blue, #1843AD); }
.elig-med-chip.on { background: var(--crp-blue, #1843AD); border-color: var(--crp-blue, #1843AD); color: #fff; }
.elig-med-chip:focus-visible { outline: 2px solid var(--crp-blue, #1843AD); outline-offset: 2px; }
.d-sdetail-line.warn { color: var(--warn); }

/* ══ 30-second board (owner 2026-07-23) ══════════════════════════════════ */

/* "Needs you" strip — the first thing the provider sees. */
.needs-you { margin: 0 0 12px; }
.ny-card {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card);
  overflow: hidden;
}
/* All-clear state — calm, green, reassuring. */
.ny-card.ny-clear {
  display: flex; align-items: center; gap: 12px;
  padding: 16px 18px;
  border-color: var(--ok-border, #b7e4c7);
  background: var(--ok-bg, #f0fdf4);
}
.ny-clear-mark {
  flex: none; width: 26px; height: 26px; border-radius: 999px;
  background: var(--ok, #16a34a); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 16px; font-weight: 700;
}
.ny-clear-title { font-weight: 700; color: var(--ink); font-size: var(--fs-body); }
.ny-clear-sub { color: var(--ink-2); font-size: var(--fs-sm); margin-top: 1px; }
/* Action state — a header + tappable rows. */
.ny-head {
  padding: 9px 16px; font-size: var(--fs-sm); font-weight: 800;
  letter-spacing: .02em; text-transform: uppercase;
  color: var(--crp-navy, #072061);
  background: var(--paper, #f6f9ff);
  border-bottom: 1px solid var(--border);
}
.ny-list { display: flex; flex-direction: column; }
.ny-item {
  display: flex; align-items: center; gap: 12px;
  width: 100%; text-align: left; cursor: pointer;
  padding: 9px 16px; border: 0; border-bottom: 1px solid var(--border-soft, #eef2f8);
  background: transparent; font-family: inherit; color: inherit;
  transition: background .12s;
}
.ny-item:last-child { border-bottom: 0; }
.ny-item:hover { background: var(--paper, #f6f9ff); }
.ny-item:focus-visible { outline: 2px solid var(--crp-blue, #1843AD); outline-offset: -2px; }
.ny-dot { flex: none; width: 10px; height: 10px; border-radius: 999px; }
.ny-dot-result { background: var(--ok, #16a34a); }
.ny-dot-confirm { background: var(--crp-orange, #FF9933); }
.ny-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.ny-name { font-weight: 700; color: var(--ink); font-size: var(--fs-body); }
.ny-line { color: var(--ink-2); font-size: var(--fs-sm); margin-top: 1px; }
.ny-cta { flex: none; font-weight: 700; font-size: var(--fs-sm); color: var(--crp-blue, #1843AD); }

/* Plain-sentence status + at-a-glance dot (replaces the pill + sub-line). */
.t-status2 { white-space: normal; }
.t-dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 999px;
  margin-right: 8px; vertical-align: middle; flex: none;
}
.t-dot-ok { background: var(--ok, #16a34a); }
.t-dot-act { background: var(--crp-orange, #FF9933); }
.t-dot-progress { background: var(--crp-blue, #1843AD); }
.t-dot-muted { background: var(--ink-3, #94a3b8); }
.t-plain { color: var(--ink); font-size: var(--fs-sm); vertical-align: middle; }
tr[data-closed] .t-plain { color: var(--ink-2); }

/* ── Row flow tracker (owner 2026-08-11: "make the flow more prominent") ──
   6 segments mirroring the pane's workflow steps: done = blue, current =
   orange (the single accent marking "you are here"), stopped = muted,
   pending = border. The label names the current step so the reader never
   has to decode segments. */
.t-flow-row { margin-bottom: 4px; }
.t-flow { display: inline-flex; gap: 3px; vertical-align: middle; }
.t-flow-seg {
  width: 18px; height: 6px; border-radius: 3px;
  background: var(--border, #c8d6e8);
}
.t-flow-done { background: var(--crp-blue, #1843AD); }
.t-flow-current { background: var(--crp-orange, #FF9933); }
.t-flow-stopped { background: var(--ink-3, #94a3b8); }
.t-flow-label {
  margin-left: 8px; vertical-align: middle;
  font-size: var(--fs-label); font-weight: 600; color: var(--navy);
  white-space: nowrap; /* the step name + position stay one phrase */
}
tr[data-closed] .t-flow-label { color: var(--ink-2); font-weight: 500; }
@media (max-width: 640px) {
  .t-flow-seg { width: 12px; }
}

/* Review lane (owner 2026-07-24) — mislabeled leads the provider's own note
   flags as a candidate. Calm BLUE treatment, distinct from the orange "needs
   you": an opportunity to review, not an alarm. Design-system cool palette. */
.review-lane .ny-card { border-color: var(--crp-blue, #1843AD); }
.review-lane .ny-head {
  color: var(--crp-blue, #1843AD);
  background: var(--crp-cyan-tint, #eef6fb);
}
.ny-dot-review, .t-dot-review { background: var(--crp-blue, #1843AD); }
.ny-note {
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical;
  overflow: hidden; color: var(--ink-2); font-style: italic;
}
/* (The standalone "Flagged for review" callout + the `d-why` note line were
   REMOVED 2026-08-02 — owner annotations #4/#5, "should be part of funnel".
   Both are now annotations on the funnel step they describe; their styling
   lives in .d-funnel-note above. Their rules are deleted rather than left
   orphaned, so nothing can re-render the old stacked cards by accident.) */

/* ── PI-review pane enrichment (2026-07-30) ──────────────────────────────── */
/* Item 1 — records + EMR at the top, next to the name. */
.d-head-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 10px 0 2px; }
.d-head-btn {
  font-family: inherit; font-size:var(--btn-fs-sm); font-weight: 600; cursor: pointer;
  padding:var(--btn-pad-sm);min-height:var(--btn-h-sm); border-radius:var(--r-control); color: #fff;
  background: var(--crp-blue, #1843AD); border: 1px solid var(--crp-blue, #1843AD);
}
.d-head-btn:hover { background: var(--crp-navy, #072061); border-color: var(--crp-navy, #072061); }
.d-head-btn:disabled { opacity: .55; cursor: default; }
.d-head-link { font-size: var(--fs-label); font-weight: 600; color: var(--crp-blue, #1843AD); text-decoration: none; }
.d-head-link:hover { text-decoration: underline; }

/* Item 2 — CRP-status highlight. */
.d-status-hl {
  margin: 12px 0 2px; padding: 12px 14px; border-radius: 10px;
  background: var(--paper, #f6f9ff); border: 1px solid var(--border, #c8d6e8);
}
.d-status-hl-main { font-size: var(--fs-body); font-weight: 700; color: var(--ink, #0b1b3a); line-height: 1.35; }
.d-status-hl-sub { font-size: var(--fs-label); color: var(--ink-2); margin-top: 3px; line-height: 1.4; }
/* 2026-08-01 pre-screen DNQ reframe — the chip's "re-review is live" sub-line. */
.d-rereview-sub { margin: 4px 0 0; }

/* ── THE FUNNEL (2026-08-02, owner annotations #1/#4/#5) ─────────────────
   "We need to show progress bar here - what was compelted what is pending".
   A VERTICAL ladder, not a horizontal bar: eight labelled steps read at 390px
   without truncation, and each step can carry its own annotation (#4/#5).
   DS tokens only, no emoji, no alarm colours — a progress ladder is neutral
   information, never a warning (no-persistent-alarm doctrine). */
.d-funnel {
  margin: 12px 0 2px; padding: 12px 14px; border-radius: 10px;
  background: var(--paper, #f6f9ff); border: 1px solid var(--border, #c8d6e8);
}
.d-funnel-steps { list-style: none; margin: 10px 0 0; padding: 0; }
.d-funnel-step {
  position: relative; display: grid;
  grid-template-columns: 14px minmax(0, 1fr) auto;
  align-items: center; gap: 8px; padding: 3px 0; min-height: 22px;
}
/* The connecting rail, drawn between dots rather than as a separate element. */
.d-funnel-step + .d-funnel-step::before {
  content: ""; position: absolute; left: 6px; top: -6px; width: 2px; height: 12px;
  background: var(--border, #c8d6e8);
}
.d-funnel-dot {
  width: 10px; height: 10px; border-radius: 999px; justify-self: center;
  border: 2px solid var(--border, #c8d6e8); background: #fff; box-sizing: border-box;
}
.d-funnel-step.is-done .d-funnel-dot { background: var(--crp-blue, #1843AD); border-color: var(--crp-blue, #1843AD); }
.d-funnel-step.is-current .d-funnel-dot {
  border-color: var(--crp-navy, #072061); background: #fff;
  box-shadow: 0 0 0 3px rgba(7, 32, 97, 0.10);
}
.d-funnel-label { font-size: var(--fs-label); color: var(--ink-2); line-height: 1.35; }
.d-funnel-step.is-done .d-funnel-label { color: var(--ink-2); }
.d-funnel-step.is-current .d-funnel-label { color: var(--ink, #0b1b3a); font-weight: 700; }
.d-funnel-step.is-todo .d-funnel-label { color: var(--ink-3); }
.d-funnel-state {
  font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: .03em;
  text-transform: uppercase; color: var(--ink-3); white-space: nowrap;
}
.d-funnel-step.is-current .d-funnel-state { color: var(--crp-navy, #072061); }
/* #4/#5 — an annotation belongs to its STEP, indented under it. */
.d-funnel-note {
  grid-column: 2 / -1; margin: 4px 0 6px; padding: 8px 10px; border-radius: 8px;
  background: #fff; border: 1px solid var(--border, #c8d6e8);
}
.d-funnel-note-title {
  display: block; font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 2px;
}
.d-funnel-note-body { font-size: var(--fs-label); color: var(--ink-2); line-height: 1.45; }
.d-funnel-note-review { border-color: var(--crp-cyan, #A2DCEB); }
/* ── 2026-08-04 ONE-VIEW WORKFLOW additions ──
   Per-step attribution ("Dr. Leventhal · Aug 1, 2026"), the step's own
   comment line, Practice-review sub-bullets, and the inline per-step action
   slot (annotation 8). All neutral DS tokens — a workflow is information. */
.d-funnel-att {
  grid-column: 2 / -1; font-size: var(--fs-eyebrow); color: var(--ink-3);
  letter-spacing: .02em; margin-top: 1px;
}
.d-funnel-comment {
  grid-column: 2 / -1; font-size: var(--fs-label); color: var(--ink-2);
  line-height: 1.4; margin-top: 1px; word-break: break-word;
}
.d-funnel-subs { grid-column: 2 / -1; list-style: none; margin: 3px 0 2px; padding: 0 0 0 2px; }
.d-funnel-sub {
  font-size: var(--fs-label); color: var(--ink-3); line-height: 1.5;
  padding-left: 12px; position: relative;
}
.d-funnel-sub::before {
  content: ""; position: absolute; left: 0; top: .58em; width: 5px; height: 5px;
  border-radius: 999px; background: var(--border, #c8d6e8);
}
.d-funnel-sub.is-done { color: var(--ink-2); }
.d-funnel-sub.is-done::before { background: var(--crp-blue, #1843AD); }
.d-funnel-actions { grid-column: 2 / -1; margin: 5px 0 4px; }
.d-step-btns { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.d-step-btns button[disabled] { opacity: .55; cursor: not-allowed; }
.d-step-owner { font-size: var(--fs-eyebrow); color: var(--ink-3); letter-spacing: .02em; }
.d-funnel-step.is-stopped .d-funnel-dot { background: var(--ink-3); border-color: var(--ink-3); }
.d-funnel-step.is-stopped .d-funnel-label { color: var(--ink-2); }
/* The DNQ "why" line under the pill row (annotation 6). */
.d-dnq-reason { font-size: var(--fs-label); color: var(--ink-2); margin: 4px 0 0; line-height: 1.45; }

/* The criteria ACCORDION (annotation 10) — collapsed compact study header
   rows; ONE study expands at a time. */
.d-study-acc { border: 1px solid var(--border, #c8d6e8); border-radius: 8px; margin-top: 8px; background: #fff; }
.d-study-acc-head {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  width: 100%; text-align: left; padding: 9px 12px; border: 0; background: transparent;
  cursor: pointer; border-radius: 8px; font: inherit;
}
.d-study-acc-head:hover { background: var(--paper, #f6f9ff); }
.d-study-acc-head[aria-expanded="true"] { border-bottom: 1px solid var(--border, #c8d6e8); border-radius: 8px 8px 0 0; }
.d-study-acc-caret {
  margin-left: auto; font-size: var(--fs-eyebrow); font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--crp-blue, #1843AD);
}
.d-study-acc-body { padding: 10px 12px; }
.d-study-acc-body .pc-panel { border: 0; margin: 0; }
.d-other-studies { margin-top: 12px; }
.d-other-studies-sum {
  cursor: pointer; font-size: var(--fs-label); font-weight: 700; color: var(--ink-2);
  padding: 6px 2px;
}

@media (max-width: 420px) {
  .d-funnel { padding: 10px 11px; }
  /* The label wraps (minmax(0,1fr)); the state marker stays — it is the
     NON-COLOUR signal of what is done vs pending, so it must survive at
     mobile width, which is where this pane is read today. */
  .d-funnel-step { align-items: start; }
  .d-funnel-dot { margin-top: 4px; }
}

/* (The "Why they may qualify" paragraph styles are DELETED — owner
   annotation 9, 2026-08-04: the block is gone from the product, and dead CSS
   invites it back.) */

/* Clinical summary (2026-08-01, owner directive H) — the chart-shaped lines
   above the eligibility criteria: demographics + primary diagnosis, key lab
   positives, current medications. Lead line carries the weight; the rest read
   as supporting detail. Neutral/navy only — these are facts, not statuses. */
.d-clin-line {
  font-size: var(--fs-sm); color: var(--ink-2); line-height: 1.5;
  margin-top: 4px; word-break: break-word;
}
.d-clin-line.d-clin-lead {
  font-weight: 600; color: var(--ink); font-size: var(--fs-base, var(--fs-sm)); margin-top: 6px;
}
/* ── ORGANIZED clinical summary (2026-08-02, owner annotation #6) ────────
   "Clinical summary should include the medical conditions medication and labs
   - orgamized - this applies across the board". Three labelled groups under
   the chart lead line; labs reuse the existing .d-labs table so they read as
   test / value + unit / date instead of the run-on string that was annotated. */
.d-clin-group { margin-top: 10px; }
.d-clin-group-title {
  font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: 4px;
}
.d-clin-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.d-clin-chip {
  display: inline-flex; align-items: center; padding: 3px 10px;
  border: 1px solid var(--border, #c8d6e8); border-radius: 999px;
  font-size: var(--fs-label); color: var(--ink-2); background: var(--paper, #f6f9ff);
}
.d-clin-group .d-meds { margin-top: 0; }
.d-clin-group .d-note { margin-top: 6px; }

/* "+N more … not shown" — the disclosure for a capped clinical list
   (2026-08-03). It must read as a WARNING that the list is incomplete, not as
   a soft footnote like .d-note, because an investigator who mistakes a
   truncated medication list for a complete one can approve a patient whose
   prohibited drug was cut off the bottom. Warning tone, never an alarm colour
   (owner: no persistent alarm warnings) — it is a statement of fact about the
   list, not an incident. */
.d-omitted-note {
  margin-top: 6px;
  font-size: var(--fs-label);
  font-weight: 600;
  color: var(--warn, #b45309);
  background: var(--warn-bg, #fff8f0);
  border: 1px solid var(--border, #c8d6e8);
  border-radius: 6px;
  padding: 6px 10px;
  line-height: 1.45;
}

/* Medications — from the practice's own records (2026-08-01). */
.d-meds { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.d-med-chip {
  display: inline-flex; align-items: center; padding: 3px 10px;
  border: 1px solid var(--border, #c8d6e8); border-radius: 999px;
  font-size: var(--fs-label); color: var(--ink-2); background: var(--paper, #f6f9ff);
}

/* Item 3 — the CRIO journey ("What's happened"). */
.d-journey { display: flex; flex-direction: column; }
.d-journey-row {
  display: flex; gap: 10px; align-items: baseline; padding: 6px 0;
  border-top: 1px solid var(--border-soft, #eef2f8); font-size: var(--fs-label);
}
.d-journey-row:first-child { border-top: 0; }
.d-journey-date { flex: 0 0 88px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.d-journey-what { color: var(--ink); line-height: 1.4; }
.d-journey-study { display: inline-block; margin-left: 8px; color: var(--crp-blue, #1843AD); font-weight: 600; }
.d-journey-by { display: inline-block; margin-left: 8px; color: var(--ink-3); font-style: italic; }
.d-journey-appt_noshow .d-journey-what, .d-journey-appt_cancelled .d-journey-what { color: var(--err, #b42318); }
.d-journey-appt_scheduled .d-journey-what { color: var(--ok, #067647); }

/* Item 4 — prohibited-medication status line. */
.d-pmed-status { font-size: var(--fs-label); line-height: 1.45; margin: 2px 0 6px; }
.d-pmed-status.warn { color: var(--warn, #b54708); font-weight: 600; }
.d-pmed-status.ok { color: var(--ink-2); }

/* Item 5 — labs & vitals. */
.d-labs { display: flex; flex-direction: column; }
.d-lab-row {
  display: flex; gap: 10px; align-items: baseline; padding: 5px 0;
  border-top: 1px solid var(--border-soft, #eef2f8); font-size: var(--fs-label);
}
.d-lab-row:first-child { border-top: 0; }
.d-lab-name { flex: 1 1 auto; color: var(--ink-2); }
.d-lab-val { font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.d-lab-date { flex: 0 0 88px; text-align: right; color: var(--ink-3); font-variant-numeric: tabular-nums; }

/* Item 7 — each matched study in its own clearly-bounded card. */
.d-study-card {
  border: 1px solid var(--border, #c8d6e8); border-radius: 10px;
  padding: 12px 14px; margin-top: 12px; background: var(--surface, #fff);
}
.d-study-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin-bottom: 6px; }
.d-study-card .d-study-name { margin: 0; }
.d-study-phase {
  font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: .03em; text-transform: uppercase;
  color: var(--ink-3); border: 1px solid var(--border, #c8d6e8); border-radius: 999px; padding: 1px 8px;
}
/* The protocol chip (2026-08-02, "Where are the sudies?") — a study card must
   identify a STUDY, so the protocol rides beside a condition-shaped label. */
.d-study-proto {
  font-size: var(--fs-eyebrow); font-weight: 600; letter-spacing: .02em;
  color: var(--ink-3); background: var(--surface-2, #f3f7fc);
  border: 1px solid var(--border, #c8d6e8); border-radius: 6px; padding: 1px 7px;
}
.d-study-detail .d-study-head { margin-bottom: 4px; }
.d-study-nct { font-size: var(--fs-xs); font-weight: 600; color: var(--crp-blue, #1843AD); text-decoration: none; }
.d-study-nct:hover { text-decoration: underline; }

/* Item 8 — close-date badges. */
.d-close-badge {
  font-size: var(--fs-eyebrow); font-weight: 800; letter-spacing: .02em; text-transform: uppercase;
  color: var(--crp-navy, #072061); background: var(--crp-orange, #FF9933);
  border-radius: 999px; padding: 2px 9px;
}
.d-close-soft { font-size: var(--fs-eyebrow); font-weight: 600; color: var(--ink-3); }

/* Item 6 — protocol arms + open/closed. */
.d-arms { display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 8px; }
.d-arm {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-xs); font-weight: 600; border-radius: 999px; padding: 2px 10px;
  border: 1px solid var(--border, #c8d6e8); color: var(--ink-2);
}
.d-arm-dot { width: 7px; height: 7px; border-radius: 999px; background: var(--ink-3); }
.d-arm-open { color: var(--ok, #067647); border-color: var(--ok, #067647); }
.d-arm-open .d-arm-dot { background: var(--ok, #067647); }
.d-arm-closed { color: var(--ink-3); }

/* Closed-fold control — the single quiet line that hides the noise. */
.closed-fold-cell { padding: 0 !important; background: transparent !important; border: 0 !important; }
.closed-fold-btn {
  width: 100%; text-align: left; cursor: pointer;
  padding:var(--btn-pad-md);min-height:var(--btn-h-md); border: 0; border-top: 1px solid var(--border-soft, #eef2f8);
  background: transparent; font-family: inherit;
  font-size:var(--btn-fs-md); font-weight: 600; color: var(--ink-2);
  transition: background .12s, color .12s;
}
.closed-fold-btn:hover { background: var(--paper, #f6f9ff); color: var(--crp-blue, #1843AD); }
.closed-fold-btn:focus-visible { outline: 2px solid var(--crp-blue, #1843AD); outline-offset: -2px; }
tr[data-closed] { background: var(--paper-2, #fbfcfe); }

/* ── Notification preferences (opt-out) — punch-list §2.3 ─────────────── */
.notif-list { display: flex; flex-direction: column; gap: 4px; }
.notif-item {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 14px 4px; border-bottom: 1px solid var(--border-soft, #eef2f8);
  cursor: pointer;
}
.notif-item:last-child { border-bottom: 0; }
.notif-item input[type="checkbox"] { margin-top: 3px; width: 18px; height: 18px; flex: 0 0 auto; accent-color: var(--crp-blue, #1843AD); }
.notif-text { display: flex; flex-direction: column; gap: 2px; }
.notif-label { font-weight: 600; color: var(--ink-1, #0b1e3f); font-size: var(--fs-body); }
.notif-desc { color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.45; }
.notif-actions { display: flex; align-items: center; gap: 14px; margin-top: 18px; flex-wrap: wrap; }
/* Text notifications (#1 SMS leg PR-B, 2026-07-31) */
.sms-phone-row { display: flex; flex-direction: column; gap: 4px; margin: 10px 0 2px 30px; max-width: 320px; }
.sms-phone-row input[type="tel"] { font: inherit; font-size: var(--fs-input); padding: 8px 12px;
  border: 1px solid var(--border, #c8d6e8); border-radius: 8px; }
.sms-disclosure { margin: 12px 0 0; font-size: var(--fs-xs); color: var(--ink-2); line-height: 1.5; }

/* ── "Ask about this patient" question thread (§2.7 answer round-trip) ── */
.q-list { display: flex; flex-direction: column; gap: 14px; margin-top: 6px; }
.q-empty { color: var(--ink-2); font-size: var(--fs-body); line-height: 1.5; margin: 14px 0; }
.q-card {
  border: 1px solid var(--border, #c8d6e8); border-radius: 10px;
  background: var(--surface, #fff); padding: 16px 18px;
  box-shadow: 0 1px 2px rgba(7, 32, 97, 0.05);
}
/* Unread (answered, not yet opened) — a subtle tint, never a left stripe. */
.q-card.q-unread { background: var(--tint-blue, #f3f7fd); border-color: var(--crp-blue, #1843AD); }
.q-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.q-pill {
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  padding: 2px 9px; border-radius: 999px;
}
.q-pill-pending { background: var(--border-soft, #eef2f8); color: var(--ink-2, #4a5b78); }
.q-pill-answered { background: var(--crp-blue, #1843AD); color: #fff; }
/* The single accent (orange) marks the one thing that needs the eye. */
.q-new {
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--crp-orange, #FF9933);
}
.q-time { font-size: var(--fs-label); color: var(--ink-3, #6b7a94); margin-left: auto; }
.q-question { font-size: var(--fs-body); color: var(--ink-1, #0b1e3f); line-height: 1.5; margin: 0; white-space: pre-wrap; }
.q-pending-note { font-size: var(--fs-sm); color: var(--ink-2, #4a5b78); margin: 10px 0 0; font-style: italic; }
.q-answer {
  margin-top: 12px; padding: 12px 14px; border-radius: 8px;
  background: var(--border-soft, #eef2f8);
}
.q-answer-label {
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--crp-navy, #072061); margin-bottom: 5px;
}
.q-answer-body { font-size: var(--fs-body); color: var(--ink-1, #0b1e3f); line-height: 1.5; margin: 0; white-space: pre-wrap; }
.q-answer-time { display: block; margin-left: 0; margin-top: 6px; }

/* Partner-contribution "Portal engagement (all lanes)" cell — the total on
   one line, the legacy-vs-new by-lane split on a muted sub-line so the
   migration gap reads at a glance. */
.eng-total { font-weight: 600; }
.eng-lanes { font-size: var(--fs-label); color: var(--ink-2); margin-top: 2px; }

/* ── Time & invoicing (2026-07-28, RULE-COVERAGE 8881) ──────────────────
   The running total is the one number a practice manager actually wants, so
   it gets to be big; everything else on the page supports it. Dashboard
   density (10-14px padding, 6-10px radii), cool borders, no left-stripe
   accents — per the design-system rules. */
.inv-total {
  display: flex; flex-direction: column; gap: 2px;
  padding: 18px 20px; margin: 4px 0 16px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--border-soft, #eef2f8);
}
.inv-total-figure {
  font-size: 2rem; font-weight: 700; line-height: 1.1;
  color: var(--crp-navy, #072061); font-variant-numeric: tabular-nums;
}
.inv-total-sub { font-size: var(--fs-label); color: var(--ink-2, #4a5b78); }
.inv-amount { font-variant-numeric: tabular-nums; font-weight: 600; }

.inv-actions {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 14px;
}

.inv-form {
  display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end;
  margin-top: 4px;
}
.inv-field { display: flex; flex-direction: column; gap: 4px; min-width: 140px; }
.inv-field-wide { flex: 1 1 260px; }
.inv-field-action { min-width: 0; }
.inv-field label {
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--crp-navy, #072061);
}
.inv-field select,
.inv-field input {
  font: inherit; font-size: var(--fs-sm); padding: 9px 10px;
  border: 1px solid var(--border); border-radius: 8px;
  background: #fff; color: var(--ink-1, #0b1e3f);
}
.inv-field select:focus,
.inv-field input:focus { outline: 2px solid var(--crp-blue, #1843AD); outline-offset: 1px; }
.inv-optional { font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--ink-3, #6b7a94); }
.inv-row-actions { text-align: right; white-space: nowrap; }

/* Inline time capture on the patient board — the whole point of the feature is
   that logging time happens where the work happens, not on a separate page. */
.inv-inline {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  margin-top: 10px; padding-top: 10px;
  border-top: 1px solid var(--border-soft);
}
.inv-inline-label { font-size: var(--fs-label); color: var(--ink-2, #4a5b78); }
.inv-inline select,
.inv-inline input {
  font: inherit; font-size: var(--fs-label); padding: 6px 8px;
  border: 1px solid var(--border); border-radius: 6px; background: #fff;
}
.inv-inline input { width: 76px; }

/* Readability measure (owner typography directive 2026-07-31): prose ledes
   cap at ~70ch so lines stay in the 50-75 character comfort band. Tables,
   rails, and controls are untouched — this is prose-only. */
#page-lede, .card .lede, .lede { max-width: 70ch; }

/* ── Warm-moment booking — the Schedule-visit step control (2026-08-04,
   RULE-COVERAGE 9278). Dashboard-dense: 8px-grid spacing, cool borders,
   navy/blue only (orange stays the single accent, unused here). ── */
.bv-host { display: block; width: 100%; }
.bv-open {
  font: inherit; font-size: var(--fs-label); font-weight: 600;
  color: #fff; background: var(--crp-blue, #1843AD);
  border: 1px solid var(--crp-blue, #1843AD); border-radius: 8px;
  padding: 6px 14px; cursor: pointer;
}
.bv-open:hover { background: var(--crp-navy, #072061); border-color: var(--crp-navy, #072061); }
.bv-open:disabled { opacity: 0.55; cursor: default; }
.bv-note { margin-top: 4px; }
.bv-pick { margin-top: 8px; border: 1px solid var(--border, #c8d6e8); border-radius: 8px; padding: 10px 12px; }
.bv-pick-head { font-size: var(--fs-label); color: var(--ink-2, #33415e); margin-bottom: 8px; line-height: 1.45; }
.bv-day { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 6px 0; }
.bv-day-label { font-size: var(--fs-label); font-weight: 600; color: var(--crp-navy, #072061); min-width: 88px; }
.bv-slot {
  font: inherit; font-size: var(--fs-label); color: var(--crp-blue, #1843AD);
  background: #fff; border: 1px solid var(--border, #c8d6e8); border-radius: 6px;
  padding: 4px 10px; cursor: pointer;
}
.bv-slot:hover { border-color: var(--crp-blue, #1843AD); }
.bv-slot:disabled { opacity: 0.5; cursor: default; }
.bv-status { font-size: var(--fs-label); color: var(--ink-3, #5b6b8c); margin-top: 6px; line-height: 1.45; }
.bv-status-ok { color: var(--ok, #1a7f4e); font-weight: 600; }
.bv-status-warn { color: var(--warn, #9a5b00); }
.bv-status-info { color: var(--ink-2, #33415e); }

/* ── Identified-patient detail pane (2026-08-18) ───────────────────────────
   The clinical summary + pre-screen tick boxes that open when a provider
   selects an "Identified — awaiting your OK" row. Type/spacing follow the
   portal scale (>=16px body, 8px grid) rather than inventing a second one. */
.ipane-defs { display: flex; flex-direction: column; gap: 8px; }
.ipane-row { display: grid; grid-template-columns: 40% 1fr; gap: 12px; align-items: start; }
.ipane-label { color: var(--ink-3); font-size: var(--fs-sm); }
.ipane-val { color: var(--ink); font-size: var(--fs-sm); font-weight: 600; overflow-wrap: anywhere; }
.ipane-note { color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.5; margin: 0 0 12px; }

.ipane-checks { display: flex; flex-direction: column; gap: 4px; }
/* A whole row is the hit target, not just the 16px box — this is worked
   through on a phone at the bedside, not on a desktop with a mouse. */
.ipane-check {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 10px 8px; border-radius: 8px; cursor: pointer;
  font-size: var(--fs-sm); line-height: 1.5; color: var(--ink);
}
.ipane-check:hover { background: var(--bg-2, rgba(0,0,0,.03)); }
.ipane-check input { margin-top: 3px; width: 18px; height: 18px; flex: none; cursor: pointer; }
.ipane-check input:disabled { cursor: progress; }
.ipane-check-text { overflow-wrap: anywhere; }
.ipane-kind {
  display: inline-block; margin-left: 8px; padding: 1px 8px; border-radius: 999px;
  background: var(--bg-2, rgba(0,0,0,.05)); color: var(--ink-3);
  font-size: var(--fs-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  white-space: nowrap;
}
.ipane-savemsg { margin-top: 10px; font-size: var(--fs-xs); color: var(--ink-3); min-height: 1em; }
.ipane-savemsg.err { color: var(--danger, #b42318); font-weight: 600; }


/* ── Board polish, 2026-08-18 ───────────────────────────────────────────
   Measured before changing anything: identified rows were 113px each, from a
   study name duplicated out of the group header (2 lines), a sub-line that
   wrapped after the masked phone, and two decision buttons that wrapped to a
   second row. On a 407-patient board that is thousands of pixels of scroll
   that carry no information. Type is untouched — the board floor is a
   deliberate, test-locked 14px. */
.nobreak{white-space:nowrap}

/* STACKED, always (revised 2026-08-18 after measuring the live pane).
   Two columns cannot both fit here: the pane is ~335px wide at 1440 and
   narrower on a laptop, so any label column wide enough for "Prohibitive
   medications" starves the value, and any column narrow enough for the value
   wraps the label. First attempt kept two columns above 1200px and the labels
   still wrapped. The label now sits ABOVE its value and each gets the full
   width — nothing wraps mid-phrase. */
.ipane-row{grid-template-columns:1fr;gap:1px}
.ipane-label{hyphens:none;font-size:var(--fs-label);line-height:1.4}
.ipane-val{line-height:1.45}
.ipane-defs{gap:14px}
@media(max-width:1200px){
  .ipane-row{gap:1px}
}

/* ── Footer, mirroring joinresearchstudies.com/refer (2026-08-18) ────────
   The public referral page closes on a navy band: contact strip, three trust
   badges, and the legal line. The portal closed on one grey sentence. Same
   company, two different endings — and the portal is the surface a referring
   physician spends the most time on.

   Mirrored, not copied: the public page carries these as inline style
   attributes, which the portal's CSP (style-src 'self') forbids. Same colours,
   same shield mark, same wording — expressed as classes. The shields use
   currentColor so each badge tints from ONE property. */
.portal-foot {
  /* Was left-aligned inside the container; the band it mirrors is centred. */
  align-items: center;
  text-align: center;
  background: var(--navy, #072061);
  color: #fff;
  max-width: none;
  padding: 32px var(--gutter) 32px;
  margin-top: 40px;
  gap: 0;
}
.portal-foot a { color: #fff; opacity: .85; }
.portal-foot a:hover { opacity: 1; text-decoration: underline; }
.portal-foot .foot-logo { height: 48px; opacity: .95; margin-bottom: 4px; filter: brightness(0) invert(1); }

.foot-contact {
  display: flex; gap: 16px; justify-content: center; flex-wrap: wrap;
  margin-top: 16px; font-size: var(--fs-label);
}

.foot-badges {
  display: flex; gap: 16px; justify-content: center; flex-wrap: wrap;
  margin: 20px 0 0; padding: 0; list-style: none;
}
.foot-badge {
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(255,255,255,.1); border: 1px solid rgba(255,255,255,.15);
  padding: 6px 14px; border-radius: 6px;
  font-size: 11px; font-weight: 700; letter-spacing: .5px; white-space: nowrap;
}
.foot-badge .fb-mark { flex: none; }
.fb-hipaa { color: #10b981; }
.fb-irb   { color: #60a5fa; }
.fb-fda   { color: #FF9933; }

.foot-legal { margin-top: 16px; font-size: 13px; opacity: .7; line-height: 1.6; color: #fff; }

@media (max-width: 640px) {
  .portal-foot { padding: 24px 16px; }
  .foot-contact, .foot-badges { gap: 10px; }
}

/* Header alignment follows its cells. "Your decision" sat left-aligned over
   right-aligned buttons, so the column read as two different columns. */
#identified-table thead th:last-child{text-align:right}


/* ── Make the button scale actually BIND (2026-08-18, round 2) ───────────
   Round 1 gave every control a min-height from the scale, and measuring the
   live page showed FOUR rendered heights anyway: 33 / 36 / 40 / 47px.

   min-height is a FLOOR, not a height. A control renders taller whenever
   line-height + padding + borders exceed it, and the borders were themselves
   inconsistent — 1px, 1.5px and 2px across the same row of buttons. So
   .cbtn (min 36) rendered 40, .prail-signout (min 44) rendered 47, and the
   segment chips had no floor at all and rendered 33.

   Three things make the token the ACTUAL height:
     1. one border width, so the box maths is the same everywhere,
     2. a fixed line-height, so the text box is predictable rather than
        inheriting 'normal' from whatever font is resolved,
     3. padding small enough that the floor is what binds.
   box-sizing is stated rather than assumed — the whole point is that the
   declared height is the rendered one. */
.btn, .btn-sm, .cbtn, .ident-controls .cbtn, .pi-btn, .pi-records-btn,
.pi-clinical-btn, .btn-row-upl, .result-download-btn, .tc-refer-btn,
.d-head-btn, .closed-fold-btn, .ar-btn, .btn-google,
.appbar-signout button, .prail-signout button, .seg, .board-refresh {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1.2;
  border-width: 1px;
  border-style: solid;
}
/* The segment chips and the board Refresh had no floor at all — they are
   controls the provider taps, so they join the dense tier rather than
   rendering 3px shorter than everything beside them. */
.seg, .board-refresh { min-height: var(--btn-h-sm); }
/* Padding trimmed to the binding threshold: at line-height 1.2 and a 1px
   border, these leave the min-height as the tallest term, so sm/md/lg render
   at exactly 36 / 44 / 48. */
:root {
  --btn-pad-sm: 6px 14px;
  --btn-pad-md: 10px 18px;
  --btn-pad-lg: 12px 22px;
}

/* ── /about — the PUBLIC page (rebuilt 2026-08-19) ──────────────────────
   First cut reused .card-page, the container built for the SHORT sign-in
   panel, and put a full document inside it: the navy band stopped at 210px,
   the white card straddled it with no bottom edge, and the content ran off
   the viewport with nothing anchoring it. It read as broken because it was
   the wrong container.

   This is a document layout: a navy masthead carrying the app name, a
   readable measure for the prose, and the real portal footer so the page
   ends deliberately and matches every other surface. */
.doc-page { margin: 0; background: var(--paper, #f4f6fb); }

.doc-head {
  background: var(--navy, #072061);
  color: #fff;
  padding: 56px 24px 48px;
  text-align: center;
}
.doc-logo { height: 44px; width: auto; margin-bottom: 24px; filter: brightness(0) invert(1); }
.doc-head h1 {
  /* 20ch broke "Clinical Research Philadelphia Provider Portal" into THREE
     lines. The name is long; give it room to sit on one or two. */
  max-width: 30ch; margin: 0 auto 12px;
  font-size: clamp(1.75rem, 3.5vw, 2.25rem); line-height: 1.2; color: #fff;
  text-wrap: balance;
}
.doc-sub {
  max-width: 58ch; margin: 0 auto; color: rgba(255,255,255,.82);
  font-size: var(--fs-body, 1rem); line-height: 1.6;
}
/* A BARE .btn carries no background — the colour lives on its variants
   (.btn-navy and friends), so `class="btn"` alone rendered as near-invisible
   link text on the navy masthead. This CTA states its own colours. */
.doc-cta {
  margin-top: 28px;
  background: #fff;
  color: var(--navy, #072061);
  border-color: #fff;
  text-decoration: none;
  font-weight: 700;
}
.doc-cta:hover { background: rgba(255,255,255,.9); border-color: rgba(255,255,255,.9); }

.doc-body { max-width: 68ch; margin: 0 auto; padding: 48px 24px 56px; }
.doc-body section + section { margin-top: 36px; }
.doc-body h2 {
  font-size: var(--fs-h3, 1.25rem); font-weight: 700; color: var(--ink);
  margin: 0 0 10px;
}
.doc-body p { margin: 0 0 12px; line-height: 1.65; color: var(--ink-2); }
.doc-body ul { margin: 0; padding-left: 22px; color: var(--ink-2); line-height: 1.65; }
.doc-body li { margin-bottom: 8px; }
.doc-body a { color: var(--blue); }

@media (max-width: 640px) {
  .doc-head { padding: 40px 18px 36px; }
  .doc-body { padding: 32px 18px 40px; }
}
/* The app name must READ as the app name — Google's branding check compares
   the consent-screen name against visible text on the home page, and an alt
   attribute does not count. */
/* The one-sentence purpose, sitting directly under the app name. It used to
   be a second NAME ("Provider Portal") — which is precisely what Google's
   branding check read as "the app name on your home page does not match".
   One name on this page, then what the app does. */
.about-appname {
  font-size: var(--fs-body, 1rem); font-weight: 600; color: var(--ink);
  line-height: 1.6; margin: 0 0 16px !important;
}

/* ── `hidden` must actually hide (2026-08-19) ───────────────────────────
   The HTML `hidden` attribute works only through the UA rule
   [hidden]{display:none}, which ANY author display rule outranks. The rail
   sets `.prail-nav a { display:flex }`, so every rail link marked hidden
   rendered anyway.

   Measured live: #prail-tab-invoicing had hidden=true and computed
   display:flex. Time & invoicing therefore showed for all 7 partners while
   /api/invoicing returns 403 invoicing_disabled for every one of them — a
   nav item that cannot work. The SAME defeat applied to the admin-only
   Settings reveal.

   This is a gate that silently did not gate. The reveal logic in prail-nav.js
   was correct the whole time; the CSS was quietly overruling it. */
[hidden] { display: none !important; }
