/* 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;
  /* Stepped type scale. The file previously carried SIXTEEN sizes including
     10.5 / 11.5 / 12.5 / 13.5 -- half-pixel values are the fingerprint of
     per-element nudging, and they are why the text read as squeezed. */
  --t-micro: 11px;
  --t-small: 12px;
  --t-body: 13px;
  --t-base: 14px;
  --t-lead: 16px;
  --t-h2: 20px;
  --t-h1: 26px;
  /* Radii: controls / cards / pills. Nothing else. */
  --r-control: 8px;
  /* 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: 20px;
  --r-card: 12px;
  --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: 14px;
  line-height: 1.55;
  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: 26px;
  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: 38px; margin: 0 auto 10px; }
.brand-eyebrow {
  font-size: 11px;
  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: 13px;
  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: 12px;
  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;
  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: 12px;
  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 {
  margin: 0 0 6px;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--navy);
}
.page-lede {
  margin: 0;
  max-width: 62ch;
  font-size: 14px;
  color: var(--ink-2);
}

/* ── Cards ──────────────────────────────────────────────────────────── */
.panel {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(7, 32, 97, 0.08);
  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 {
  margin: 0;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  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: 12px;
  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: 13px;
}
.report-table th {
  text-align: left;
  font-size: 11px;
  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: 12px; color: var(--ink-3); }

/* ── Pills (stage / verdict) — informational only, never alarm ─────── */
.pill,
.stage-pill {
  display: inline-block;
  font-size: 12px;
  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 ────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  border-radius: 8px;
  padding: 12px 22px;
  cursor: pointer;
  border: 1px solid transparent;
  text-decoration: none;
  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: 12px; padding: 6px 13px; border-radius: 8px; }

/* 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: 13px; 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: 14px;
}
.empty-title { font-weight: 700; color: var(--ink); margin: 0 0 4px; font-size: 14px; }

/* 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: 20px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--navy);
}
.card .lede { margin: 0 0 18px; font-size: 14px; color: var(--ink-2); }
.card label {
  display: block;
  font-size: 11px;
  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: 8px;
  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: 8px; }
.btn-sm:focus-visible { border-radius: 8px; }
.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: 16px;
  font-weight: 600;
  border-radius: 8px;
  padding: 14px 18px;
  min-height: 48px;
  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: 12px; color: var(--ink-3); }
.fine a, .auth-fine a { color: var(--blue); }

/* ── Results section on the board page ─────────────────────────────── */
.result-new { margin-left: 8px; }
.download-note,
.board-fine {
  padding: 10px 20px 16px;
  font-size: 12px;
  color: var(--ink-3);
  margin: 0;
}
.board-updated { font-size: 12px; color: var(--ink-3); margin: 4px 0 0; }
.board-subhead { font-size: 11px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: var(--navy); margin: 0; }
.result-download-btn {
  font: inherit; font-size: 12px; font-weight: 700; padding: 6px 14px;
  background: var(--card); color: var(--blue); border: 1px solid var(--border);
  border-radius: 8px; 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: 13px;
  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: 13px; text-transform: none; letter-spacing: 0; }
.tc-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(7, 32, 97, 0.08);
  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);
  background: var(--paper);
}
.tc-proto {
  margin: 0;
  font-size: 14px;
  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: 14px; color: var(--ink); }
.tc-name strong { font-weight: 700; }
.tc-meta { font-size: 12px; color: var(--ink-3); }
.tc-detail { font-size: 12px; 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: 12px; font-weight: 700; padding: 8px 16px;
  background: var(--navy); color: #fff; border: none; border-radius: 8px; 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: 12px; 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: 12px; 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: 11px;
  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: 13px; 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: 13px; color: var(--ink); }
.tc-q-opts { display: flex; gap: 5px; flex-shrink: 0; }
.tc-q-opt {
  font: inherit; font-size: 13px; 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: 13px; 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: 560px; }
/* 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 {
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-2);
  margin-bottom: 6px;
}
.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: 12px;
  /* 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: 40px; width: auto; opacity: 0.75; 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: 13px; }
  .page-hero { padding: 10px 16px 0; }
  .page-hero .page-title { font-size: 20px; margin-bottom: 4px; }
  .page-hero .page-lede { font-size: 13px; 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: 6px 12px; }
  /* 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: 13px;
  }
  .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: 13px;
  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: 13px;
  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; }
/* 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: 20px;
  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: 13px; color: var(--ink-2); }
.ref-fine { font-size: 12px; 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: 14px; font-weight: 700; color: var(--navy); }
.ref-block p { margin: 0 0 8px; font-size: 13px; 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: 12px; color: var(--ink-2); }
.ref-title-wrap { min-width: 0; }
.ref-study-meta { margin-top: 3px; font-size: 12px; color: var(--ink-2); }
.ref-study-body { padding: 12px 20px 14px; }
.ref-detrow { font-size: 13px; 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: 13px;
  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: 11px; 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: 13px; 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: 12px;
  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: 13px; 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: 11px;
  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: 13px; font-weight: 700; }
.pc-count { font-size: 12px; 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: 12px; 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: 13px; font-weight: 700; color: var(--navy); }
.upl-note { margin: 0; font-size: 12px; color: var(--ink-2); }
.upl-field {
  font: inherit;
  font-size: 14px;
  color: var(--ink);
  background: var(--card);
  border: 1.5px solid var(--border);
  border-radius: 8px;
  padding: 11px 13px;
  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: 13px; 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: 13px; 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: 13px; color: var(--ink-3); margin-top: 1px; }
.t-status-why { font-size: 13px; 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 * 13px + 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: 13px;
  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: 11px;
  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: 12px;
  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: 14px;
  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; }

/* 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: 12px;
  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: 12px;
  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: 13px;
  font-weight: 600;
  color: var(--blue);
  background: var(--card);
  border: 1.5px solid var(--border);
  border-radius: 8px;
  padding: 8px 14px;
  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: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.sf-select {
  font: inherit;
  font-size: 14px;
  color: var(--ink);
  background: var(--card);
  border: 1.5px solid var(--border);
  border-radius: 8px;
  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); }

/* ── 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: 13px; 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: 14px; 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: 14px; font-weight: 600; color: var(--navy); }
.grant-row-meta { font-size: 13px; color: var(--ink-2); }
.grant-row-side { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.grant-note { font-size: 13px; 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: 13px;
  color: var(--ink);
  cursor: pointer;
}
.grant-ack input { margin-top: 2px; }
.grant-all-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
