
:root{--navy:#103a5c;--ink:#0f172a;--teal:#0e7c7b;--bg:#f7fafc;--line:#dbe4ec;--navy-soft:#e7f0f8;--navy-soft-line:#b9d2e4;--teal-soft:#e9f6f3;--warn:#b54708;--ok:#067647;--err:#b42318;--info:#3538cd;--err-soft:#fef2f1;--warn-soft:#fef0c7;--ok-soft:#d1fadf;
/* soft tinted borders: the .notice.warn/.err border values, as tokens (U6b) */
--warn-line:#f0d3a6;--err-line:#f2c4c0;
--cpk-pathology:#5925dc;--cpk-radiology:#0086c9;--cpk-procedure:#c4320a;--cpk-consult:#0e7c7b;--cpk-other:#475467;
--space-1:4px;--space-2:8px;--space-3:12px;--space-4:16px;--space-5:24px;--space-6:32px;
--radius-sm:6px;--radius:8px;--radius-lg:12px;
--fs-xs:12px;--fs-sm:13px;--fs-base:14px;--fs-md:15px;--fs-lg:18px;--fs-xl:24px;
--shadow-1:0 1px 2px rgba(16,58,92,.06);--shadow-2:0 8px 28px rgba(16,58,92,.18)}
/* Navigation progress bar. Every page is a full server render, so the wait the
   user actually feels is the round trip AFTER a click, while the OLD page is
   still on screen — a splash overlay in the new HTML would only ever appear once
   the wait was already over. This bar starts on click/submit and dies when the
   new document replaces the DOM. ponytail: no % tracking, one long decelerating
   transition to 90% fakes progress well enough.

   The bar OVERLAYS the top 3px of the header, so its colour is set by what sits
   behind it, not by the brand palette. On admin that is the navy header: the
   brand teal scores only 2.35:1 there (WCAG 1.4.11 wants 3:1 for non-text UI)
   and is all but invisible, so admin uses a light teal — 7.9:1. Patient headers
   are white, where the brand teal is 5:1, so they keep it. */
