:root{
  --ink:#1a1f24; --muted:#6b7580; --line:#dfe4ea; --bg:#f5f7f9; --card:#fff;
  --brand:#2f7d4f; --brand-d:#276542; --amber:#fff5e0; --amber-b:#e6a817;
  --red:#fdecea; --red-b:#c0392b; --blue:#eef4ff;
  /* Height of the sticky topbar. Named because anchor targets have to clear
     it — see the scroll-margin rule below. */
  --topbar-h:3rem;
}
*{box-sizing:border-box}
body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  color:var(--ink);background:var(--bg);line-height:1.4}
a{color:var(--brand);text-decoration:none}
a:hover{text-decoration:underline}
.wrap{max-width:1000px;margin:0 auto;padding:1rem}
/* Sticky, because the pages are long — a patient with years of visits, or the
   review screen — and the nav scrolling away meant going back to the top of the
   document to reach anything. z-index sits below the bottom action bar (50) and
   the save toast (60), which is the order they should overlap in. */
.topbar{position:sticky;top:0;z-index:40;
  display:flex;flex-wrap:wrap;align-items:center;gap:.4rem 1rem;background:#fff;
  border-bottom:1px solid var(--line);padding:.6rem 1rem}

/* Records search links straight at a visit (#enc-<id>, _content_results.html).
   Without this the sticky bar covers the heading it just jumped to.
   Generous, because the bar WRAPS on a narrow screen and is then two rows
   tall — landing a heading under the nav is the failure this exists to stop,
   so the margin errs high rather than exact. */
[id^="enc-"]{scroll-margin-top:calc(var(--topbar-h) * 2 + .5rem)}
.brand{font-weight:700;font-size:1.1rem}
.tagline{color:var(--muted);font-size:.9rem}
h1{font-size:1.5rem;margin:.4rem 0}
h2{font-size:1.2rem;margin:1.2rem 0 .4rem}
h3{font-size:1rem;margin:.8rem 0 .3rem}
.muted{color:var(--muted)}
.small{font-size:.82rem}
.back{display:inline-block;margin:.2rem 0 .6rem;color:var(--muted)}

/* search / home */
.hero{max-width:640px;margin:2rem auto}
.search-box{width:100%;font-size:1.15rem;padding:.8rem 1rem;border:2px solid var(--line);
  border-radius:10px}
.search-box:focus{outline:none;border-color:var(--brand)}
/* search box + the photo-import camera on one row (workbench). The input takes
   the room; the button keeps its square. */
.search-row{display:flex;align-items:stretch;gap:.5rem}
.search-row .search-box{flex:1;min-width:0}
.photoform-compact{display:flex;align-items:center;gap:.4rem;margin:0}
/* A label, not a button, because it wraps the hidden file input — so it needs
   the button's look spelled out here. Matches .search-box's height and radius so
   the pair reads as one control. */
.icon-btn{display:flex;align-items:center;justify-content:center;height:100%;
  min-width:3rem;padding:0 .8rem;font-size:1.3rem;line-height:1;cursor:pointer;
  background:var(--card);border:2px solid var(--line);border-radius:10px}
.icon-btn:hover{border-color:var(--brand)}
/* Visible to a screen reader, and to nothing else: the camera glyph alone is not
   a label. */
.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}
.htmx-indicator{opacity:0;color:var(--muted);font-size:.85rem;transition:opacity .2s}
.htmx-request .htmx-indicator,.htmx-indicator.htmx-request{opacity:1}
.results{margin-top:1rem}
.patient-list{list-style:none;padding:0;margin:.5rem 0}
.patient-list.tight li{margin:.2rem 0}
.patient-row{display:flex;flex-direction:column;background:var(--card);border:1px solid var(--line);
  border-radius:8px;padding:.6rem .9rem;margin:.35rem 0}
.patient-row:hover{border-color:var(--brand);text-decoration:none}
/* Same row as a submit button (photo import files the visit under an existing
   patient), so it needs the defaults a <button> brings and an <a> does not. */
button.patient-row{width:100%;text-align:left;font:inherit;color:inherit;cursor:pointer}
.pname{font-weight:600}
.pmeta{color:var(--muted);font-size:.85rem}
.btn-newpatient{display:inline-block;margin-top:.6rem;padding:.55rem .9rem;border:1px dashed var(--brand);
  border-radius:8px;color:var(--brand)}
/* Clinical Memory results sit BELOW the local ones and are visibly a separate
   list. Merging the two would hide which system a patient is actually in — and
   the difference matters: one is on this Pi and works offline, the other is a
   record elsewhere that has to be pulled across before it can be worked on. */
.cm-results{margin-top:1.1rem}
.cm-heading{color:var(--muted);font-size:.8rem;text-transform:uppercase;
  letter-spacing:.05em;margin:0 0 .2rem}
.cm-pull{flex-direction:row;align-items:center;flex-wrap:wrap;gap:.2rem .8rem}
.cm-pull .pname{flex:0 0 auto}
.cm-pull .pmeta{flex:1 1 100%;order:3}
.cm-pull button{margin-left:auto}
.all-patients{margin-top:1.2rem;font-size:.95rem}
.pager{display:flex;gap:1rem;align-items:center;justify-content:center;margin:1rem 0}

