/* ============================================================
   iPCR — Modern ePCR UI concept
   Mobile-forward, responsive to desktop.
   Styles for ipcr-redesign.html (see app.js for behavior).
   ============================================================ */

:root{
  /* palette */
  --bg:#eef1f6;
  --surface:#ffffff;
  --surface-2:#f7f9fc;
  --surface-3:#eef2f8;
  --line:#e2e8f2;
  --line-strong:#cbd5e6;
  --text:#1a2333;
  --text-2:#5a6782;
  --text-3:#8a97b0;
  --primary:#2f6bff;
  --primary-ink:#1b4bd6;
  --primary-wash:#e9f0ff;
  --teal:#0fb5ba;
  --teal-wash:#e2f7f7;
  --danger:#e5484d;
  --danger-wash:#fdeaea;
  --warn:#f5a524;
  --warn-wash:#fdf3e2;
  --ok:#22a06b;
  --ok-wash:#e6f6ee;
  --purple:#7c5cff;
  --purple-wash:#efeaff;

  /* shape / depth */
  --r-sm:9px;
  --r:14px;
  --r-lg:20px;
  --shadow-1:0 1px 2px rgba(20,30,55,.06),0 1px 3px rgba(20,30,55,.05);
  --shadow-2:0 6px 20px rgba(20,30,55,.10);
  --shadow-3:0 18px 50px rgba(20,30,55,.22);
  --ring:0 0 0 3px rgba(47,107,255,.22);

  --nav-w:264px;
  --header-h:60px;
  --font:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
}