#navprog{position:fixed;top:0;left:0;height:3px;width:0;background:#5eead4;box-shadow:0 0 8px rgba(94,234,212,.55);z-index:9999;opacity:0;pointer-events:none;transition:opacity .15s}
body.cb-patient #navprog{background:var(--teal);box-shadow:0 0 8px rgba(14,124,123,.5)}
#navprog.on{opacity:1;width:90%;transition:width 10s cubic-bezier(0,.7,.15,1),opacity .1s}
/* Reduced motion: still say "loading", but as a static bar with no travel. */
@media (prefers-reduced-motion:reduce){#navprog.on{width:100%;transition:opacity .1s}}
@media print{#navprog{display:none}}
/* additive utility layer (foundation for incremental adoption; existing inline styles untouched) */
.u-stack{display:flex;flex-direction:column;gap:var(--space-3)}
.u-row{display:flex;gap:var(--space-3);align-items:center}
.u-wrap{flex-wrap:wrap}.u-between{justify-content:space-between}
.u-gap-2{gap:var(--space-2)}.u-gap-4{gap:var(--space-4)}
.u-card{background:#fff;border:1px solid var(--line);border-radius:var(--radius-lg);padding:var(--space-5)}
*{box-sizing:border-box}
/* The [hidden] attribute must always win, even over an inline display:flex/grid
   (e.g. the calendar reschedule modal & worker toast set display inline). Without
   this an element kept "closed" via .hidden=true stays visible — the reschedule
   modal showed on every day-view load and could not be dismissed. */
[hidden]{display:none!important}
/* overflow-x: clip (not hidden) — hidden turns body into a scroll container,
   which silently kills position:sticky for every descendant (the pinned patient
   header). clip clips without creating a scroll container; the hidden fallback
   keeps old browsers clipped (they just lose stickiness). */
body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:var(--bg);color:#1a2733;line-height:1.55;overflow-x:hidden;overflow-x:clip}
/* position+z-index: the top bar owns a stacking context ABOVE page content, so
   what pops out of it (global search results, tooltips) clears the pinned
   patient header (.pf-sticky, z-index:45). Stays under the mobile nav backdrop
   (55) and drawer (60) so those still cover it. */
header.site{background:var(--navy);color:#fff;padding:14px 20px;display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:2px 16px;position:relative;z-index:50}
header.site .brand{font-weight:700;font-size:17px}header.site .sub{font-size:13px;opacity:.85}
/* Patient-facing pages wear the warm Colonoscopy Brisbane identity (terracotta
   on white) rather than the navy admin bar; the admin console keeps navy. */
header.site.patient{background:#fff;color:#2f3638;border-top:3px solid #c86a4a;border-bottom:1px solid #e6e0d6}
header.site.patient .brand{color:#c86a4a;font-family:"Playfair Display",Georgia,"Times New Roman",serif;font-size:20px;letter-spacing:.2px}
header.site.patient .sub{color:#5e6a6c;opacity:1}
/* dual-brand header (check-in kiosk): the two-practice name is long — size it to
   fit an iPad (and shrink further on phones) so it never wraps ugly */
header.site.patient .brand.dual{font-size:19px;letter-spacing:.1px}
@media (max-width:560px){header.site.patient .brand.dual{font-size:13px;letter-spacing:0}}
main{max-width:760px;margin:0 auto;padding:24px 16px 64px}
main.wide{max-width:1100px}
h1{font-size:24px;color:var(--ink)}h2{font-size:18px;color:var(--ink);margin-top:28px}
h3{font-size:16px;color:var(--ink);margin-top:22px}h4{font-size:15px;color:var(--ink);margin-top:18px}h5{font-size:14px;font-weight:700;color:var(--ink);margin-top:14px}h6{font-size:13px;font-weight:700;color:var(--ink);margin-top:12px}
/* patient-facing flows get a slightly airier line-height; admin shell (.amain) stays at body's 1.55 */
main:not(.amain){line-height:1.6}
.card{background:#fff;border:1px solid var(--line);border-radius:10px;padding:20px;margin:16px 0}
label{display:block;font-weight:600;font-size:14px;margin:14px 0 4px}
input[type=text],input[type=email],input[type=tel],input[type=date],input[type=password],input[type=url],input[type=number],select,textarea{width:100%;padding:10px;border:1px solid var(--line);border-radius:8px;font-size:15px;background:#fff;font-family:inherit}
/* url/number were never in the rule above (2026-09-11) — they rendered as bare ~120px
   browser inputs everywhere. Number keeps slim side padding: inline 58–68px boxes exist. */
input[type=number]{padding:10px 6px}
.row{display:flex;gap:12px}.row>div{flex:1}
.radio-group{display:flex;gap:10px;margin:6px 0}
.radio-group label{flex:1;border:1.5px solid var(--line);border-radius:8px;padding:12px;text-align:center;cursor:pointer;font-weight:600;margin:0}
.radio-group input{position:absolute;opacity:0;width:1px;height:1px;pointer-events:none}.radio-group input:checked+span{color:var(--teal)}
.radio-group label:has(input:checked){border-color:var(--teal);background:#ecfdf9}
.radio-group label:has(input:focus-visible){outline:2px solid var(--teal);outline-offset:2px}
.checks label{font-weight:400;margin:6px 0;display:flex;gap:8px;align-items:flex-start}
.checks input{margin-top:3px}
/* Library document attach-lists can be long (every PDF in the library). Cap the
   box to ~10 rows and scroll, so it doesn't take over the screen. Scoped class —
   applied only to those containers, never to short consent/ack .checks lists. */
.doc-attach-scroll{max-height:340px;overflow-y:auto;border:1px solid #dbe2ea;border-radius:8px;padding:8px 10px}
button.primary,a.primary{background:var(--teal);color:#fff;border:0;border-radius:8px;padding:13px 26px;font-size:16px;font-weight:700;cursor:pointer;margin-top:20px}
a.primary{display:inline-block;text-decoration:none}
button.primary:hover,a.primary:hover{filter:brightness(1.07)}
.muted{color:#5b6b7b;font-size:13px}
/* Patient-facing "Having trouble?" disclosure on the sign-in / sign-up doors
   (hubTroubleshootingUi.ts). Quiet by design: it must never compete with the
   form above it. Also renders on Hub pages — renderHubPage layers the gh
   stylesheet on top of this one, so one rule covers both worlds. */
.trouble{margin:12px 0 0}
.trouble>summary{padding:13px 0;cursor:pointer;font-weight:600}
.trouble-list{margin:0 0 6px;padding-left:20px;line-height:1.55}
.trouble-list li{margin:6px 0}.error{color:var(--err);font-weight:600;font-size:14px;margin-top:10px}
.hidden{display:none}
/* Stage-1 colour language (owner 2026-07-28): notices are soft tinted panels —
   full 1px same-hue border, no 4px side bar. Semantics via modifier classes; the
   old inline style="border-left:4px solid …" call sites were swept onto these. */
.notice{border:1px solid #aedcd2;background:#ecfdf9;padding:12px 14px;border-radius:8px;font-size:14px}
.notice.warn{border-color:#f0d3a6;background:#fdf6ec}
.notice.err{border-color:#f2c4c0;background:#fef2f1}
.notice.ok{border-color:#b5e3c8;background:#eefaf3}
.notice.info{border-color:#c7c9f0;background:#f1f1fd}
.notice.brand{border-color:var(--navy-soft-line);background:var(--navy-soft)}
/* admin */
table.list{width:100%;border-collapse:collapse;font-size:14px;background:#fff;border:1px solid var(--line);border-radius:10px;overflow:hidden}
table.list th{background:#f1f5f9;color:#41566b;text-align:left;padding:9px 12px;font-size:12.5px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;border-bottom:1px solid var(--line)}
table.list td{padding:9px 12px;border-top:1px solid var(--line)}
table.list tr:hover td{background:#f0f6fb}
/* accessible clickable rows (C1): real link on the name cell, stretched to fill the row for the mouse */
td.rowlink{position:relative}a.rl{color:inherit;text-decoration:none;font-weight:inherit}
/* ⚠ The stretched overlay is SCOPED to .rowlink. An unscoped a.rl::after has no
   positioned ancestor outside a rowlink cell, so inset:0 resolves against the
   PAGE — an invisible full-page click target. With several such links rendered
   (the review-request queue cards), the last one painted over every button on
   the page and every click opened a patient file (owner 2026-08-28: "any button
   takes me to the patient file"). Outside .rowlink, a.rl is just quiet link
   styling. test/prefetchSafety.test.js pins the scoping. */
.rowlink a.rl::after{content:"";position:absolute;inset:0}a.rl:focus-visible{outline:2px solid var(--teal);outline-offset:-2px}
.pill{display:inline-block;padding:2px 10px;border-radius:999px;font-size:12px;font-weight:700}
/* ── locked pill colour tiers (R2): ok=green done/paid/confirmed · warn=amber waiting/unpaid · bad=red cancelled/problem · info=blue pending/online · muted=grey inactive/void ── */
.pill.ok,.pill.VERIFIED,.pill.RECONCILED,.pill.APPLIED,.pill.CONFIRMED,.pill.COMPLETED,.pill.PAID,.pill.CONVERTED,.pill.DONE,.pill.LINKED,.pill.CREATED_NEW,.pill.MATCHED,.pill.FILED{background:#d1fadf;color:var(--ok)}
.pill.warn,.pill.PENDING,.pill.PENDING_VERIFICATION,.pill.ARRIVED,.pill.CONTACTED,.pill.REVIEW,.pill.UNMATCHED,.pill.HELD{background:#fef0c7;color:var(--warn)}
.pill.bad,.pill.VERIFICATION_FAILED,.pill.CONFLICT,.pill.DNA,.pill.CANCELLED,.pill.OVERDUE,.pill.FAILED,.pill.ERROR{background:#fee4e2;color:var(--err)}
.pill.info,.pill.smart,.pill.MANUAL_REVIEW,.pill.SYNCED_FROM_GENTU,.pill.BOOKED,.pill.IN_CONS,.pill.SENT,.pill.NEW{background:#e0eaff;color:#3538cd}
.pill.muted,.pill.ARCHIVED,.pill.DRAFT,.pill.VOID,.pill.VOIDED,.pill.LOST{background:#eef1f4;color:#5b6b7b}
/* ── notification-centre category tags + severity row accents ── */
.pill.purple{background:#f4ebff;color:#6941c6}
.pill.teal{background:#ccfbef;color:#0e7c7b}
tr.nsev-warn>td:first-child{border-left:3px solid var(--warn)}
tr.nsev-critical>td:first-child{border-left:3px solid var(--err)}
/* ── patient-file flags banner (Gentu-style). Compacted 2026-08-04 (Option A
   signals spec): one slim line per flag — same tiers/classes/actions, ~60% of
   the old height, so two flags no longer push the file below the fold. ── */
.pf-flags{display:flex;flex-direction:column;gap:5px;margin:10px 0 0}
.pf-flag{display:flex;align-items:center;gap:8px;padding:6px 11px;border-radius:8px;font-size:13px;font-weight:700;border-left:4px solid;line-height:1.3}
/* Treating clinicians (0272). Plain rows, no card-within-a-card: the colour dot
   is the only ornament, and it matches the provider colour used on the calendar
   and in the access console so one clinician reads the same everywhere. */
.pf-clin-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
.pf-clin-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.pf-clin-row form{margin-left:auto}
.pf-clin-dot{width:9px;height:9px;border-radius:50%;flex:0 0 auto}
.pf-flag .pf-label{flex:1;min-width:0;word-break:break-word;white-space:pre-line}
.pf-flag .icon{flex:none}
.pf-flag.pf-alert{background:#fee4e2;border-color:var(--err);color:#7a271a}
.pf-flag.pf-warn{background:#fef0c7;border-color:var(--warn);color:#7a2e0e}
.pf-flag.pf-info{background:#e0eaff;border-color:#3538cd;color:#2d3282}
.pf-flag .pf-act{flex:none;font-weight:700;font-size:13px;white-space:nowrap;color:inherit;background:rgba(255,255,255,.6);border:1px solid currentColor;border-radius:999px;padding:3px 11px;text-decoration:none;cursor:pointer;font-family:inherit;line-height:1.3}
.pf-flag .pf-act:hover{background:#fff;text-decoration:underline}
.pf-flag form{margin:0;display:flex}
.pf-flag .pf-x{appearance:none;background:none;border:0;cursor:pointer;color:inherit;opacity:.7;font-size:16px;line-height:1;padding:2px 4px;border-radius:6px}
.pf-flag .pf-x:hover{opacity:1}.pf-flag .pf-x:focus-visible{outline:2px solid currentColor;outline-offset:1px;opacity:1}
.pf-addflag{display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin:8px 0 0}
.pf-addflag input[type=text]{flex:1;min-width:180px;width:auto}.pf-addflag select{width:auto}
.pf-addflag-wrap{margin:8px 0 0}
/* The patient-file header action row. Children arrive with their own margins
   (.pf-addflag-wrap has margin-top:8px for its stacked use, button.primary has
   margin-top:20px) which, inside align-items:center, shift that child by HALF
   the margin and knock the row out of line. The row owns its own spacing. */
.pf-headactions{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.pf-headactions>*{margin:0}.pf-addflag-wrap>summary{cursor:pointer;list-style:none;display:inline-block;font-size:13px}
.pf-addflag-wrap>summary::-webkit-details-marker{display:none}
/* ── "Waiting on" header pills (Option A signals row, 2026-08-04): two-segment
   pill — WHAT was sent (white, navy) + WHERE it's up to (locked-tier tint +
   dot). Same tint hexes as the .pill tiers; no new colours. ── */
.wpill{display:inline-flex;align-items:stretch;border:1px solid var(--line);border-radius:999px;background:#fff;overflow:hidden;font-size:12px;line-height:1.25;text-decoration:none;white-space:nowrap}
.wpill:hover .wt{text-decoration:underline}
.wpill .wt{display:flex;align-items:center;gap:5px;padding:3px 8px 3px 10px;color:var(--navy);font-weight:700}
.wpill .ws{display:flex;align-items:center;gap:6px;padding:3px 10px 3px 8px;border-left:1px solid var(--line);font-weight:600}
.wpill .wdot{width:7px;height:7px;border-radius:50%;flex:none}
.wpill.w-warn .ws{background:#fef0c7;color:var(--warn)}.wpill.w-warn .wdot{background:#e08a2e}
.wpill.w-info .ws{background:#e0eaff;color:#3538cd}.wpill.w-info .wdot{background:#5a5fe0}
.wpill.w-ok .ws{background:#d1fadf;color:var(--ok)}.wpill.w-ok .wdot{background:#12a35c}
.wpill.w-bad .ws{background:#fee4e2;color:var(--err)}.wpill.w-bad .wdot{background:#d64533}
.wpill.w-muted .ws{background:#eef1f4;color:#5b6b7b}.wpill.w-muted .wdot{background:#93a3b3}
.pf-safety{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0 0;align-items:center}
/* "Booked online" provenance chip (0430): a native <details> whose summary IS
   the pill; the panel floats under it. On the ≤560px chip rail the row is
   overflow-x:auto, which would clip the panel — :has() lets the rail wrap and
   show while one is open. */
.pf-origin{position:relative;display:inline-block}
.pf-origin>summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:3px}
.pf-origin>summary::-webkit-details-marker{display:none}
.pf-origin>summary::after{content:"";width:0;height:0;border:4px solid transparent;border-top-color:currentColor;border-bottom:0;margin-left:5px;opacity:.7}
.pf-origin[open]>summary::after{transform:rotate(180deg)}
.pf-origin>summary:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
.pf-origin-panel{position:absolute;left:0;top:calc(100% + 6px);z-index:30;width:min(340px,calc(100vw - 32px));background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:0 8px 24px rgba(15,23,42,.14);padding:10px 12px 8px;font-size:12.5px;font-weight:500;line-height:1.45;color:#0f172a;text-align:left;white-space:normal}
.pf-origin-panel p{margin:0 0 7px}
.pf-origin-panel .k{display:block;color:#7b8a97;font-weight:700;font-size:10px;text-transform:uppercase;letter-spacing:.05em;line-height:1.3}
.pf-origin-panel .pf-origin-act{margin:4px 0 0;padding-top:8px;border-top:1px solid var(--line)}
@media (max-width:560px){.pf-safety:has(.pf-origin[open]){flex-wrap:wrap;overflow:visible}}
/* ≤560px: the signals row becomes ONE swipe lane instead of a tall wrapped
   stack — waiting pills stay reachable without eating the viewport. */
@media (max-width:560px){.pf-safety{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;padding-bottom:2px}.pf-safety::-webkit-scrollbar{display:none}.pf-safety .pill{white-space:nowrap;flex:none}}
.statbar{display:flex;gap:12px;flex-wrap:wrap;margin:14px 0}
.stat{background:#fff;border:1px solid var(--line);border-radius:10px;padding:12px 18px;min-width:130px}
.stat .n{font-size:26px;font-weight:800;color:var(--ink)}.stat .l{font-size:12px;color:#5b6b7b}
/* minmax(0,…) on BOTH tracks + min-width:0 on the cells: a grid child defaults to
   min-width:auto, so one long unbreakable value (a UUID, an email, the Copy UUID
   button beside it) grew the track and pushed text out past the card edge at
   narrow widths (owner 2026-08-06). The label column now yields space too. */
dl.kv{display:grid;grid-template-columns:minmax(0,190px) minmax(0,1fr);gap:6px 14px;font-size:14px}dl.kv dt{min-width:0;font-weight:600;color:#41566b;overflow-wrap:anywhere}dl.kv dd{margin:0;min-width:0;overflow-wrap:anywhere}
/* kv group subheading — a full-width divider labelling a cluster of rows
   (Details card: Identity / Contact / Funding / Referral …). */
dl.kv .kv-grp{grid-column:1/-1;margin:10px 0 0;padding:6px 0 2px;border-top:1px solid var(--line);font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:#8395a4}
dl.kv .kv-grp:first-child{margin-top:0;padding-top:0;border-top:0}
/* .tickgate — a card whose detail fields appear only once its checkbox confirms
   they apply (new-patient Medicare / private health cover). CSS-only so it works
   with JS off, and @supports-gated so a browser without :has() shows the fields
   rather than hiding them forever — this must fail OPEN. */
@supports selector(:has(*)){
.tickgate>.tickgate-body{display:none}
.tickgate:has(input[type=checkbox]:checked)>.tickgate-body{display:block}
}
/* inv-step — numbered stage heading inside a long form (New invoice). Same
   idiom as .kv-grp: a slim divider + small caps label, not a wizard. */
.inv-step{margin:16px 0 8px;padding-top:10px;border-top:1px solid var(--line);font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:#8395a4}
.inv-step:first-child{margin-top:0;padding-top:0;border-top:0}
a{color:var(--teal)}
/* ⚠ line-height is LOAD-BEARING here (and no backticks in this comment — the
   whole stylesheet is a template literal). A <button> does NOT inherit
   line-height from the page: the UA stylesheet says normal, while <a> and
   <summary> do inherit it. So an identical .btn-link rendered 32.5px tall as a
   button and 37.1px as an anchor, and every mixed row — the patient-file header
   (Start encounter · SMS · Wrap-up · + Add · Add flag) — carried two or three
   different button heights. Pinning it makes every .btn-link the same height
   whatever the tag, and lines up their icons with it. */
.btn-link{background:#fff;border:1.5px solid var(--teal);color:var(--teal);border-radius:8px;padding:7px 14px;font-size:13px;font-weight:700;line-height:1.5;cursor:pointer;text-decoration:none;display:inline-block}
/* .solid — the filled variant, for the ONE primary action in a card (anchors can't
   use button.primary). Modifier on .btn-link so padding/radius stay in one place. */
.btn-link.solid{background:var(--teal);border-color:var(--teal);color:#fff}
.btn-link.solid:hover{filter:brightness(1.07)}
/* "Send later" split button (scheduleSend.ts) — the Send action keeps its usual
   look and grows a caret opening the preset menu. Shared by the patient-file SMS
   composer and both enquiry composers so scheduling looks the same everywhere. */
.split{display:inline-flex;position:relative;vertical-align:middle}
.split>button.primary{border-radius:8px 0 0 8px}
.sched-dd>summary{list-style:none;background:var(--teal);color:#fff;border-radius:0 8px 8px 0;padding:13px 11px;font-size:16px;font-weight:700;cursor:pointer;border-left:1px solid rgba(255,255,255,.35);height:100%;display:flex;align-items:center}
.sched-dd>summary::-webkit-details-marker{display:none}
.sched-dd>summary::after{content:"▾";line-height:1}
.sched-dd>summary:hover{filter:brightness(1.07)}
.sched-dd>summary:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.sched-menu{position:absolute;z-index:60;top:calc(100% + 6px);left:0;min-width:250px;background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:0 8px 22px rgba(16,58,92,.16);padding:6px}
.sched-menu .mi{display:flex;justify-content:space-between;align-items:center;gap:14px;width:100%;text-align:left;background:none;border:0;border-radius:7px;padding:8px 10px;font-size:13.5px;font-weight:600;color:var(--ink);cursor:pointer;font-family:inherit}
.sched-menu .mi:hover{background:var(--teal-soft)}
.sched-menu .mi .when{color:#5b6b7b;font-size:12.5px;font-weight:400}
.sched-menu .mi:first-child{border-bottom:1px solid var(--line);border-radius:7px 7px 0 0;margin-bottom:4px;padding-bottom:9px}
.sched-armed{display:flex;align-items:center;gap:9px;flex-wrap:wrap;background:#fffaf0;border:1px solid #f4e3bd;border-radius:8px;padding:8px 12px;font-size:13px;margin:8px 0}
.sched-armed .icon{color:var(--warn)}
.sched-custom{margin:8px 0}
/* Practice-management action hierarchy: one obvious dark primary action at the
   top-right of a page/card, with quieter outline controls for secondary work. */
.pm-primary-action{appearance:none;background:var(--teal);border:1.5px solid var(--teal);color:#fff;border-radius:8px;padding:8px 14px;font-size:13px;font-weight:750;line-height:1.35;cursor:pointer;text-decoration:none;display:inline-flex;align-items:center;gap:5px;white-space:nowrap;box-shadow:var(--shadow-1)}
.pm-primary-action:hover{background:#0b5a53;border-color:#0b5a53;color:#fff}.pm-primary-action:disabled{opacity:.55;cursor:not-allowed}
.pm-section-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;flex-wrap:wrap;margin-bottom:10px}
.pm-section-head>.sechead{flex:1;min-width:220px}.pm-section-actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-left:auto}
/* A complete data set stays on one page but cannot grow the page indefinitely.
   The viewport owns both axes so the right scrollbar and sticky column labels
   remain visible, including on macOS where overlay scrollbars otherwise hide.
   Height GROWS WITH THE WINDOW (owner 2026-09-02: the old fixed 590px/475px/
   370px caps hid most rows on "My tasks" behind an inner scrollbar that never
   used the rest of the page). calc(100vh - Npx) — the offset is a rough budget
   for the header + page chrome above the viewport, not exact per page; a
   min-height floor keeps it usable on very short/zoomed viewports. */
.pm-list-viewport{max-height:max(280px,calc(100vh - 320px));overflow:auto;overscroll-behavior:contain;border:1px solid var(--line);border-radius:10px;background:#fff;scrollbar-gutter:stable}
.pm-list-viewport table.list{display:table;overflow:visible;border:0;border-radius:0;min-width:100%}
.pm-list-viewport table.list th{position:sticky;top:0;z-index:2;box-shadow:0 1px 0 var(--line)}
.pm-list-viewport--patient{max-height:max(240px,calc(100vh - 360px))}
/* Inbox (SMS replies, 2026-09-16): the message cell wraps in full (never
   truncated), unread rows read bold, chips + row actions sit in one wrapping
   group each. Prefixed .inbox- — grep'd for collisions. */
.inbox-toolbar{display:grid;gap:12px;margin:0 0 16px}
.inbox-filter-group{display:grid;grid-template-columns:80px minmax(0,1fr);gap:12px;align-items:start}
.inbox-filter-label{display:flex;align-items:center;min-height:44px;font-size:13px;font-weight:600;color:var(--quiet)}
.inbox-filters{display:flex;gap:8px;flex-wrap:wrap;align-items:center;min-width:0}
.inbox-source-count{font-size:12px;font-weight:400;font-variant-numeric:tabular-nums}
@media(max-width:560px){.inbox-filter-group{grid-template-columns:minmax(0,1fr);gap:6px}.inbox-filter-label{min-height:0}}
.inbox-msg{max-width:64ch}
.inbox-meta{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.inbox-who{font-weight:600}
.inbox-text{white-space:pre-wrap;overflow-wrap:anywhere;margin:4px 0 2px}
.inbox-unread .inbox-text{font-weight:700}
.inbox-when{white-space:nowrap}
.inbox-actions{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.inbox-actions form{margin:0}
@media (max-width:560px){.pm-section-head{align-items:stretch}.pm-section-actions{width:100%;margin-left:0}.pm-section-actions>.pm-primary-action{justify-content:center;flex:1}}
/* Shared filter-bar shell (item 3, 2026-09-02) — one chips row + one aligned
   row of labelled controls with a right-aligned search slot, reused by every
   admin list filter instead of each page hand-rolling its own arrangement. */
.fbar-chips{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 8px}
.fbar-row{display:flex;flex-wrap:wrap;gap:12px;align-items:center;padding:8px 10px;background:#f8fafc;border:1px solid var(--line);border-radius:8px;margin:0 0 12px}
.fbar-row label{display:flex;gap:6px;align-items:center;font-size:13px;font-weight:600;white-space:nowrap}
.fbar-search{margin-left:auto;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
@media (max-width:560px){.fbar-row{flex-direction:column;align-items:stretch}.fbar-search{margin-left:0}}
/* global patient search in the admin top bar (Gentu-style) */
.gsearch{position:relative;width:min(340px,46vw)}
.gsearch>input{width:100%;padding:8px 12px;font-size:14px;border:1px solid rgba(255,255,255,.45);border-radius:8px;background:rgba(255,255,255,.97);color:#1a2733}
.gsearch>div{position:absolute;left:0;right:0;top:calc(100% + 2px);z-index:40;background:#fff;border:1px solid #ddd;border-radius:8px;display:none;max-height:340px;overflow:auto;box-shadow:0 8px 24px rgba(0,0,0,.18)}
.gsearch>div a{display:block;padding:9px 12px;border-bottom:1px solid #f0f0f0;color:#111;text-decoration:none;font-size:14px}
.gsearch>div a:hover{background:#f0f6fb}.gsearch>div a span{color:#888}.gsearch .gnore{padding:10px;color:#888;font-size:14px}
.gsearch .ggrp{padding:7px 12px 3px;color:#5f6b70;font-size:12px;font-weight:700;border-bottom:1px solid #f0f0f0}
@media (max-width:560px){.gsearch{width:min(220px,52vw)}}
/* portal-worker status: dashboard light (green/red pill) + dismissable login toast — separate from tasks */
.worker-light{font-weight:700}.worker-light .icon{vertical-align:-.12em;margin-right:3px}
/* ── Enquiry→conversion pipeline stepper (0208) ── */
.lpipe{display:flex;align-items:flex-start;margin:8px 2px 2px;position:relative}
.lstep{flex:1;display:flex;flex-direction:column;align-items:center;text-align:center;position:relative;min-width:0}
.lstep .ldot{width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:14px;background:#fff;border:2.5px solid var(--line,#e2e8f0);color:#94a3b8;position:relative;z-index:2}
.lstep.done .ldot{background:var(--teal,#0f766e);border-color:var(--teal,#0f766e);color:#fff}
.lstep.current .ldot{border-color:var(--teal,#0f766e);color:var(--teal,#0f766e);animation:lpulse 2s infinite}
.lstep.warn .ldot{border-color:var(--warn,#b45309);color:var(--warn,#b45309)}
@keyframes lpulse{0%{box-shadow:0 0 0 0 rgba(15,118,110,.35)}70%{box-shadow:0 0 0 9px rgba(15,118,110,0)}100%{box-shadow:0 0 0 0 rgba(15,118,110,0)}}
.lbar{position:absolute;top:15px;left:calc(-50% + 16px);right:calc(50% + 16px);height:3px;background:var(--line,#e2e8f0);z-index:1;border-radius:2px;overflow:hidden}
.lstep:first-child .lbar{display:none}
.lbar i{display:block;height:100%;background:var(--teal,#0f766e);border-radius:2px;transform:scaleX(0);transform-origin:left}
.lstep.done .lbar i,.lstep.current .lbar i,.lstep.warn .lbar i{transform:scaleX(1);transition:transform .5s ease}
.lstep .llabel{font-size:11.5px;font-weight:600;margin-top:7px;line-height:1.2}
.lstep.pending .llabel{color:#94a3b8;font-weight:500}
.lstep .ldate{font-size:10.5px;color:var(--mut,#64748b);margin-top:1px;line-height:1.25}
.lstep .ldate .lauto{color:var(--teal,#0f766e)}
.lstep .lmark{margin-top:3px;font-size:10px;color:var(--teal,#0f766e);border:1px dashed #99c9c4;border-radius:6px;padding:0 6px;cursor:pointer;background:#e6f4f2;list-style:none}
.lstep .lmark::-webkit-details-marker{display:none}
.lstep details[open] .lmark{background:#d3ece9}
.lmark-pop{position:absolute;z-index:20;left:50%;transform:translateX(-50%);margin-top:4px;background:#fff;border:1px solid #cbd5e1;border-radius:8px;box-shadow:0 6px 18px rgba(15,23,42,.15);padding:8px;white-space:nowrap}
.lpipe-lost{opacity:.55}
.lhow summary{list-style:none;cursor:pointer;display:inline-flex;gap:6px;align-items:center;font-size:12px;color:var(--mut,#64748b);font-weight:600}
.lhow summary::-webkit-details-marker{display:none}
.lhow[open] summary{color:var(--teal,#0f766e)}
.lhow-b{margin-top:8px;border:1px solid var(--line,#e2e8f0);border-radius:9px;background:#fbfcfe;padding:10px 14px;max-width:640px}
.lhow-r{display:grid;grid-template-columns:120px 1fr;gap:10px;font-size:12px;padding:3px 0}
.lhow-r b{font-weight:600}
.lhow-r span{color:var(--mut,#64748b)}
/* list-view mini dots */
.pdots{display:inline-flex;gap:3px;align-items:center}
.pdots i{width:8px;height:8px;border-radius:50%;background:var(--line,#e2e8f0)}
.pdots i.on{background:var(--teal,#0f766e)}
.pdots i.cur{background:#fff;border:2px solid var(--teal,#0f766e);width:6px;height:6px}
.pdots i.warn{background:var(--warn,#b45309)}
/* ⚠ ORDER IS LOAD-BEARING. The base rule must come FIRST: both selectors are
   (0,1,0), so an unconditional .lpipe-mob display:none written AFTER the media
   query beats it at every width — which is exactly what shipped, and it meant
   the stepper hid below 640px while its mobile replacement stayed hidden too,
   so a phone got an EMPTY pipeline card. Never move the base rule below.
   (No backticks in this comment: the whole stylesheet is a template literal.) */
.lpipe-mob{display:none;margin:8px 2px}
@media(max-width:640px){.lpipe{display:none}.lpipe-mob{display:block}}
/* care pathway (0232) — same dot/step vocabulary as the lead pipeline above, but the shape
   branches, so it gets its own classes rather than overloading .lstep's linear/mobile rules */
.cp-tree{display:flex;gap:10px;align-items:flex-start;overflow-x:auto;padding:4px 2px 10px}
.cp-col{display:flex;flex-direction:column;gap:8px;min-width:200px}
.cp-colhead{font-size:11px;text-transform:uppercase;letter-spacing:.6px;padding-left:2px}
.cp-cell{display:flex;flex-direction:column;gap:2px}
.cp-node{display:block;border:1px solid var(--line);border-radius:10px;padding:8px 10px;background:#fff;text-decoration:none;color:inherit}
.cp-node:hover{border-color:var(--teal)}
.cp-node.cp-sel{border-color:var(--teal);box-shadow:0 0 0 2px var(--navy-soft)}
.cp-kind{display:flex;align-items:center;gap:6px;font-size:10px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted)}
.cp-label{display:block;margin:2px 0;font-weight:600;font-size:14px}
.cp-meta{display:flex;gap:8px;align-items:center;font-size:12px;color:var(--muted)}
.cp-clip{margin-left:auto}
.cp-dot{width:10px;height:10px;border-radius:50%;display:inline-block;flex:0 0 auto}
.cp-planned{background:var(--line)}.cp-ordered{background:var(--warn)}.cp-result_in{background:var(--info)}.cp-reviewed{background:var(--ok)}
.cp-join{font-size:11px;color:var(--muted);padding-left:4px}
.cp-layout{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:12px;align-items:start}
@media(max-width:900px){.cp-layout{grid-template-columns:1fr}}
.cp-panel-head{display:flex;justify-content:space-between;align-items:baseline;gap:8px}
.cp-inline{display:inline-flex;gap:8px;align-items:flex-end;flex-wrap:wrap;margin:0 0 8px}
.cp-inline label{display:flex;flex-direction:column;font-size:12px;gap:2px}
.cp-actions{display:flex;gap:8px;flex-wrap:wrap;margin:8px 0}
.cp-actions form{margin:0}
.cp-add{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;border-top:1px solid var(--line);margin-top:10px;padding-top:10px}
.cp-add label{display:flex;flex-direction:column;font-size:12px;gap:2px}
.cp-docs{list-style:none;padding:0;margin:4px 0}
.cp-docs li{display:flex;gap:8px;align-items:center;padding:2px 0}
.cp-also{border:1px solid var(--line);border-radius:8px;padding:6px 10px;margin:6px 0}
.cp-also legend{font-size:11px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);padding:0 4px}
.cp-also label{display:flex;gap:6px;align-items:center;font-size:13px;padding:1px 0}
.cp-tags{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.cp-list{margin:4px 0;padding-left:18px}
.cp-kanban{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}
@media(max-width:900px){.cp-kanban{grid-template-columns:1fr 1fr}}
.cp-kcol h3{font-size:12px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);margin:0 0 6px}
.cp-kcol .cp-node{margin-bottom:6px}
.cp-canvas-bar{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin-bottom:6px}
#cp-canvas{background:#fff;border:1px solid var(--line);border-radius:10px;touch-action:none;user-select:none}
.cp-gnode .cp-gcard{fill:#fff;stroke:var(--line);stroke-width:1.5}
.cp-gnode.cp-gsrc .cp-gcard{stroke:var(--teal);stroke-width:2.5;stroke-dasharray:4 3}
.cp-gnode text{font-size:12px;fill:var(--navy);pointer-events:none}
.cp-gnode .cp-glabel{font-weight:600}
.cp-gnode text.cp-gkind{font-size:9px;text-transform:uppercase;letter-spacing:.5px}
.cp-k-pathology .cp-gband,.cp-k-pathology .cp-gkind{fill:var(--cpk-pathology)}
.cp-k-radiology .cp-gband,.cp-k-radiology .cp-gkind{fill:var(--cpk-radiology)}
.cp-k-procedure .cp-gband,.cp-k-procedure .cp-gkind{fill:var(--cpk-procedure)}
.cp-k-consult .cp-gband,.cp-k-consult .cp-gkind{fill:var(--cpk-consult)}
.cp-k-other .cp-gband,.cp-k-other .cp-gkind{fill:var(--cpk-other)}
.cp-spill{rx:6px}.cp-spill-planned{fill:var(--line)}.cp-spill-ordered{fill:var(--warn)}
.cp-spill-result_in{fill:var(--info)}.cp-spill-reviewed{fill:var(--ok)}
.cp-gnode text.cp-spilltxt{font-size:8px;letter-spacing:.4px;fill:#fff}.cp-gnode text.cp-spilltxt-planned{fill:var(--navy)}
.cp-due{fill:var(--navy-soft)}.cp-due.cp-odue{fill:var(--err)}
.cp-gnode text.cp-duetxt{font-size:8px;fill:var(--navy)}.cp-gnode text.cp-duetxt.cp-odue{fill:#fff}
.cp-gnode text.cp-gmeta{font-size:9px;fill:var(--navy);opacity:.6}
a.cp-node{border-left-width:4px}
a.cp-node.cp-k-pathology{border-left-color:var(--cpk-pathology)}
a.cp-node.cp-k-radiology{border-left-color:var(--cpk-radiology)}
a.cp-node.cp-k-procedure{border-left-color:var(--cpk-procedure)}
a.cp-node.cp-k-consult{border-left-color:var(--cpk-consult)}
a.cp-node.cp-k-other{border-left-color:var(--cpk-other)}
.cp-canvas-wrap{position:relative}
.cp-addpop{position:absolute;background:#fff;border:1px solid var(--line);border-radius:10px;padding:10px 12px;box-shadow:var(--shadow-2);display:none;flex-direction:column;gap:6px;z-index:5;min-width:220px}
.cp-addpop label{display:flex;flex-direction:column;font-size:12px;gap:2px}
.cp-minimap{position:absolute;right:14px;bottom:14px;background:#fff;border:1px solid var(--line);border-radius:8px;opacity:.92;cursor:pointer}
.cp-minimap .cp-mmn{fill:var(--navy-soft-line)}
.cp-minimap .cp-mmv{fill:none;stroke:var(--teal);stroke-width:1.5}
.cp-canvas-wrap:fullscreen{background:#fff;padding:12px;overflow:auto}
.cp-canvas-wrap:fullscreen #cp-canvas{height:calc(100vh - 70px)}
path.cp-edge{stroke:var(--line);stroke-width:2;fill:none;marker-end:url(#cp-arr);cursor:pointer}
#cp-arr path{fill:var(--line)}
path.cp-edge:hover{stroke:var(--err);stroke-width:2.5}
path.cp-hit{stroke:transparent;stroke-width:14;marker-end:none}
.cp-duein{display:flex;gap:6px;align-items:center}
.cp-duein input{width:70px}
.cp-inline input,.cp-inline select,.cp-add input,.cp-add select{height:36px;box-sizing:border-box}
.cp-inline .btn-link,.cp-add .btn-link{height:36px;display:inline-flex;align-items:center}
.cp-footrow{display:flex;gap:20px;align-items:flex-end;flex-wrap:wrap}
.cp-footrow .cp-inline{margin:0}
.cp-tick{margin:2px 0 6px}
.cp-tick .btn-link{color:var(--ok);font-weight:600;padding:0}
.cp-kcol .cp-tick{margin:-2px 0 8px 2px}
/* clinical workspace (2026-07-27): one context switcher shared by the Encounter Hub and the
   care-pathway page, plus the compact pathway summaries that replaced the mini diagrams. */
.cws-nav{display:flex;flex-wrap:wrap;gap:6px 14px;align-items:center;padding:8px 0;margin:0 0 4px;border-bottom:1px solid var(--line);font-size:13px}
.cws-link,.cws-current{display:inline-flex;align-items:center;gap:6px;padding:3px 2px}
.cws-current{color:var(--muted);font-weight:600}
.cws-link{color:var(--teal);text-decoration:none}
.cws-link:hover{text-decoration:underline}
.cws-primary{font-weight:600}
.cp-summary-rows{display:flex;flex-direction:column;gap:2px;margin:6px 0 10px}
.cp-summary-row{display:grid;grid-template-columns:minmax(160px,1.2fr) minmax(160px,1.4fr) minmax(140px,1fr) auto;gap:10px;align-items:center;padding:10px 2px;border-top:1px solid var(--line)}
.cp-summary-row:first-child{border-top:0}
.cp-summary-id{display:flex;flex-direction:column;gap:2px}
.cp-summary-id a{font-weight:600;text-decoration:none}
.cp-summary-id .muted{font-size:12px}
.cp-summary-prog{display:flex;flex-direction:column;gap:5px;font-size:12px}
.cp-summary-next{display:flex;gap:8px;align-items:center;flex-wrap:wrap;font-size:13px}
.cp-summary-act{justify-self:end}
.cp-progress{height:4px;border-radius:2px;background:var(--line);overflow:hidden}
.cp-progress span{display:block;height:100%;background:var(--ok)}
.cp-summary{display:flex;gap:10px;align-items:baseline;flex-wrap:wrap}
.cp-starters{display:flex;flex-wrap:wrap;gap:8px;margin:6px 0}
.cp-starters .cp-start{margin:0}
.cp-starters .btn-link{border:1px solid var(--line);border-radius:8px;padding:6px 10px}
.cp-starters .btn-link:hover{border-color:var(--teal)}
.cp-custom{margin-top:6px}
.enc-idbar{position:sticky;top:0;z-index:4}
.enc-pathways{margin-bottom:10px}
.enc-pathways-panel{margin-top:8px}
.enc-pathways-panel>summary{cursor:pointer;font-weight:600}
.cp-wsplan{padding:8px 0;border-top:1px solid var(--line)}
.cp-wsplan h3{font-size:14px;margin:0 0 6px;display:flex;gap:8px;align-items:baseline;flex-wrap:wrap}
.cp-wsplan h3 .muted{font-weight:400;font-size:12px}
.cp-wssteps{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}
.cp-wsstep{display:grid;grid-template-columns:minmax(90px,auto) minmax(140px,1.4fr) minmax(120px,auto) auto;gap:8px;align-items:center;padding:6px 2px;border-top:1px solid var(--line)}
.cp-wsstep:first-child{border-top:0}
.cp-wsacts{display:flex;gap:8px;align-items:center;flex-wrap:wrap;justify-self:end}
.cp-wsact{display:inline-flex;gap:4px;align-items:center;margin:0}
.cp-wsdue{gap:2px;font-size:12px}
.cp-wsfoot{display:flex;gap:14px;flex-wrap:wrap;margin:8px 0 0}
.cp-consult-events .cp-list{margin:6px 0 0}
@media(max-width:700px){
  .cp-summary-row,.cp-wsstep{grid-template-columns:1fr;align-items:start}
  .cp-summary-act,.cp-wsacts{justify-self:start}
}
@media(prefers-reduced-motion:reduce){.enc-pathways-panel,.cp-progress span{transition:none}}
@media print{.cws-nav,.enc-pathways-panel,.cp-wsacts,.cp-starters{display:none}}
.worker-toast{position:fixed;top:64px;right:16px;z-index:1000;display:flex;gap:10px;align-items:flex-start;max-width:min(380px,calc(100vw - 32px));background:#fffaf5;color:#7a2e0e;border:1px solid #f0d3a6;border-radius:10px;padding:12px 12px 12px 14px;box-shadow:0 8px 28px rgba(16,58,92,.18);font-size:14px;line-height:1.45}
/* header worker-status icon — hidden until /admin/worker-status reports a problem;
   click re-opens the popup any time (the popup itself auto-shows once per session) */
.wt-ico{display:none;background:none;border:0;cursor:pointer;padding:4px;border-radius:8px;color:var(--warn);position:relative}
.wt-ico.on{display:inline-flex;align-items:center}
.wt-ico.is-critical{color:var(--err)}
.wt-ico:hover{background:rgba(255,255,255,.12)}
.wt-ico .wt-dot{position:absolute;top:2px;right:2px;width:8px;height:8px;border-radius:50%;background:var(--warn);border:1.5px solid #12314e}
.wt-ico.is-critical .wt-dot{background:var(--err)}
.worker-toast.is-critical{background:#fff5f4;color:#7a271a;border-color:var(--err);border-left-color:var(--err)}
.worker-toast .icon{flex:none;color:var(--warn);margin-top:1px}.worker-toast.is-critical .icon{color:var(--err)}
.worker-toast .wt-body{flex:1;min-width:0}.worker-toast .wt-msg{margin:0 0 4px;font-weight:700}
.worker-toast .wt-link{color:inherit;font-weight:700;font-size:13px}
.worker-toast .wt-x{flex:none;background:none;border:0;cursor:pointer;color:inherit;font-size:16px;line-height:1;padding:2px 4px;opacity:.7;border-radius:6px}
.worker-toast .wt-x:hover{opacity:1}.worker-toast .wt-x:focus-visible{outline:2px solid currentColor;outline-offset:2px}
@media (prefers-reduced-motion:no-preference){.worker-toast{animation:wt-in .18s ease-out}}
@keyframes wt-in{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
.sent-toast{position:fixed;top:64px;right:16px;z-index:1001;display:flex;gap:8px;align-items:center;max-width:min(340px,calc(100vw - 32px));background:#f0faf4;color:#14532d;border:1px solid #b5e3c8;border-radius:10px;padding:10px 12px;box-shadow:0 8px 28px rgba(16,58,92,.18);font-size:14px;font-weight:700;line-height:1.4}
.sent-toast .icon{flex:none;color:#15803d}
.sent-toast .st-x{flex:none;background:none;border:0;cursor:pointer;color:inherit;font-size:15px;line-height:1;padding:2px 4px;opacity:.7;border-radius:6px}
.sent-toast .st-x:hover{opacity:1}.sent-toast .st-x:focus-visible{outline:2px solid currentColor;outline-offset:2px}
@media (prefers-reduced-motion:no-preference){.sent-toast{animation:wt-in .18s ease-out}}
/* Staff-tasks bulk-action bar — floats bottom-centre, reactive (shown only when
   1+ tasks ticked, via the form hidden attr toggled in bulkBar's JS). Fixed so
   it escapes the .pm-list-viewport overflow clip; z-index 50 sits above content +
   sticky table headers (z2) but below the mobile nav drawer (55/60), the task
   modal (230) and toasts (1000+), so none of those get covered. */
.bulk-float{position:fixed;left:50%;bottom:18px;transform:translateX(-50%);z-index:50;display:flex;gap:10px;flex-wrap:wrap;align-items:center;justify-content:center;margin:0;padding:10px 16px;max-width:calc(100vw - 20px);background:#eef6fb;border:1px solid #b8cfdf;border-radius:12px;box-shadow:0 8px 28px rgba(16,58,92,.22)}
.bulk-float[hidden]{display:none}
@media (prefers-reduced-motion:no-preference){.bulk-float:not([hidden]){animation:bulkfloat-in .18s ease-out}}
@keyframes bulkfloat-in{from{opacity:0;transform:translate(-50%,14px)}to{opacity:1;transform:translate(-50%,0)}}
/* queue keys (U8, src/bulkSelect.ts queueKeysScript): the j/k current row and the ? list */
tr.qk-cur{outline:2px solid var(--teal);outline-offset:-2px}tr.qk-cur>td{background:var(--teal-soft)}
.qk-help{position:fixed;right:18px;bottom:18px;z-index:51;width:270px;max-width:calc(100vw - 32px);padding:12px 14px;background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:0 8px 28px rgba(16,58,92,.22);font-size:13px}
.qk-help[hidden]{display:none}.qk-help dl{display:grid;grid-template-columns:auto 1fr;gap:5px 10px;margin:8px 0 0}.qk-help dt{white-space:nowrap}.qk-help dd{margin:0}
.qk-help kbd{font:12px ui-monospace,SFMono-Regular,Menlo,monospace;padding:0 5px;border:1px solid var(--line);border-radius:4px;background:var(--bg)}
footer{max-width:760px;margin:0 auto;padding:0 16px 40px;color:#5b6b7b;font-size:13px}
/* global keyboard focus ring (A2) */
:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
/* mobile: stack form rows (A1) */
@media (max-width:560px){.row{flex-direction:column;gap:0}}
/* Wide admin tables get their OWN horizontal scroll container at ALL widths, so a
   table wider than its (shrunken) column scrolls instead of bleeding rightward under
   a sticky column and being clipped by body{overflow-x:hidden} — the owner-reported
   Bookings-vs-Send-a-link overlap, 2026-07-05. Was mobile-only. fixed-layout tables
   (.fixedcols: month grid, invoice line-items) keep their own overflow-x wrappers. */
/* width:100% explicit here too (owner 2026-09-02, C3 follow-up): the base
   table.list rule already carries it, but display:block is what actually
   drives this table's box — restate width on the SAME rule that sets display
   so a table narrower than its card (a short column set) still stretches to
   fill it instead of shrink-wrapping its content. */
table.list:not(.fixedcols){display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%}
@media (max-width:760px){table.list:not(.fixedcols){white-space:nowrap}}
/* Patient search results must escape the lead conversion table's scroll/clipping box. */
table.list.lcv-table{display:table;overflow:visible}
.lcv-patient-cell{min-width:260px}
.lcv-mobile-label{display:none}
@media (max-width:760px){
  table.list.lcv-table{display:block;white-space:normal}
  .lcv-table tbody,.lcv-table tr.lcv-row,.lcv-table td{display:block}
  .lcv-table tr:first-child{display:none}
  .lcv-table tr.lcv-row{border-top:1px solid var(--line)}
  .lcv-table td{border-top:0}
  .lcv-table .lcv-patient-cell{min-width:0}
  .lcv-mobile-label{display:block;margin-bottom:4px;color:var(--quiet,#526069);font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}
}
/* Visible scrollbars (V5, owner 2026-07-07): macOS hides overlay scrollbars when
   idle, so a wide table/box that already scrolls looked like it was just clipped
   — with no h-scroll mouse the owner couldn't reach the off-screen content. Force
   a PERMANENT bar on every already-scrolling box (tables, .scrollx, inline
   overflow-x wrappers) + always-reserve the vertical page gutter. body's
   overflow-x:hidden stays (removing it re-introduces the bleed); the per-box bars
   surface the hidden horizontal content. No layout change — sticky sidebar/pfnav
   untouched. */
html{overflow-y:scroll}
table.list, .scrollx, [style*="overflow-x:auto"], [style*="overflow:auto"]{scrollbar-width:auto;scrollbar-color:#9aa7b4 transparent}
table.list::-webkit-scrollbar, .scrollx::-webkit-scrollbar, [style*="overflow-x:auto"]::-webkit-scrollbar, [style*="overflow:auto"]::-webkit-scrollbar{height:12px;width:12px;-webkit-appearance:none}
table.list::-webkit-scrollbar-thumb, .scrollx::-webkit-scrollbar-thumb, [style*="overflow-x:auto"]::-webkit-scrollbar-thumb, [style*="overflow:auto"]::-webkit-scrollbar-thumb{background:#b7c3cf;border-radius:8px;border:3px solid transparent;background-clip:content-box}
table.list::-webkit-scrollbar-track, .scrollx::-webkit-scrollbar-track, [style*="overflow-x:auto"]::-webkit-scrollbar-track, [style*="overflow:auto"]::-webkit-scrollbar-track{background:transparent}
.scrollx{overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%}
/* ── UX helper layer (Wave 1): icons · info tooltips · section headers · help text ── */
.icon{display:inline-block;vertical-align:-.14em;flex:none}
.icon.i-ok{color:var(--ok)}.icon.i-warn{color:var(--warn)}.icon.i-bad{color:var(--err)}.icon.i-muted{color:#5b6b7b}
/* honest status-icon rail (V3): fixed slots line up down a list; an unreached
   slot is a faint outline (si-off) so columns stay aligned. */
.staticon-row{display:inline-flex;gap:5px;align-items:center}
.staticon-row .si-slot{display:inline-flex;line-height:0}
.staticon-row .icon.si-off{color:#c7d0d9;opacity:.5}
.btn-link .icon,button.primary .icon,.adminnav .icon{margin-right:5px;vertical-align:-.12em}button.primary .icon{color:#fff}
.pill .icon{vertical-align:-.12em;margin-right:3px}
/* CSS-only accessible info tooltip — shows on hover + keyboard focus + tap, no JS.
   Opens BELOW the icon: most (i) icons sit beside page/section headings near the
   viewport top, where an upward tooltip clips off-screen (UI audit 2026-07-12 —
   confirmed on 5+ pages). Below can always be scrolled to; above the fold cannot. */
.info{position:relative;display:inline-flex;vertical-align:middle}
.info-t{appearance:none;background:none;border:0;padding:0 2px;margin:0;color:var(--teal);cursor:help;line-height:1;display:inline-flex}
.info-t:focus-visible{outline:2px solid var(--teal);outline-offset:2px;border-radius:4px}
.au-workspace button:not(.info-t):not(.primary):not(.pm-primary-action){background:#fff;border:1.5px solid var(--teal);color:var(--teal);border-radius:8px;padding:9px 14px;font:inherit;font-weight:600;min-height:44px;cursor:pointer}.au-workspace button:disabled{opacity:.5;cursor:not-allowed}.au-workspace .info-t{min-width:44px;min-height:44px;align-items:center;justify-content:center}.au-workspace input,.au-workspace textarea,.au-workspace select{max-width:100%;box-sizing:border-box}.au-workspace form+form{margin-top:12px}
.au-info{display:inline-flex;vertical-align:middle}.au-info .info-t{min-width:44px;min-height:44px;align-items:center;justify-content:center}
.info-b{position:absolute;top:calc(100% + 8px);left:50%;transform:translateX(-50%);z-index:50;min-width:160px;max-width:min(280px,80vw);background:var(--navy);color:#fff;font-size:12.5px;font-weight:400;line-height:1.45;text-align:left;white-space:normal;word-break:break-word;overflow-wrap:break-word;padding:8px 10px;border-radius:8px;box-shadow:0 4px 14px rgba(16,58,92,.25);opacity:0;visibility:hidden;transition:opacity .12s ease;pointer-events:none}
.info-b::after{content:"";position:absolute;bottom:100%;left:50%;transform:translateX(-50%);border:6px solid transparent;border-bottom-color:var(--navy)}
.info:hover .info-b,.info:focus-within .info-b{opacity:1;visibility:visible}
.info-r .info-b{left:auto;right:0;transform:none}.info-r .info-b::after{left:auto;right:10px;transform:none}
@media (max-width:560px){.info-b{max-width:78vw}.info-t{padding:2px 4px}}
/* iconed section header + descriptor */
.sechead{margin:0 0 12px}.sechead h2{display:flex;align-items:center;gap:8px}.sechead h2 .icon{color:var(--navy);flex:none}.card>.sechead:first-child{margin-top:0}
/* descriptor / help text under a control or heading */
.help{color:#5b6b7b;font-size:12.5px;line-height:1.4;margin:4px 0 0}label+.help{margin-top:-2px;margin-bottom:6px}
/* two-way SMS messenger thread (Wave D): outbound right (teal), inbound left (white) */
.msgthread{max-height:340px;overflow-y:auto;display:flex;flex-direction:column;gap:8px;padding:10px;background:#f8fafc;border:1px solid var(--line);border-radius:10px}
.bubble{max-width:82%;padding:8px 11px;border-radius:13px;font-size:13.5px;line-height:1.42;white-space:pre-wrap;word-break:break-word}
.bubble.out{align-self:flex-end;background:var(--teal);color:#fff;border-bottom-right-radius:4px}
.bubble.in{align-self:flex-start;background:#fff;border:1px solid var(--line);border-bottom-left-radius:4px}
.bubble .b-meta{display:block;margin-top:4px;font-size:11px;opacity:.85}
.bubble.in .b-meta{color:#5b6b7b}
/* Not sent yet: a "send later" message waiting on its release time. Dashed +
   amber so it never reads as part of the sent conversation. */
.bubble.out.sched{background:#fffaf0;color:var(--ink);border:1.5px dashed #eab308}
.bubble.out.sched .b-meta{color:var(--warn);opacity:1}
.bubble.out.sched .btn-link{border-color:var(--warn);color:var(--warn);background:transparent}
/* SMS | Email pane switch on the same messenger (0439) — underline tabs, the
   house tab idiom (design-language §8), never a solid fill */
.chan-seg{display:flex;gap:2px;border-bottom:1px solid var(--line);margin:0 0 10px}
.chan-tab{background:transparent;border:0;border-bottom:2px solid transparent;color:#5b6b7b;padding:7px 13px;font:inherit;font-size:13.5px;cursor:pointer;display:inline-flex;align-items:center;gap:6px;border-radius:7px 7px 0 0;margin-bottom:-1px}
.chan-tab:hover{color:var(--ink);background:#f1f5f9}.chan-tab[aria-selected="true"]{color:var(--ink);border-bottom-color:var(--teal);font-weight:700}
.chan-tab:focus-visible{outline:2px solid var(--teal);outline-offset:-2px}
.chan-n{font-size:11px;background:#fef3c7;color:#92400e;border-radius:999px;padding:0 6px;font-weight:700;font-variant-numeric:tabular-nums}
/* email pane: stacked notes, not chat bubbles */
.ethread{max-height:460px}
.enote{border:1px solid var(--line);border-radius:10px;padding:8px 12px;background:#fff;font-size:13.5px}
.enote.out{background:#f8fafc}
.enote.out.sched{background:#fffaf0;border:1.5px dashed #eab308}
.enote.sys{padding:6px 12px;background:#f8fafc}.enote.sys summary{cursor:pointer;font-size:12.5px;color:#5b6b7b;display:flex;gap:8px;align-items:center;flex-wrap:wrap;list-style:none}
.enote.sys summary::before{content:"▸";font-size:11px}.enote.sys[open] summary::before{content:"▾"}.enote.sys .enote-body{color:#5b6b7b;font-size:13px}
.enote-meta{display:flex;gap:8px;align-items:center;flex-wrap:wrap;font-size:12px;color:#5b6b7b}.enote-meta strong{color:var(--navy)}
.enote-actions{margin-left:auto;display:inline-flex;gap:4px}
.enote-subj{font-weight:600;font-size:13px;margin-top:2px}.enote-body{white-space:pre-wrap;margin-top:4px;word-break:break-word}
.erow{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.echip{display:inline-flex;align-items:center;gap:6px;background:#eef4f8;border-radius:999px;padding:2px 6px 2px 10px;font-size:12.5px;color:#41566b}
.eform input.locked{background:#f1f5f9;color:#41566b}
.esig{margin-top:6px}.esigbody{margin-top:6px;padding:8px 10px;border:1px solid var(--line);border-radius:8px;background:#fafcfd;font-size:12.5px;overflow-x:auto}
/* ── left-sidebar admin shell (Wave 3 Phase A; opt-in via layout adminActive) ── */
.ashell{display:flex;align-items:flex-start;min-height:calc(100vh - 52px)}
/* The rail is a VIEWPORT-height flex column so .navfoot (Staff Overview /
   Settings / help) pins to the bottom of the screen. It must NOT be
   align-self:stretch — .ashell is align-items:flex-start, so stretch makes
   the rail as tall as the MAIN CONTENT, which would push the footer thousands of
   pixels below the fold on a long list. Scrolling is scoped to :not(.collapsed):
   the collapsed rail's hover tooltips are positioned OUTSIDE it
   (left:calc(100% + 10px)), and a scroll container would clip every one. */
.asidebar{flex:none;width:210px;align-self:flex-start;height:100vh;display:flex;flex-direction:column;background:#fbfcfe;border-right:1px solid var(--line);padding:14px 10px;position:sticky;top:0}
.asidebar:not(.collapsed){overflow-y:auto}
.navfoot{margin-top:auto;border-top:1px solid var(--line);padding-top:6px}
/* Discreet orientation link — quiet by default, legible on hover/focus. */
.asidebar a.navhelp{color:#7b8a97;font-size:12.5px;font-weight:600;padding:7px 11px}
.asidebar a.navhelp:hover,.asidebar a.navhelp:focus-visible{color:var(--navy);background:#eef4f9}
.asidebar a{display:flex;align-items:center;gap:9px;color:#41566b;text-decoration:none;font-size:14px;font-weight:600;padding:9px 11px;border-radius:8px;margin:2px 0;line-height:1.2}
.asidebar a .icon{flex:none;color:inherit}
.asidebar a:hover{background:#eef4f9;color:var(--navy)}
.asidebar a[aria-current=page]{background:var(--teal-soft);color:var(--navy);font-weight:800;box-shadow:inset 3px 0 0 var(--teal)}
.navbadge{margin-left:auto;background:#e53e3e;color:#fff;font-size:11px;font-weight:800;line-height:1;padding:3px 7px;border-radius:999px}
/* ── "Needs action" strip (owner 2026-08-23) — the ONE place queue counts live.
   A row renders only while its queue has work (or it is the current page), so
   the rail stays short on a clear day. Red badge = money/decision waiting;
   .soft = routine count. Neutral 1px container per design-language — the
   badges carry the urgency, the container does not shout. */
.navstrip{margin:2px 0 4px;padding:3px;border:1px solid var(--line);border-radius:10px;background:#fff}
.navstrip a{padding:6px 9px;font-size:13.5px;margin:1px 0;border-radius:7px}
.navstrip .navbadge.soft{background:#eef2f6;color:#41566b}
.ns-clear{display:flex;align-items:center;gap:7px;margin:2px 0 4px;padding:7px 10px;border:1px solid var(--line);border-radius:10px;background:#fff;color:var(--teal,#0f766e);font-size:13px;font-weight:700}
.ns-clear .icon{flex:none}
/* Conversation @mention picker (thread composer). Unpicked = quiet outline;
   picked = filled teal (house style: teal is the action colour) with a ✓, so
   "I have told Gail" is readable at a glance instead of being guessed from the
   textarea text. aria-pressed carries the same state for screen readers. */
.mention-pick{background:#fff;border:1px solid var(--line);border-radius:999px;padding:3px 10px;font:inherit;font-size:12.5px;line-height:1.3;color:var(--navy);cursor:pointer}
.mention-pick:hover{border-color:var(--teal,#0f766e);color:var(--teal,#0f766e)}
.mention-pick:focus-visible{outline:2px solid var(--teal,#0f766e);outline-offset:2px}
.mention-pick[aria-pressed=true]{background:var(--teal,#0f766e);border-color:var(--teal,#0f766e);color:#fff;font-weight:700}
/* \2713 = ✓. The doubled backslash is for the TS template literal, not CSS —
   the stylesheet receives a single one. */
.mention-pick[aria-pressed=true]::before{content:"\2713 ";font-weight:700}
/* @mention pills INSIDE the composer field (owner 2026-09-17: "I want the actual
   name of the user to be a pill WITHIN the conversation box"). A backdrop mirror
   sits BEHIND a transparent-background field and repaints the same text with the
   resolvable @tokens wrapped in a .mention-tok mark; only the mark's BOX paints
   (the backdrop's own text is transparent), so what you read is still the real
   field's text, in the field's own colour, with a real caret and selection.
   .mention-on is added by JS once the backdrop exists — with JS off the field is
   untouched. .mention-tok is shared with the SENT message (thread bubble, scratch
   row) so a mention looks the same before and after Send. */
.mention-wrap{position:relative;display:block}
/* display:block, not the field's default inline-block: a line box under an
   inline-block field makes the WRAPPER ~3px taller than the field, and the
   backdrop (inset:0) inherits that — so a scrolled textarea's last line sat
   3px out of register. */
.mention-wrap>textarea,.mention-wrap>input{position:relative;z-index:1;display:block}
.mention-wrap.mention-on>textarea,.mention-wrap.mention-on>input{background:transparent}
.mention-bd{position:absolute;inset:0;z-index:0;margin:0;color:transparent;pointer-events:none;overflow:hidden}
.mention-tok{background:var(--teal-soft);border:1px solid var(--teal);border-radius:999px;padding:1px 4px;-webkit-box-decoration-break:clone;box-decoration-break:clone}
.bubble .mention-tok,.sp-text .mention-tok{color:var(--teal);font-weight:700}
/* Solid-teal outbound bubble: a white FILL would lift the ground and drop the
   bubble's white body text under 4.5:1, so the pill is a ring there. */
.bubble.out .mention-tok{background:transparent;border-color:rgba(255,255,255,.8);color:#fff}
/* In the backdrop the negative margin cancels the pill's own padding+border
   (-5 +1 +4 = 0 per side), so a pill can never move the text it sits behind. */
.mention-bd .mention-tok{color:transparent;margin:0 -5px}
/* header notifications bell — badge sits top-right of the icon */
.notifbell{position:relative;display:inline-flex;align-items:center;color:var(--navy);text-decoration:none;padding:4px}
.notifbell:hover{color:var(--teal)}
/* On the navy site header the bell/help icons were navy-on-navy (invisible,
   owner 2026-07-14) — light them up there; the red badge already reads. */
header.site .notifbell{color:#dbe7f2}
header.site .notifbell:hover{color:#fff}
.notifbell:focus-visible{outline:2px solid var(--teal);outline-offset:2px;border-radius:6px}
.notifbell .navbadge{position:absolute;top:-3px;right:-3px;margin-left:0;padding:2px 5px;font-size:10px}
button.notifbell{background:none;border:0;cursor:pointer;font:inherit}
/* header notifications dropdown (tray) — mirrors the worker-toast surface */
.notifpanel{position:fixed;top:60px;right:16px;z-index:1001;width:min(360px,calc(100vw - 24px));max-height:min(72vh,540px);display:flex;flex-direction:column;background:#fff;color:var(--navy);border:1px solid #d9e2ec;border-radius:12px;box-shadow:0 10px 30px rgba(16,58,92,.22);overflow:hidden;font-size:14px}
.notifpanel[hidden]{display:none}
.notifpanel .np-head{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 12px;border-bottom:1px solid #eef2f6}
.notifpanel .np-head strong{font-size:14px}
.notifpanel .np-bulk{background:none;border:0;color:var(--navy);font-weight:600;cursor:pointer;font-size:13px;padding:4px 6px;border-radius:6px}
.notifpanel .np-bulk:disabled{color:#b6c1cc;cursor:default}
.notifpanel .np-bulk:not(:disabled):hover{color:var(--err)}
.notifpanel .np-list{list-style:none;margin:0;padding:0;overflow-y:auto;flex:1}
.notifpanel .np-row{display:flex;align-items:flex-start;gap:8px;padding:10px 12px;border-bottom:1px solid #f2f5f8}
.notifpanel .np-row:last-child{border-bottom:0}
.notifpanel .np-sel{flex:none;margin-top:4px}
.notifpanel .np-dot{flex:none;width:8px;height:8px;border-radius:50%;margin-top:5px;background:var(--warn)}
.notifpanel .np-row.sev-critical .np-dot{background:var(--err)}
.notifpanel .np-row.sev-info .np-dot{background:var(--teal)}
.notifpanel .np-row.read .np-dot{background:#c7d0d9}
.notifpanel .np-main{flex:1;min-width:0}
.notifpanel .np-title{display:block;color:var(--navy);text-decoration:none;font-weight:600;line-height:1.35;overflow-wrap:anywhere}
.notifpanel .np-row.read .np-title{font-weight:400;color:#5a6b7b}
.notifpanel a.np-title:hover{color:var(--teal);text-decoration:underline}
.notifpanel .np-meta{color:#8a97a3;font-size:12px;margin-top:2px}
/* patient chip on a tray row (2026-08-25 — the bell may name patients);
   resolved at render, links to the patient file */
.notifpanel .np-pt{white-space:nowrap;font-size:12px;font-weight:400;color:var(--teal);text-decoration:none}
.notifpanel a.np-pt:hover{text-decoration:underline}
.notifpanel .np-x{flex:none;background:none;border:0;cursor:pointer;color:#9aa6b2;font-size:15px;line-height:1;padding:2px 5px;border-radius:6px}
.notifpanel .np-x:hover{color:var(--err);background:#fbeaea}
/* conversation alerts (task/lead replies + scratch mentions) — section header + a
   ✓ mark-read control (never a "complete"; that's a board action). */
.notifpanel .np-sub{padding:7px 12px 3px;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:#8a97a3;background:#fafcfe;list-style:none}
.notifpanel .np-read{flex:none;background:none;border:0;cursor:pointer;color:var(--teal);font-size:15px;line-height:1;padding:2px 6px;border-radius:6px}
.notifpanel .np-read:hover{color:#0b5a53;background:#e9f6f3}
.notifpanel .np-convo .np-dot{background:var(--teal)}
.notifpanel .np-empty{padding:26px 16px;text-align:center;color:#8a97a3;list-style:none}
.notifpanel .np-foot{padding:9px 12px;border-top:1px solid #eef2f6;background:#fafcfe}
.notifpanel .np-foot a{color:var(--navy);font-weight:600;font-size:13px}
@media (prefers-reduced-motion:no-preference){.notifpanel{animation:wt-in .16s ease-out}}
.asidebar a:focus-visible{outline:2px solid var(--teal);outline-offset:1px}
/* grouped sidebar: a small uppercase label introduces each functional block */
.asidebar .navgroup{color:#8a97a3;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.07em;padding:13px 11px 3px;margin:0;line-height:1.2}
.asidebar .navgroup:first-child{padding-top:2px}
/* Care Coordination hub: parent links to the hub page; children fly out on hover/focus */
/* Click-expand nav groups (owner 2026-07-10): the chevron BUTTON toggles an
   inline sub-list; no hover fly-outs (they were unreachable by touch). */
.navhub{position:relative}
.navhub-row{display:flex;align-items:stretch}
.navhub-row>.navhub-parent{flex:1;min-width:0}
.navhub-toggle{flex:none;display:inline-flex;align-items:center;justify-content:center;width:26px;border:0;background:transparent;color:#7b8a97;cursor:pointer;border-radius:8px;margin:2px 0}
.navhub-toggle:hover,.navhub-toggle:focus-visible{background:#eef4f9;color:var(--navy)}
.navhub-caret{display:inline-block;opacity:1;font-weight:900;font-size:19px;line-height:1;transition:transform .15s}
.navhub.open .navhub-caret{transform:rotate(90deg)}
.navhub-parent.cc-active{background:var(--teal-soft);color:var(--navy);font-weight:800;box-shadow:inset 3px 0 0 var(--teal)}
/* Animated disclosure: the 0fr→1fr grid track is the one way to transition to
   "auto" height without JS measurement. visibility is paired with it because a
   0fr row still renders its links into the TAB ORDER — without it a closed
   submenu is invisible but keyboard-focusable. Never give .navhub-sub vertical
   padding: padding does not collapse with the track and would leave a gap. */
.navhub-sub{display:grid;grid-template-rows:0fr;visibility:hidden;padding-left:14px;transition:grid-template-rows .18s ease,visibility 0s linear .18s}
.navhub-sub>.navhub-subin{overflow:hidden;min-height:0}
.navhub.open>.navhub-sub{grid-template-rows:1fr;visibility:visible;transition:grid-template-rows .18s ease}
@media (prefers-reduced-motion:reduce){.asidebar *{transition:none!important;animation:none!important}}
/* mobile drawer toggle (#9) — hidden on desktop, shown in the header on phones */
.navtoggle{display:none;background:none;border:0;color:#fff;font-size:22px;line-height:1;cursor:pointer;padding:4px 8px;margin-right:2px;border-radius:6px}
.navtoggle:focus-visible{outline:2px solid #fff;outline-offset:1px}
.nav-backdrop{display:none}
/* ── desktop sidebar collapse (icon-only rail; maximise the working area) ──
   The toggle lives at the top of the rail; collapsed state is a cookie the server
   reads so it survives every full page load (no flash, works no-JS). Collapse is
   DESKTOP-ONLY — the mobile hamburger/off-canvas drawer below owns ≤760px. */
.sbcollapse{display:flex;align-items:center;justify-content:space-between;width:100%;gap:6px;background:#eef2f6;border:0;color:#5b6b7b;font-size:19px;line-height:1;cursor:pointer;padding:5px 12px 5px 8px;margin:0 0 6px;border-radius:8px}
.sb-brand{font-size:13px;font-weight:800;color:#41566b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sbcollapse:hover{background:#e2e8f0;color:var(--navy)}
.sbcollapse:focus-visible{outline:2px solid var(--teal);outline-offset:1px}
@media (min-width:761px){
  .asidebar.collapsed{width:60px;padding:12px 8px}
  .asidebar.collapsed .sbcollapse{justify-content:center;padding:5px}
  .asidebar.collapsed .sb-brand{display:none}
  /* Collapsed rail: the group LABEL has no room, so it becomes a hairline divider
     — the icon list still reads as five blocks instead of one undifferentiated
     column. */
  .asidebar.collapsed .navgroup{display:block;height:1px;padding:0;margin:8px 6px;background:var(--line);font-size:0;color:transparent;overflow:hidden}
  .asidebar.collapsed>div:not(.navhub):not(.navfoot):not(.navstrip){display:none} /* hide the role chip when collapsed */
  /* Collapsed rail: the strip's container chrome has no room — rows become the
     same icon+dot+tooltip idiom as every other collapsed link. All-clear hides
     (an icon-only ✓ row with no label reads as a mystery button). */
  .asidebar.collapsed .navstrip{border:0;padding:0;background:transparent}
  .asidebar.collapsed .ns-clear{display:none}
  .asidebar.collapsed .navhelp{font-size:0} /* icon only; the label is the tooltip */
  .asidebar.collapsed a{gap:0;justify-content:center;padding:11px 0;position:relative}
  .asidebar.collapsed .navhub-toggle{display:none} /* rail: parent icon only */
  .asidebar.collapsed .navhub-sub{display:none!important} /* replaced by the label tooltip */
  /* the LABEL span (first span; not the badge/caret span) stays in the DOM
     (accessible name) but becomes a hover/focus tooltip to the right of the icon —
     no clipping (the rail has no overflow) */
  .asidebar.collapsed a>span:first-of-type{position:absolute;left:calc(100% + 10px);top:50%;transform:translateY(-50%);white-space:nowrap;background:#0d3250;border:1px solid #0b2c45;color:#fff;font-size:13px;font-weight:600;padding:6px 10px;border-radius:8px;box-shadow:0 8px 22px rgba(0,0,0,.4);opacity:0;visibility:hidden;pointer-events:none;transition:opacity .12s ease;z-index:80}
  .asidebar.collapsed a:hover>span:first-of-type,.asidebar.collapsed a:focus-visible>span:first-of-type{opacity:1;visibility:visible}
  /* the count badge → a small red dot on the icon (the number returns on expand/hover) */
  .asidebar.collapsed .navbadge{position:absolute;top:6px;right:12px;margin:0;padding:0;width:8px;height:8px;min-width:0;border-radius:50%;font-size:0;color:transparent;line-height:0;overflow:hidden}
}
/* Tablets (761–1100px, e.g. an iPad in portrait): the icon rail by DEFAULT —
   the expanded 230px rail left too little room for the Appointment Book and
   planner. .rail-auto is set only while the staffer has no saved sidebar
   cookie, so one tap on the (still visible) toggle expands the full labelled
   nav and that saved choice wins from then on. Same specificity as .collapsed. */
@media (min-width:761px) and (max-width:1100px){
  .asidebar.rail-auto{width:60px;padding:12px 8px}
  .asidebar.rail-auto .sbcollapse{justify-content:center;padding:5px}
  .asidebar.rail-auto .sb-brand{display:none}
  /* Collapsed rail: the group LABEL has no room, so it becomes a hairline divider
     — the icon list still reads as five blocks instead of one undifferentiated
     column. */
  .asidebar.rail-auto .navgroup{display:block;height:1px;padding:0;margin:8px 6px;background:var(--line);font-size:0;color:transparent;overflow:hidden}
  .asidebar.rail-auto>div:not(.navhub):not(.navfoot):not(.navstrip){display:none} /* hide the role chip when collapsed */
  /* Collapsed rail: the strip's container chrome has no room — rows become the
     same icon+dot+tooltip idiom as every other collapsed link. All-clear hides
     (an icon-only ✓ row with no label reads as a mystery button). */
  .asidebar.rail-auto .navstrip{border:0;padding:0;background:transparent}
  .asidebar.rail-auto .ns-clear{display:none}
  .asidebar.rail-auto .navhelp{font-size:0} /* icon only; the label is the tooltip */
  .asidebar.rail-auto a{gap:0;justify-content:center;padding:11px 0;position:relative}
  .asidebar.rail-auto .navhub-toggle{display:none} /* rail: parent icon only */
  .asidebar.rail-auto .navhub-sub{display:none!important} /* replaced by the label tooltip */
  /* the LABEL span (first span; not the badge/caret span) stays in the DOM
     (accessible name) but becomes a hover/focus tooltip to the right of the icon —
     no clipping (the rail has no overflow) */
  .asidebar.rail-auto a>span:first-of-type{position:absolute;left:calc(100% + 10px);top:50%;transform:translateY(-50%);white-space:nowrap;background:#0d3250;border:1px solid #0b2c45;color:#fff;font-size:13px;font-weight:600;padding:6px 10px;border-radius:8px;box-shadow:0 8px 22px rgba(0,0,0,.4);opacity:0;visibility:hidden;pointer-events:none;transition:opacity .12s ease;z-index:80}
  .asidebar.rail-auto a:hover>span:first-of-type,.asidebar.rail-auto a:focus-visible>span:first-of-type{opacity:1;visibility:visible}
  /* the count badge → a small red dot on the icon (the number returns on expand/hover) */
  .asidebar.rail-auto .navbadge{position:absolute;top:6px;right:12px;margin:0;padding:0;width:8px;height:8px;min-width:0;border-radius:50%;font-size:0;color:transparent;line-height:0;overflow:hidden}
}
@media (max-width:760px){.sbcollapse{display:none}} /* the hamburger owns mobile */
/* Week grids (planner + Appointment Book) keep legible columns up to tablet width
   and h-scroll inside their own box, instead of squeezing into 7 slivers. */
@media (max-width:1100px){
  .sched-weekgrid{min-width:760px}
  .cal-weekrow{min-width:820px}
}
/* ── patient-file "+ Add" quick-action menu (Gentu-style) ── */
.pf-add{position:relative;display:inline-block}
.pf-add-btn{white-space:nowrap}
.pf-add-menu{position:absolute;right:0;top:calc(100% + 4px);z-index:60;background:#fff;border:1px solid var(--line);border-radius:var(--radius-lg);box-shadow:var(--shadow-2);padding:6px;min-width:226px;max-height:72vh;overflow:auto}
.pf-add-menu a{display:flex;align-items:center;gap:9px;padding:9px 11px;border-radius:7px;color:#1a2733;text-decoration:none;font-size:14px;font-weight:600;white-space:nowrap}
.pf-add-menu a:hover,.pf-add-menu a:focus-visible{background:#ecfdf9;color:var(--teal);outline:none}
.pf-add-menu a .icon{flex:none;color:var(--teal)}
.pf-add-sep{height:1px;background:var(--line);margin:5px 2px}
/* Audit M02 (2026-07-31): on phones the anchored dropdown's bottom passed the
   viewport and hid under the sticky action bar. Bottom SHEET instead: fixed to
   the bottom, clamped to the visual viewport, internal scroll, 44px rows, above
   the action bar (z 50). The existing outside-click/Escape close still applies. */
@media (max-width:560px){
  .pf-add-menu{position:fixed;left:0;right:0;top:auto;bottom:0;border-radius:14px 14px 0 0;border-bottom:0;max-height:calc(100dvh - 90px);overflow-y:auto;z-index:70;box-shadow:0 -10px 30px rgba(16,58,92,.30);padding:8px 8px calc(10px + env(safe-area-inset-bottom,0px))}
  .pf-add-menu a{min-height:44px}
}
.amain{flex:1;min-width:0;max-width:none;margin:0;padding:24px 22px 64px}
@media (max-width:760px){
  .ashell{flex-direction:column;min-height:0}
  .navtoggle{display:inline-flex;align-items:center}
  /* off-canvas drawer: slides in from the left over a backdrop (replaces the old horizontal strip) */
  /* visibility:hidden when closed (audit M01 2026-07-31): a badge/box-shadow sliver
     of the translated drawer stayed visible at the left edge. Delayed so the
     slide-out transition still shows; nav-open flips it back on instantly. */
  /* height:100% is LOAD-BEARING. It must override the desktop height:100vh (which
     overflows the visible area in mobile Safari), and it must NOT be left as
     auto: with auto the drawer sizes to its CONTENT (measured 1981px in an 844px
     viewport — a pre-existing bug), so it never scrolls internally and everything
     past the fold, including the pinned .navfoot, is unreachable. 100% resolves
     against the fixed-position containing block = the viewport, giving a
     viewport-tall drawer that scrolls its own overflow. */
  .asidebar{position:fixed;top:0;left:0;bottom:0;height:100%;width:248px;max-width:84vw;z-index:60;flex-direction:column;flex-wrap:nowrap;overflow-y:auto;-webkit-overflow-scrolling:touch;transform:translateX(-100%);visibility:hidden;transition:transform .22s ease,visibility 0s .22s;border-right:1px solid var(--line);border-bottom:0}
  .asidebar a{white-space:normal;margin:2px 0;padding:12px 14px}
  /* In the mobile drawer the flyout would clip — show the hub's children inline
     instead. The chevron toggle is hidden at this width, so these MUST override
     both the grid collapse AND its paired visibility:hidden, or every hub becomes
     invisible and unreachable on phones. */
  .navhub-sub{display:block;visibility:visible;padding:0 0 0 14px} /* drawer: all groups open */
  .navhub-toggle{display:none}
  body.nav-open .asidebar{transform:none;visibility:visible;transition:transform .22s ease}
  .nav-backdrop{position:fixed;inset:0;background:rgba(15,42,75,.45);z-index:55}
  body:not(.nav-open) .nav-backdrop{display:none}
  body.nav-open .nav-backdrop{display:block}
  .amain{padding:18px 14px 56px;max-width:none}
  /* Audit M03 (2026-07-31) — mobile touch-target contract, portal-wide: 13px
     checkboxes and 25-39px link-buttons were the norm across 76/87 pages. One
     shared rule instead of per-page fixes; desktop is untouched. */
  input[type=checkbox],input[type=radio]{width:20px;height:20px;flex:none}
  .btn-link{min-height:44px;display:inline-flex;align-items:center;gap:4px}
  .pm-primary-action{min-height:44px}
  .pftab{min-height:44px}
}
/* Audit M04 (2026-07-31): the 7-tab patient strip was an 805px horizontal scroller
   inside a 362px container with no cue — on phones let it WRAP so every section
   is simply visible. Desktop keeps the single row. */
@media (max-width:560px){
  .pftabs{flex-wrap:wrap;overflow-x:visible;row-gap:2px}
}
/* ── patient-file section navigator (PF-nav): a sticky icon rail that smooth-scrolls to each card ── */
html{scroll-behavior:smooth}
.pflayout{display:flex;gap:16px;align-items:flex-start}
.pflayout>.pfbody{flex:1;min-width:0}
/* Gentu-style collapsible right rail (owner 2026-07-11): Scratch pad + Send-a-link
   live in a right column with a ‹/› edge toggle; collapsing reclaims the width for
   the cards. Persists via the pfrail cookie (no first-paint flash). Full-width and
   always-open on mobile (the edge tab makes no sense once the columns stack). */
.pfrail{flex:none;width:340px;position:relative;display:flex;flex-direction:column;min-width:0}
.pfrail-inner{display:flex;flex-direction:column;gap:16px;min-width:0}
.pfrail-inner>.card{margin:0}
.pfrail textarea{width:100%;min-height:120px;font-size:13.5px;line-height:1.5;resize:vertical}
.pfrail-toggle{position:absolute;top:2px;left:-13px;z-index:6;width:26px;height:26px;padding:0;display:flex;align-items:center;justify-content:center;border:1px solid var(--line);border-radius:50%;background:#fff;color:var(--navy);cursor:pointer;box-shadow:0 1px 4px rgba(16,58,92,.12)}
.pfrail-toggle:hover{background:#ecfdf9;color:var(--teal)}
.pfrail-toggle:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
.pfrail-caret{font-size:16px;font-weight:800;line-height:1;transition:transform .15s}
.pfrail.collapsed{width:26px}
.pfrail.collapsed .pfrail-inner{display:none}
.pfrail.collapsed .pfrail-toggle{left:0}
.pfrail.collapsed .pfrail-caret{transform:rotate(180deg)}
.pfnav{flex:none;width:46px;position:sticky;top:64px;display:flex;flex-direction:column;gap:4px;background:#fff;border:1px solid var(--line);border-radius:12px;padding:6px}
.pfnav-item{display:block}
.pfnav-link{display:flex;align-items:center;justify-content:center;width:34px;height:34px;border-radius:8px;color:var(--navy);text-decoration:none}
.pfnav-link:hover{background:#ecfdf9;color:var(--teal)}
.pfnav-link.active{background:var(--navy-soft);color:var(--navy);box-shadow:inset 0 0 0 1.5px var(--navy-soft-line)}
.pfnav-link:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
.pfnav-link{position:relative}
.pfnav-badge{position:absolute;top:-3px;right:-3px;min-width:16px;height:16px;padding:0 4px;border-radius:999px;background:#3538cd;color:#fff;font-size:10px;font-weight:700;line-height:16px;text-align:center;box-shadow:0 0 0 2px #fff}
.pf-section{scroll-margin-top:64px}
/* F2/F5 — the Details editor. Four named groups instead of eighteen unlabelled
   rows: a fieldset/legend is the one grouping a screen reader announces, and it
   is also what makes the form readable at a glance. Two columns for tightly
   related short fields (.row already does that) collapsing to one at 720px. */
.pf-fs{border:1px solid var(--line,#dbe3ea);border-radius:10px;padding:12px 14px 10px;margin:0 0 14px;min-width:0}
.pf-fs>legend{font-size:12.5px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--navy,#1f3448);padding:0 6px}
.pf-fs .help{font-size:12.5px;color:#5b6b7b;margin:6px 0 0}
/* Sticky action bar: on a long form the Save button must never be somewhere you
   have to hunt for. 44px targets (F5). */
.pf-savebar{position:sticky;bottom:0;z-index:5;display:flex;gap:12px;align-items:center;flex-wrap:wrap;
  margin-top:12px;padding:10px 2px;background:var(--bg,#fff);border-top:1px solid var(--line,#dbe3ea)}
.pf-savebar button,.pf-savebar .btn-link{min-height:44px}
.pf-savebar .muted{font-size:12.5px}
/* Invalid fields carry a visible mark AND aria-invalid — never colour alone. */
.pf-invalid{border-color:#b42318 !important;box-shadow:0 0 0 1px #b4231855}
@media (max-width:720px){.pf-fs{padding:10px}}
#pf-top{scroll-margin-top:64px}
/* ── patient-file TAB strip (Wave 1, 2026-07-03) — real links to the 5 sibling tab routes ── */
.pftabs{display:flex;gap:4px;margin:12px 0 14px;border-bottom:2px solid var(--line);overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch}
/* Pinned patient header (owner 2026-07-10, Gentu-style): name + identity strip +
   safety chips + tab strip stay put while the file scrolls. Bleeds to the .amain
   edges (negative margins mirror .amain padding) so cards slide under it cleanly.
   Alert banners (flags/merge) render BELOW it and scroll away — the strip stays lean. */
.pf-sticky{position:sticky;top:0;z-index:45;background:var(--bg);margin:0 -22px 16px;padding:16px 22px 0;box-shadow:0 3px 10px rgba(16,58,92,.07)}
/* The -24px top bleed cancels .amain's padding so the header sits flush at the
   very top — but ONLY when nothing precedes it. With a notice/merge banner above,
   that negative margin pulled the opaque z-45 header up over the banner and sliced
   it in half (owner 2026-08-06: "confirmations routinely cut off"). Scoped to the
   desktop breakpoint so it can't out-specify the ≤760px static override below. */
@media (min-width:761px){.amain>.pf-sticky:first-child{margin-top:-24px}}
.pf-sticky .pftabs{margin-bottom:0}
/* Collapse-on-scroll (owner 2026-09-02, approved): past ~120px the ~180px
   header shrinks to one line — name · DOB · mobile · status pill — via a class
   a tiny nonce'd scroll listener toggles (pfCollapseHeader script, below the
   patient-file header). CSS-only otherwise: no .collapsed class ⇒ the full
   header, so JS-off renders exactly as before. A hard display swap (no
   transition) is reduced-motion-safe by construction — nothing animates. */
.pf-collapsed-line{display:none;align-items:center;gap:8px;min-width:0;font-size:15px;font-weight:700;flex-wrap:wrap}
.pf-collapsed-line .pill{font-size:12px}
.pf-collapsed-line .pill .icon{display:inline-block}
/* Wrapper spans for the mobile slim bar only — transparent here so the desktop line lays out as before. */
.pf-cl-meta,.pf-cl-chips{display:contents}
/* A long allergy string must not push the other safety chips off-screen (D-1). */
.pf-safety a.pill.bad{max-width:min(340px,100%);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}
.pf-sticky.collapsed .pf-namerow{display:none}
.pf-sticky.collapsed .pf-collapsed-line{display:flex}
.pf-sticky.collapsed .pf-idbar,.pf-sticky.collapsed .pf-safety{display:none}
/* baseline (not center) alignment: the strip mixes 13px values, 11px caps labels
   and pills — centering floats the small caps above their value's baseline. */
/* Identity strip = a UNIFIED label-over-value grid (owner 2026-08-07: the old
   strip mixed labelled and unlabelled fragments at one size — no hierarchy,
   nothing lined up). Every field is the same two-row column: 10px uppercase
   label, value beneath. The always-visible row (DOB - Sex - Mobile - Fund - ID)
   reads at 13.5px/600; the folded "All details" row steps down to 12.5px/400 so
   the primary facts visibly outrank the secondary ones. Columns top-align, so
   labels form one straight line and values another. */
.pf-idbar{display:flex;flex-wrap:wrap;gap:8px 26px;align-items:start;margin:8px 0 0;color:#41525f}
.pf-idcol{display:inline-grid;grid-template-rows:auto auto;row-gap:1px;min-width:0;font-size:13.5px;font-weight:600;color:#243642;line-height:1.35}
.pf-idmore-body .pf-idcol{font-size:12.5px;font-weight:400;color:#41525f}
/* Linked columns (Fund, Ref) must sit on the same grid as unlinked ones — the
   inline <a> wrapper added its own line box and nudged them a few px lower.
   display:contents dissolves the wrapper; the hover-underline rule still fires
   because :hover on the child propagates to the ancestor link. */
.pf-idbar .pf-idlink{display:contents}
/* Name row: name + age + status/next chips share one flex line, chips centred on
   the name's cap height, and the whole row wraps cleanly at laptop/mobile widths. */
.pf-namerow{display:flex;align-items:center;flex-wrap:wrap;gap:4px 8px;min-width:0}
/* Chips beside the patient name must sit on ONE line (owner 2026-08-07: they
   "don't line up"). .pill is inline-block, so a pill containing an inline
   svg.icon (baseline-aligned by default) grew taller than a text-only
   pill and the two sat at different heights. Make every chip in this row the
   same flex box, centre its icon, and give the popup BUTTON wrapper the same
   box so a plain pill and a button-wrapped pill align. Scoped to .pf-namerow —
   pills elsewhere are untouched. */
.pf-namerow .pill{display:inline-flex;align-items:center;gap:4px;line-height:1.5;vertical-align:middle}
.pf-namerow .pill .icon{flex:none;vertical-align:middle}
/* .pf-idmore folds the secondary identity columns. Desktop (2026-08-07 unified
   grid): summary hidden + forced open, but the fold is a FULL-WIDTH block so the
   secondary tier sits on its OWN line under the primary one — two clean rows,
   not one line of mixed sizes. Mobile (audit §7.2 2026-07-31): a tappable
   "All details" summary; the inline matchMedia snippet closes it on load. */
.pf-idmore{display:block;width:100%}
.pf-idmore>summary{display:none}
.pf-idmore-body{display:flex;flex-wrap:wrap;align-items:start;gap:8px 22px;padding:2px 0 0}
@media (max-width:560px){
  .pf-idmore>summary{display:inline-flex;list-style:none;cursor:pointer;padding:4px 0}
  .pf-idmore>summary::-webkit-details-marker{display:none}
  .pf-idmore-body{padding:2px 0 4px}
}
.pf-idlabel{display:block;color:#7b8a97;font-weight:700;font-size:10px;text-transform:uppercase;letter-spacing:.05em;line-height:1.3}
/* 0489 verified tick beside Medicare / the fund: quiet teal check on a soft
   disc (a settled state — text-weight, not a green pill; design-language §7). */
.pf-verified{display:inline-flex;align-items:center;justify-content:center;width:1.2em;height:1.2em;margin-left:5px;border-radius:50%;background:var(--teal-soft,#e9f6f3);color:var(--teal,#0e7c7b);vertical-align:-.2em}
.pf-verified .icon{width:.8em;height:.8em;stroke-width:3}
/* "How this file is organised" explainer (generated from PATIENT_FILE_TABS) —
   a ⓘ CSS-only tooltip beside the patient-file h1 (owner 2026-09-02, was a
   full-width <details class="pf-howto"> row above every tab's content). Reuses
   .info/.info-t/.info-b (hover/:focus-within show, no JS); widened here since
   the two-column dl needs more room than the default 280px tooltip. */
.info-b.pf-howto-b{min-width:300px;max-width:min(420px,90vw);text-align:left}
.pf-howto-b strong{display:block;margin-bottom:6px;color:#fff}
.pf-howto-b dl{display:grid;grid-template-columns:120px 1fr;gap:6px 14px;font-size:12.5px;margin:0}
.pf-howto-b dt{font-weight:700;color:#fff;display:flex;align-items:center;gap:6px}
.pf-howto-b dt .icon{color:#fff}
.pf-howto-b dd{margin:0;color:#dbe6f0}
@media(max-width:560px){.info-b.pf-howto-b{min-width:0;max-width:78vw}.pf-howto-b dl{grid-template-columns:1fr;gap:2px 0}.pf-howto-b dt{margin-top:6px}}
@media (max-width:760px){.pf-sticky{position:static;margin:0 0 12px;padding:0;box-shadow:none}
/* Slim pinned bar (owner 2026-10-01): the full header scrolls away on a phone, but once the
   scroll script adds .collapsed it re-pins as ONE slim bar — name + bad-class safety chips +
   Message + Add; tabs and the other header buttons are hidden meanwhile. -14px mirrors
   .amain's mobile padding. (0,2,0) out-specifies the static rule above. Layout: grid, name
   and actions on row 1, chips as a one-row swipe lane on row 2 (.pf-collapsed-line is
   display:contents so its children join #pf-top's grid; !important beats the inline flex). */
.pf-sticky.collapsed{position:sticky;top:0;margin-left:-14px;margin-right:-14px;padding:4px 14px;background:var(--bg);box-shadow:0 3px 10px rgba(16,58,92,.07)}
.pf-sticky.collapsed .pftabs{display:none}
.pf-sticky.collapsed #pf-top{display:grid!important;grid-template-columns:minmax(0,1fr) auto;gap:0 8px;align-items:center}
.pf-sticky.collapsed .pf-collapsed-line{display:contents}
.pf-sticky.collapsed .pf-cl-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pf-sticky.collapsed .pf-cl-meta{display:none}
.pf-sticky.collapsed .pf-cl-chips{grid-column:1/-1;grid-row:2;display:flex;flex-wrap:nowrap;gap:6px;overflow-x:auto;scrollbar-width:none;padding-bottom:4px}
.pf-sticky.collapsed .pf-cl-chips::-webkit-scrollbar{display:none}
.pf-sticky.collapsed .pf-cl-chips .pill{white-space:nowrap;flex:none}
.pf-sticky.collapsed .pf-cl-chips:empty{display:none}
.pf-sticky.collapsed .pf-headactions{flex-wrap:nowrap}
.pf-sticky.collapsed .pf-headactions>:not(#pf-smspop-btn):not(#pfAdd){display:none}
}
/* Keep the underline inside the scroll box: a negative bottom margin makes
   otherwise single-line staff navigation overflow vertically. */
.pftab{display:flex;align-items:center;gap:6px;padding:8px 14px;margin-bottom:0;border-bottom:2px solid transparent;border-radius:8px 8px 0 0;color:var(--navy);text-decoration:none;font-size:13.5px;font-weight:600;white-space:nowrap;position:relative}
.pftab:hover{background:#ecfdf9;color:var(--teal)}
.pftab.active{border-bottom-color:var(--teal);color:var(--teal)}
.pftab:focus-visible{outline:2px solid var(--teal);outline-offset:-2px}
/* This short directory strip wraps instead of using horizontal scrolling. */
.pftabs.ab-tabs{flex-wrap:wrap;overflow:visible;max-width:100%;row-gap:2px}
.ab-tabs .pftab{min-height:44px;box-sizing:border-box;margin-bottom:0}
.pftab .pfnav-badge{position:static;margin-left:2px;box-shadow:none}
/* ── patient-file shared vocabulary (2026-07-18 redesign) — ONE idiom each for
   in-row buttons, action rows, expandable parameter strips, sub-blocks and small
   chips. Each class replaces a retired ad-hoc pattern; the patient-file section
   adds no new inline style="" for anything these cover. ── */
.btn-link.sm{padding:3px 9px;font-size:12px;font-weight:600;border-width:1px;border-radius:7px}
.btn-link.danger{border-color:#e4b6b1;color:var(--err)}
.btn-link.danger:hover{border-color:var(--err);background:#fff8f7}
.pill.sm{padding:1px 8px;font-size:11px}
.pill.outline{background:#fff;border:1px solid var(--line);color:#41525f;font-weight:600}
/* row toolbar — the ONE way a table row exposes its actions (retires stacked per-row forms) */
.rowbar{display:flex;flex-wrap:wrap;gap:4px 6px;align-items:flex-start}
.rowbar form{display:contents}
.rowbar .sep{align-self:center;width:1px;height:15px;background:var(--line);margin:0 2px}
/* inline action row — the ONE flex row for grouped controls (retires the hand-inlined flex divs) */
.actrow{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.actrow form{display:contents}
/* compact in-row/in-strip controls — without this, stripping inline sizes makes
   selects full-width 15px (global select{width:100%}) */
.actrow select,.actrow input,.pstrip-b select,.pstrip-b input{width:auto;font-size:12.5px;padding:4px 8px}
/* parameter strip — a native <details> holding an action's form inline in the row.
   JS-free, JS-off identical; help text visible at point of use (replaces per-row ⓘ). */
.pstrip{display:inline-block}
.pstrip[open]{display:block;flex-basis:100%}
.pstrip>summary{list-style:none;cursor:pointer}
.pstrip>summary::-webkit-details-marker{display:none}
.pstrip>summary::after{content:" ▾";font-size:9px;opacity:.8}
.pstrip[open]>summary::after{content:" ▴";font-size:9px}
.pstrip-b{margin:6px 0 2px;padding:9px 11px;border:1px solid var(--line);border-radius:8px;background:#f8fafc;display:flex;flex-direction:column;gap:6px;max-width:460px}
.pstrip-b form{display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin:0}
.pstrip-h{color:#5b6b7b;font-size:12px;line-height:1.4;margin:0}
/* A tick inside a .pstrip form ("no cancellation fee"): its own full-width row,
   so the checkbox is never squeezed between two inline controls. */
.pstrip-tick{flex-basis:100%;display:flex;align-items:center;gap:6px;color:#5b6b7b;font-size:12px;line-height:1.4;font-weight:400}
/* Supplier records (/admin/remittances address book). A SAVED supplier reads as a
   record; its 8 fields exist only inside the row's Edit .pstrip. The old section
   rendered every supplier as a permanently-open form grid, so a stray keystroke
   could silently rewrite a BSB and nothing on screen said "saved". */
.sup-row{display:grid;grid-template-columns:minmax(170px,1.3fr) minmax(170px,1.1fr) minmax(170px,1.2fr) auto;gap:4px 16px;align-items:start;padding:11px 2px;border-top:1px solid var(--line)}
.sup-row:first-of-type{border-top:0}
.sup-row.is-off{opacity:.6}
.sup-name{font-weight:600;display:flex;gap:7px;align-items:center;flex-wrap:wrap;min-width:0;overflow-wrap:anywhere}
.sup-f{font-size:12.5px;color:#5b6b7b;line-height:1.55;min-width:0;overflow-wrap:anywhere}
.sup-f b{font-weight:600;color:#41566b}
.sup-act{justify-self:end}
/* An OPEN edit takes the whole row — trapped in the narrow actions column the
   8 fields stacked into a one-per-line ladder. :has() is the load-bearing bit;
   without it the panel still works, just narrow. */
.sup-row:has(.sup-act details[open]){background:#f8fafc;border-radius:10px}
.sup-row:has(.sup-act details[open]) .sup-act{grid-column:1/-1;justify-self:stretch;width:100%}
.sup-wide{grid-column:1/-1}
.sup-edit{max-width:none}
.sup-edit form{display:block;margin:0}
.sup-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:9px 12px;margin-bottom:10px}
/* specificity note: .pstrip-b label (inline-flex, centred, nowrap) is declared
   later and would otherwise centre every field label over its input. */
.sup-edit .sup-fields label{font-size:12px;display:flex;flex-direction:column;align-items:flex-start;text-align:left;white-space:normal;gap:2px;color:#41566b;font-weight:600}
.sup-fields input,.sup-fields select,.sup-fields textarea{width:100%;font-size:13.5px;padding:6px 8px}
.sup-fields .sup-fwide{grid-column:1/-1}
/* unpaid-bill group: a supplier+brand block inside the section card. Was a nested
   .card — a card in a card is never the answer; a divider says the same thing. */
.rem-group{padding:12px 0 14px;border-top:1px solid var(--line)}
.rem-group:first-of-type{border-top:0;padding-top:2px}
@media(max-width:760px){.sup-row{grid-template-columns:1fr}.sup-act{justify-self:start}}
/* Documents ▾ menu on the Timeline row: each entry is a full-label link (title +
   descriptor), replacing the old bare Consent/Attach/Letter verbs. */
.docmenu{max-width:420px}
.docmenu-item{display:flex;flex-direction:column;gap:1px;padding:7px 9px;border-radius:7px;text-decoration:none;color:inherit}
.docmenu-item:hover{background:#eef2f7}
.docmenu-t{font-size:13px;font-weight:600;color:var(--accent,#0f4c81)}
.docmenu-d{font-size:11.5px;color:#5b6b7b;line-height:1.35}
/* Send-a-link panel: the two routes (booking link vs registration form) sit side
   by side so they can be compared, instead of hiding behind a nested tree. Brand
   panes, the chosen-scope wording and the summary line all switch with :has() —
   no JS at all, so the panel is fully usable JS-off. */
.sl-seg{display:flex;border:1.5px solid var(--line);border-radius:9px;overflow:hidden;margin:0 0 12px}
.sl-seg label{flex:1;margin:0;padding:8px 6px;text-align:center;font-size:12.5px;font-weight:600;color:#5b6b7a;cursor:pointer;border-right:1px solid var(--line)}
.sl-seg label:last-child{border-right:0}
.sl-seg label:has(input:checked){background:var(--navy-soft);color:var(--navy);box-shadow:inset 0 0 0 1.5px var(--navy-soft-line);font-weight:700}
.sl-seg label:has(input:focus-visible){outline:2px solid var(--teal);outline-offset:-2px}
.sl-seg input{position:absolute;opacity:0;width:1px;height:1px;pointer-events:none}
.sl-route{background:#fff;border:1.5px solid var(--line);border-radius:10px;padding:12px;margin:0 0 9px}
.sl-route.primary{border-color:var(--teal)}
/* Collapsible route tiles (2026-08-29): each route is a <details> whose summary
   is the heading row — closed tiles read as a slim picker list. The native
   "name" attribute makes each brand pane an exclusive accordion, still no JS. */
.sl-route>summary{list-style:none;cursor:pointer;position:relative;padding-right:24px}
.sl-route>summary::-webkit-details-marker{display:none}
.sl-route>summary::after{content:'\276F';position:absolute;right:4px;top:50%;transform:translateY(-50%) rotate(0);transition:transform .15s;color:var(--navy);font-size:12px;font-weight:800;opacity:.7}
.sl-route[open]>summary::after{transform:translateY(-50%) rotate(90deg)}
.sl-route:not([open]){background:#f8fafc}
.sl-route h4{display:flex;align-items:baseline;gap:8px;margin:0;font-size:14px;color:var(--navy)}
.sl-route h4 .sl-badge{margin-left:auto;font-size:10.5px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--teal)}
.sl-route h4 .sl-badge.later{color:var(--warn)}
/* Review route (0249) — amber deliberately breaks the teal action language:
   this pathway is doctor-initiated ("your results are back"), not admin
   onboarding, and staff must never confuse it with the new-patient link. */
.sl-route h4 .sl-badge.review{color:#b54708}
.sl-route.sl-review{border-color:#f0c9a0}
.sl-rv-row{display:flex;flex-wrap:wrap;gap:4px 12px;align-items:center;margin:8px 0 0;font-size:12.5px}
.sl-rv-row label{display:inline-flex;align-items:center;gap:4px;color:#41525f}
.sl-rv-row label:has(input:disabled){opacity:.5}
.sl-rv-lab{font-weight:700;font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:#8395a4;min-width:74px}
.sl-rv-sms{width:100%;margin:2px 0 0;padding:8px 10px;border:1px solid #cbd5e1;border-radius:8px;font-size:12.5px;line-height:1.45;font-family:inherit;resize:vertical}
.sl-route p{margin:5px 0 0;font-size:12.5px;color:#5b6b7a}
.sl-route .radio-group{gap:6px;margin:10px 0 0}
.sl-route .radio-group label{padding:8px 6px;font-size:12px}
.sl-gets{margin:9px 0 0;padding:8px 10px;background:#f8fafc;border:1px solid var(--line);border-radius:7px;font-size:12px;color:#41525f}
.sl-gets b{display:block;margin-bottom:3px;font-size:10px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:#8395a4}
.sl-sum{margin:9px 0 0;padding:9px 11px;background:#f0f9f9;border:1px solid #b9dedd;border-radius:8px;font-size:12.5px;color:#0b4a4a}
.sl-send{width:100%;margin-top:10px;padding:11px;border:0;border-radius:9px;background:var(--teal);color:#fff;font-size:13.5px;font-weight:700;cursor:pointer}
.sl-send:hover{background:#0b6968}
.sl-send.secondary{background:#fff;color:var(--navy);border:1.5px solid var(--line)}
.sl-send.secondary:hover{background:#f7fafc}
.sl-send[disabled]{background:#c4d0da;cursor:not-allowed}
/* Split "send now / send later" button (2026-08-02). The shared .split rules
   assume a .primary submit; these routes style theirs .sl-send, which is also
   width:100% — inside an inline-flex .split that would collapse the row. Make
   the wrapper the full-width block the plain button used to be, and hand the
   squared inner corner to .sl-send. */
.sl-route .split{display:flex;width:100%;margin-top:10px}
.sl-route .split>button.sl-send{flex:1;width:auto;margin-top:0;border-radius:9px 0 0 9px}
.sl-route .split>.sched-dd>summary{border-radius:0 9px 9px 0}
.sl-more{margin-top:10px;padding-top:9px;border-top:1px solid var(--line)}
.sl-more>summary{list-style:none;font-size:12.5px;color:#5b6b7a;cursor:pointer;text-decoration:underline;text-underline-offset:2px}
.sl-more>summary::-webkit-details-marker{display:none}
/* One brand pane at a time; one scope phrase at a time. */
#pf-sendlink:has(#sl-brand-ue:checked) .sl-pane-cb,
#pf-sendlink:has(#sl-brand-cb:checked) .sl-pane-ue{display:none}
.sl-w{display:none}
/* ⚠ These key on IDs and BOTH panes are always in the DOM (the pane switch above
   is CSS-only), so the UES pane MUST use its own ids — duplicating #sl-scope-*
   there would swap the wrong words in both panes at once. */
.sl-route:has(#sl-scope-proc:checked) .sl-w-proc,
.sl-route:has(#sl-scope-tele:checked) .sl-w-tele,
.sl-route:has(#sl-scope-inperson:checked) .sl-w-inperson,
.sl-route:has(#sl-scope-consult:checked) .sl-w-consult,
.sl-route:has(#sl-scope-both:checked) .sl-w-both,
.sl-route:has(#sl-ue-scope-tele:checked) .sl-w-ue-tele,
.sl-route:has(#sl-ue-scope-inperson:checked) .sl-w-ue-inperson,
.sl-route:has(#sl-ue-scope-consult:checked) .sl-w-ue-consult{display:inline}
/* A toggled BLOCK (the in-person inventory hint) — higher specificity than the
   inline rule above, and after it, so the paragraph keeps its own line. */
.sl-route:has(#sl-scope-consult:checked) p.sl-w-consult,
.sl-route:has(#sl-scope-inperson:checked) p.sl-w-inperson,
.sl-route:has(#sl-ue-scope-inperson:checked) p.sl-w-ue-inperson,
.sl-route:has(#sl-ue-scope-consult:checked) p.sl-w-ue-consult{display:block}
/* Quiet supporting line inside a route tile: inventory hints + the exact sentence
   the patient will read. Not a .sl-sum (that is the "what this sends" summary). */
.sl-hint{margin:7px 0 0;font-size:11.5px;line-height:1.45;color:#6b7a88}
/* Route-tile status chips (2026-08-20): small facts above the pickers — what we
   hold for this patient and which live link a send would replace. */
.sl-chips{display:flex;flex-wrap:wrap;gap:5px;margin:8px 0 0}
.sl-chip{display:inline-block;padding:3px 9px;border-radius:8px;font-size:11px;font-weight:600;line-height:1.4;background:#f1f5f9;border:1px solid var(--line);color:#41525f}
.sl-chip.ok{background:#eef7f2;border-color:#bfdccd;color:#166534}
.sl-chip.warn{background:#fffaeb;border-color:#f0dca0;color:#8a5a00;font-weight:500}
.sl-chip a{color:inherit;font-weight:600}
/* card-sub — the ONE way to stack labelled blocks inside a card */
.card-sub{margin-top:16px;padding-top:12px;border-top:1px solid var(--line)}
.card-sub>h3{margin:0 0 8px;font-size:13.5px;text-transform:uppercase;letter-spacing:.03em;color:var(--navy)}
/* subcard — a bordered sub-item row (replaces card-in-card) */
.subcard{border:1px solid var(--line);border-radius:8px;padding:10px 12px;margin:8px 0;background:#fff}
/* two-column card grid (Clinical tab) — stacks under 900px */
.pf-grid2{display:grid;grid-template-columns:1fr 1fr;gap:0 16px;align-items:start}
@media (max-width:900px){.pf-grid2{grid-template-columns:1fr}}
.notice.warn{border-left-color:var(--warn);background:#fffaeb}
/* booking-timeline row model: one tbody per booking (main row + optional sub-row) */
tbody.bk>tr+tr>td{border-top:0;padding-top:0}
.bk-sub{display:flex;gap:12px 16px;align-items:flex-start;justify-content:space-between;flex-wrap:wrap}
.bk-note{flex:1;min-width:220px;font-size:13px;color:#5b6b7b;border-left:3px solid var(--cb-primary,#c86a4a);padding-left:8px}
.bk-sub .appt-activity{margin-left:auto}
.pstrip-b label{font-size:12px;display:inline-flex;gap:4px;align-items:center;white-space:nowrap;margin:0}
a.pill{text-decoration:none}
/* Clickable-vs-static grammar (banner audit 2026-07-27): anything that navigates
   underlines on hover; static pills (allergies, Do-not-SMS…) never do. Covers
   both bare <a class="pill"> chips and links wrapping a pill/idcol span. */
a.pill:hover,a:hover>.pill,a.pf-idlink:hover .pf-idcol{text-decoration:underline}
a.pf-idlink{text-decoration:none}
tbody.bk:target>tr>td{background:#fef3c7}
tbody.bk:hover>tr>td{background:#f8fafc}
tbody.bk.is-terminal>tr>td{color:#8494a3;background:#fafbfc}
tbody.bk.is-terminal>tr>td .pill{opacity:.85}
tbody.bk.is-terminal:hover>tr>td{background:#f4f6f8}
table.pf-dense td,table.pf-dense th{padding:6px 10px}
table.pf-dense td{font-variant-numeric:tabular-nums}
/* ── Documents timeline (repatriated from the route-emitted <style> block,
   2026-07-18 redesign: bounded-height grid rows — date rail | content | release) ── */
.doc-split{display:flex;gap:14px;align-items:stretch}
.doc-list{flex:0 0 360px;min-width:0;display:flex;flex-direction:column;gap:8px;max-height:72vh;overflow-y:auto;padding-right:2px}
.doc-item{display:grid;grid-template-columns:auto 72px minmax(0,1fr) auto;grid-template-areas:"sel when line1 rel" "sel when meta rel";gap:2px 10px;border:1px solid var(--line);border-radius:10px;padding:8px 11px;background:#fff;cursor:pointer}
.doc-item:hover{border-color:#94a3b8;background:#f8fafc}
.doc-item.active{border-color:var(--teal);background:#f0f6fb;box-shadow:inset 3px 0 0 var(--teal)}
.doc-item.released{background:#f0fdf4}
.doc-when{grid-area:when;display:flex;flex-direction:column;gap:1px;font-size:12px;color:#5b6b7b;font-variant-numeric:tabular-nums}
.doc-line1{grid-area:line1;display:flex;flex-wrap:wrap;gap:3px 6px;align-items:center;min-width:0}
.doc-line1 .doc-open{min-width:0;flex:1 1 100%;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere;font-size:13.5px;font-weight:600;text-decoration:none}
.doc-type{flex:none;font-size:11px;font-weight:700;color:#5b6b7b;text-transform:uppercase;letter-spacing:.02em}
.doc-meta{grid-area:meta;white-space:normal}
.doc-by{flex:1 1 100%;font-size:11.5px;color:var(--quiet,#5b6b7b)}
.doc-rel{grid-area:rel;align-self:start;justify-self:end}
.doc-rel label{display:inline-flex;align-items:center;gap:5px;cursor:pointer;margin:0}
.doc-savebar{position:sticky;bottom:0;margin-top:auto;padding:6px 0 2px;background:linear-gradient(rgba(255,255,255,0),#fff 45%);display:flex;justify-content:flex-end;gap:8px;align-items:center;flex-wrap:wrap}
/* bulk-selection (0211): row checkbox column + the selection bar in the savebar */
.doc-sel{grid-area:sel;align-self:center;min-width:15px;display:flex;margin:0;cursor:pointer}
.doc-sel input{width:15px;height:15px;accent-color:var(--teal);cursor:pointer;margin:0}
.doc-item.selected{border-color:var(--teal);background:#f0fdfa}
.doc-item.archived{opacity:.8;background:#f8fafc}
.doc-bulkbar{display:flex;gap:8px;align-items:center;flex-wrap:wrap;background:#fff;border:1px solid var(--line);border-radius:10px;padding:6px 10px;box-shadow:0 4px 14px rgba(15,23,42,.08);margin-right:auto}
.doc-bulk-tag>summary{list-style:none}.doc-bulk-tag>summary::-webkit-details-marker{display:none}
.doc-bulk-tag .dtag-menu{bottom:calc(100% + 4px)}
.doc-menu>summary{font-weight:800;color:#5b6b7b;font-size:14px;line-height:1;padding:0 5px;letter-spacing:1px}
.doc-menu .dtag-menu{right:0}
/* Rename row in the ⋯ menu — display name only, so it sits with the other
   per-document actions rather than opening a dialog. */
.doc-rename{display:flex;gap:4px;align-items:center;padding:5px 6px 3px;margin-top:2px;border-top:1px solid var(--line)}
.doc-rename input,.doc-rename select{flex:1;min-width:0;font-size:12px;padding:3px 6px;border:1px solid #cbd5e1;border-radius:6px}
.dtag-menu .doc-rename button{width:auto;flex:none;font-weight:700;color:#0f766e;padding:4px 6px}
.doc-preview{flex:1;min-width:0;border:1px solid var(--line);border-radius:10px;background:#fff;display:flex;flex-direction:column;height:72vh}
.doc-pv-head{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:8px 12px;border-bottom:1px solid var(--line)}
.doc-pv-head strong{font-size:14px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.doc-pv-head .btn-link{flex:none}
#doc-pv-frame{flex:1;width:100%;border:0;border-radius:0 0 10px 10px}
@media (max-width:900px){.doc-preview{display:none!important}.doc-list{flex:1;max-height:none}}
.dtag{display:inline-flex;align-items:center;gap:3px;font-size:11px;font-weight:700;padding:2px 4px 2px 7px;border-radius:999px;margin:1px 3px 1px 0;background:color-mix(in srgb, var(--tc) 14%, #fff);color:var(--tc);border:1px solid color-mix(in srgb, var(--tc) 45%, #fff)}
.dtag-rm{display:inline;margin:0}.dtag-rm button{border:0;background:none;color:inherit;cursor:pointer;font-size:13px;line-height:1;padding:0 1px;opacity:.7}.dtag-rm button:hover{opacity:1}
.dtag-add{display:inline-block;position:relative}.dtag-add>summary{list-style:none;cursor:pointer;color:#0f766e;font-weight:800;font-size:13px;padding:0 4px}.dtag-add>summary::-webkit-details-marker{display:none}
.dtag-menu{position:absolute;z-index:20;background:#fff;border:1px solid #cbd5e1;border-radius:8px;box-shadow:0 6px 20px rgba(0,0,0,.12);padding:4px;min-width:150px;max-height:220px;overflow:auto}
.dtag-menu form{margin:0}.dtag-menu button,.dtag-menu>a{display:block;width:100%;text-align:left;border:0;background:none;cursor:pointer;padding:5px 8px;border-radius:6px;font-size:13px;color:inherit;text-decoration:none;box-sizing:border-box}.dtag-menu button:hover,.dtag-menu>a:hover{background:#f1f5f9}
.dtag-more>summary{list-style:none;cursor:pointer;display:inline-flex}.dtag-more>summary::-webkit-details-marker{display:none}
.dtag-more{display:inline-block;position:relative}.dtag-more .dtag-menu{padding:6px 8px}
/* pinned-header next-appointment chip (replaces per-site inline styles) */
.pf-nextchip{text-decoration:none;font-size:12.5px;font-weight:600;vertical-align:middle}
/* header SMS popup (repatriated from the route-emitted <style> block).
   [hidden] wins because display is only set on the :not([hidden]) rule. */
#pf-smspop:not([hidden]){display:flex}
#pf-smspop{position:fixed;right:18px;bottom:18px;z-index:1200;width:min(520px,calc(100vw - 24px));max-height:min(72vh,680px);background:#fff;border:1px solid var(--line);border-radius:14px;box-shadow:0 14px 44px rgba(15,32,54,.35);flex-direction:column}
.pf-smspop-head{display:flex;justify-content:space-between;align-items:flex-start;gap:10px;padding:10px 14px;border-bottom:1px solid var(--line)}
.pf-smspop-body{padding:12px 14px;overflow-y:auto;flex:1}
/* header registration-status popover — click the status chip to action it in place */
/* episode header — slim label over an adjacent run of docs sharing a booking */
.doc-episode{display:flex;gap:6px;align-items:center;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--navy);margin:6px 0 -2px;padding-left:2px}
.doc-episode .icon{color:var(--teal)}
/* documents tag-filter chips: state via aria-pressed, not inline-style mutation */
#cf-typefilter button[aria-pressed="true"]{background:#e0eaff!important;border-color:#3538cd}
/* ── patient-file subsection groups (8 named groups) — a clear heading per group + a hairline divider, with a little vertical breathing room between groups. ── */
.pf-group{scroll-margin-top:64px;margin:0 0 18px}
.pf-group+.pf-group{margin-top:6px}
.pf-grouphead{display:flex;align-items:center;gap:8px;margin:0 0 8px;padding:0 0 6px;border-bottom:1px solid var(--line);color:var(--navy);font-size:13px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}
.pf-grouphead .icon{color:var(--teal)}
/* ── send-link panel: booking-link history (metadata only — no URL ever stored) ── */
.pf-linkhist{margin:12px 0 0;padding-top:10px;border-top:1px solid var(--line)}
.pf-linkhist-head{margin:0 0 6px;font-size:13px;font-weight:700;color:var(--navy)}
.pf-linkhist-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
.pf-linkhist-row{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:12px}
.pf-linkhist-meta{display:flex;align-items:center;gap:5px;flex-wrap:wrap}
/* One block per minted link (2026-08-12): the mint reads as the heading, its own
   invites indent under it behind a hairline, the outcome closes it. Separation
   between blocks is a slim divider, not a card or a coloured edge — nested cards
   and thick side-borders are both out (design-language §6). */
.pf-linkgrp+.pf-linkgrp{margin-top:9px;padding-top:9px;border-top:1px solid var(--line)}
.pf-linkgrp-sends{margin:5px 0 0 3px;padding-left:9px;border-left:1px solid var(--line)}
.pf-linkgrp-out{margin:5px 0 0;font-size:11.5px}
.pf-linkgrp-lab{margin:0 0 3px;font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--navy)}
.pf-linkgrp-ref{font-size:11px;font-variant-numeric:tabular-nums}
@media (max-width:760px){
  .pflayout{flex-direction:column;gap:10px}
  .pfnav{flex-direction:row;width:auto;position:sticky;top:0;overflow-x:auto;-webkit-overflow-scrolling:touch;border-radius:10px}
  .pfnav .info-b{display:none}
  .pflayout>.pfbody{width:100%}
  /* rail stacks full-width below the cards; the edge toggle is meaningless once
     stacked, so hide it and always show the contents. */
  .pfrail,.pfrail.collapsed{width:100%}
  .pfrail-toggle{display:none}
  .pfrail.collapsed .pfrail-inner{display:flex}
}
/* ── patient-file sticky action footer (mobile only): highest-value actions
   pinned to the bottom of the viewport on phones. Desktop is untouched. The bar
   is position:sticky at the bottom, so it never overlaps the .pfnav (which is a
   top:0 sticky row on mobile). Body bottom-padding leaves room above the OS bar. ── */
.pf-actionbar{display:none}
@media (max-width:760px){
  .pf-actionbar{display:flex;gap:8px;position:sticky;bottom:0;z-index:50;margin:14px -14px -56px;padding:8px 12px calc(8px + env(safe-area-inset-bottom));background:rgba(255,255,255,.97);border-top:1px solid var(--line);box-shadow:0 -4px 16px rgba(16,58,92,.10);backdrop-filter:saturate(1.1) blur(2px)}
  .pf-actionbar a,.pf-actionbar button{flex:1;display:inline-flex;align-items:center;justify-content:center;gap:5px;margin:0;padding:11px 8px;font-size:13px;text-align:center;white-space:nowrap}
  .amain:has(.pf-actionbar){padding-bottom:72px}
}
/* ── calendar day-view mobile list fallback (P0-3): the absolute time-grid is
   unusable on phones, so under 560px we hide it (.cal-daygrid) and show a stacked
   tappable list (.cal-mobile-list). Week view keeps its horizontal scroll. ── */
.cal-mobile-list{display:none}
.cal-mrow{display:flex;gap:10px;align-items:flex-start;padding:11px 12px;margin:7px 0;border-radius:9px;text-decoration:none;color:#0f172a;box-shadow:0 1px 2px rgba(16,58,92,.06)}
.cal-mrow .cal-mtime{flex:0 0 86px;font-weight:700;font-size:13px}
.cal-mrow .cal-mbody{flex:1;min-width:0;word-break:break-word}
.cal-mrow .cal-mstat{flex:none}
/* Floating ＋ (phone-only): the stacked list is read-only, so this is the phone's
   ONLY way into the new-appointment modal (booking + block-outs). 52px target,
   safe-area padded for iOS, z below the modal stack (301). */
.cal-fab{display:none;position:fixed;right:16px;bottom:calc(16px + env(safe-area-inset-bottom,0px));z-index:120;width:52px;height:52px;border-radius:50%;border:0;background:var(--teal);color:#fff;font-size:27px;line-height:52px;text-align:center;padding:0;box-shadow:0 6px 20px rgba(14,124,123,.45);cursor:pointer}
@media (max-width:560px){.cal-daygrid{display:none}.cal-mobile-list{display:block}.cal-fab{display:block}}
/* ── mobile touch targets ≥44px (P0-4); gated so desktop density is untouched ── */
@media (max-width:760px){
  .pfnav-link{width:44px;height:44px}
  .asidebar a{padding:12px 14px}
  input[type=text],input[type=email],input[type=tel],input[type=date],input[type=password],input[type=url],input[type=number],select,textarea{padding:12px}
  button.primary{padding:14px 28px}
  .btn-link{padding:10px 14px}
}
/* ── mobile gap-fill sweep (additive; desktop untouched — everything below is
   gated to ≤760px and scoped to the admin content area .amain) ──
   1. Inline-styled flex toolbars/button-rows may wrap on phones. body has
      overflow-x:hidden, so a non-wrapping row would be CLIPPED and its trailing
      buttons unreachable. Rows that must never wrap opt out by declaring
      flex-wrap or flex-direction inline (the :not() guards). The calendar
      week/day grid rows are unaffected: their columns shrink (flex:1;min-width:0
      with absolutely-positioned tiles), so they never reach the wrap threshold —
      and they live inside their own overflow-x scroll containers anyway.
   2. Inline-styled grids stack to one column (remittance capture form, invoice-
      template settings, the Care-Coordination/Invoicing/Settings hub tiles).
      !important is required to beat the inline declaration — mobile only.
   3. dl.kv detail lists stack label-over-value (the 190px label column plus a
      value can't share a phone row). body.cb-patient keeps its own higher-
      specificity auto/1fr rule, so patient pages are untouched. */
@media (max-width:760px){
  /* .amain's cross-axis auto margins disable flex "stretch", so width:auto
     resolves to FIT-CONTENT — a white-space:nowrap table then inflated the whole
     column to its content width, and body{overflow-x:hidden} clipped everything
     to the right of the viewport (unreachable). Pin it to the viewport so wide
     tables scroll INSIDE their own box instead of widening the page. */
  .amain{width:100%}
  .amain [style*="display:flex"]:not([style*="flex-wrap"]):not([style*="flex-direction"]){flex-wrap:wrap}
  .amain [style*="grid-template-columns"]{grid-template-columns:1fr!important}
  dl.kv{grid-template-columns:1fr;gap:2px 14px}
  dl.kv dt{margin-top:8px}
  dl.kv dt:first-child{margin-top:0}
}
/* ── mobile sweep 2026-07-18 (all ≤760/≤560-gated; desktop ≥761px untouched) ──
   Closes the four escape routes the blanket rules above can't reach: class-based
   rules in per-page <style> blocks, plain tables, the site header (outside
   .amain), and touch-target classes off the 44px allowlist. */
.cal-mday{margin:14px 0 4px;font-size:13px}
.cal-mday a{color:var(--navy);text-decoration:none;font-weight:800}
/* tasks assign popover (moved off inline styles so ≤760px can reflow it) */
.asg-pop{position:absolute;right:0;top:100%;z-index:30;background:#fff;border:1px solid #cbd5e1;border-radius:8px;padding:10px 12px;box-shadow:0 4px 14px rgba(15,23,42,.15);min-width:210px;text-align:left}
/* task row actions: one horizontal strip, not a stacked pile (cosmetic 2026-07-21) */
.rowacts{display:flex;gap:4px 8px;align-items:center;flex-wrap:wrap;white-space:nowrap}
/* sub-task checklists: quiet header instead of the navy banner (cosmetic 2026-07-21) */
table.substeps th{background:#f1f5f9;color:#475569;font-size:11.5px;text-transform:uppercase;letter-spacing:.04em}
@media (max-width:560px){
  .cal-weekgrid{display:none} /* week grid → stacked .cal-mobile-list */
  .pm-moves{columns:1} /* merge "what moves" list */
  .q-actions{flex-direction:column} /* quote Accept/Decline stack; Accept spans */
  .q-actions form,.q-actions button{width:100%}
}
@media (max-width:760px){
  .asg-pop{position:static;box-shadow:none;min-width:0} /* flows in-row — absolute would clip inside .pm-list-viewport */
  .td-aside{width:100%!important;order:2} /* task-detail list pane stacks BELOW the detail */
  .dtag-menu{max-width:calc(100vw - 24px)}
  .cap-srow>span,.cap-srow>a{width:auto!important;text-align:left!important} /* capacity rows wrap tidily */
  table.sched-month{min-width:640px} /* planner month h-scrolls in .scrollx */
  .ab-chip{min-height:44px;display:inline-flex;align-items:center} /* appt/procedure builder chips join the 44px allowlist */
  .hdr-tools{flex-wrap:wrap;justify-content:flex-end} /* header search/help/bell sits outside .amain, so the blanket wrap misses it */
  .rv-bar{flex-wrap:wrap}  /* report review Save/Preview/Download row (class-based flex) */
  .pn-bbps{flex-wrap:wrap} /* BBPS segment-score row */
  .stack-cols tr,.stack-cols td{display:block;width:100%} /* opt-in: side-by-side compare tables stack (patient merge) */
}
/* ── Tasks card-ify (opt-in via class "list-cards" on a wide table.list) ──
   The staff-task tables carry 7-8 cols + a fat Actions cell; on a phone the
   ≤760 nowrap rule pushed Priority/Due/Status/Actions off-screen inside a cramped
   ~370px scroll box (2-axis scroll). Here each DATA row becomes a stacked,
   labelled card. Bucket-header rows (th[colspan]: Overdue/Today/…) stay as
   headings; the column-header row (first tr) is hidden — its labels ride on each
   td via data-label. Every rule is ≤760-gated + .list-cards-scoped ⇒ desktop
   (≥761px) is byte-identical. :has() is safe on this internal staff portal. */
@media (max-width:760px){
  table.list.list-cards{display:block}
  table.list.list-cards tr{display:block}
  table.list.list-cards tr:first-child{display:none} /* column-header row (mobile drops per-table select-all) */
  table.list.list-cards tr:has(>td){border:1px solid var(--line);border-radius:10px;background:#fff;padding:8px 12px;margin:0 0 10px}
  table.list.list-cards tr:hover td{background:transparent} /* kill desktop hover-fill on touch */
  table.list.list-cards td{display:block;border-top:0;padding:3px 0;white-space:normal} /* beats the ≤760 nowrap on table.list */
  table.list.list-cards td[data-label]:not([data-label=""])::before{content:attr(data-label) ": ";font-weight:700;color:#5b6b7b;font-size:12px}
  table.list.list-cards th[colspan]{display:block;padding:10px 2px 4px} /* Overdue/Today/This week/Later group headers */
  .pm-list-viewport:has(table.list-cards){max-height:none;overflow:visible;border:0} /* cards grow with the page, not a 370px inner box */
  #due_at{padding:12px!important} /* task date-picker tap target — beats the inline compact padding, phones only */
}

/* Brand fonts, self-hosted FIRST-PARTY from this worker (payloads in
   src/brandFont.ts, brand assignment in src/brandType.ts, /assets routes in
   routes/register.ts) — keeps the "no third-party origins" PII guarantee while
   rendering the brand faces on every device. font-display:swap → system stack
   until the latin-subset woff2 arrives. */
@font-face{font-family:"Sentient";font-style:normal;font-weight:500;font-display:swap;src:url(/assets/sentient-500.woff2) format("woff2")}
@font-face{font-family:"General Sans";font-style:normal;font-weight:400;font-display:swap;src:url(/assets/general-sans-400.woff2) format("woff2")}
@font-face{font-family:"General Sans";font-style:normal;font-weight:600;font-display:swap;src:url(/assets/general-sans-600.woff2) format("woff2")}
@font-face{font-family:"Fragment Mono";font-style:normal;font-weight:400;font-display:swap;src:url(/assets/fragment-mono-400.woff2) format("woff2")}
body.cb-patient{
  /* brand palette */
  --cb-primary:#c86a4a;--cb-primary-hover:#b0512f;--cb-text:#2f3638;--cb-text-muted:#5e6a6c;
  --cb-bg:#f4efe8;--cb-card:#fff;--cb-gold:#c9a66b;--cb-border:#d8d2c7;--cb-info:#7a9381;
  --cb-info-soft:#eaf0ec;--cb-primary-soft:#fbefe9;--cb-err:#b04a3a;--cb-err-soft:#fbeeec;
  /* typography tokens — the single source of truth is src/brandType.ts */
  --cb-serif:"Sentient",Georgia,"Times New Roman",serif;--cb-serif-wt:500;--cb-sans:"General Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;--cb-mono:"Fragment Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  /* spacing scale (Open Props rhythm: 4/8/12/16/24/32/48) */
  --cb-space-1:4px;--cb-space-2:8px;--cb-space-3:12px;--cb-space-4:16px;--cb-space-5:24px;--cb-space-6:32px;--cb-space-7:48px;
  /* radius + very-soft shadow ramp (low-opacity, adapted from Open Props) */
  --cb-radius:10px;--cb-radius-lg:14px;--cb-radius-pill:999px;
  --cb-shadow-sm:0 1px 2px rgba(47,54,56,.05),0 1px 3px rgba(47,54,56,.04);
  --cb-shadow-md:0 4px 14px rgba(47,54,56,.07),0 2px 6px rgba(47,54,56,.05);
  /* tightened type scale — tiny helper/eyebrow text raised to a readable ≥13px */
  --cb-stone:#d8d2c7;
  --cb-fs-eyebrow:13px;--cb-fs-sm:13px;--cb-fs-help:13px;--cb-fs-base:16px;--cb-fs-lead:17px;
  --cb-fs-h3:18px;--cb-fs-h2:23px;--cb-fs-h1:30px;--cb-fs-hero:38px;
  background:var(--cb-bg);color:var(--cb-text);font-family:var(--cb-sans);line-height:1.6;
}
/* single column, generous whitespace, comfortable reading measure */
body.cb-patient main{max-width:680px;padding:var(--cb-space-6) var(--cb-space-4) var(--cb-space-7)}
/* skip link (layout() patient branch): off-screen until keyboard focus; the
   <main id="main" tabindex="-1"> target takes focus without a ring */
body.cb-patient .cb-skip{position:fixed;left:16px;top:8px;z-index:1000;transform:translateY(-160%);background:var(--cb-text);color:#fff;padding:10px 14px;border-radius:var(--cb-radius);text-decoration:none;font-weight:600}
body.cb-patient .cb-skip:focus{transform:translateY(0)}
body.cb-patient main:focus{outline:0}
body.cb-patient main.wide{max-width:760px}
/* type hierarchy: brand serif headings (weight from brandType.ts), brand sans
   body, muted secondary text */
body.cb-patient h1{font-family:var(--cb-serif);font-weight:var(--cb-serif-wt,700);font-size:var(--cb-fs-h1);line-height:1.18;color:var(--cb-text);margin:0 0 var(--cb-space-4)}
body.cb-patient h2{font-family:var(--cb-serif);font-weight:var(--cb-serif-wt,700);font-size:var(--cb-fs-h2);line-height:1.25;color:var(--cb-text);margin:0 0 var(--cb-space-4)}
body.cb-patient h3{font-family:var(--cb-serif);font-weight:var(--cb-serif-wt,700);font-size:var(--cb-fs-h3);color:var(--cb-text);margin:var(--cb-space-5) 0 var(--cb-space-2)}
body.cb-patient h4,body.cb-patient h5,body.cb-patient h6{font-family:var(--cb-sans);color:var(--cb-text)}
/* label/figures voice: mono on CB, tabular Figtree on UES (brandType.ts) —
   used for invoice figures, references and dates so digits align */
body.cb-patient .num{font-family:var(--cb-mono);font-variant-numeric:tabular-nums}
body.cb-patient .help{color:var(--cb-text-muted);font-size:var(--cb-fs-help)}
body.cb-patient h1 .icon,body.cb-patient h2 .icon{color:var(--cb-primary);flex:none}
body.cb-patient p{margin:0 0 var(--cb-space-3);font-size:var(--cb-fs-base);line-height:1.6}
body.cb-patient a{color:var(--cb-primary)}
body.cb-patient .muted{color:var(--cb-text-muted);font-size:var(--cb-fs-sm)}
/* minimalist soft cards: hairline + very subtle shadow, airy padding, float on limestone.
   A barely-there elevation transition reads as premium polish on hover (not on inputs). */
body.cb-patient .card{background:var(--cb-card);border:1px solid var(--cb-border);border-radius:var(--cb-radius-lg);padding:var(--cb-space-5);margin:var(--cb-space-4) 0;box-shadow:var(--cb-shadow-sm);transition:box-shadow .2s ease,border-color .2s ease}
@media (prefers-reduced-motion:no-preference){body.cb-patient .card:hover{box-shadow:var(--cb-shadow-md);border-color:var(--cb-stone,#d8d2c7)}}
/* calmer notice: soft eucalyptus accent, no harsh fill */
body.cb-patient .notice{border-left:3px solid var(--cb-info);background:var(--cb-info-soft);padding:var(--cb-space-3) var(--cb-space-4);border-radius:0 var(--cb-radius) var(--cb-radius) 0;font-size:15px;color:var(--cb-text);margin:var(--cb-space-3) 0}
/* calmer inputs: airy padding, soft 1px border, soft terracotta focus ring.
   16px, never less: iOS Safari zooms the page on focus of any field under 16px. */
body.cb-patient input[type=text],body.cb-patient input[type=email],body.cb-patient input[type=tel],body.cb-patient input[type=date],body.cb-patient input[type=password],body.cb-patient input[type=url],body.cb-patient input[type=number],body.cb-patient select,body.cb-patient textarea{
  width:100%;padding:13px 14px;border:1px solid var(--cb-border);border-radius:var(--cb-radius);
  font-family:var(--cb-sans);font-size:16px;color:var(--cb-text);background:#fff;
  transition:border-color .15s,box-shadow .15s}
body.cb-patient textarea{resize:vertical;line-height:1.5}
body.cb-patient input:focus,body.cb-patient select:focus,body.cb-patient textarea:focus{outline:0;border-color:var(--cb-primary);box-shadow:0 0 0 3px rgba(200,106,74,.14)}
body.cb-patient label{display:block;font-weight:600;font-size:15px;color:var(--cb-text);margin:var(--cb-space-4) 0 var(--cb-space-2)}
/* calm inline error state — no harsh red fill */
body.cb-patient .error{color:var(--cb-err);font-weight:600;font-size:14px;margin-top:var(--cb-space-2)}
body.cb-patient [aria-invalid="true"]{border-color:var(--cb-err);box-shadow:0 0 0 3px rgba(176,74,58,.10)}
/* soft segmented radio cards */
body.cb-patient .radio-group{display:flex;gap:var(--cb-space-2);margin:var(--cb-space-2) 0;flex-wrap:wrap}
body.cb-patient .radio-group label{flex:1;min-width:90px;border:1.5px solid var(--cb-border);border-radius:var(--cb-radius);padding:13px;text-align:center;cursor:pointer;font-weight:600;font-size:14px;margin:0;background:#fff;color:var(--cb-text);transition:border-color .15s,background .15s,color .15s}
body.cb-patient .radio-group input{position:absolute;opacity:0;width:1px;height:1px;pointer-events:none}
body.cb-patient .radio-group label:has(input:checked){border-color:var(--cb-primary);background:var(--cb-primary-soft);color:var(--cb-primary);font-weight:700}
body.cb-patient .radio-group label:has(input:focus-visible){outline:2px solid var(--cb-primary);outline-offset:2px}
/* full-width, terracotta primary CTA — premium hover lift + soft terracotta shadow,
   pressed state, smooth transitions. Applies on register + booking-link + pay pages. */
body.cb-patient button.primary,body.cb-patient a.primary{background:var(--cb-primary);color:#fff;border:0;border-radius:var(--cb-radius);padding:15px 32px;font-family:var(--cb-sans);font-size:16px;font-weight:600;cursor:pointer;margin-top:var(--cb-space-5);box-shadow:0 2px 8px rgba(200,106,74,.18);transition:background .15s ease,transform .15s ease,box-shadow .15s ease}
body.cb-patient a.primary{display:inline-block;text-decoration:none}
body.cb-patient button.primary:hover,body.cb-patient a.primary:hover{background:var(--cb-primary-hover);filter:none;box-shadow:0 6px 18px rgba(200,106,74,.26)}
body.cb-patient button.primary:active,body.cb-patient a.primary:active{transform:translateY(1px);box-shadow:0 2px 8px rgba(200,106,74,.22)}
@media (prefers-reduced-motion:no-preference){body.cb-patient button.primary:hover{transform:translateY(-1px)}}
body.cb-patient button.primary:focus-visible{outline:2px solid var(--cb-primary);outline-offset:2px}
body.cb-patient button.primary[disabled],body.cb-patient button.primary[aria-busy="true"]{transform:none;box-shadow:none}
/* booking slot day-heading (slotRadios emits h3.rg-sub) + escape-hatch disclosure */
body.cb-patient h3.rg-sub{font-family:var(--cb-serif);font-weight:var(--cb-serif-wt,700);font-size:16px;color:var(--cb-text);margin:var(--cb-space-4) 0 var(--cb-space-2)}
/* one booking day = one fieldset (screen readers announce the date as the group);
   the legend wears the same day-heading look the h3 had */
body.cb-patient fieldset.rg-day{border:0;margin:var(--cb-space-4) 0 0;padding:0;min-width:0}
body.cb-patient fieldset.rg-day>legend.rg-sub{font-family:var(--cb-serif);font-weight:var(--cb-serif-wt,700);font-size:16px;color:var(--cb-text);padding:0;margin:0 0 var(--cb-space-2)}
body.cb-patient fieldset.sf-dayset{border:0;margin:0;padding:0;min-width:0}
body.cb-patient .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
/* booking submit names the chosen payment path (CSS only, JS-off safe; a browser
   without :has() keeps the card wording, which is the default-checked path) */
body.cb-patient .pay-lbl-bank{display:none}
body.cb-patient form:has(input[name="pay_method"][value="bank_transfer"]:checked) .pay-lbl-card{display:none}
body.cb-patient form:has(input[name="pay_method"][value="bank_transfer"]:checked) .pay-lbl-bank{display:inline}
body.cb-patient .fee-today{font-size:17px;margin:0 0 var(--cb-space-3)}
body.cb-patient details.elig-hatch summary{color:var(--cb-primary)}
/* key/value detail list */
body.cb-patient dl.kv{display:grid;grid-template-columns:auto 1fr;gap:var(--cb-space-2) var(--cb-space-4);font-size:15px}
body.cb-patient dl.kv dt{font-weight:600;color:var(--cb-text-muted)}body.cb-patient dl.kv dd{margin:0;color:var(--cb-text)}
/* secondary buttons (e.g. the signature-pad Clear) re-branded from admin teal */
body.cb-patient .btn-link{border-color:var(--cb-border);color:var(--cb-primary)}
body.cb-patient .btn-link:hover{border-color:var(--cb-primary)}
/* signature-pad canvas border on brand stone (not the admin --line grey-blue) */
body.cb-patient .sigwrap canvas{border-color:var(--cb-border)}
/* brand keyboard focus ring */
body.cb-patient :focus-visible{outline:2px solid var(--cb-primary);outline-offset:2px}
/* warm, minimal footer */
body.cb-patient footer{color:var(--cb-text-muted);font-size:var(--cb-fs-sm);max-width:680px;padding-top:var(--cb-space-3);border-top:1px solid var(--cb-border)}
/* patient header: minimal warm identity */
header.site.patient{background:var(--cb-card,#fff);color:var(--cb-text,#2f3638);border-top:3px solid var(--cb-primary,#c86a4a);border-bottom:1px solid #e6e0d6;padding:16px 24px}
header.site.patient .brand{color:var(--cb-primary,#c86a4a);font-family:var(--cb-serif,Georgia,serif);font-size:21px;letter-spacing:.3px;font-weight:var(--cb-serif-wt,700)}
header.site.patient .sub{color:var(--cb-text-muted,#5e6a6c);opacity:1;font-size:13px}
/* mobile: full-width CTA + comfortable tap targets (≥44px), spacing collapses
   gracefully, no horizontal overflow */
@media (max-width:560px){
  body.cb-patient main{padding:var(--cb-space-5) var(--cb-space-4) var(--cb-space-6)}
  body.cb-patient h1{font-size:25px;line-height:1.22}
  body.cb-patient button.primary{width:100%;padding:16px 24px;min-height:48px}
  body.cb-patient .radio-group label{min-width:0;min-height:48px;display:flex;align-items:center;justify-content:center}
  body.cb-patient a{overflow-wrap:break-word;word-break:break-word}
}