/* name-field type-ahead dropdown (new patient form) */
.dd-anchor{position:relative}
.name-dd{list-style:none;margin:0;padding:0;position:absolute;left:0;right:0;top:100%;
  z-index:30;background:#fff;border:1px solid var(--line);border-radius:0 0 8px 8px;
  box-shadow:0 6px 18px rgba(0,0,0,.12);max-height:40vh;overflow-y:auto}
.name-dd .dd-head{padding:.4rem .7rem;font-size:.75rem;font-weight:400;color:var(--muted);
  background:var(--amber);border-bottom:1px solid var(--line)}
.name-dd li a{display:flex;flex-direction:column;padding:.5rem .7rem;font-size:16px;
  border-bottom:1px solid var(--line);font-weight:400}
.name-dd li:last-child a{border-bottom:none}
.name-dd li a:hover{background:var(--blue);text-decoration:none}

/* cards / forms */
.card{background:var(--card);border:1px solid var(--line);border-radius:10px;padding:1rem;max-width:640px}
/* A backup/secondary card (patient.html's "Bill this visit" and "Add a
   report") -- collapsed by default, and quieter than a primary action even
   once opened, so it doesn't compete with the clinical content this page
   actually exists for. Input/select font-size is deliberately left alone
   (16px, unshrunk) -- that's what stops iOS Safari auto-zooming on focus,
   not worth trading away just to save a few px of card height. */
.card.compact{padding:.55rem .75rem;max-width:480px}
.card.compact summary{font-size:.85rem;cursor:pointer;color:var(--muted)}
.card.compact summary:hover{color:inherit}
.card.compact .btn-primary,.card.compact .btn{font-size:.8rem;padding:.35rem .6rem}
.card.compact table{font-size:.8rem}
.card.compact label{font-size:.75rem}
label{display:block;font-weight:600;font-size:.9rem;margin:.5rem 0}
input,select,textarea{width:100%;font-size:16px;padding:.55rem .6rem;border:1px solid var(--line);
  border-radius:7px;font-family:inherit;background:#fff}
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--brand)}
.row{display:flex;gap:.8rem;flex-wrap:wrap}
.row>label{flex:1;min-width:140px}
textarea.dictation{font-size:16px;line-height:1.5;min-height:8rem}
/* The dictation reads back rather than types back: it is the record of what
   was said, and the sections below are what gets edited. Looking like an
   input is what would make it feel broken. */