[data-theme="dark"]{
  --bg:#0c111c;
  --surface:#141b2b;
  --surface-2:#1a2233;
  --surface-3:#212b40;
  --line:#26314a;
  --line-strong:#33415f;
  --text:#e8edf7;
  --text-2:#9fadc9;
  --text-3:#6f7d9c;
  --primary:#5b8bff;
  --primary-ink:#8fb0ff;
  --primary-wash:#17233f;
  --teal-wash:#123334;
  --danger-wash:#3a1c1f;
  --warn-wash:#3a2c15;
  --ok-wash:#153027;
  --purple-wash:#241c47;
  --shadow-1:0 1px 2px rgba(0,0,0,.4);
  --shadow-2:0 8px 24px rgba(0,0,0,.5);
  --shadow-3:0 20px 60px rgba(0,0,0,.65);
}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
  font-family:var(--font);
  background:var(--bg);
  color:var(--text);
  -webkit-font-smoothing:antialiased;
  font-size:15px;
  line-height:1.45;
}
button{font-family:inherit}
::selection{background:var(--primary);color:#fff}

/* ---------- App shell ---------- */
.app{
  display:grid;
  grid-template-columns:var(--nav-w) 1fr;
  grid-template-rows:100vh;
  min-height:100vh;
}

/* ---------- Sidebar (desktop) ---------- */
.sidebar{
  background:var(--surface);
  border-right:1px solid var(--line);
  display:flex;
  flex-direction:column;
  min-height:0;
}
.brand{
  display:flex;align-items:center;gap:11px;
  padding:18px 20px;
  border-bottom:1px solid var(--line);
}
.brand-mark{
  width:38px;height:38px;border-radius:11px;
  background:linear-gradient(135deg,var(--primary),var(--teal));
  display:grid;place-items:center;color:#fff;flex:none;
  box-shadow:0 4px 12px rgba(47,107,255,.35);
}
.brand-mark svg{width:22px;height:22px}
.brand-txt b{display:block;font-size:15px;letter-spacing:.2px}
.brand-txt span{font-size:11.5px;color:var(--text-3);font-weight:500}

.patient-chip{
  margin:14px 14px 6px;padding:12px;border-radius:var(--r);
  background:var(--surface-2);border:1px solid var(--line);
  display:flex;gap:11px;align-items:center;
}
.avatar{
  width:40px;height:40px;border-radius:11px;flex:none;
  background:var(--primary-wash);color:var(--primary-ink);
  display:grid;place-items:center;font-weight:700;font-size:15px;
}
.patient-chip .n{font-weight:650;font-size:14px}
.patient-chip .m{font-size:12px;color:var(--text-2)}
.incident-pill{
  font-size:11px;font-weight:600;color:var(--text-2);
  background:var(--surface-3);border-radius:20px;padding:2px 9px;
  display:inline-block;margin-top:3px;
}

.nav-scroll{overflow:auto;flex:1;padding:8px 12px 12px}
.nav-label{
  font-size:11px;font-weight:700;letter-spacing:.7px;text-transform:uppercase;
  color:var(--text-3);padding:14px 10px 6px;
}
.nav-item{
  --dot:var(--text-3);
  display:flex;align-items:center;gap:12px;width:100%;
  padding:10px 12px;border:none;background:none;cursor:pointer;
  border-radius:11px;color:var(--text-2);font-size:14.5px;font-weight:550;
  text-align:left;position:relative;transition:.15s;
}
.nav-item:hover{background:var(--surface-2);color:var(--text)}
.nav-item.active{background:var(--primary-wash);color:var(--primary-ink);font-weight:650}
.nav-item .ico{width:20px;height:20px;flex:none}
.nav-item .badge{
  margin-left:auto;font-size:11px;font-weight:700;
  min-width:20px;height:20px;padding:0 6px;border-radius:20px;
  display:grid;place-items:center;
  background:var(--danger-wash);color:var(--danger);
}
.nav-item .badge.done{background:var(--ok-wash);color:var(--ok)}
.nav-item .stat{
  margin-left:auto;width:8px;height:8px;border-radius:50%;background:var(--dot);
}
.nav-item.active .stat{background:var(--primary)}

.progress-card{
  margin:6px 14px 14px;padding:13px;border-radius:var(--r);
  border:1px solid var(--line);background:var(--surface-2);
}
.tmpl-card{margin:14px 14px 6px;padding:13px;border-radius:var(--r);border:1px solid var(--line);background:var(--surface-2)}
.tmpl-card .tmpl-label{font-size:11px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;color:var(--text-3);margin-bottom:8px}
.tmpl-card select.ctrl{height:38px;font-size:13px;padding:0 10px}
.progress-card .top{display:flex;justify-content:space-between;font-size:12.5px;font-weight:600;margin-bottom:8px}
.progress-card .top b{color:var(--primary-ink)}
.bar{height:7px;border-radius:20px;background:var(--surface-3);overflow:hidden}
.bar>i{display:block;height:100%;width:68%;border-radius:20px;
  background:linear-gradient(90deg,var(--primary),var(--teal))}
#syncProgressBar{transition:width .25s ease}
#syncCloseBtn:disabled{opacity:.6;cursor:not-allowed}

/* ---------- Main column ---------- */
.main{display:flex;flex-direction:column;min-width:0;min-height:0}

.header{
  height:var(--header-h);flex:none;
  background:var(--surface);border-bottom:1px solid var(--line);
  display:flex;align-items:center;gap:12px;padding:0 20px;
  position:sticky;top:0;z-index:20;
}
.header .menu-btn{display:none}
.h-title{min-width:0}
.h-title b{font-size:16px;display:block;line-height:1.2}
.h-title span{font-size:12px;color:var(--text-3)}
/* min-width:0 lets this shrink below its buttons' natural combined width
   instead of forcing .header (and the whole page) wider than the
   viewport — without it, a mid-width viewport with the full-label button
   row (e.g. a landscape phone: narrower than desktop but still above the
   820px breakpoint that hides labels) overflows the page horizontally,
   which was the real cause of "empty space on the right" in landscape —
   the button row pushed the document's scrollable width out past what
   the actual page content used. overflow-x:auto turns any remaining
   overflow into a scroll *within the button row itself* instead. */
.h-actions{margin-left:auto;display:flex;align-items:center;gap:8px;min-width:0;overflow-x:auto;scrollbar-width:none}
.h-actions::-webkit-scrollbar{display:none}

.btn{
  display:inline-flex;align-items:center;gap:7px;
  height:38px;padding:0 15px;border-radius:10px;cursor:pointer;
  font-size:13.5px;font-weight:600;border:1px solid var(--line-strong);
  background:var(--surface);color:var(--text-2);transition:.15s;white-space:nowrap;
}
.btn:hover{background:var(--surface-2);color:var(--text)}
.btn svg{width:16px;height:16px}
.btn.primary{background:var(--primary);border-color:var(--primary);color:#fff;box-shadow:0 4px 12px rgba(47,107,255,.3)}
.btn.primary:hover{background:var(--primary-ink);color:#fff}
.btn.ghost{border-color:transparent;background:transparent}
.btn.ghost:hover{background:var(--surface-2)}
.btn.icon{width:38px;padding:0;justify-content:center}
.btn.pill{border-radius:20px}
.btn.tealish{color:var(--teal);border-color:var(--teal)}
.btn.tealish:hover{background:var(--teal-wash)}

/* content region */
.content{overflow:auto;flex:1;padding:22px 24px 120px}
.view{display:none;animation:rise .28s ease}
.view.active{display:block}
@keyframes rise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}

.grid{display:grid;grid-template-columns:1fr 1fr;gap:18px;align-items:start}
.grid.wide{grid-template-columns:1fr}
.span2{grid-column:1 / -1}

/* Per-screen top-level card layout — CSS multi-column (masonry-style),
   not CSS Grid: cards vary a lot in height (e.g. Dispatch's "Response &
   Location" vs. its 4-field "Odometer"), and standard grid rows size to
   the tallest item in the row, stranding empty space next to every
   shorter card paired with a taller one. Multi-column flows each card
   into whichever column has room next, so no row height is shared and
   there's nothing to strand. Trade-off: reading order becomes top-to-
   bottom-then-next-column rather than left-right row pairing — the
   .grid class (above) is kept as-is and still used unchanged for
   strict field-pair layouts *within* a card (e.g. Dispatch's Incident
   card), which still need real row alignment, not a waterfall. */
.card-grid{columns:2;column-gap:18px}
.card-grid.wide{columns:1}
.card-grid .span2{column-span:all}
.card-grid>*{margin-bottom:18px;break-inside:avoid}

/* ---------- Card ---------- */
.card{
  background:var(--surface);border:1px solid var(--line);
  border-radius:var(--r-lg);box-shadow:var(--shadow-1);overflow:hidden;
}
.card-h{
  display:flex;align-items:center;gap:10px;
  padding:14px 18px;border-bottom:1px solid var(--line);
}
.card-h .cico{
  width:30px;height:30px;border-radius:9px;flex:none;display:grid;place-items:center;
  background:var(--primary-wash);color:var(--primary-ink);
}
.card-h .cico svg{width:17px;height:17px}
.card-h h3{margin:0;font-size:14.5px;font-weight:680;letter-spacing:.1px}
.card-h .sub{font-size:12px;color:var(--text-3);font-weight:500}
.card-h .right{margin-left:auto;display:flex;gap:6px;align-items:center}
.card-b{padding:16px 18px}

.p-teal .cico{background:var(--teal-wash);color:var(--teal)}
.p-purple .cico{background:#efeaff;color:var(--purple)}
.p-warn .cico{background:var(--warn-wash);color:var(--warn)}

/* ---------- Collapsible section (native <details>/<summary>) ----------
   Used by the Assessment modal (assessment.js) to group its many field
   groups into collapsed-by-default panels -- a plain <details> needs no
   open/close JS of its own (assessment.js only ever sets .open
   programmatically, for the has-data/body-map-tap cases), just marker
   styling to match this app's own card-header look (.card-h/h3 above). */
.assess-section{border:1px solid var(--line);border-radius:var(--r);margin-bottom:10px;overflow:hidden}
.assess-section-h{
  list-style:none;cursor:pointer;user-select:none;
  padding:10px 14px;font-size:14px;font-weight:680;letter-spacing:.1px;
  display:flex;align-items:center;gap:8px;background:var(--surface-2);
}
.assess-section-h::-webkit-details-marker{display:none}
.assess-section-h::before{content:'▸';font-size:11px;color:var(--text-3);transition:transform .12s;flex:none}
details[open]>.assess-section-h::before{transform:rotate(90deg)}
.assess-section-count{
  font-size:11px;font-weight:600;color:var(--text-2);
  background:var(--surface-3);border-radius:20px;padding:2px 9px;
}
.assess-section-b{padding:14px}

/* ---------- Fields ---------- */
.field{margin-bottom:14px}
.field:last-child{margin-bottom:0}
.field label{
  display:flex;align-items:center;gap:6px;
  font-size:12.5px;font-weight:600;color:var(--text-2);margin-bottom:6px;
}
.req{color:var(--danger);font-weight:700}
.field .hint{font-size:11.5px;color:var(--text-3);font-weight:500}
.ctrl,select.ctrl,textarea.ctrl,input.ctrl{
  width:100%;height:44px;padding:0 13px;font-size:14.5px;font-family:inherit;
  border:1.5px solid var(--line-strong);border-radius:11px;background:var(--surface-2);
  color:var(--text);transition:.15s;outline:none;appearance:none;
}
textarea.ctrl{height:auto;min-height:84px;padding:11px 13px;resize:vertical;line-height:1.5}
.ctrl::placeholder{color:var(--text-3)}
.ctrl:hover{border-color:var(--primary)}
.ctrl:focus{border-color:var(--primary);box-shadow:var(--ring);background:var(--surface)}
/* Lightweight "this doesn't look right" cue for a simple client-side
   format check (e.g. email) -- deliberately NOT .field-flag-error (that's
   a wrapper-level outline reserved for real Schematron/NEMSIS validation
   results), just the input's own border, so the two don't read as the
   same kind of problem. */
.ctrl.format-invalid{border-color:var(--danger)}
.ctrl.format-invalid:focus{box-shadow:0 0 0 3px rgba(224,64,64,.18)}
select.ctrl{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%235a6782' stroke-width='2.4' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 13px center;padding-right:38px;cursor:pointer;
}
.two{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.three{display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px}
.row-inline{display:grid;grid-template-columns:1fr auto;gap:10px}

/* input with trailing action */
.input-act{position:relative}
.input-act .ctrl{padding-right:46px}
.input-act .act{
  position:absolute;right:6px;top:6px;width:32px;height:32px;border-radius:8px;border:none;cursor:pointer;
  display:grid;place-items:center;background:var(--surface-3);color:var(--text-2);
}
.input-act .act.warnact{background:var(--danger-wash);color:var(--danger)}
.input-act .act:hover{filter:brightness(.95)}

/* segmented control */
.seg{display:inline-flex;background:var(--surface-3);border-radius:11px;padding:3px;gap:2px}
.seg button{
  border:none;background:none;cursor:pointer;padding:8px 15px;border-radius:9px;
  font-size:13.5px;font-weight:600;color:var(--text-2);transition:.12s;
}
.seg button.on{background:var(--surface);color:var(--primary-ink);box-shadow:var(--shadow-1)}
.seg.full{display:grid;grid-auto-flow:column;width:100%}

/* chips / multiselect */
.chips{display:flex;flex-wrap:wrap;gap:8px}
.chip{
  display:inline-flex;align-items:center;gap:7px;
  padding:7px 12px;border-radius:20px;font-size:13px;font-weight:600;cursor:pointer;
  background:var(--surface-2);border:1.5px solid var(--line-strong);color:var(--text-2);transition:.12s;
}
.chip:hover{border-color:var(--primary)}
.chip.on{background:var(--primary-wash);border-color:var(--primary);color:var(--primary-ink)}
.chip.on .x{opacity:1}
.chip .x{opacity:.55}
.chip.add{border-style:dashed;color:var(--primary);border-color:var(--primary)}

/* Treatment picker -- category chips (.chip) drill into this grouped list */
.treat-group-h{font-size:12px;font-weight:700;color:var(--text-3);text-transform:uppercase;letter-spacing:.03em;margin:14px 0 6px}
.treat-group-h:first-child{margin-top:0}
.treat-pick-row{cursor:pointer}

/* searchable multiselect */
.msel{position:relative}
/* align-items:center (not flex-start) — .msel-tags is one flex item from
   .msel-control's perspective even though it wraps multiple tags
   internally, so this centers the whole tag block (single- or multi-line)
   as a unit rather than pinning it to the top and leaving the box's
   min-height slack stranded below it. */
.msel-control{
  display:flex;align-items:center;gap:8px;min-height:44px;padding:7px 13px;
  /* Same border/radius/background/transition as .ctrl (a plain <select>)
     above -- these two were drifting apart (var(--r)'s 14px vs .ctrl's
     hardcoded 11px, and --surface vs --surface-2, so a multiselect always
     looked like a focused select even at rest) despite being the same kind
     of control from the user's perspective and needing to look like it. */
  border:1.5px solid var(--line-strong);border-radius:11px;background:var(--surface-2);cursor:pointer;transition:.15s;
}
.msel-control:hover{border-color:var(--primary)}
.msel.open .msel-control{border-color:var(--primary);box-shadow:var(--ring);background:var(--surface)}
.msel-tags{display:flex;flex-wrap:wrap;gap:6px;flex:1;min-width:0}
.msel-placeholder{color:var(--text-3);font-size:14.5px;padding:3px 2px}
/* Font-size/weight/color match a plain .ctrl's own value text exactly
   (14.5px/400/var(--text)) -- previously blue-tinted (--primary-wash/
   -primary-ink) and noticeably smaller/bolder (12.5px/650) than a regular
   pick list's selected value, which read as an unrelated, different kind
   of control rather than "the same field, multi-valued." Neutral
   background (--surface-3, the same muted chip fill .seg/.input-act .act
   already use elsewhere) keeps each value visually separable without
   reintroducing a color cue that isn't there for a single-select. .pn
   below is a deliberate exception -- that IS a meaningful semantic color
   (pertinent-negative flag), not this same inconsistency. */
.msel-tag{
  display:inline-flex;align-items:center;gap:5px;background:var(--surface-3);color:var(--text);
  border-radius:8px;padding:4px 6px 4px 9px;font-size:14.5px;font-weight:400;line-height:1.3;max-width:100%;
}
.msel-tag span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.msel-tag-x{cursor:pointer;opacity:.6;font-size:11px;flex:none}
.msel-tag-x:hover{opacity:1}
/* PN ("Symptom Not Present"-style pertinent negative) toggle -- same
   warn color language as the NV/PN popup (.nvpn-btn.active) elsewhere. */
.msel-tag-pn{
  cursor:pointer;flex:none;border:1px solid var(--line-strong);border-radius:6px;background:var(--surface);
  color:var(--text-3);font-size:9.5px;font-weight:800;line-height:1;padding:3px 4px;
}
.msel-tag-pn:hover{border-color:var(--warn)}
.msel-tag-pn.on{background:var(--warn-wash);color:var(--warn);border-color:var(--warn)}
.msel-tag.pn{background:var(--warn-wash);color:var(--warn)}
.msel-caret{color:var(--text-3);flex:none;transition:.15s;font-size:11px}
.msel.open .msel-caret{transform:rotate(180deg)}
.msel-panel{
  /* position:fixed (not absolute) + JS-computed top/bottom/left/width
     (see positionMselPanel() in global.js) — deliberate: an ancestor
     modal's overflow:hidden (or #content's overflow:auto) clips an
     absolutely-positioned panel no matter which direction it opens, since
     it's still confined to that ancestor's own box. Fixed positioning is
     relative to the viewport, so it escapes that clipping entirely. */
  display:none;position:fixed;z-index:200;
  background:var(--surface);border:1px solid var(--line-strong);border-radius:var(--r);
  box-shadow:var(--shadow-2);max-height:280px;flex-direction:column;overflow:hidden;
}
.msel.open .msel-panel{display:flex}
.msel-search{border:none;border-bottom:1px solid var(--line);padding:10px 12px;font-size:14px;outline:none;background:none;color:var(--text)}
.msel-list{overflow-y:auto;padding:6px}
.msel-opt{display:flex;align-items:center;gap:9px;padding:9px 10px;border-radius:8px;cursor:pointer;font-size:13.5px;color:var(--text-2)}
.msel-opt:hover{background:var(--surface-2)}
.msel-opt.on{color:var(--primary-ink);font-weight:650}
.msel-check{width:14px;flex:none;color:var(--primary);font-weight:800;font-size:12px}
.msel-empty{padding:14px;text-align:center;color:var(--text-3);font-size:13px}

/* Custom 24hr time picker (see #timePickerPanel in the HTML) — same
   position:fixed + JS-computed placement rationale as .msel-panel above
   (escapes a modal's overflow:hidden), and the same z-index so it renders
   above a modal too, since plenty of .tl-time-rows live inside one
   (HPI's Last Seen Normal/CPR times, Billing's PCS date, etc.). */
.time-picker-panel{
  display:none;position:fixed;z-index:200;padding:14px;
  background:var(--surface);border:1px solid var(--line-strong);border-radius:var(--r-lg);
  box-shadow:var(--shadow-2);
}
.time-picker-panel.open{display:block}
.time-picker-cols{display:flex;align-items:center;gap:8px}
.time-picker-col{display:flex;flex-direction:column;align-items:center;gap:5px}
.time-picker-col label{font-size:10px;font-weight:700;color:var(--text-3);letter-spacing:.5px}
.time-picker-col select{
  width:62px;height:40px;text-align:center;text-align-last:center;
  font-size:16px;font-weight:700;font-variant-numeric:tabular-nums;
  border:1.5px solid var(--line-strong);border-radius:var(--r);background:var(--surface-2);color:var(--text);
}
.time-picker-actions{display:flex;justify-content:space-between;gap:8px;margin-top:12px}

/* NV/PN code entry popup (see #nvpnPanel in the HTML) — same
   position:fixed placement pattern as .time-picker-panel above. */
.nvpn-panel{
  display:none;position:fixed;z-index:200;padding:10px;width:220px;
  background:var(--surface);border:1px solid var(--line-strong);border-radius:var(--r-lg);
  box-shadow:var(--shadow-2);
}
.nvpn-panel.open{display:block}
.nvpn-btns{display:flex;flex-wrap:wrap;gap:6px}
.nvpn-btn{
  flex:1 1 calc(50% - 6px);display:flex;flex-direction:column;align-items:flex-start;gap:1px;
  padding:6px 8px;border:1.5px solid var(--line-strong);border-radius:var(--r);
  background:var(--surface-2);color:var(--text);cursor:pointer;text-align:left;
}
.nvpn-btn b{font-size:13px;font-weight:800;color:var(--primary)}
.nvpn-btn span{font-size:10px;color:var(--text-3)}
.nvpn-btn:hover{border-color:var(--primary)}
.nvpn-btn.active{border-color:var(--primary);background:var(--primary-wash)}
.nvpn-btn.active b{color:var(--primary-ink)}
.nvpn-btn.hidden{display:none}
.nvpn-actions{display:flex;justify-content:flex-end;margin-top:8px}
/* A field showing an NV/PN sentinel date needs a visible cue that it isn't
   a real date — the native <input type=date> can't render text like "NA"
   itself, so the row gets a tinted-icon treatment instead. */
.tl-row[data-nvpn]{background:var(--warn-wash);border-radius:var(--r)}

/* data list rows */
.list{display:flex;flex-direction:column;gap:10px}
.list-row{
  display:flex;align-items:center;gap:12px;padding:12px 14px;
  border:1px solid var(--line);border-radius:var(--r);background:var(--surface-2);
}
.list-row .t{display:grid;place-items:center;width:44px;height:44px;border-radius:11px;flex:none;
  background:var(--surface);border:1px solid var(--line);font-weight:700;font-size:12px;color:var(--text-2);text-align:center;line-height:1.05}
.list-row .t.ok{background:var(--ok-wash);color:var(--ok);border-color:transparent}
.list-row .t.crit{background:var(--danger-wash);color:var(--danger);border-color:transparent}
/* Attachments: a real photo thumbnail fills the same 44x44 badge slot
   every other .list-row consumer puts a short text/icon label in. */
.list-row .t img{width:100%;height:100%;object-fit:cover;border-radius:inherit}
.list-row .body{min-width:0;flex:1}
.list-row .body b{font-size:14px;display:block}
.list-row .body span{font-size:12.5px;color:var(--text-2)}
.list-row .del{width:32px;height:32px;border-radius:9px;border:none;cursor:pointer;flex:none;
  background:var(--danger-wash);color:var(--danger);display:grid;place-items:center}
/* Treatments/Vitals feed: .t here holds a full HH:MM:SS time (every other
   .list-row consumer puts a short icon in it instead), so the fixed 44x44
   icon-badge size clips it -- widened to fit its actual content instead of
   a fixed square. Scoped to this list only, not the shared .list-row rule
   above, since every other consumer's icon still fits 44x44 fine. */
#treatmentsList .list-row .t{width:auto;min-width:44px;height:auto;min-height:38px;
  padding:4px 10px;font-size:14px;white-space:nowrap}
#treatmentsList .list-row .body b{font-size:16px}
#treatmentsList .list-row .body span{font-size:14px}
.tag{font-size:11px;font-weight:700;padding:2px 8px;border-radius:20px}
.tag.ok{background:var(--ok-wash);color:var(--ok)}
.tag.crit{background:var(--danger-wash);color:var(--danger)}
.tag.warn{background:var(--warn-wash);color:var(--warn)}
.tag.info{background:var(--primary-wash);color:var(--primary-ink)}

/* validation results */
.val-issue{display:flex;gap:10px;align-items:flex-start;padding:11px 0;border-top:1px dashed var(--line)}
.val-issue:first-child{border-top:none}
.val-issue .tag{flex:none;margin-top:2px}
.val-issue .body{min-width:0}
.val-issue .body b{font-size:13.5px;display:block;line-height:1.4}
.val-issue .body span{font-size:12px;color:var(--text-3)}
.val-issue.clickable{cursor:pointer}
.val-issue.clickable:hover .body b{color:var(--primary-ink)}
/* Required/validation flags -- colors the LABEL + the CONTROL itself,
   not an outline around the whole field wrapper. The old approach (a 2px
   outline-offset outline + background wash on the entire .field/.tl-row)
   visibly merged into one blob wherever two flagged fields sat close
   together -- confirmed live against Incident City + State, adjacent
   fields in a .two row with only a 10px gap between their boxes, per the
   user directly. Coloring the label text and the control's own
   border/background instead keeps each field's own color strictly inside
   its own column, so this can't happen regardless of layout density.

   .field and .tl-row are the two field-shaped wrap types fieldWrapFor()/
   fieldWrapForItem() (global.js) actually return in practice -- both have
   a clean label-vs-control split to re-target. Anything else they can
   return (a bare button like #vitalsBtn, or a [data-modal] jump target
   with no such split) keeps the old outline+wash look below, since
   there's nothing finer-grained to color on those. */
.field-flag-error:not(.field):not(.tl-row){outline:2px solid var(--danger);outline-offset:2px;border-radius:8px;background:var(--danger-wash)}
.field-flag-warning:not(.field):not(.tl-row){outline:2px solid var(--warn);outline-offset:2px;border-radius:8px;background:var(--warn-wash)}
.field-required:not(.field):not(.tl-row){outline:2px solid var(--purple);outline-offset:2px;border-radius:8px;background:var(--purple-wash)}

.field.field-flag-error>label,.field.field-flag-error .chk-inline{color:var(--danger)}
.field.field-flag-warning>label,.field.field-flag-warning .chk-inline{color:var(--warn)}
.field.field-required>label,.field.field-required .chk-inline{color:var(--purple)}
.field.field-flag-error .ctrl,.field.field-flag-error .msel-control{border-color:var(--danger);background:var(--danger-wash)}
.field.field-flag-warning .ctrl,.field.field-flag-warning .msel-control{border-color:var(--warn);background:var(--warn-wash)}
.field.field-required .ctrl,.field.field-required .msel-control{border-color:var(--purple);background:var(--purple-wash)}

.tl-row.field-flag-error .lab{color:var(--danger)}
.tl-row.field-flag-warning .lab{color:var(--warn)}
.tl-row.field-required .lab{color:var(--purple)}
.tl-row.field-flag-error .tl-dt{border-color:var(--danger);background:var(--danger-wash)}
.tl-row.field-flag-warning .tl-dt{border-color:var(--warn);background:var(--warn-wash)}
.tl-row.field-required .tl-dt{border-color:var(--purple);background:var(--purple-wash)}

/* required-fields config panel */
.req-group-label{font-size:11px;font-weight:800;letter-spacing:.5px;text-transform:uppercase;color:var(--text-3);margin:16px 0 6px}
.req-group-label:first-child{margin-top:0}
.req-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 2px;border-top:1px dashed var(--line)}
.req-row:first-of-type{border-top:none}
.req-row .req-name{font-size:13.5px;font-weight:600;color:var(--text)}
.req-toggle{position:relative;width:40px;height:24px;flex:none;border-radius:20px;background:var(--surface-3);border:1.5px solid var(--line-strong);cursor:pointer;transition:.15s}
.req-toggle i{position:absolute;top:2px;left:2px;width:17px;height:17px;border-radius:50%;background:var(--surface);box-shadow:var(--shadow-1);transition:.15s}
.req-toggle.on{background:var(--purple);border-color:var(--purple)}
.req-toggle.on i{transform:translateX(16px);background:#fff}

/* locations lookup */
.loc-list{border:1px solid var(--line);border-radius:var(--r);overflow:hidden;margin-top:6px}
.loc-row{display:flex;justify-content:space-between;align-items:baseline;gap:14px;padding:11px 14px;border-bottom:1px solid var(--line)}
.loc-row:last-child{border-bottom:none}
.loc-row .lbl{font-weight:700;font-size:13.5px;color:var(--text);flex:none}
.loc-row .val{font-size:13.5px;color:var(--primary-ink);font-weight:600;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* live validation bar — pinned under the header, updates on blur */
.val-bar{border-bottom:1px solid var(--line);background:var(--surface);flex:none}
.val-bar-head{
  width:100%;display:flex;align-items:center;gap:10px;padding:10px 24px;
  border:none;background:none;cursor:pointer;font-size:13px;font-weight:650;color:var(--text-2);text-align:left;
}
.val-bar-dot{width:9px;height:9px;border-radius:50%;background:var(--ok);flex:none}
.val-bar-dot.warn{background:var(--warn)}
.val-bar-dot.crit{background:var(--danger)}
.val-bar-chev{margin-left:auto;color:var(--text-3);transition:.15s;flex:none}
.val-bar.open .val-bar-chev{transform:rotate(180deg)}
.val-bar-body{display:none;max-height:260px;overflow-y:auto;padding:2px 24px 14px}
.val-bar.open .val-bar-body{display:block}
.val-debug-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:6px 0 10px;flex-wrap:wrap}
.val-debug-toggle{
  display:flex;align-items:center;gap:7px;font-size:12px;color:var(--text-3);
  font-weight:600;cursor:pointer;user-select:none;
}
.val-debug-toggle input{cursor:pointer}
/* Small standalone boolean flag next to a field (e.g. Patient Info's "Age
   is approximate") -- same visual language as .val-debug-toggle above but
   not tied to the validation debug panel specifically. */
.chk-inline{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--text-3);font-weight:500;cursor:pointer;user-select:none;margin-top:6px}
.chk-inline input{cursor:pointer}
/* View/Download XML — a temporary debug convenience (not a real app
   feature) for feeding the exact built NEMSIS XML into an external
   validator when tracking down a Schematron result that's hard to trust
   from inside the app alone. */
.val-debug-xml-btns{display:flex;gap:6px}
.val-debug-xml-btns .btn{height:28px;padding:0 10px;font-size:11.5px;border-radius:7px}
/* Raw Schematron `test` XPath for a fired rule — off by default (too
   technical for normal use), shown per-issue when the debug toggle above
   is on. This is the real "why" for cross-field rules whose trigger
   condition isn't obvious from the plain-English message alone. */
.val-issue-debug{
  margin-top:6px;padding:8px 10px;border-radius:8px;background:var(--surface-3);
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:11px;line-height:1.5;color:var(--text-2);white-space:pre-wrap;word-break:break-word;
}
.val-issue-debug b{color:var(--text-3);font-weight:700;font-family:inherit}

.add-tile{
  display:flex;align-items:center;justify-content:center;gap:9px;
  width:100%;padding:14px;border:1.5px dashed var(--line-strong);border-radius:var(--r);
  background:var(--surface-2);color:var(--primary);font-weight:650;font-size:14px;cursor:pointer;transition:.15s;
}
.add-tile:hover,.add-tile.dragover{border-color:var(--primary);background:var(--primary-wash)}

.wong-baker-faces{display:flex;gap:8px;justify-content:space-between}
.wong-baker-face{
  flex:1;display:flex;flex-direction:column;align-items:center;gap:4px;
  padding:8px 4px;border:1.5px solid var(--line-strong);border-radius:var(--r);
  background:var(--surface-2);cursor:pointer;transition:.15s;
}
.wong-baker-face:hover,.wong-baker-face.selected{border-color:var(--primary);background:var(--primary-wash)}
.wong-baker-face .face{font-size:26px;line-height:1}
.wong-baker-face .score{font-size:11px;font-weight:650;color:var(--text-3)}

/* call-times timeline */
/* gap needs to comfortably clear 2x outline-offset (2px+2px) from adjacent
   flagged rows (.field-flag-error/-warning, applied directly to .tl-row —
   there's no .field wrapper here for fieldWrapFor() to target instead), or
   their outlines touch/merge into one solid block when several rows in a
   row are flagged. */
.timeline{display:flex;flex-direction:column;gap:8px}
/* 132px label | 1fr time+date — was a 3rd "auto" column for the removed
   "Now" button (times are charted after the fact, not stamped live, per
   the user — the button implied real-time entry that doesn't match how
   this is actually used). */
.tl-row{display:grid;grid-template-columns:132px 1fr;align-items:center;gap:12px;padding:9px 0;position:relative}
.tl-row+.tl-row{border-top:1px dashed var(--line)}
.tl-row .lab{font-size:13px;font-weight:600;color:var(--text-2);display:flex;align-items:center;gap:9px}
/* A plain text field, not <input type="time"> — native time inputs render
   in the browser/OS's own locale format (often 12hr AM/PM in en-US), and
   that can't be forced to 24hr via the `lang` attribute in current Chrome
   (tested: no effect). Times in EMS charting are always 24hr/military, so
   this is masked to a fixed HH:MM:SS digit pattern instead (data-mask,
   handled by global.js's existing formatMaskedInput — the same mechanism
   Zip/Phone/DOB already use), guaranteeing 24hr entry regardless of the
   user's device locale. .tl-time-row wraps it with a custom clock icon —
   a plain text input has no native icon of its own, and the previous
   native <input type=time>'s icon rendered oversized and misaligned
   against the date input's own (differently-sized) native icon below it. */
/* .tl-date-row mirrors .tl-time-row exactly (own custom calendar icon,
   native date-picker indicator hidden below) rather than leaning on the
   browser's native icon for one row and a custom one for the other — two
   differently-sized/positioned native-vs-custom icons is what was
   actually causing the "icons don't line up" complaint in the first
   place. Both inputs share the same fixed width, so both icons land at
   the exact same x-offset regardless of how wide the displayed value is. */
/* One box, matching .ctrl's exact height/border/radius/background — same
   control chrome as a text input or <select>, not a bespoke look. Time
   and date sit on ONE line (a vertical stack read as arbitrary/unexplained
   — there's no reason a single control's two halves should be on separate
   rows when there's room for both side by side), separated by a hairline
   divider rather than each getting its own separate box. Font-size,
   weight, and color are identical between time and date AND identical to
   .ctrl's own value text (14.5px/400/var(--text)) — previously date was
   deliberately muted/smaller as "secondary" info, but that just read as
   inconsistent rather than intentional, so that distinction is gone: both
   are a value the user entered, both should look like one. */
.tl-dt{
  display:flex;align-items:center;height:44px;gap:12px;
  border:1.5px solid var(--line-strong);border-radius:11px;
  background:var(--surface-2);padding:0 13px;transition:.15s;
}
.tl-dt:hover{border-color:var(--primary)}
.tl-time-row,.tl-date-row{display:flex;align-items:center;gap:7px;flex:none}
.tl-time-row{padding-right:12px;border-right:1px solid var(--line)}
.tl-date-row{position:relative}
.tl-time-row svg,.tl-date-row svg{width:14px;height:14px;flex:none;color:var(--text-3);cursor:pointer}
.tl-time-input,.tl-date-input{
  border:none;background:none;padding:0;font-family:inherit;
  font-size:14.5px;font-weight:400;color:var(--text);
}
.tl-time-input{width:78px;font-variant-numeric:tabular-nums;cursor:text}
.tl-time-input::placeholder{color:var(--text-3)}
.tl-date-input{width:96px;cursor:pointer}
.tl-date-input::-webkit-calendar-picker-indicator{display:none}
/* NV/PN code badge for a .tl-date-input — the native date input can't
   display text like "NA" itself (see setNvpnDateBadge() in global.js), so
   it's hidden (opacity, not visibility — stays clickable/focusable to
   reopen the popup) and a plain-text badge is laid over the same spot
   (.tl-date-row's own position:relative, set above, is what this
   absolute positioning is relative to). */
.tl-date-input.nvpn-hidden{opacity:0}
.tl-nvpn-badge{
  position:absolute;left:0;top:0;width:96px;height:100%;
  display:flex;align-items:center;
  font-size:14.5px;font-weight:700;color:var(--warn);
  pointer-events:none;
}

/* repeatable agency entry */
.agency-entry{border:1px solid var(--line);border-radius:var(--r);padding:14px;margin-bottom:12px;background:var(--surface-2)}
.agency-entry .field:last-of-type{margin-bottom:0}
.agency-remove{margin-top:4px;border:none;background:none;color:var(--danger);font-weight:650;font-size:12.5px;cursor:pointer;padding:4px 0}
.agency-remove:hover{text-decoration:underline}

/* odometer strip */
.odo{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}
.odo .cell{border:1px solid var(--line);border-radius:var(--r);padding:11px;background:var(--surface-2);text-align:center}
.odo .cell span{font-size:11px;text-transform:uppercase;letter-spacing:.5px;color:var(--text-3);font-weight:700}
.odo .cell input{border:none;background:none;text-align:center;font-size:17px;font-weight:700;width:100%;color:var(--text);margin-top:4px;outline:none}

/* review / narrative preview */
.review{font-size:13.5px;line-height:1.65}
.review h5{margin:14px 0 4px;font-size:12px;text-transform:uppercase;letter-spacing:.6px;color:var(--primary-ink);font-weight:700}
.review h5:first-child{margin-top:0}
.review p{margin:0 0 4px;color:var(--text)}
.review .muted{color:var(--text-3)}

/* body diagram */
.body-wrap{display:grid;grid-template-columns:280px 1fr;gap:18px;align-items:start}
.body-wrap.solo{grid-template-columns:1fr;text-align:center}
.body-wrap.solo .body-stage{min-height:340px;width:100%;max-width:320px;margin:0 auto}
.body-wrap.solo .body-stage svg{max-height:320px}
.body-stage{
  border:1px solid var(--line);border-radius:var(--r-lg);background:
   radial-gradient(120% 80% at 50% 0%,var(--surface-2),var(--surface));
  padding:18px;display:grid;place-items:center;min-height:430px;position:relative;
}
.body-stage svg{max-height:420px;width:auto;filter:drop-shadow(0 8px 20px rgba(20,30,55,.14))}
.marker{position:absolute;width:26px;height:26px;border-radius:50%;border:3px solid #fff;
  display:grid;place-items:center;font-size:12px;font-weight:800;color:#fff;box-shadow:var(--shadow-2);cursor:pointer}
.marker.pain{background:var(--danger)}
.marker.trauma{background:var(--warn)}
.body-hot{cursor:pointer;transition:.15s}
.body-hot:hover{fill:var(--primary-wash);stroke:var(--primary)}

/* supplemental search list */
.supp-search{margin-bottom:14px}
.supp-list{display:flex;flex-direction:column;gap:1px;border-radius:var(--r);overflow:hidden;border:1px solid var(--line)}
.supp-row{display:flex;align-items:center;gap:12px;padding:13px 16px;background:var(--surface);cursor:pointer;transition:.12s}
.supp-row:hover{background:var(--surface-2)}
.supp-row+.supp-row{border-top:1px solid var(--line)}
.supp-row .lab{font-weight:600;font-size:14px}
.supp-row .val{margin-left:auto;font-size:13px;color:var(--text-2);display:flex;align-items:center;gap:8px}
.supp-row .val.empty{color:var(--text-3)}
.supp-row .chev{color:var(--text-3)}
.group-label{font-size:11.5px;font-weight:800;letter-spacing:.8px;text-transform:uppercase;color:var(--text-3);padding:16px 4px 8px}
/* Plain (non-repeatable) fields are edited directly inline, right on this
   row -- no drill-down. Stacked (label above, full-width control below),
   same as every other screen's .field -- NOT side-by-side/right-aligned:
   that read as odd and inconsistent with the rest of the app (a ~150px
   right-aligned control looks nothing like this app's normal full-width
   fields). Only the repeatable-group summary rows (data-kind="group")
   still navigate anywhere on click, so .supp-row-input suppresses the
   pointer cursor/hover treatment those get. */
.supp-row-input{display:block;cursor:default}
.supp-row-input:hover{background:var(--surface)}
.supp-row-input .lab{display:block;margin-bottom:8px}
.supp-row-input .ctrl,.supp-row-input .msel{width:100%}
.supp-row-input .agency-entry{display:flex;align-items:center;gap:8px}
/* A Time/datetimewithseconds field renders the app's own .tl-row widget
   (same one Dispatch's call timeline uses) instead of a plain .ctrl --
   .tl-row's own padding is 0 (designed to sit directly in a card, not a
   bordered .supp-list row), so it's tightened here instead of doubling up. */
.supp-row-time{padding:5px 16px;cursor:default}
.supp-row-time:hover{background:var(--surface)}
.supp-row-time .tl-row{width:100%}

/* ---------- Bottom nav (mobile) ---------- */
.tabbar{display:none}
.fab{display:none}

/* ---------- Modal ---------- */
.modal-scrim{
  position:fixed;inset:0;background:rgba(10,16,30,.55);backdrop-filter:blur(4px);
  z-index:60;display:none;align-items:flex-end;justify-content:center;
}
.modal-scrim.open{display:flex}
.modal{
  background:var(--surface);width:min(980px,100%);max-height:94vh;
  border-radius:22px 22px 0 0;box-shadow:var(--shadow-3);
  display:flex;flex-direction:column;overflow:hidden;animation:sheet .32s cubic-bezier(.2,.8,.2,1);
}
@keyframes sheet{from{transform:translateY(30px);opacity:.4}to{transform:none;opacity:1}}
.modal-h{display:flex;align-items:center;gap:12px;padding:16px 20px;border-bottom:1px solid var(--line)}
.modal-h h3{margin:0;font-size:16px;font-weight:700}
.modal-h .grab{position:absolute;top:8px;left:50%;transform:translateX(-50%);width:42px;height:5px;border-radius:20px;background:var(--line-strong)}
.modal-b{overflow:auto;padding:20px}
.modal-f{display:flex;gap:10px;padding:14px 20px;border-top:1px solid var(--line);background:var(--surface-2)}
.modal-f .btn{flex:1;justify-content:center;height:46px}

/* ---------- Gate screens (Login, PCR chooser) ----------
   Full-viewport overlays, siblings of .app in the DOM. z-index:55 is
   deliberate: above the mobile nav drawer (.sidebar, z-index:50) and its
   .scrim (45), but below .modal-scrim (60) -- the sync modal opens
   automatically right after login and must render on top of the gate
   screen still showing underneath it. */
.gate-screen{
  position:fixed;inset:0;z-index:55;display:none;
  align-items:center;justify-content:center;padding:24px;
  background:var(--bg);
}
.gate-screen.open{display:flex}
.gate-logout-btn{position:absolute;top:20px;right:20px}
.gate-card{
  width:min(420px,100%);background:var(--surface);border:1px solid var(--line);
  border-radius:var(--r-lg);box-shadow:var(--shadow-2);padding:32px 28px;
}
.gate-card h1{margin:0 0 4px;font-size:20px;font-weight:750}
.gate-card .sub{margin:0 0 24px;font-size:13px;color:var(--text-3)}
.gate-card .field:last-of-type{margin-bottom:20px}
.gate-card .btn.primary{width:100%;justify-content:center;height:46px}

/* PCR chooser -- two big tap targets */
.chooser-card{width:min(560px,100%)}
.chooser-tiles{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:22px}
@media(max-width:520px){.chooser-tiles{grid-template-columns:1fr}}
.chooser-tile{
  display:flex;flex-direction:column;align-items:center;gap:10px;text-align:center;
  padding:26px 16px;border:1.5px solid var(--line-strong);border-radius:var(--r-lg);
  background:var(--surface-2);cursor:pointer;transition:.15s;
}
.chooser-tile:hover{border-color:var(--primary);background:var(--primary-wash)}
.chooser-tile .cico{
  width:44px;height:44px;border-radius:12px;display:grid;place-items:center;
  background:var(--primary-wash);color:var(--primary-ink);
}
.chooser-tile .cico svg{width:22px;height:22px}
.chooser-tile b{font-size:14.5px}
.chooser-tile span{font-size:12px;color:var(--text-3)}

/* ---------- Signature pad ---------- */
.sig-pad-wrap{border:1.5px solid var(--line-strong);border-radius:var(--r);background:#fff;overflow:hidden}
.sig-pad{display:block;width:100%;height:140px;touch-action:none;cursor:crosshair}
.sig-pad-actions{display:flex;justify-content:space-between;align-items:center;padding:6px 10px;border-top:1px solid var(--line);background:var(--surface-2)}
.sig-pad-hint{font-size:11.5px;color:var(--text-3)}
.sig-pad-clear{border:none;background:none;color:var(--primary);font-weight:650;font-size:12.5px;cursor:pointer;padding:4px 0}
.sig-pad-clear:hover{text-decoration:underline}

/* Crew row / Disposition Authorization+Refusal "Sign" widget -- the actual
   drawing surface lives in the shared #signatureCaptureModal, not inline
   here (see that modal's HTML comment); this button just reflects
   signed/unsigned state. .sig-store is the per-row bitmap-store canvas --
   previously always display:none with only this small text button as the
   click target, easy to miss entirely (user feedback); now shown directly
   as a bordered "tap to sign" box, with the button as a secondary
   affordance beside it. Its CSS display size here is independent of its
   drawing-resolution width/height attributes -- onboarding.js's pos()
   already scales pointer coordinates by canvas.width/rect.width, so
   resizing this on-screen doesn't need any JS change. */
.sig-sign-btn.signed{color:var(--ok);border-color:var(--ok)}
.sig-canvas-wrap{position:relative;margin:6px 0 8px}
.sig-canvas-wrap .sig-store{display:block;width:100%;height:110px;background:var(--surface-2);border:1.5px dashed var(--line-strong);border-radius:var(--r);cursor:pointer}
.sig-canvas-wrap .sig-store.has-signature{border-style:solid;border-color:var(--ok);background:#fff}
.sig-hint{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:12.5px;font-weight:600;color:var(--text-3);pointer-events:none}
.sig-hint.hidden{display:none}
/* .sig-meta-fields sits inline (hidden, see index.html) next to its
   .sig-owner at rest, and is shown + relocated into
   #signatureCaptureMetaSlot while that signature is being signed (see
   onboarding.js) -- condensed here since it's now bundled into the same
   small popup as the drawing canvas, not spread across the full
   Authorization/Refusal modal. */
#signatureCaptureMetaSlot .sig-meta-fields{margin-bottom:10px;padding-bottom:10px;border-bottom:1.5px solid var(--line)}
#signatureCaptureMetaSlot .sig-meta-fields .field{margin-bottom:8px}

/* Scrollable account-configured legal text block (Disposition's
   Authorization/Refusal modals) -- long (2000+ char) agency-specific
   billing/consent language, not meant to dominate the whole modal. */
.legal-text{
  max-height:220px;overflow-y:auto;white-space:pre-wrap;
  font-size:12px;line-height:1.5;color:var(--text-2);
  border:1.5px solid var(--line);border-radius:var(--r);
  padding:10px 12px;margin-bottom:14px;background:var(--surface-2);
}

/* ---------- HPI narrative preview ----------
   Matches the real product's live "Subjective Information" panel: a bold
   underlined heading per documented section, plain text value(s) below,
   breathing room between sections. Only sections with something entered
   are ever shown -- see renderHpiNarrative() in hpi.js. */
.narrative-section{margin-bottom:16px}
.narrative-section:last-child{margin-bottom:0}
.narrative-heading{font-weight:700;text-decoration:underline;font-size:13.5px;margin-bottom:4px}
.narrative-line{font-size:13.5px;color:var(--text);margin-bottom:2px}

/* vitals dark modal */
.vitals-modal{background:#0e1524;color:#e8edf7}
.vitals-modal .modal-h{border-color:#22304d}
.vitals-modal .modal-f{background:#0b1120;border-color:#22304d}
.vgrid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.vcard{background:#151f33;border:1px solid #24314f;border-radius:var(--r);padding:14px}
.vcard h4{margin:0 0 12px;font-size:12px;letter-spacing:.6px;text-transform:uppercase;color:#8fa3c9;font-weight:700;display:flex;align-items:center;gap:8px}
.vcard h4 .d{width:8px;height:8px;border-radius:50%;background:var(--teal)}
.vinput{width:100%;height:46px;border-radius:10px;border:1.5px solid #2a3a5c;background:#0f1830;color:#e8edf7;
  padding:0 12px;font-size:16px;font-weight:600;outline:none}
.vinput:focus{border-color:var(--primary);box-shadow:0 0 0 3px rgba(91,139,255,.25)}
.vlab{font-size:11px;color:#7f90b5;font-weight:600;margin-bottom:5px;display:block}
.bp{display:grid;grid-template-columns:1fr 20px 1fr;align-items:center;gap:6px}
.bp .sl{text-align:center;font-size:22px;color:#5a6b90}
.avpu{display:inline-flex;background:#0f1830;border-radius:11px;padding:3px}
.avpu button{width:44px;height:38px;border:none;background:none;color:#8fa3c9;font-weight:800;border-radius:8px;cursor:pointer}
.avpu button.on{background:var(--primary);color:#fff}
.gcs-total{font-size:30px;font-weight:800;color:var(--teal);text-align:center}
.vitals-modal .vinput option{background:#0f1830}

/* completion pill in header */
.done-pill{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;
  padding:5px 11px;border-radius:20px;background:var(--ok-wash);color:var(--ok)}
.warn-pill{background:var(--warn-wash);color:var(--warn)}
/* Matches .field-required's purple (not .warn-pill's yellow/orange) — the
   "N required" count is the admin-configured Required Fields feature, not
   a Schematron warning, and shouldn't read as one at a glance. */
.purple-pill{background:var(--purple-wash);color:var(--purple)}

/* section subhead inside cards */
.subhead{font-size:11.5px;font-weight:800;letter-spacing:.6px;text-transform:uppercase;color:var(--text-3);
  margin:6px 0 10px;display:flex;align-items:center;gap:8px}
.subhead::after{content:"";flex:1;height:1px;background:var(--line)}

/* radios as buttons */
.radio-btns{display:inline-flex;gap:8px;flex-wrap:wrap}
.radio-btns label{cursor:pointer}
.radio-btns input{display:none}
.radio-btns span{display:inline-block;padding:9px 16px;border-radius:10px;font-size:13.5px;font-weight:600;
  border:1.5px solid var(--line-strong);background:var(--surface-2);color:var(--text-2)}
.radio-btns input:checked+span{background:var(--primary-wash);border-color:var(--primary);color:var(--primary-ink)}

/* ---------- Responsive ---------- */
@media(max-width:1080px){
  .grid{grid-template-columns:1fr}
  .card-grid{columns:1}
  .body-wrap{grid-template-columns:1fr}
}
@media(max-width:820px){
  .app{grid-template-columns:1fr}
  .sidebar{
    position:fixed;inset:0 auto 0 0;width:290px;z-index:50;
    transform:translateX(-100%);transition:transform .28s cubic-bezier(.2,.8,.2,1);
    box-shadow:var(--shadow-3);
  }
  body.nav-open .sidebar{transform:none}
  .scrim{position:fixed;inset:0;background:rgba(10,16,30,.5);z-index:45;display:none}
  body.nav-open .scrim{display:block}
  .header .menu-btn{display:grid}
  .content{padding:16px 15px 130px}
  .header{padding:0 14px}
  .h-actions .lbl{display:none}
  .h-actions .btn.primary .lbl{display:inline}
  .modal{border-radius:22px 22px 0 0;max-height:92vh}
  .vgrid{grid-template-columns:1fr}

  /* bottom tab bar */
  .tabbar{
    display:flex;position:fixed;left:0;right:0;bottom:0;z-index:40;
    background:var(--surface);border-top:1px solid var(--line);
    padding:6px 6px calc(6px + env(safe-area-inset-bottom));
    box-shadow:0 -6px 24px rgba(20,30,55,.10);
  }
  .tabbar button{
    flex:1;border:none;background:none;cursor:pointer;padding:6px 2px;
    display:flex;flex-direction:column;align-items:center;gap:3px;
    color:var(--text-3);font-size:10px;font-weight:650;border-radius:11px;position:relative;
  }
  .tabbar button svg{width:22px;height:22px}
  .tabbar button.active{color:var(--primary)}
  .tabbar button.active::before{content:"";position:absolute;top:0;width:26px;height:3px;border-radius:20px;background:var(--primary)}
  .tabbar button .dot{position:absolute;top:4px;right:calc(50% - 16px);width:7px;height:7px;border-radius:50%;background:var(--danger)}

  .fab{
    display:grid;place-items:center;position:fixed;right:16px;bottom:78px;z-index:41;
    width:56px;height:56px;border-radius:18px;border:none;cursor:pointer;
    background:linear-gradient(135deg,var(--primary),var(--teal));color:#fff;
    box-shadow:0 10px 28px rgba(47,107,255,.45);
  }
  .fab svg{width:26px;height:26px}
}
@media(max-width:820px){ .desktop-only{display:none} }
@media(min-width:821px){ .mobile-only{display:none} }

/* ============================================================
   Report Overview modal — shows the actual generated PDF inline (an
   <iframe> pointed at a blob URL from jsPDF's doc.output('bloburl'), see
   showReportOverview() in print.js), not an HTML approximation of it —
   what the user sees here is exactly what "Download PDF" would save.
   #printModalBody gets its padding zeroed out just for this modal so the
   iframe fills the available space edge-to-edge.
   ============================================================ */
#printModalBody{padding:0}
#printPdfFrame{width:100%;height:75vh;border:none;display:block}