textarea.dictation[readonly]{background:var(--bg);color:var(--ink);cursor:default}
.btn,.btn-primary{display:inline-block;font-size:1rem;padding:.6rem 1rem;border-radius:8px;
  border:1px solid var(--line);background:#fff;cursor:pointer;color:var(--ink)}
.btn-primary{background:var(--brand);color:#fff;border-color:var(--brand);font-weight:600}
.btn-primary:hover{background:var(--brand-d);text-decoration:none}
.btn.small{font-size:.85rem;padding:.4rem .7rem}
.phead{display:flex;justify-content:space-between;align-items:flex-start;flex-wrap:wrap;gap:1rem}

/* bulk photo-import queue */
.pi-item{max-width:none}
.pi-row{display:flex;gap:1rem;align-items:flex-start;flex-wrap:wrap}
.pi-thumb{width:140px;height:auto;max-height:180px;object-fit:contain;border:1px solid var(--line);
  border-radius:7px;background:#fff;flex-shrink:0}
.pi-fields{flex:1;min-width:280px}
.pi-select{display:flex;align-items:center;gap:.5rem;font-weight:400;background:var(--blue);
  border-radius:7px;padding:.5rem .7rem}
.pi-select input{width:auto}

/* Patient identity as a disclosure: the name and meta line ARE the <summary>,
   with a caret that turns from ▸ to ▾. Editing a registration is a rare
   correction, so it gets a caret rather than a bar of its own. */
.pedit{min-width:0}
.pedit-summary{list-style:none;cursor:pointer}
.pedit-summary::-webkit-details-marker{display:none}   /* Safari's own triangle */
.pedit-summary h1{display:flex;align-items:center;gap:.35rem;margin:0}
.pedit-caret{width:1.1rem;height:1.1rem;flex:none;color:var(--muted);
  transition:transform .15s ease}
.pedit-summary:hover .pedit-caret{color:var(--brand)}
.pedit[open] .pedit-caret{transform:rotate(90deg)}
/* Keyboard users get the focus ring on the caret, not a box round the name. */
.pedit-summary:focus{outline:none}
.pedit-summary:focus-visible .pedit-caret{outline:2px solid var(--brand);
  outline-offset:2px;border-radius:3px}
.pedit-summary .pmeta{display:block;margin-top:.15rem}
.pedit-form{margin:.7rem 0 .2rem;padding:.7rem .9rem;background:var(--card);
  border:1px solid var(--line);border-radius:8px}
.pedit-form .row{margin-bottom:.5rem}

/* badges */
.badge{display:inline-block;font-size:.7rem;text-transform:uppercase;letter-spacing:.04em;
  padding:.1rem .45rem;border-radius:20px;vertical-align:middle}
.badge.draft{background:#fff3cd;color:#7a5b00}
.badge.final{background:#d7f0e0;color:#1d6b3f}
.badge.super{background:#eee;color:#888}
/* A brand that has not been matched against this formulary with confidence.
   Amber rather than red: it is a question, not a refusal — but finalize will
   not let it print until it has been answered. */
.badge.warn{background:var(--amber);color:#7a5b00}
/* A medicine pulled forward from an earlier visit -- informational, not a
   warning (it's already confirmed, never blocks finalize), so a quieter
   neutral tone than .badge.warn's amber. */
.badge.carried-fwd{background:#e6eef5;color:#3a5a78}

/* boxes */
.warnbox,.errbox,.redbox{border-radius:8px;padding:.7rem .9rem;margin:.6rem 0}
.warnbox{background:var(--blue);border:1px solid #b9d0f5}
.warnbox.amber{background:var(--amber);border:1px solid var(--amber-b)}
.errbox{background:var(--red);border:1px solid var(--red-b);color:var(--red-b)}
/* Prescribing cautions: advisory, never printed. 'high' reads like the red
   unsorted box because it is the one that stops a finalize until acknowledged. */
.cautionbox{border:1px solid var(--amber-b);background:var(--amber);
  border-radius:8px;padding:.7rem .9rem;margin:.6rem 0}
.cautionbox h3{margin:.1rem 0 .5rem}
.caution{border-left:4px solid var(--amber-b);padding:.1rem 0 .1rem .7rem;margin:.55rem 0}
.caution-high{border-left-color:var(--red-b)}
.caution p{margin:.2rem 0}
.caution-ack{display:block;margin:.35rem 0 .1rem;font-size:.9rem}
.caution-ack input{margin-right:.4rem}
.redbox{background:var(--red);border:1px solid var(--red-b)}
.redbox .uns-item{display:flex;gap:.5rem;margin:.35rem 0;flex-wrap:wrap}
.redbox .uns-item input[type=text]{flex:2;min-width:180px}
.redbox .uns-item select{flex:1;min-width:130px}

/* second reader (advisory flags) */
.srbox{background:#f3eefc;border:1px solid #c3aee6;border-radius:9px;padding:.55rem .8rem;margin:.6rem 0}
.sr-head{font-weight:700;font-size:.92rem;margin-bottom:.15rem}
.srflag{display:flex;justify-content:space-between;align-items:center;gap:.6rem;
  padding:.32rem 0;border-top:1px dashed #d8c9ef;font-size:.9rem}
.srflag.ok{color:#1d6b3f}
.sr-msg{flex:1}

/* review layout — dictation stacked on top, subsections below, both full
   width, so medicine rows get the whole page to work with instead of a
   squeezed side column. */
.review-cols{display:flex;flex-direction:column;gap:1.2rem}
.raw-pane{background:var(--bg)}

/* Review screen only: uncapped, unlike the site-wide 1000px .wrap every
   other page uses -- a fixed max-width here centers the page and leaves
   equal dead margin on both sides on anything wider than that cap, which
   on an ordinary laptop screen read as the sidebar "not starting from the
   left edge" rather than as normal page margin. Fluid instead, so the
   sidebar sits flush against the real edge and the form gets whatever
   width the window actually has. */
.wrap.review-wrap{max-width:none}

/* The prescription preview is a stand-in for a printed page -- letting it
   stretch edge-to-edge along with the now-fluid .review-wrap above (a wide
   laptop screen was making its columns spread out nothing like an actual
   sheet of paper would) would fight that purpose, so it keeps a page-like
   width of its own regardless of how wide review-main gets. Scoped to
   review-main specifically -- .preview-frame also appears un-nested in a
   patient's visit timeline (patient.html), which is not this page and
   should not pick up this cap. */
.review-main .preview-frame{max-width:900px}

/* Review-screen jump nav. Sticky, hidden below 900px -- no room to spare
   beside the form at that width, and this stays a nice-to-have, not
   load-bearing (the page reads fine top-to-bottom without it either way).
   Width is sized to fit "Clinical History", the longest label, on one
   line; now that .review-wrap is fluid this is a small fraction of the
   window either way, so it doesn't need to be squeezed any tighter than
   that. The right border still gives the eye an actual edge to stop at.
   top:50% + translateY(-50%) is the standard trick for a vertically
   *centered* sticky sidebar (as opposed to pinned-to-top): the nav is
   short next to the very long form beside it, and stuck under the topbar
   it read as stranded at the top of the screen rather than a map to the
   whole page. */
.review-sidenav{display:none}
@media(min-width:900px){
  .review-page{display:flex;align-items:flex-start;gap:.75rem}
  .review-sidenav{display:block;flex:0 0 140px;position:sticky;
    top:50%;transform:translateY(-50%);border-right:1px solid var(--line);
    padding-right:.6rem}
  .review-main{flex:1;min-width:0}
}
.review-sidenav a{display:block;padding:.25rem .4rem;border-radius:5px;
  font-size:.85rem;line-height:1.25;color:var(--ink);white-space:nowrap}
.review-sidenav a:hover{background:var(--bg);text-decoration:none}

/* Same clearance trick as [id^="enc-"] above -- keeps the sticky topbar
   from covering whatever the sidebar just jumped to. */
#preview-frame,#sec_complaints,#sec_vitals,#sec_examination,
#sec_investigations,#sec_diagnosis,#meds-section,#sec_advice,
#sec_referral,#review_raw,#chat_message{
  scroll-margin-top:calc(var(--topbar-h) + .6rem);
}

/* Brief flash confirming arrival -- the standing :focus ring elsewhere in
   this file is a deliberately subtle border/box-shadow change, easy to
   miss on a fast click between sections. */
.nav-highlight{animation:nav-flash 1.4s ease-out}
@keyframes nav-flash{
  0%{box-shadow:0 0 0 3px var(--brand)}
  100%{box-shadow:0 0 0 3px rgba(47,125,79,0)}
}
.secgrid{display:grid;grid-template-columns:1fr 1fr;gap:.4rem 1rem}
@media(max-width:640px){.secgrid{grid-template-columns:1fr}}
/* Collapsed by default (_review_body.html) -- the direct .secgrid child now,
   so grid-column:1/-1 lives here instead of on .photoctl (nested inside it,
   no longer a grid item itself); without it Diagnosis, the next field,
   would share this row instead of sitting alone on the left. */
.report-upload-card{grid-column:1/-1;border:1px solid var(--line);border-radius:8px;
  padding:.4rem .6rem;margin:.2rem 0}
.report-upload-card summary{font-size:.85rem;color:var(--muted);cursor:pointer}
.report-upload-card summary:hover{color:inherit}
.report-upload-card[open] summary{margin-bottom:.3rem}
/* Report upload controls, sitting in the section grid between Investigations
   and Diagnosis. One row of its own so it doesn't get read as a section field. */
.photoctl{display:flex;align-items:end;flex-wrap:wrap;gap:.5rem;
  margin:.2rem 0 .4rem}
.photoctl label{display:flex;flex-direction:column;gap:.2rem;margin:0}
.report-import .photoctl{margin:0}
/* Its own row below .photoctl (see _report_import_controls.html), not a
   flex child of it. grid-column:1/-1 because it sits directly in .secgrid
   (a 2-column grid) as .photoctl's sibling -- without it, this becomes the
   grid's next left-column cell and Diagnosis (the following field) gets
   pulled into the right column beside it, off on its own instead of
   sitting alone on the left the way every other trailing field does. */
.separate-reports-ck{display:block;grid-column:1/-1;font-size:.85rem;font-weight:400;
  margin:.3rem 0 .2rem}
/* input,select,textarea{width:100%} (global form-control rule, above) would
   otherwise stretch this checkbox to fill the row and push its own label
   text onto the next line -- same override already used for every other
   checkbox/radio in this file (e.g. .cand input[type=radio]). */
.separate-reports-ck input{width:auto;vertical-align:middle;margin:0 .35rem 0 0;padding:0}

/* Medicines: one row per medicine (_med_row.html), not a card -- a taper
   textarea open by default on every row, whether or not that medicine ever
   had one, used to be the single biggest source of scrolling on this
   screen. Wrapped in its own horizontal-scroll container (not the page
   body) on a narrow viewport, the same "wide content scrolls in its own
   box" rule the print preview already follows -- there just isn't room to
   reflow seven columns into a phone-width column without either
   truncating data or going back to a multi-row card. */
.med-table-wrap{overflow-x:auto;margin-top:.4rem}
.med-table{width:100%;border-collapse:collapse;min-width:640px}
.med-table th{text-align:left;font-size:.72rem;text-transform:uppercase;letter-spacing:.03em;
  color:var(--muted);font-weight:600;padding:0 .3rem .25rem}
.med-table td{padding:.15rem .3rem;vertical-align:middle}
.med-table input,.med-table select{padding:.35rem .4rem;font-size:.85rem}
.med-row{border-top:1px solid var(--line)}
.med-row.needs{background:var(--amber)}
.med-row .med-num{white-space:nowrap;font-weight:700;color:var(--brand);font-size:.8rem}
.med-num-n{vertical-align:middle}
.carried-fwd-dot{margin-left:.2rem;cursor:help;font-size:.68rem;font-weight:600;
  color:var(--muted);text-transform:uppercase;letter-spacing:.02em}
.med-brand{display:flex;gap:.2rem;min-width:11rem}
.form-prefix{flex:0 0 auto;width:auto !important;min-width:3.6rem;color:var(--muted)}
.brand-in{flex:1;min-width:6rem;font-weight:600}
.med-comp{min-width:9rem}
.med-comp input{text-overflow:ellipsis}
.med-dose,.med-timings,.med-duration,.med-food{min-width:5rem}
.med-del{text-align:center}
.med-del .del-icon{background:none;border:none;cursor:pointer;color:var(--red-b);font-size:1rem;line-height:1;padding:2px 4px}
.med-del .del-icon:hover{opacity:.7}
.med-confirm-row td,.med-extra-row td{padding:.2rem .3rem .5rem;border-top:none}
.med-extra-row:last-child td{padding-bottom:.6rem}
/* Collapsed by default, open only when the medicine already has taper
   steps (see _med_row.html) -- most medicines never get one. */
.taper-details{margin-top:.2rem}
.taper-details summary{font-size:.8rem;color:var(--muted);cursor:pointer}
.taper-details summary:hover{color:inherit}
.taper-details[open] summary{margin-bottom:.3rem}
.confirm{margin:.3rem 0;font-size:.9rem}
.cands{display:flex;flex-direction:column;gap:.2rem;margin-top:.3rem}
.cand{font-weight:400;font-size:.85rem;display:flex;align-items:center;gap:.4rem;margin:0}
.cand input[type=radio]{width:auto}
.cand input[type=text]{width:auto;flex:1}
.taper-view{font-size:.82rem;color:#444}
.taper-view ul{margin:.2rem 0 0 1rem;padding:0}
.taper-steps{margin-top:.4rem;padding:.4rem .5rem;border:1px dashed var(--line);border-radius:8px}
.taper-step-row{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap;margin:.3rem 0}
.taper-step-row .step-idx{font-weight:700;color:var(--brand);width:1.2em}
.taper-step-row input[type=text],.taper-step-row input:not([type]){flex:1;min-width:6rem}
.taper-step-row .ovr{display:flex;align-items:center;gap:.3rem;font-weight:400;font-size:.78rem;
  color:var(--brand-d);width:100%}
@media(min-width:640px){.taper-step-row .ovr{width:auto}}
.taper-step-row .ovr input{width:auto}
.rememberf{display:flex;align-items:center;gap:.35rem;margin:.4rem 0 0;font-weight:400;
  font-size:.82rem;color:var(--brand-d)}
.rememberf input{width:auto}
.med-actions{display:flex;gap:.6rem;flex-wrap:wrap;margin-top:.4rem}

.past-panel:not(:empty){border:1px solid var(--line);border-radius:9px;padding:.6rem .7rem;
  margin:.5rem 0;background:var(--bg)}
.past-head{display:flex;align-items:baseline;gap:.5rem;margin-bottom:.4rem}
.past-visit{padding:.35rem 0;border-top:1px dashed var(--line)}
.past-visit:first-of-type{border-top:none}
.past-date{display:block;font-weight:600;font-size:.82rem;cursor:pointer}
.past-date input[type=checkbox]{width:auto;margin:0 .4rem 0 0;padding:0;vertical-align:middle}
.past-meds{margin:.2rem 0 .2rem 1.2rem;display:flex;flex-direction:column;gap:.15rem}
.past-med{position:relative;display:block;padding-right:1.7rem;font-size:.8rem;font-weight:400;cursor:pointer}
.past-med input[type=checkbox]{position:absolute;right:0;top:.15rem;width:auto;margin:0;padding:0;vertical-align:middle}
.past-brand{font-weight:600}
.past-actions{display:flex;gap:.6rem;margin-top:.5rem}
/* saved medicine sets ("Rx templates") picker */
.set-list{display:flex;flex-direction:column;gap:.25rem;margin:.35rem 0}
.set-row{display:flex;align-items:center;gap:.5rem;padding:.1rem 0}
.set-add{flex:none}
.set-name{font-weight:600;font-size:.85rem}
.set-count{font-size:.78rem}
.set-del{margin-left:auto;line-height:1}
.set-save{display:flex;gap:.5rem;align-items:center;flex-wrap:wrap;margin-top:.5rem;
  padding-top:.5rem;border-top:1px dashed var(--line)}
.set-save .set-name-input{flex:1;min-width:180px;width:auto}
.set-msg{margin:.2rem 0;font-weight:600}
.set-msg.ok{color:var(--brand)}
.set-msg.err{color:var(--red-b)}

.actions{display:flex;gap:.6rem;flex-wrap:wrap;margin-top:1rem}
.actions.sticky{position:fixed;left:0;right:0;bottom:0;z-index:50;margin:0;
  justify-content:center;padding:.6rem 1rem;
  background:var(--card);border-top:1px solid var(--line);box-shadow:0 -2px 10px rgba(0,0,0,.08)}
@media print{.actions.sticky{display:none}}
/* clearance so the viewport-fixed action bar never hides the bottom of the review */
#reviewroot{padding-bottom:5rem}

/* preview */
.preview-frame{background:#fff;border:1px solid var(--line);border-radius:10px;padding:.5rem 1rem;
  margin-top:1.2rem;box-shadow:0 1px 6px rgba(0,0,0,.05)}
.chat-frame{margin-top:1.2rem;background:var(--bg);border:1px solid var(--line);
  border-radius:10px;padding:.6rem 1rem}
.chat-log{max-height:260px;overflow-y:auto;margin:.4rem 0;display:flex;flex-direction:column;gap:.5rem}
.chat-turn{display:flex;flex-direction:column;gap:.1rem;padding:.4rem .6rem;border-radius:8px}
.chat-user{background:rgba(0,0,0,.04);align-self:flex-end;max-width:85%}
.chat-assistant{background:rgba(60,120,220,.08);align-self:flex-start;max-width:85%}
.chat-who{font-size:.72rem;font-weight:600;color:var(--muted)}
.chat-text{white-space:pre-wrap}
.chat-empty{margin:.4rem 0}
.chat-form{display:flex;flex-direction:column;gap:.4rem}
.chat-form textarea{width:100%;resize:vertical;font:inherit;padding:.4rem .6rem;
  border:1px solid var(--line);border-radius:8px}
.chat-actions{display:flex;align-items:center;justify-content:flex-end;gap:.6rem}
.timeline{margin-top:1.2rem}
.timeline summary{cursor:pointer;font-weight:600}
.timeline ul{list-style:none;padding:0}
.timeline li{padding:.35rem 0;border-bottom:1px dashed var(--line)}
.timeline li.superseded a{text-decoration:line-through;color:var(--muted)}
.earlier>summary{cursor:pointer;font-weight:600;font-size:1.1rem;margin:1.2rem 0 .4rem}
.visit{margin:.8rem 0 1.4rem;border:1px solid var(--line);border-radius:8px;padding:.4rem .8rem}
.visit>h3{font-size:1rem;font-weight:600}
.visit.superseded>h3{color:var(--muted);text-decoration:line-through}
.visit .preview-frame{margin-top:.8rem}

/* ---- roles / reception / workbench / billing --------------------------- */
/* WRAPS. The doctor nav is seven links now, and a flex row that cannot wrap
   does not shrink or scroll — it runs off the right edge, and the last items
   simply cannot be reached. On a phone at the clinic that silently hid
   Formulary and Clinical Memory, which looked like the features were missing
   rather than the link being off-screen. */
.topnav{margin-left:auto;display:flex;flex-wrap:wrap;gap:.4rem 1rem;
  align-items:center;font-size:.9rem}
.topnav a{color:var(--ink);white-space:nowrap}

/* "Settings" — a native <details> disclosure grouping the config/reference
   links used far less than the rest of the bar (see nav-settings-menu
   below). No JS: opens/closes on its own like any other <details>. */
.nav-settings{position:relative}
.nav-settings summary{cursor:pointer;color:var(--ink);list-style:none}
.nav-settings summary::-webkit-details-marker{display:none}
.nav-settings summary::after{content:" ▾";font-size:.75em;color:var(--muted)}
.nav-settings-menu{position:absolute;top:calc(100% + .4rem);right:0;
  background:var(--card);border:1px solid var(--line);border-radius:8px;
  box-shadow:var(--shadow-hover);padding:.4rem;display:flex;
  flex-direction:column;gap:.15rem;min-width:170px;z-index:45}
.nav-settings-menu a{display:block;padding:.3rem .5rem;border-radius:6px}
.nav-settings-menu a:hover{background:var(--bg);text-decoration:none}

.rolepick{max-width:680px;margin:2rem auto;text-align:center}
.role-cards{display:flex;gap:1rem;justify-content:center;flex-wrap:wrap;margin-top:1.2rem}
.role-card{flex:1;min-width:240px;max-width:300px;background:var(--card);border:1px solid var(--line);
  border-radius:12px;padding:1.4rem 1rem;display:flex;flex-direction:column;align-items:center;gap:.5rem}
.role-emoji{font-size:2.4rem}
.role-card h2{margin:.2rem 0}
.pin-label{width:100%;display:flex;flex-direction:column;gap:.2rem;font-size:.85rem;font-weight:600;text-align:left}
.pin-label input{padding:.5rem;border:1px solid var(--line);border-radius:8px;font-size:1rem}

.tiles{display:flex;gap:.8rem;flex-wrap:wrap;margin:.6rem 0 1rem}
.tile{flex:1;min-width:120px;background:var(--card);border:1px solid var(--line);border-radius:10px;
  padding:.8rem 1rem;text-align:center}
.tile.total{background:var(--blue)}
.tile-n{display:block;font-size:1.7rem;font-weight:700}
.tile-l{display:block;color:var(--muted);font-size:.8rem;text-transform:uppercase;letter-spacing:.04em}
.tile-link{display:block;text-decoration:none;color:inherit;cursor:pointer}
.tile-link:hover{border-color:var(--brand)}

.queue{list-style:none;padding:0;margin:.4rem 0}
.queue-row{display:flex;align-items:center;justify-content:space-between;gap:.6rem;
  padding:.5rem .7rem;border:1px solid var(--line);border-radius:8px;margin:.35rem 0;background:var(--card)}
.queue-row.waiting{border-left:3px solid var(--amber-b)}
.queue-row.seen{border-left:3px solid var(--brand)}
.queue-row a{display:flex;flex-direction:column}
.queue-row .pmeta{color:var(--muted);font-size:.8rem}
.wb-acts{display:flex;gap:.4rem;align-items:center}
.wb-cols{display:grid;grid-template-columns:1fr 1fr;gap:1.2rem}
@media(max-width:700px){.wb-cols{grid-template-columns:1fr}}

.bill-table,.earn-table{width:100%;border-collapse:collapse;margin:.5rem 0}
.bill-table th,.bill-table td,.earn-table th,.earn-table td{padding:.4rem .5rem;border-bottom:1px solid var(--line);text-align:left}
.bill-table .num,.earn-table .num{text-align:right}
.bill-table input,.earn-table input{width:100%;padding:.3rem .4rem;border:1px solid var(--line);border-radius:6px}
.bill-form{display:flex;gap:.6rem;flex-wrap:wrap;align-items:flex-end;margin-top:.8rem}
.bill-form label{display:flex;flex-direction:column;font-size:.8rem;font-weight:600;gap:.2rem}
.bill-form select,.bill-form input{padding:.45rem;border:1px solid var(--line);border-radius:8px;font-size:.95rem}
.btn-x{background:none;border:none;color:var(--red-b);cursor:pointer;font-size:1rem}
.bill-edit{display:inline-block;position:relative}
.bill-edit summary{display:inline;cursor:pointer;color:var(--brand);font-size:1rem;list-style:none}
.bill-edit summary::-webkit-details-marker{display:none}
.bill-edit-form{position:absolute;right:0;z-index:5;margin-top:.3rem;padding:.6rem;
  background:#fff;border:1px solid var(--line);border-radius:8px;box-shadow:0 2px 8px rgba(0,0,0,.12);
  display:flex;gap:.4rem;flex-wrap:nowrap;align-items:center;white-space:nowrap}
.bill-edit-form select,.bill-edit-form input{padding:.35rem;border:1px solid var(--line);border-radius:6px;font-size:.85rem;flex-shrink:0}
.bill-edit-form input[type=number]{width:5.5em}
.bill-edit-form select[name=head_key]{width:9em}
.bill-edit-form select[name=mode]{width:6em}
.new-head{margin-top:1rem;border:1px solid var(--line);border-radius:8px;padding:.6rem .8rem;display:flex;gap:.8rem;flex-wrap:wrap}
.new-head label{display:flex;flex-direction:column;font-size:.8rem;font-weight:600;gap:.2rem}
.new-head input{padding:.4rem;border:1px solid var(--line);border-radius:6px}
.day-pick{margin:.4rem 0}
.rx-lang{display:inline-flex;align-items:center;gap:.5rem;margin:.2rem 0 .6rem;font-size:.8rem;font-weight:600}
.rx-lang select{padding:.35rem .5rem;border:1px solid var(--line);border-radius:6px;font-size:.9rem}

/* Structured taper step-row converter (taper.js). Reuses the pre-existing
   .taper-steps/.taper-step-row/.step-idx/.ovr shape (already server-rendered
   for dictated tapers); only the header bar, the "+ Taper schedule" toggle's
   spacing, and the per-step remove button need new rules. */
.taper-toggle{margin-top:.4rem}
.taper-head{display:flex;align-items:center;justify-content:space-between;gap:.5rem;margin-bottom:.25rem}
.taper-x{width:auto;flex:0 0 auto;padding:.15rem .55rem;font-size:1.05rem;line-height:1;
  border:1px solid var(--line);border-radius:6px;background:#fff;color:var(--muted);cursor:pointer}
.taper-x:hover{border-color:var(--red-b);color:var(--red-b)}

/* ------------------------------------------------------------------ *
 * Design refresh (2026-07-25): calmer, more compact, minimal.
 * Appended override block — cleanly overrides the base rules above and
 * can be removed wholesale to revert. Static/CSS only; no restart.
 * Semantic colours (amber "needs confirm", red delete, brand green)
 * are deliberately left untouched.
 * ------------------------------------------------------------------ */
:root{
  --ink:#1a222b; --muted:#697079; --line:#e7eaee; --bg:#f6f7f9; --card:#fff;
  --shadow:0 1px 2px rgba(17,24,39,.05);
  --shadow-hover:0 2px 6px rgba(17,24,39,.09);
  --radius:9px;
}

/* Subtle elevation instead of relying on borders alone — cards read as
   distinct surfaces on the page without heavy outlines. */
.card,.patient-row,.tile,.role-card,.queue-row,
.past-panel:not(:empty),.preview-frame,.chat-frame{
  box-shadow:var(--shadow);
}
.card,.tile,.role-card,.preview-frame,.chat-frame{border-radius:var(--radius)}
.patient-row:hover,.role-card:hover{box-shadow:var(--shadow-hover)}

/* Modern, accessible focus ring (keeps the brand-coloured border too). */
input:focus,select:focus,textarea:focus,.search-box:focus{
  box-shadow:0 0 0 3px rgba(47,125,79,.13);
}

/* Tighter, more even vertical rhythm — less dead space, denser but calm. */
h1{margin:.3rem 0}
h2{margin:.9rem 0 .35rem}
h3{margin:.65rem 0 .3rem}
.review-cols{gap:1rem}
.actions{margin-top:.8rem}

/* Quieter topbar divider. */
.topbar{box-shadow:var(--shadow)}

/* "Draft saved" confirmation toast (see preview-scroll.js). Deliberately in
   the top-right corner, clear of the bottom sticky action bar. */
.save-toast{position:fixed;top:.8rem;right:.8rem;z-index:60;
  background:var(--brand);color:#fff;font-size:.85rem;font-weight:600;
  padding:.5rem .9rem;border-radius:8px;box-shadow:0 3px 10px rgba(0,0,0,.18);
  opacity:0;transform:translateY(-6px);transition:opacity .2s,transform .2s;pointer-events:none}
.save-toast.show{opacity:1;transform:translateY(0)}

/* Preview medicine drag-to-reorder (static/med-reorder.js) -- a floating
   label following the pointer plus a line showing where it'll land, both
   position:fixed so they float above the sheet regardless of scroll, and
   pointer-events:none so they never intercept the drag they're illustrating. */
.med-drag-ghost{position:fixed;z-index:70;pointer-events:none;
  background:#fff;border:1px solid var(--line);border-radius:8px;
  padding:.3rem .7rem;font-size:.85rem;font-weight:600;color:var(--brand);
  box-shadow:0 4px 14px rgba(0,0,0,.2);opacity:0;transform:scale(.9);
  transition:opacity .12s,transform .12s}
.med-drag-ghost.show{opacity:1;transform:scale(1)}
.med-drag-indicator{position:fixed;z-index:69;height:3px;background:var(--brand);
  border-radius:2px;pointer-events:none;opacity:0;transition:top .12s ease,opacity .12s}
.med-drag-indicator.show{opacity:1}

/* Other editions of one visit — an amendment still open, or a pair of finals
   from before Amend was guarded. Deliberately cramped: an edition is not a
   visit, and laying it out like one is what made the timeline read as a thread. */
.editions{margin:.4rem 0 0}
.editions > summary{cursor:pointer;color:var(--muted);font-size:.85rem}
.edition{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;
  padding:.35rem 0;border-top:1px dashed var(--line);font-size:.9rem}

/* Language sits on the print bar beside Save/Finalize, not at the top of the
   edit pane — it describes the sheet being printed, so it belongs with the
   actions that print it. Quieter than a form field: a toolbar control. */
.actions.sticky .rx-lang{margin:0;font-weight:500;color:var(--muted)}
.actions.sticky .rx-lang select{padding:.3rem .4rem;font-size:.85rem}

/* Age beside the patient's name on the review screen. It is demographic and
   almost never touched, so it reads as part of the identity line — but it stays
   an input, because a patient with no recorded date of birth has this typed at
   intake and this is the only place a wrong one can be fixed for that visit. */
/* Ordinary inline flow, so "(", the field and ")" sit together as text rather
   than as flex items with their own boxes. */
.age-inline{padding:0;border:none;background:transparent;
  color:inherit;font:inherit;text-align:left;vertical-align:baseline;
  /* Sized to what it holds, so the closing bracket stays next to the age
     instead of floating a fixed field-width away. width must stay auto for
     field-sizing to have anything to do — an explicit width wins over it, which
     is what left a character of slack the first time. */
  width:auto;field-sizing:content;min-width:2ch;max-width:14ch}
@supports not (field-sizing:content){
  /* Fallback: snug for the "25 y" this almost always is. */
  .age-inline{width:4.5ch}
}
.age-inline:hover,.age-inline:focus{background:var(--card);
  box-shadow:0 0 0 1px var(--line);border-radius:4px}
.age-inline:focus{outline:none;box-shadow:0 0 0 2px var(--brand)}

/* What this visit contributes to the patient's trends. Small and quiet: a
   confirmation that a number landed, not a section of its own. */
.obs-chips{display:flex;flex-wrap:wrap;gap:.3rem;margin:.35rem 0 0}
.chip{font-size:.78rem;font-weight:500;padding:.12rem .5rem;border-radius:20px;
  background:var(--blue);color:var(--ink);border:1px solid #b9d0f5}
.chip-warn{background:var(--amber);border-color:var(--amber-b)}
.chip-bad{background:var(--red);border-color:var(--red-b);color:var(--red-b)}
/* Clinical Memory history on a patient page. Visually quieter than a Synapse
   visit and never inside the prescription frame: this is another system's
   record, shown so the doctor can read it, and it must not be mistakable for
   something Synapse wrote or will print. */
.cm-history{margin-top:1.2rem}
.cm-earlier>summary{color:var(--muted)}
.cm-visit{border-left:3px solid var(--line);padding-left:.8rem;margin:.8rem 0}
.cm-block{margin:.5rem 0}
.cm-block-label{color:var(--muted);font-size:.78rem;text-transform:uppercase;
  letter-spacing:.04em}
.cm-text{white-space:pre-wrap;margin:.15rem 0}
.cm-rows,.cm-rx{border-collapse:collapse;width:100%;font-size:.9rem;margin:.25rem 0}
.cm-rows th{text-align:left;font-weight:normal;color:var(--muted);
  padding:.15rem .6rem .15rem 0;width:12rem;vertical-align:top}
.cm-rows td,.cm-rx td,.cm-rx th{padding:.2rem .5rem .2rem 0;vertical-align:top}
.cm-rx th{text-align:left;color:var(--muted);font-weight:normal;
  border-bottom:1px solid var(--line)}
.cm-rx tr+tr td{border-top:1px solid var(--line)}
/* Clinical Memory visits inside the "add from past visits" picker. Same rows,
   visibly a different source — one is a Synapse visit already confirmed against
   this formulary, the other is a medicine from elsewhere meeting it for the
   first time. Letting the two lists look interchangeable would hide that. */
.cm-heading-row{margin-top:.7rem;padding-top:.6rem;border-top:1px dashed var(--line)}
.cm-past-visit{border-left:2px solid var(--line);padding-left:.5rem}
.past-med .badge.warn{margin-left:.4rem;font-size:.7rem}
