*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
/* Dashboard-only tokens (everything else comes from /assets/tokens.css).
   --grad-side derives from --t/--b so brand colour stays single-source. */
:root{
  /* --accent* moved to tokens.css (28/09) — shared with admin + the spinner in components.css */
  --grad-side:linear-gradient(168deg,var(--teal-bright) 0%,var(--b) 118%);
  --canvas:#F4F6F8;--sw:248px;
  --shadow-card:0 1px 2px rgba(16,24,40,.04),0 1px 3px rgba(16,24,40,.06);
  /* ── Proposal re-skin tokens (dashboard.html) ── */
  --sh:0 1px 2px rgba(15,23,42,.05), 0 4px 14px rgba(15,23,42,.06), 0 0 0 1px rgba(15,23,42,.03);
  /* --ok/--warn/--high/--b-* removed 26/09 — every var() call site now points
     straight at tokens.css's --green/--amber/--red/--blue (+ -bg/-tx), so a
     token edit there cascades here instead of silently drifting two ways.
     --surf removed too — it duplicated tokens.css's own --surf with a
     different value; the 2 call sites now inherit the real one. */
}
html,body{height:100%;font-family:'Inter',system-ui,sans-serif;background:var(--canvas);color:var(--color-text);font-size:var(--text-sm);-webkit-font-smoothing:antialiased}
button{cursor:pointer;font-family:inherit}input,select,textarea{font-family:inherit}
:focus-visible{outline:2px solid var(--t);outline-offset:2px}

/* ── Login ──────────────────────────────────────────────── */
.login-wrap{min-height:100vh;display:flex;align-items:center;justify-content:center;background:var(--color-surface-subtle)}
.login-card{width:380px;background:var(--color-surface-card);border-radius:var(--r);box-shadow:0 8px 40px rgba(0,0,0,.10);overflow:hidden}
.login-top{padding:32px 32px 24px;text-align:center;border-bottom:1px solid var(--color-border)}
.login-brand{display:flex;align-items:center;justify-content:center;gap:12px;margin-bottom:10px}
.login-brand h1{font-size:var(--text-xl);font-weight:800;letter-spacing:-.5px;color:var(--color-text)}
.login-top p{font-size:var(--text-sm);color:var(--color-text-secondary)}
.login-body{padding:28px 32px 32px}
.login-body label{display:block;font-size:var(--text-sm);font-weight:700;color:var(--color-text-secondary);text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px}
.login-body .field{margin-bottom:16px}
.login-body input{width:100%;height:46px;border:2px solid var(--color-border);border-radius:var(--rs);padding:0 14px;font-size:var(--text-base);outline:none;transition:border-color .2s;background:var(--color-surface-card)}
.login-body input:focus{border-color:var(--t);box-shadow:0 0 0 3px rgba(15,184,184,.12)}
.login-btn{width:100%;height:50px;border-radius:var(--rs);background:var(--grad);color:#fff;font-size:var(--text-base);font-weight:700;border:none;cursor:pointer;margin-top:4px;transition:opacity .2s}
.login-btn:disabled{opacity:.6;cursor:not-allowed}
.login-err{background:var(--red-soft);border:1px solid var(--red-bd);color:var(--red-dk);border-radius:var(--rxs);padding:10px 12px;font-size:var(--text-sm);margin-bottom:16px;display:none}

/* ── Shell ──────────────────────────────────────────────── */
.shell{display:flex;height:var(--app-h,100vh);overflow:hidden}

/* ── Sidebar ────────────────────────────────────────────── */
/* Light rail (30/09, was dark navy --sidebar → softened from near-black #0F1F2E
   before that): white background, the brand gradient lives only in the logo
   mark (canonical usage, @design.md Logo) — a coloured header band was tried
   and rejected ("looked off"). Admin keeps its own dark --sidebar unchanged
   (admin-components.css, separate file, out of scope — @decisions.md 28/09). */
.sidebar{width:var(--sw);background:var(--color-surface-card);color:var(--color-text);border-right:1px solid var(--color-border);display:flex;flex-direction:column;flex-shrink:0}
.sb-brand{padding:22px 20px 16px}
.sb-logo{display:flex;align-items:center;gap:10px}
.sb-logo-text{font-size:var(--text-lg);font-weight:800;letter-spacing:-.4px;color:var(--color-text)}
.sb-sub{font-size:var(--text-xs);color:var(--color-text-muted);margin-top:3px}
.sb-nav{flex:1;padding:6px 12px;overflow-y:auto}
.sb-section{font-size:var(--text-xs);font-weight:700;color:var(--color-text-muted);text-transform:uppercase;letter-spacing:.8px;padding:10px 8px 4px}
.nav-item{display:flex;align-items:center;gap:11px;padding:10px 12px;margin-bottom:3px;font-size:var(--text-sm);font-weight:500;color:var(--color-text-secondary);cursor:pointer;position:relative;transition:all .15s;border:none;background:none;width:100%;text-align:left;border-radius:var(--rm)}
.nav-item:hover{background:var(--td-bg);color:var(--color-text-action)}
.nav-item.active{background:linear-gradient(180deg,var(--brand-0) 0%,var(--brand-100) 100%) left/3px 100% no-repeat,var(--td-bg);color:var(--color-text-action);font-weight:700;box-shadow:none}
.nav-item.active svg{color:var(--color-text-action)}
.nav-item:focus-visible{outline:2px solid var(--color-border-focus);outline-offset:-2px}
/* Neutral count chip (not red) — red is reserved for the crisis band only. */
.nav-badge{margin-left:auto;min-width:20px;height:20px;background:var(--td-bg);color:var(--color-text-action);border-radius:var(--rpill);padding:0 6px;font-size:var(--text-xs);font-weight:700;display:flex;align-items:center;justify-content:center}
/* Nav badge draws attention once when a new case lands (improve.md §A) — stays its real teal (a patient
   count, not an alarm); only "something changed" animates, colour never escalates to red. */
@media (prefers-reduced-motion:no-preference){.nav-badge.nb-pulse{animation:nb-pulse 1.6s ease-out 3}}
@keyframes nb-pulse{0%{transform:scale(1)}30%{transform:scale(1.28)}60%,100%{transform:scale(1)}}
.sb-footer{padding:12px;border-top:1px solid var(--color-border)}
.sb-user{display:flex;align-items:center;gap:10px}
/* Station = information chip under the logo (not a menu row); language + log out share one footer utility row.
   Owner-approved proposal 30/09 (styleguide Proposal tab) — the two used to look exactly like the first two menu items. */
.sb-station{display:flex;flex-direction:column;gap:2px;margin:0 12px 8px;padding:8px 12px;background:var(--color-surface-subtle);border-radius:var(--rs)}
.sb-station-k{font-size:var(--text-xs);font-weight:700;color:var(--color-text-secondary);text-transform:uppercase;letter-spacing:.5px}
.sb-station .hd-ward{font-size:var(--text-sm);font-weight:700;color:var(--color-text);line-height:1.35}
.sb-util{display:flex;align-items:center;justify-content:space-between;gap:8px}
.sb-util .nav-item{flex:1;width:auto;margin-bottom:0}
/* Language control (owner rule 05/10): not a toggle, one pill that names the OTHER language ("Tiếng Việt" while the dashboard
   is English, "English" while it is Vietnamese). Same look as the login page's language pill. Hidden in the icon rail. */
.sb-lang{display:inline-flex;align-items:center;gap:5px;flex-shrink:0;border:none;border-radius:var(--rpill);padding:6px 12px;background:var(--color-surface-subtle);color:var(--color-text-action);font-family:inherit;font-size:var(--text-sm);font-weight:700;white-space:nowrap;cursor:pointer}
@media (hover:hover){.sb-lang:hover{background:var(--color-border)}}
.sb-user-btn{display:flex;align-items:center;gap:10px;width:100%;border:none;background:none;cursor:pointer;color:var(--color-text);padding:8px;border-radius:var(--rm);transition:background .15s;margin-bottom:2px;text-align:left;font-family:inherit}
.sb-user-btn:hover{background:var(--color-surface-subtle)}
.sb-user-chev{color:var(--color-text-muted)} /* the expand-chevron .ico — muted, not a nav-item so no shared muted class fits */
.sb-avatar{width:36px;height:36px;border-radius:var(--rpill);background:var(--td-bg);color:var(--color-text-action);display:flex;align-items:center;justify-content:center;font-size:var(--text-base);font-weight:700;flex-shrink:0}
.sb-name{font-size:var(--text-sm);font-weight:600;line-height:1.3;color:var(--color-text);text-overflow:ellipsis}
.sb-role-tag{display:inline-block;font-size:var(--text-xs);font-weight:700;padding:2px 7px;border-radius:var(--rpill);background:var(--color-surface-subtle);color:var(--color-text-secondary);margin-top:2px}
.logout-a{display:block;font-size:var(--text-sm);color:var(--color-text-muted);margin-top:8px;text-decoration:none;transition:color .15s}
.logout-a:hover{color:var(--color-text)}

/* ── Main ───────────────────────────────────────────────── */
.main{flex:1;overflow-y:auto;display:flex;flex-direction:column}
.page-head{background:transparent;padding:26px 32px 8px;display:flex;align-items:flex-start;justify-content:space-between;gap:16px}
.page-head h1{font-size:var(--text-xl);font-weight:800;letter-spacing:-.6px;line-height:1.15}
.page-head p{font-size:var(--text-sm);color:var(--color-text-secondary);margin-top:4px}
.page-body{padding:14px 32px 30px;flex:1}
.page{display:none}.page.active{display:block}

/* ── Stat / KPI cards (proposal .kpi) ───────────────────── */
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:13px;margin-bottom:20px}
/* Doctor overview has 5 KPI cards — one row instead of 4 + orphan (≤1200px falls back to 2-col below) */
@media(min-width:1201px){.stats:has(> :nth-child(5)){grid-template-columns:repeat(5,1fr)}}
.stat{display:block;width:100%;text-align:left;background:var(--color-surface-card);border-radius:var(--rm);padding:14px 15px 15px;border:none;box-shadow:var(--sh);cursor:pointer;transition:transform .12s,box-shadow .15s;font-family:inherit;position:relative;overflow:hidden}
.stat:hover{transform:translateY(-1px);box-shadow:0 3px 6px rgba(15,23,42,.07),0 10px 22px rgba(15,23,42,.09),0 0 0 1px rgba(15,23,42,.03)}
.stat::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--accent);opacity:.9}
.stat.a-high::before{background:var(--red)}.stat.a-warn::before{background:var(--amber)}
.stat.a-teal::before{background:var(--t)}.stat.a-ok::before{background:var(--green)}
.stat.a-neutral::before{background:var(--mute)}
.stat-top{display:flex;align-items:center;gap:8px;margin-bottom:10px}
.stat-ic{width:30px;height:30px;border-radius:var(--rxs);display:flex;align-items:center;justify-content:center;flex-shrink:0;background:var(--accent-lt);color:var(--accent)}
.stat-ic svg{width:16px;height:16px}
.stat-ic.high{background:var(--red-bg);color:var(--color-text-danger)}.stat-ic.warn{background:var(--amber-bg);color:var(--amber-tx)}
.stat-ic.teal{background:var(--tl);color:var(--color-text-action)}.stat-ic.ok{background:var(--green-bg);color:var(--green-tx)}
/* A count is not a risk signal (improve.md §D Exhibit B, decided 03/10) — lighter than --fog so a mere
   count doesn't compete with the real risk tints (high/warn) in the same row. */
.stat-ic.neutral{background:var(--color-surface-sunken);color:var(--color-text-muted)}
.stat-row{display:flex;align-items:baseline;justify-content:space-between;gap:8px}
.stat-label{font-size:var(--text-sm);font-weight:600;color:var(--color-text-secondary);letter-spacing:0;line-height:1.3}
.stat-val{font-size:var(--text-2xl);font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-1px;line-height:.9;color:var(--color-text)}
.stat-delta{font-size:var(--text-xs);color:var(--color-text-muted);margin-top:6px}

/* ── Triage / crisis band "Cần xử lý ngay" (proposal .critband) ── */
.triage-card,.critband{border:1px solid var(--red-bd);border-radius:var(--r);background:linear-gradient(100deg,var(--red-bg),var(--amber-bg));box-shadow:0 4px 16px rgba(220,38,38,.10);overflow:hidden;margin-bottom:16px}
.triage-head,.critband .ch{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 16px;border-bottom:1px solid rgba(246,192,184,.6)}
.triage-title,.critband .ct{display:flex;align-items:center;gap:10px;font-weight:800;font-size:var(--text-sm);color:var(--red-dk)}
.triage-ic,.critband .cic{width:28px;height:28px;border-radius:var(--rxs);background:var(--red-soft);color:var(--color-text-danger);display:flex;align-items:center;justify-content:center;flex-shrink:0}
.triage-ic svg,.critband .cic svg{width:16px;height:16px}
.triage-sub,.critband .ccount{font-size:var(--text-sm);color:var(--color-text-danger);font-weight:600;text-align:right}
.triage-row,.critrow{display:flex;align-items:center;gap:12px;padding:10px 16px}
.triage-row+.triage-row,.critrow+.critrow{border-top:1px solid rgba(246,192,184,.4)}
.triage-bar,.critrow .cbar{width:4px;height:34px;border-radius:2px;flex-shrink:0;background:var(--red)}
.critrow .cav{width:32px;height:32px;border-radius:50%;background:var(--red-bg);color:var(--color-text-danger);display:flex;align-items:center;justify-content:center;font-size:var(--text-sm);font-weight:700;flex-shrink:0;box-shadow:inset 0 0 0 1px var(--red-bd)}
.triage-name,.critrow .cn{font-weight:700;font-size:var(--text-sm);color:var(--color-text)}
.triage-meta,.critrow .cmeta{display:flex;align-items:center;gap:6px;font-size:var(--text-xs);color:var(--color-text-secondary);margin-top:1px}
.triage-type{font-weight:600;color:var(--color-text-danger)}
.critrow .cbp{font-family:'Inter',system-ui,sans-serif;font-variant-numeric:tabular-nums;font-size:var(--text-md);font-weight:600;color:var(--color-text-danger);margin-left:auto}
.critrow .cact{display:flex;gap:7px;flex-shrink:0}
.triage-more{width:100%;text-align:center;padding:9px;font-size:var(--text-sm);font-weight:600;color:var(--color-text-danger);background:none;border:none;border-top:1px solid rgba(246,192,184,.4);cursor:pointer;font-family:inherit}
.triage-more:hover{background:rgba(255,255,255,.5)}
@media(max-width:640px){.triage-sub,.critband .ccount{display:none}}

/* Crisis band collapses to the .ch summary line by default (improve.md §C) — the band keeps its red
   weight even closed, so it reads as unresolved, not dismissed. .in (the case list) only shows when open. */
.critband .ch{width:100%;border:none;background:none;cursor:pointer;font:inherit;color:inherit;text-align:left}
.critband:not(.open) .ch{border-bottom:none}
.critband .ch:hover{background:rgba(255,255,255,.35)}
.critband .cnew{flex-shrink:0;font-size:var(--text-xs);font-weight:800;color:#fff;background:var(--red);border-radius:var(--rpill);padding:2px 9px;letter-spacing:.3px}
@media (prefers-reduced-motion:no-preference){.critband.has-new .cnew{animation:critband-pulse 1.8s ease-in-out infinite}}
@keyframes critband-pulse{0%,100%{opacity:1}50%{opacity:.55}}
.critband .cchev{display:inline-flex;color:var(--red-dk);transition:transform var(--motion-fast);flex-shrink:0}
.critband.open .cchev{transform:rotate(90deg)}

/* ── Overview 2-col grid (work list · side panels) ──────── */
.ov-grid{display:grid;gap:16px;align-items:start;margin-bottom:18px;grid-template-columns:1fr}
.ov-grid>div{margin-bottom:0!important}
.ov-col{display:flex;flex-direction:column;gap:16px;min-width:0}
.ov-col .tcard{margin-bottom:0}
@media(min-width:1000px){.ov-grid.cols2{grid-template-columns:1.5fr 1fr}}

/* ── "Hôm nay" work rows (proposal .wrow) ───────────────── */
.today-row{display:flex;align-items:center;gap:12px;padding:11px 16px;border-top:1px solid var(--color-border-subtle)}
.today-row:first-child{border-top:none}
.today-row.thigh{box-shadow:inset 3px 0 0 var(--red)}
.today-dot{width:9px;height:9px;border-radius:50%;flex-shrink:0}
.today-name{font-size:var(--text-sm);font-weight:600;color:var(--color-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.today-hdid{font-size:var(--text-xs);color:var(--color-text-muted);margin-top:1px}
.today-bp{text-align:right;flex-shrink:0}
.today-bpval{font-family:'Inter',system-ui,sans-serif;font-variant-numeric:tabular-nums;font-weight:600;font-size:var(--text-base)}
.today-src{font-size:var(--text-xs);color:var(--color-text-muted);margin-top:1px}
/* ── Risk distribution card (donut markup: riskDonutHtml) ── */
.risk{padding:14px 18px}
/* ── Weekly activity card (trend markup: weekTrendHtml) ───── */
.week{padding:15px 18px}
.week .wtop{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:12px}
.week .wtot{font-size:var(--text-lg);font-weight:600;color:var(--color-text);font-variant-numeric:tabular-nums}
.week .wtot span{font-size:var(--text-sm);color:var(--color-text-secondary);font-weight:400;font-family:'Inter'}
.week .wchip{font-size:var(--text-xs);font-weight:700;color:var(--color-text-secondary);background:var(--color-surface-sunken);border-radius:var(--rpill);padding:2px 8px}

/* ── Table card ─────────────────────────────────────────── */
.tcard{background:var(--color-surface-card);border-radius:var(--r);border:1px solid var(--color-border);box-shadow:var(--shadow-card);overflow:hidden;margin-bottom:18px}
.tcard-head{display:flex;align-items:center;justify-content:space-between;padding:15px 20px;border-bottom:1px solid var(--color-border)}
.tcard-title{font-size:var(--text-base);font-weight:600}
.tcard-count{font-size:var(--text-sm);color:var(--color-text-secondary);margin-left:var(--sp-2)}
.toolbar{display:flex;gap:10px;padding:11px 16px;background:var(--color-surface-sunken);border-bottom:1px solid var(--color-border);flex-wrap:wrap}
.search{height:34px;padding:0 10px 0 32px;border:1px solid var(--color-border);border-radius:var(--rxs);font-size:var(--text-sm);outline:none;background:var(--color-surface-card);min-width:180px;transition:border-color .15s}
.search:focus{border-color:var(--t);box-shadow:0 0 0 3px rgba(15,184,184,.12)}
.fsel{height:34px;padding:0 8px;border:1px solid var(--color-border);border-radius:var(--rxs);font-size:var(--text-sm);background:var(--color-surface-card);outline:none}
table{width:100%;border-collapse:collapse}
thead{background:var(--color-surface-sunken)}
th{position:sticky;top:0;z-index:1;padding:11px 16px;font-size:var(--text-xs);font-weight:700;color:var(--color-text-muted);text-transform:uppercase;letter-spacing:.03em;text-align:left;background:var(--color-surface-sunken);border-bottom:1px solid var(--color-border);white-space:nowrap}
td{padding:11px 16px;font-size:var(--text-sm);color:var(--color-text-body);border-bottom:1px solid var(--color-border-subtle);vertical-align:middle}
tr:last-child td{border-bottom:none}
tbody tr:hover{background:var(--color-surface-sunken)}
/* No row background tint. High-risk rows keep only a thin red left-edge line. */
tbody tr.thigh td:first-child{box-shadow:inset 3px 0 0 var(--red)}
/* .bpnum = BP measurements: Inter with tabular figures (font-variant-numeric). Everything else = Inter too. */
.mono{font-family:'Inter',system-ui,sans-serif;font-variant-numeric:tabular-nums;font-size:var(--text-sm)}
.bpnum{font-family:'Inter',system-ui,sans-serif;font-variant-numeric:tabular-nums}
.bold{font-weight:700}
/* Sparkline (mini 7-reading trend) */
.spark{width:90px;height:28px;flex-shrink:0;vertical-align:middle}
/* BP value colour helpers in tables */
.bpv-high{color:var(--color-text-danger)}.bpv-warn{color:var(--amber-tx)}.bpv-ok{color:var(--green-tx)}

/* ── Badges / pills (proposal .pill — dot + tint) ───────── */
/* .badge + .b-red/.b-amb/.b-grn/.b-blu/.b-gray/.b-teal → components.css (no status dot; opt in with .badge-dot). Dashboard-only: */
.b-vhigh{background:var(--red-soft);color:var(--red-dk)}
.badge .rdot{width:6px;height:6px;border-radius:50%;display:inline-block}

/* ── Patient list cell ──────────────────────────────────── */
.pcell{display:flex;align-items:center;gap:10px;min-width:0}
.pcell-av{width:32px;height:32px;border-radius:50%;background:var(--color-surface-sunken);color:var(--color-text-secondary);font-weight:700;font-size:var(--text-sm);display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:inset 0 0 0 1px var(--bord)}
.pcell-name{font-size:var(--text-sm);font-weight:600;color:var(--color-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pcell-sub{font-size:var(--text-xs);color:var(--color-text-muted);margin-top:1px;font-variant-numeric:tabular-nums}

/* ── Patient record (full-page) ─────────────────────────── */
.rec-back{display:inline-flex;align-items:center;gap:6px;font-size:var(--text-sm);font-weight:500;color:var(--color-text-secondary);background:none;border:none;cursor:pointer;font-family:inherit;transition:color .15s;margin-bottom:14px}
.rec-back:hover{color:var(--color-text)}
.rcard{background:var(--color-surface-card);border-radius:var(--r);border:1px solid var(--color-border);box-shadow:var(--shadow-card);padding:18px}
.rcard.nopad{padding:0}
/* Back link + toolbar share one row (owner 24/10): each page's own back button sits beside
   #recToolbar (filled by recToolbarHtml()) instead of the actions stacking below it. */
.rec-topbar{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:14px}
.rec-topbar .rec-back{margin-bottom:0}
.rec-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
/* Name+meta / reading / target as 3 grid tracks (owner 24/10, ratio tuned 25/10): reading
   needs room for number + badge + pulse on one line, target is just a value + Edit now that
   its gap-to-target line moved to the reading column, so it gets the smallest share. The
   reading moved up here from the BP card so it's seen with the patient, not after scrolling
   into the grid below. */
.rec-head{display:grid;grid-template-columns:1fr;gap:16px}
/* Reading and target size to their own content (owner 24/10): a fixed fr split either
   starved the name column (it needed more than its share) or left reading/target with
   dead space (their content didn't need as much as its share) depending on the patient.
   Name is the one column with genuinely unpredictable length, so it alone takes the
   flexible track; reading and target just claim what their content needs.
   Capped at 140-320px (owner 24/10, round 2): a bare 1fr name column still claimed every
   leftover pixel on a wide card with a short name, stranding the reading column far right
   of the name instead of right after it. `fr` can't be nested inside `min()` (silently
   invalidates the whole declaration, collapsing the grid to 1 column — caught testing
   this locally), so the cap is a plain minmax() length instead.
   No 4th flex track (owner 24/10, round 5): a trailing minmax(0,1fr) spacer absorbed the
   leftover space but drew as its own visible column + gap in the DevTools grid overlay —
   confusing, and not what "3 columns" means to anyone reading it. Without any `fr` track
   the grid already packs to the start and leaves the container's own leftover space after
   the last column for free (no `justify-content` needed), so dropping the spacer track
   changes nothing on screen, only the inspector.
   Gap cut to 12px + a divider line (owner 24/10, round 6): the bare 28px gap read as dead
   air between columns in the DevTools overlay. Reading/Target now carry their own
   `border-left` + 12px padding (below, on the existing `.rec-reading-col`/`#recTarget`
   hooks — no new class, no markup change) so the line sits roughly where the gap used to
   be and the columns read as 3 DIVIDED fields, not 3 floating ones.
   Reading/Target capped, no longer bare `auto` (owner 25/10, round 7): `auto` sized each
   to its own widest line (~470px reading, ~304px target on a typical patient), far more
   than either needs — the owner asked for the reading column at roughly 2/3 of that and
   target at roughly half. `minmax(200px,310px)`/`minmax(100px,150px)`: the existing
   ellipsis/nowrap rules on `.rc-bp`, `.rc-bp-badge-tx`, `.rc-gap-inline`, `.rc-tgtv` (item
   8) are what keeps a long reading/badge/gap line readable at the new width instead of
   overflowing or wrapping to a 2nd line — this item doesn't add new ones.
   Name column's 320px cap REMOVED, back to `minmax(140px,1fr)` (owner 25/10, round 8):
   item 7's cap is what the round-7 cut freed on the right went to otherwise (dead space
   after Target, same blank-space problem item 7 just fixed on the other two columns) —
   owner wants ALL of it to go to Name instead. This is the exact shape item 2 warned
   never to bring back for a SHORT name (it reads as dead space again, just inside the
   name column's own box this time instead of before Reading); accepted deliberately
   this round because Reading/Target are now hard-capped, so what used to be "the gap
   grows, stranding Reading" is now "Name's own box grows, Reading stays put right next
   to it" — a different failure shape, not the one item 2 was about.
   Reading's cap +15px, 310→325 (owner 25/10, round 9): stress-tested with the longest
   Vietnamese tier label ("Tăng huyết áp") at 3-digit/3-digit + a 3-digit pulse, it stayed
   on one line but the badge itself lost its last ~8px to the ellipsis — owner wants that
   not to happen at all, not just not wrap. */
@media(min-width:768px){.rec-head{grid-template-columns:minmax(140px,1fr) minmax(200px,325px) minmax(100px,150px);align-items:start;gap:12px}
  .rec-reading-col,#recTarget{border-left:1.5px solid var(--color-border);padding-left:12px}}
.rec-id{display:flex;align-items:flex-start;gap:15px;min-width:0}
.rec-av{width:56px;height:56px;border-radius:50%;background:var(--bord);color:var(--color-text-secondary);font-weight:800;font-size:var(--text-xl);display:flex;align-items:center;justify-content:center;flex-shrink:0}
.rec-name{font-size:var(--text-xl);font-weight:800;letter-spacing:-.4px;line-height:1.1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;max-width:100%}
/* Badges on their own line, not sharing one with the name (owner 25/10, "never 4 lines"):
   mixed in with the name they could each drop onto their own line one by one at the
   narrowest 3-column width. nowrap + overflow:hidden caps this row at one line, always. */
.rec-badges{display:flex;align-items:center;gap:8px;flex-wrap:nowrap;overflow:hidden;margin-top:4px}
.rec-badges>*{white-space:nowrap;flex-shrink:0}
/* Nowrap + truncate (owner 25/10, "never 4 lines"): a long comorbidity list used to wrap
   the meta line onto a 2nd line, pushing name+meta to 4 lines with a long name too. The
   row now stays one line; .rec-comorb (the longest, most variable piece) truncates first. */
.rec-meta{display:flex;align-items:center;gap:10px;margin-top:7px;font-size:var(--text-sm);color:var(--color-text-secondary);flex-wrap:nowrap;overflow:hidden;min-width:0}
.rec-meta>*{white-space:nowrap;flex-shrink:0}
.rec-comorb{overflow:hidden;text-overflow:ellipsis;min-width:0;flex-shrink:1}
.rec-meta .mdot{width:4px;height:4px;border-radius:50%;background:var(--mute);flex-shrink:0}
.nr-flag{display:inline-flex;align-items:center;gap:5px;font-size:var(--text-sm);font-weight:700;color:var(--color-text-danger);background:var(--red-soft);border-radius:var(--rpill);padding:3px 10px;white-space:nowrap;flex-shrink:0}
/* Pills never wrap their own text mid-badge (owner 25/10, "never 4 lines"): a squeezed
   .rec-id/.rc-bp row would otherwise let "Không đáp ứng thuốc" or a classification label
   break across two lines inside the pill itself. */
.rec-id .badge,.rc-bp .badge{white-space:nowrap;flex-shrink:0}
.rec-name{flex-shrink:1}
.rec-grid{display:grid;grid-template-columns:1fr;gap:18px;margin-top:18px}
@media(min-width:1000px){.rec-grid{grid-template-columns:1.8fr 1.2fr}}
.rec-col{display:flex;flex-direction:column;gap:18px;min-width:0}
/* Exam/meds/stage card is first in source order (clinicians need that context
   before reading a trend), so mobile already stacks it above the chart+history
   card without any reorder; desktop puts them side by side, wide col first. */
.rsec{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:14px;flex-wrap:wrap}
.rsec-t{display:flex;align-items:center;gap:8px;font-size:var(--text-base);font-weight:700;color:var(--color-text)}
.rsec-t svg{color:var(--color-text-secondary);flex-shrink:0}
.rleg-i{display:inline-flex;align-items:center;gap:6px}
/* Reading-history table (narrow rec-col): no forced min-width/legend text per row —
   pulse stacks under BP, source is an icon with a title tooltip (legend below the
   chart already spells out the shapes), so 4 columns fit without horizontal scroll. */
.table-wrap.rc-hist-wrap table{min-width:0}
.rc-hist-wrap th,.rc-hist-wrap td{padding:9px 8px}
.rc-hist-pulse{display:block;margin-top:1px}
.rc-hist-src{display:inline-flex;align-items:center;justify-content:center}

/* ── Buttons ────────────────────────────────────────────── */
/* .btn-sm + neutral .btn-teal/.btn-grn/.btn-gray + .btn-red → components.css. Dashboard-only variants: */
/* Solid variants: red ONLY in the crisis band; primary rows = neutral slate. */
.btn-solid-teal{background:var(--accent);color:#fff}.btn-solid-teal:hover{background:var(--body)}
.btn-ghost{background:#fff;color:var(--color-text-body);box-shadow:inset 0 0 0 1px var(--bord)}.btn-ghost:hover{background:var(--color-surface-sunken)}
/* .btn-row + .btn-primary/.btn-accent (brand gradient) → components.css. */

/* ── Spinner / loading ──────────────────────────────────── */
/* .spinner + .loading-msg + .empty → components.css */
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important;scroll-behavior:auto!important}}

/* ── Modal ──────────────────────────────────────────────── */
/* .modal-wrap/.modal/.modal-h/.modal-title/.modal-x/.modal-body/.modal-acts → components.css. Dashboard-only rows: */
.modal-row{display:flex;justify-content:space-between;padding:8px 0;font-size:var(--text-sm);border-bottom:1px solid var(--fog)}
.modal-row:last-child{border-bottom:none}
.modal-row-l{color:var(--color-text-secondary)}.modal-row-v{font-weight:600;text-align:right}

/* .toast → components.css */

/* ── Empty state ────────────────────────────────────────── */
.empty-icon{font-size:var(--text-2xl);margin-bottom:10px}

/* ── Password eye ───────────────────────────────────────── */
.pw-wrap{position:relative;display:flex;align-items:center}
.pw-wrap input{flex:1;padding-right:42px !important}
.pw-eye{position:absolute;right:12px;background:none;border:none;cursor:pointer;color:var(--color-text-muted);padding:4px;display:flex;align-items:center;transition:color .15s}
.pw-eye:hover{color:var(--color-text-secondary)}

/* ── Intake form ────────────────────────────────────────── */
.intake-card{background:var(--color-surface-card);border-radius:var(--r);border:1px solid var(--color-border);overflow:hidden;max-width:720px}
.intake-section{padding:20px 24px;border-bottom:1px solid var(--color-border)}
.intake-section:last-child{border-bottom:none}
.intake-section-title{font-size:var(--text-sm);font-weight:700;color:var(--color-text-secondary);text-transform:uppercase;letter-spacing:.5px;margin-bottom:14px}
.search-wrap{position:relative}
.search-results{position:absolute;top:100%;left:0;right:0;background:var(--color-surface-card);border:1px solid var(--color-border);border-radius:var(--rs);box-shadow:0 8px 24px rgba(0,0,0,.10);z-index:100;max-height:240px;overflow-y:auto;margin-top:4px;display:none}
.search-results.open{display:block}
.search-item{padding:10px 14px;cursor:pointer;border-bottom:1px solid var(--fog);transition:background .15s}
.search-item:last-child{border-bottom:none}
.search-item:hover{background:var(--color-surface-subtle)}
.search-item-name{font-size:var(--text-sm);font-weight:600}
.search-item-sub{font-size:var(--text-xs);color:var(--color-text-secondary);margin-top:2px}
.patient-card{background:var(--accent-lt);border:1.5px solid var(--accent-md);border-radius:var(--rs);padding:12px 16px;display:flex;align-items:center;justify-content:space-between;margin-top:12px}
.patient-card-info{font-size:var(--text-sm)}
.patient-card-name{font-weight:700;font-size:var(--text-sm);margin-bottom:2px}
.patient-card-sub{color:var(--color-text-secondary);font-size:var(--text-sm)}
.patient-card-clear{background:none;border:none;color:var(--color-text-muted);font-size:var(--text-md);cursor:pointer;padding:4px;transition:color .15s}
.patient-card-clear:hover{color:var(--red)}
.bp-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:14px}
.field-group{display:flex;flex-direction:column;gap:6px}
.field-label{font-size:var(--text-sm);font-weight:700;color:var(--color-text-secondary);text-transform:uppercase;letter-spacing:.4px}
.field-input{height:50px;border:2px solid var(--color-border);border-radius:var(--rs);padding:0 14px;font-size:var(--text-md);font-family:'Inter',system-ui,sans-serif;font-variant-numeric:tabular-nums;font-weight:700;outline:none;transition:border-color .2s;text-align:center}
.field-input:focus{border-color:var(--t);box-shadow:0 0 0 3px rgba(15,184,184,.12)}
.field-input.error{border-color:var(--red)}
.field-hint{font-size:var(--text-xs);color:var(--color-text-muted);text-align:center}
.extra-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:14px}
.extra-input{height:42px;border:1.5px solid var(--color-border);border-radius:var(--rs);padding:0 12px;font-size:var(--text-sm);outline:none;transition:border-color .2s;width:100%}
.extra-input:focus{border-color:var(--t);box-shadow:0 0 0 3px rgba(15,184,184,.12)}
.intake-note{width:100%;border:1.5px solid var(--color-border);border-radius:var(--rs);padding:10px 12px;font-size:var(--text-sm);resize:vertical;outline:none;transition:border-color .2s;min-height:72px;margin-top:14px}
.intake-note:focus{border-color:var(--t);box-shadow:0 0 0 3px rgba(15,184,184,.12)}
.intake-result{padding:12px 16px;border-radius:var(--rs);margin-bottom:0;font-size:var(--text-sm);font-weight:600;display:none}
.intake-result.ok{background:var(--green-bg);color:var(--green-tx)}
.intake-result.err{background:var(--red-bg);color:var(--red-dk)}

/* ── Mobile priority-queue banner (điều dưỡng/bác sĩ solo, ≤768px) ──
   Hidden on desktop by default; JS (renderMobileQueueBanner) toggles display.
   @media(min-width:769px) below is a hard safety net regardless of JS state. */
.mobile-queue-banner{background:var(--color-surface-card);border-radius:var(--r);box-shadow:var(--sh);padding:14px;margin-bottom:16px}
.mq-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}
.mq-count{font-size:var(--text-xs);color:var(--color-text-secondary);background:none;border:0;padding:0;font-family:inherit;cursor:pointer}
.mq-body{display:flex;align-items:center;gap:10px;margin-bottom:12px}
.mq-av{width:40px;height:40px;border-radius:50%;background:var(--color-surface-sunken);display:flex;align-items:center;justify-content:center;font-size:var(--text-sm);font-weight:700;color:var(--color-text-secondary);box-shadow:inset 0 0 0 1px var(--bord);flex-shrink:0}
.mq-name{font-size:var(--text-base);font-weight:800}
.mq-meta{font-size:var(--text-sm);color:var(--color-text-secondary);margin-top:1px}
.mq-actions{display:flex;gap:10px}
.mq-crisis{background:var(--red-bg);border:1.5px solid var(--red-bd)}
.mq-av-red{background:var(--red-soft);color:var(--red)}
.mq-actions+.mq-body{border-top:1px solid var(--color-border);padding-top:12px;margin-top:12px}
.patnotice{padding:9px 18px;border-bottom:1px solid var(--color-border)}
@media(min-width:769px){.mobile-queue-banner{display:none!important}}

/* ── Tiếp nhận — two-column found-card + exam-form (proposal) ── */
.intakegrid{display:grid;grid-template-columns:1fr 1.1fr;gap:16px;align-items:start}
@media(max-width:999px){.intakegrid{grid-template-columns:1fr}}
.foundcard{background:var(--color-surface-card);border-radius:var(--r);box-shadow:var(--sh);padding:16px}
.foundcard .fh{display:flex;align-items:center;gap:12px;padding-bottom:14px;border-bottom:1px solid var(--color-border-subtle);margin-bottom:12px}
.foundcard .fav{width:46px;height:46px;border-radius:50%;background:var(--color-surface-sunken);display:flex;align-items:center;justify-content:center;font-size:var(--text-base);font-weight:700;color:var(--color-text-secondary);box-shadow:inset 0 0 0 1px var(--bord);flex-shrink:0}
.foundcard .fn{font-size:var(--text-base);font-weight:800;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.foundcard .fmeta{font-size:var(--text-sm);color:var(--color-text-secondary);margin-top:2px}
.finfo{display:flex;justify-content:space-between;gap:12px;font-size:var(--text-sm);padding:7px 0}
.finfo+.finfo{border-top:1px solid var(--color-border-subtle)}
.finfo .k{color:var(--color-text-secondary)}.finfo .v{font-weight:600;color:var(--color-text);text-align:right}
.examform{background:var(--color-surface-card);border-radius:var(--r);box-shadow:var(--sh);padding:16px}
.examform h3{font-size:var(--text-sm);font-weight:700;margin-bottom:14px;display:flex;align-items:center;gap:8px}
.examform h3 svg{width:16px;height:16px;color:var(--color-text-secondary)}
.frow{display:flex;gap:11px;margin-bottom:11px}.frow .fld{flex:1}
.fld label{display:block;font-size:var(--text-xs);font-weight:600;color:var(--color-text-secondary);margin-bottom:5px}
.inp.mono{font-family:'Inter',system-ui,sans-serif;font-variant-numeric:tabular-nums;text-align:center;font-size:var(--text-md)}
.inp.mono::placeholder{font-style:italic}   /* an example value ("120") in the same tabular-nums style as a real reading read as already-entered data — italic marks it as a placeholder, not a change to the muted colour every other input already uses */

/* ── Hamburger ──────────────────────────────────────────── */
.hamburger{display:none;width:38px;height:38px;border-radius:var(--rxs);background:var(--color-surface-subtle);border:none;align-items:center;justify-content:center;cursor:pointer;flex-shrink:0;color:var(--color-text-secondary);transition:background .15s}
.hamburger:hover{background:var(--bord)}
.sb-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:149}
.sb-overlay.open{display:block}

/* ── User chip ──────────────────────────────────────────── */
.user-chip{display:flex;align-items:center;gap:8px;padding:5px 12px 5px 5px;background:var(--color-surface-subtle);border-radius:var(--rpill);flex-shrink:0}
.user-chip-name{font-size:var(--text-sm);font-weight:600;max-width:140px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.3}
.user-chip-role{font-size:var(--text-xs);color:var(--color-text-secondary);line-height:1.3}

/* ── Bottom nav (mobile only) ───────────────────────────── */
.bottom-nav{display:none;position:fixed;bottom:0;left:0;right:0;height:56px;background:var(--color-surface-card);border-top:1px solid var(--color-border);z-index:100;align-items:stretch;padding:0 2px;gap:0;box-sizing:content-box;padding-bottom:env(safe-area-inset-bottom,0px)}
.bn-item{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;font-size:var(--text-xs);font-weight:600;color:var(--color-text-secondary);border:none;background:none;cursor:pointer;padding:4px 2px;border-top:2px solid transparent;transition:all .15s;position:relative;min-width:0}
.bn-item.active{color:var(--color-text-action);border-top-color:var(--td)}
.bn-item svg{flex-shrink:0}
.bn-badge{min-width:14px;height:14px;background:var(--mute);color:#fff;border-radius:var(--rpill);padding:0 3px;font-size:9px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;position:absolute;top:3px;right:calc(50% - 20px)}

/* ── Table scroll wrapper ────────────────────────────────── */
.table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
.table-wrap table{min-width:560px}

/* ── Screening form ─────────────────────────────────────── */
.screen-tabs{display:flex;gap:0;border-bottom:2px solid var(--color-border);margin-bottom:20px}
.screen-tab{padding:9px 18px;font-size:var(--text-sm);font-weight:600;color:var(--color-text-secondary);background:none;border:none;cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-2px;transition:all .15s}
.screen-tab.active{color:var(--color-text-action);border-bottom-color:var(--td)}
.reg-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-bottom:14px}
.reg-label{font-size:var(--text-sm);font-weight:700;color:var(--color-text-secondary);text-transform:uppercase;letter-spacing:.4px;display:block;margin-bottom:5px}
.reg-gender{display:flex;gap:10px}
.reg-gender label{flex:1;display:flex;align-items:center;justify-content:center;gap:7px;height:44px;border:1.5px solid var(--color-border);border-radius:var(--rs);font-size:var(--text-sm);font-weight:600;cursor:pointer;transition:all .15s}
.reg-gender input[type=radio]{display:none}
.reg-gender input[type=radio]:checked + label{background:rgba(15,184,184,.08);border-color:var(--t);color:var(--color-text-action)}
.dob-row-s{display:grid;grid-template-columns:1fr 1fr 1.4fr;gap:8px}
.screen-result{border-radius:var(--rs);padding:14px 16px;margin-bottom:14px;display:none;font-size:var(--text-sm)}
.screen-result.ok{background:var(--green-soft);border:1.5px solid var(--green-bd);color:var(--green-dk)}
.screen-result.err{background:var(--red-soft);border:1.5px solid var(--red-bd);color:var(--red-dk)}
.screen-found-card{background:var(--accent-lt);border:1.5px solid var(--accent-md);border-radius:var(--rs);padding:14px 16px;margin-top:12px;display:flex;align-items:center;justify-content:space-between;gap:10px}

/* ── Screening Wizard ───────────────────────────────────────── */
.sc-prog-dots{display:flex;justify-content:space-between;margin-bottom:8px}
.sc-dot{display:flex;flex-direction:column;align-items:center;gap:3px;font-size:var(--text-xs);font-weight:700;color:var(--color-text-muted);flex:1}
.sc-dot-n{width:26px;height:26px;border-radius:var(--rpill);background:var(--color-surface-subtle);border:2px solid var(--color-border);display:flex;align-items:center;justify-content:center;font-size:var(--text-sm);font-weight:700;transition:all .2s}
.sc-dot-lbl{font-size:var(--text-xs);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%;text-align:center}
.sc-dot.active .sc-dot-n{background:var(--t);border-color:var(--t);color:#fff}
.sc-dot.active{color:var(--color-text-action)}
.sc-dot.done .sc-dot-n{background:var(--green);border-color:var(--green);color:#fff}
.sc-dot.done{color:var(--green)}
/* ── BP stacked input (matches React .bp3r layout) ──────────── */
.sc-bp-row{display:flex;align-items:center;gap:14px;margin-bottom:12px}
.sc-bp-label{font-size:var(--text-sm);font-weight:700;color:var(--color-text-secondary);width:100px;flex-shrink:0;line-height:1.5}
.sc-bp-field{flex:1;background:var(--color-surface-subtle);border-radius:var(--rs);border:1.5px solid transparent;transition:border-color .15s}
.sc-bp-field:focus-within{border-color:var(--t);background:#fff}
.sc-bp-field input{width:100%;border:none;background:none;font-family:'Inter',system-ui,sans-serif;font-variant-numeric:tabular-nums;font-size:var(--text-xl);font-weight:500;color:var(--color-text);outline:none;text-align:center;padding:12px 8px}
.sc-bp-unit{font-size:var(--text-sm);color:var(--color-text-muted);width:40px;flex-shrink:0;text-align:right}

/* ── Non-responding treatment ───────────────────────────── */
.non-respond-row{background:var(--red-bg) !important}
.non-respond-flag{background:var(--red-soft);border:1px solid var(--red-bd);border-radius:6px;padding:4px 10px;font-size:var(--text-sm);font-weight:700;color:var(--red-dk);display:inline-flex;align-items:center;gap:5px}

/* ── Responsive ─────────────────────────────────────────── */
@media(max-width:1200px){.stats{grid-template-columns:repeat(2,1fr)}}
@media(max-width:999px){.bp-grid{grid-template-columns:1fr 1fr}}
@media(max-width:768px){
  :root{--sw:0px}
  .sidebar{position:fixed;left:-290px;width:280px;top:0;bottom:0;z-index:150;transition:left .28s cubic-bezier(.4,0,.2,1);height:100%;overflow-y:auto}
  .sidebar.open{left:0;box-shadow:0 0 40px rgba(0,0,0,.2)}
  .hamburger{display:flex}
  .shell{overflow:hidden}
  .page-head{padding:11px 14px;gap:8px}
  .page-head h1{font-size:var(--text-base)}
  .page-body{padding:14px}
  .stats{grid-template-columns:repeat(2,1fr);gap:10px}
  .stat{padding:14px 14px}
  .stat-val{font-size:var(--text-xl)}
  .tcard-head{padding:11px 14px}
  .tcard-title{font-size:var(--text-sm)}
  th{padding:8px 10px;font-size:var(--text-xs)}
  td{padding:8px 10px;font-size:var(--text-sm)}
  .dense{--btn-sm-h:26px;--btn-sm-px:7px;--btn-sm-fs:var(--text-xs);--btn-row-gap:4px}
  .bottom-nav{display:flex}
  .main{padding-bottom:calc(64px + env(safe-area-inset-bottom,0px))}
  .intake-card{max-width:100%}
  .bp-grid{grid-template-columns:1fr 1fr}
  .extra-grid{grid-template-columns:1fr}
  .user-chip-name{max-width:90px}
  .tcard{margin-bottom:12px}
  .reg-grid{grid-template-columns:1fr}
  /* Mobile = 1 màn hình đo (§ decisions.md 26/09): điều dưỡng/bác sĩ solo see
     ONLY Tiếp nhận at phone width — sidebar/bottom-nav/every other .page hidden.
     Supervisor is unaffected (no .mobile-intake-role class → normal responsive shell). */
  body.mobile-intake-role .sidebar,
  body.mobile-intake-role .bottom-nav,
  body.mobile-intake-role .hamburger{display:none!important}
  body.mobile-intake-role .page{display:none!important}
  body.mobile-intake-role #page-tiepnhan{display:block!important}
  body.mobile-intake-role .main{padding-bottom:0}
  /* The desktop "left column" empty-state card is redundant here — the
     priority banner (or the search box, when the queue is empty) already
     says the same thing, so showing both was 3 stacked "nothing selected"
     messages on one screen. */
  body.mobile-intake-role #intakeEmptyLeft{display:none!important}
}
@media(max-width:640px){
  .stats{grid-template-columns:1fr 1fr}
  .stat-val{font-size:var(--text-lg)}
  .bp-grid{grid-template-columns:1fr}
}
/* Responsive tables (.resp) → stacked cards on mobile (no horizontal scroll) */
@media(max-width:640px){
  .table-wrap.resp{overflow:visible}
  .table-wrap.resp table{min-width:0}
  .table-wrap.resp thead{display:none}
  .table-wrap.resp tbody,.table-wrap.resp tr,.table-wrap.resp td{display:block}
  .table-wrap.resp tbody,.table-wrap.resp td{width:100%}   /* not tr: width:100% + its 12px side margins pushed every card 24px past the table card and clipped its right edge (06/10) */
  .table-wrap.resp tr{border:1px solid var(--color-border);border-radius:var(--rm);margin:0 12px 10px;padding:4px 2px;background:#fff;box-shadow:var(--shadow-card)}
  .table-wrap.resp td{display:flex;justify-content:space-between;align-items:center;gap:12px;border:0;padding:8px 14px;font-size:var(--text-sm)}
  .table-wrap.resp td::before{content:attr(data-label);font-weight:600;color:var(--color-text-secondary);font-size:var(--text-sm);flex-shrink:0}
  .table-wrap.resp td[data-label="Bệnh nhân"]{border-bottom:1px solid var(--fog);padding:10px 14px}
  .table-wrap.resp td[data-label="Bệnh nhân"]::before,.table-wrap.resp td[data-label=""]::before{display:none}
  .table-wrap.resp td[data-label="Bệnh nhân"]>div{flex:1;min-width:0}
  .table-wrap.resp td[data-label=""]{padding-top:10px}
  .table-wrap.resp td .btn-row{justify-content:flex-end;flex:1;flex-wrap:wrap}
}

/* ══ Record page (owner-approved 30/09, proposal in the styleguide Proposal tab) ═══════════
   Two grouped cards: blood pressure (today's BP + gap + target, trend, readings under the chart) and
   "this exam" / treatment (medication, follow-up, note, details, care history). Every folded part is a bordered row. */
.rc-dob{color:var(--color-text);font-weight:700;font-family:var(--font-num);font-variant-numeric:tabular-nums}
.rec-head+.cds-band{margin-top:18px}
.cds-band+.rec-grid{margin-top:0}
.rc-k{font-size:var(--text-xs);font-weight:700;color:var(--color-text-secondary);text-transform:uppercase;letter-spacing:.5px}
.rc-sub{font-size:var(--text-sm);color:var(--color-text-secondary)}
/* Reading and target are each their own header grid column now (owner 24/10), not a
   shared boxed block, so they read like the name+meta column next to them. */
.rec-reading-col{min-width:0}
.rec-reading-col .rc-sub{margin-top:4px}
/* nowrap + clip, not wrap (owner 25/10, "never 4 lines"): at the narrowest 3-column width
   the badge used to drop to its own line, adding a 4th line (label/number+pulse/badge/gap).
   It now clips instead — number+pulse always readable, badge visible whenever it fits. */
.rc-bp{display:flex;align-items:baseline;gap:12px;margin-top:4px;flex-wrap:nowrap;overflow:hidden;min-width:0}
.rc-bp b,.rc-bp .rc-sub{flex-shrink:0;white-space:nowrap}
.rc-bp .badge{min-width:0;flex-shrink:1}
/* text-overflow doesn't apply to a flex container's own box (the badge is inline-flex, for
   its ::before dot) — ellipsis has to live on a plain inline child instead. */
.rc-bp-badge-tx{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;display:inline-block;vertical-align:bottom}
.rc-bp b{font-family:var(--font-num);font-variant-numeric:tabular-nums;font-size:var(--text-2xl);font-weight:800;letter-spacing:-.02em;line-height:1;color:var(--color-text)}
.rc-bp b.c-red{color:var(--color-text-danger)}.rc-bp b.c-amber{color:var(--amber-tx)}.rc-bp b.c-orange{color:var(--orange-tx)}
.rc-gap-inline{font-size:var(--text-xs);font-weight:700;text-transform:uppercase;letter-spacing:.5px}
.rec-reading-col .rc-gap-inline{display:block;margin-top:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rc-gap-inline.up{color:var(--color-text-danger)}.rc-gap-inline.ok{color:var(--green-tx)}
.rc-tgtv{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin-top:4px}
/* One size down from the reading's 2xl/800, secondary-grey not ink (owner 24/10, round 4): Target is
   reference info, not today's event, and matched the reading's own weight closely enough to compete
   with it for the eye instead of reading as the lesser of the two. */
.rc-tgtv b{font-family:var(--font-num);font-variant-numeric:tabular-nums;font-size:var(--text-lg);font-weight:700;color:var(--color-text-secondary)}
/* Target recolours to match the gap-to-target line's own red/green the moment it reads "above"/"at"
   (owner 24/10, round 4) — the two numbers are read together, but used to carry no visual link at all. */
.rec-head:has(.rc-gap-inline.up) .rc-tgtv b{color:var(--color-text-danger)}
.rec-head:has(.rc-gap-inline.ok) .rc-tgtv b{color:var(--green-tx)}
/* Edit/Set target on its own row (owner 25/10): freed the value row from sharing width
   with the link, so the Target column can be narrower. Left-aligned, not right (owner
   24/10, round 6): Target now reads from its own left edge like Reading does (the new
   divider border), so a right-flushed link broke that pattern instead of matching it. */
.rc-tgt-edit{display:flex;justify-content:flex-start;margin-top:4px}
/* Compliance ring + stage moved above the chart (owner 25/10); the source legend
   stays below as a footer. */
.rc-legend{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-bottom:12px;font-size:var(--text-sm);color:var(--color-text-secondary)}
.rc-foot{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:12px;padding-top:12px;border-top:1px solid var(--color-border);font-size:var(--text-sm);color:var(--color-text-secondary)}
.rleg-i{display:inline-flex;align-items:center;gap:6px}
.rc-lbl{display:block;font-size:var(--text-xs);font-weight:700;color:var(--color-text-secondary);text-transform:uppercase;letter-spacing:.5px;margin:16px 0 8px}
.rc-lbl:first-child{margin-top:0}
.rc-chips{display:flex;flex-wrap:wrap;gap:8px}
.rc-hint{font-size:var(--text-sm);color:var(--color-text-secondary);margin-top:8px}
.rc-lnk{font-family:inherit;font-size:var(--text-sm);font-weight:600;color:var(--color-text-action);background:none;border:0;padding:4px 0;cursor:pointer}
.rc-lnk.quiet{color:var(--color-text-secondary)}
.rc-meds{display:grid;gap:8px}
.rc-med{display:flex;align-items:center;justify-content:space-between;gap:12px;border:1px solid var(--color-border);border-radius:var(--rm);padding:8px 12px;font-size:var(--text-sm)}
.rc-med .sub{color:var(--color-text-secondary);margin-top:2px}
.rc-med.confirm{background:var(--red-bg);border-color:var(--red-bd);flex-direction:column;align-items:flex-start}
.rc-acts{display:flex;align-items:center;gap:20px}
.rc-add{display:flex;align-items:center;width:100%;margin-top:8px;border:1px dashed var(--color-border);border-radius:var(--rm);background:none;padding:8px 12px;font-family:inherit;font-size:var(--text-sm);font-weight:600;color:var(--color-text-action);cursor:pointer}
.rc-form{display:grid;gap:8px;border:1px solid var(--td);border-radius:var(--rm);padding:12px;background:var(--td-bg)}
.rc-form .g{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.rc-form .g3{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
.rc-form .r{display:flex;gap:8px}
.rc-form .err{color:var(--color-text-danger);font-size:var(--text-sm)}
.rc-num{width:72px}
.rc-fold{margin-top:12px}
.rc-fold>summary{cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:8px 12px;background:var(--color-surface-card);border:1px solid var(--color-border);border-radius:var(--rs);font-size:var(--text-sm);font-weight:700;color:var(--color-text);list-style:none}
.rc-fold>summary::-webkit-details-marker{display:none}
.rc-fold>summary:hover{background:var(--color-surface-subtle)}
.rc-fold>summary:focus-visible{outline:2px solid var(--color-border-focus);outline-offset:2px}
.rc-fold>summary .m{display:flex;align-items:center;gap:8px;font-weight:500;color:var(--color-text-secondary)}
.rc-chev{display:inline-flex;color:var(--color-text-secondary);transition:transform var(--motion-fast)}
.rc-fold[open] .rc-chev{transform:rotate(180deg)}
.rc-fold>.in{padding-top:12px}
.rc-care-tools{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:12px;flex-wrap:wrap}
.toast .toast-act{color:inherit;font-weight:700;text-decoration:underline;margin-left:12px}
.rc-more{font-size:var(--text-sm);font-weight:700;color:var(--red-dk);white-space:nowrap}
/* Sidebar rail — the menu folds to icons on the Record page (>=769px), click the chevron to expand */
.sidebar{transition:width var(--motion-base)}
.sb-expand{display:none}
@media(min-width:769px){
  .shell.rail .sidebar{width:64px}
  .shell.rail .sb-brand{padding:18px 0 12px;display:flex;justify-content:center}
  .shell.rail .sb-logo-text,.shell.rail .sb-sub,.shell.rail .sb-station,.shell.rail .nav-lbl,.shell.rail .sb-uinfo,.shell.rail .sb-user-chev,.shell.rail .sb-util .sb-lang{display:none}
  .shell.rail .sb-util .nav-item{display:none} /* logout hidden in the narrow rail — too easy to tap by accident next to the icon nav */
  .shell.rail .sb-nav{padding:6px 0}
  .shell.rail .nav-item{justify-content:center;width:40px;height:40px;padding:0;margin:0 auto 4px}
  .shell.rail .nav-badge{position:absolute;top:-2px;right:-4px;min-width:16px;height:16px;padding:0 4px}
  .shell.rail .sb-footer{padding:8px 0}
  .shell.rail .sb-user-btn{justify-content:center;padding:4px}
  .shell.rail .sb-util{flex-direction:column}
  .shell.rail .sb-expand{display:flex;align-items:center;justify-content:center;width:40px;height:40px;margin:0 auto 8px;border:0;border-radius:var(--rs);background:none;color:var(--color-text-secondary);cursor:pointer}
  .shell.rail .sb-expand:hover{background:var(--color-surface-subtle)}
}

/* ══ Patterns — markup is built by the shared functions in assets/dashboard-ui.js and
   rendered live in /styleguide/dashboard-patterns.html (examQueueHtml,
   renderCDSBand, careHistoryHtml, riskDonutHtml, weekTrendHtml). ══════════════ */
/* Doctor exam queue — severity-sorted worklist (was a 3-column Kanban; owner-approved 30/09) */
.qbar{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:16px}
.qhint{font-size:var(--text-sm);color:var(--color-text-secondary)}
.qstrip{display:flex;align-items:center;gap:12px;background:var(--color-surface-card);border:1px solid var(--color-border);box-shadow:inset 3px 0 0 var(--td);border-radius:var(--rm);padding:12px 16px;margin-bottom:12px}
.qstrip-k{font-size:var(--text-xs);font-weight:700;color:var(--color-text-action);text-transform:uppercase;letter-spacing:.5px}
.qstrip-who{flex:1;min-width:0;font-size:var(--text-sm);color:var(--color-text-secondary)}
.qstrip-who b{color:var(--color-text);font-size:var(--text-base)}
.qgrp{display:flex;align-items:center;gap:8px;width:100%;border:0;border-top:1px solid var(--color-border-subtle);background:var(--color-surface-sunken);padding:8px 16px;font-family:inherit;font-size:var(--text-xs);font-weight:700;color:var(--color-text-secondary);text-transform:uppercase;letter-spacing:.5px;cursor:pointer;text-align:left}
.qgrp:first-child{border-top:0}
.qgrp .n{color:var(--color-text-muted)}
.qrow{width:100%;border:0;border-top:1px solid var(--color-border-subtle);background:none;text-align:left;font-family:inherit;cursor:pointer}
.qrow:hover{background:var(--color-surface-subtle)}
.qrow:focus-visible{outline:2px solid var(--color-border-focus);outline-offset:-2px}
.tcard>.qrow:first-child{border-top:0}
.qwait{font-size:var(--text-sm);color:var(--color-text-secondary);white-space:nowrap;min-width:64px;text-align:right}
.qdone{color:var(--green-tx);display:inline-flex}
/* Clinical decision-support band (record page) */
.cds-band{margin-bottom:18px;display:flex;flex-direction:column;gap:8px}
.cds-alert{background:var(--color-surface-card);border:1px solid var(--color-border);border-left:2px solid var(--mute);border-radius:var(--rs);padding:10px 14px}
.cds-title{font-weight:600;font-size:var(--text-sm)}
.cds-msg{font-size:var(--text-sm);color:var(--color-text-body);margin-top:2px}
.cds-red{border-left-color:var(--red)}.cds-red .cds-title{color:var(--color-text-danger)}
.cds-amber{border-left-color:var(--amber)}.cds-amber .cds-title{color:var(--amber-tx)}
.cds-info{border-left-color:var(--b)}.cds-info .cds-title{color:var(--blue-tx)}
.cds-title{display:flex;align-items:center;gap:8px}

/* Seen this session (improve.md §A) — a still-true alert never hides, it just quiets down to one compact
   line (click to open) until a genuinely different value re-flags it New. Never auto-collapses by itself. */
.cds-alert.cds-compact{padding:0}
.cds-alert.cds-compact>summary{padding:7px 14px;cursor:pointer;list-style:none;display:flex;align-items:center;justify-content:space-between;gap:8px}
.cds-alert.cds-compact>summary::-webkit-details-marker{display:none}
.cds-alert.cds-compact>summary .cds-title{margin:0}
.cds-alert.cds-compact>summary .chev{flex-shrink:0;display:inline-flex;color:var(--color-text-secondary);transition:transform var(--motion-fast)}
.cds-alert.cds-compact[open]>summary .chev{transform:rotate(180deg)}
.cds-alert.cds-compact .cds-msg{padding:0 14px 9px}
/* Care history timeline (exams + contacts) */
.tl{position:relative;padding-left:16px;border-left:2px solid var(--color-border)}
.tl-item{position:relative;padding-bottom:14px}
.tl-dot{position:absolute;left:-20px;top:3px;width:8px;height:8px;border-radius:50%;background:var(--td)}
.tl-dot-amber{background:var(--amber)}.tl-dot-mute{background:var(--mute)}
.tl-title{font-size:var(--text-sm);font-weight:700;color:var(--color-text)}
.tl-meta{font-size:var(--text-xs);color:var(--color-text-secondary);margin-top:1px}
.tl-note{font-size:var(--text-sm);color:var(--color-text-body);margin-top:2px}
.tl-empty{font-size:var(--text-sm);color:var(--color-text-muted)}
/* Overview widgets: risk donut legend swatch, 7-day trend day labels */
.sw9{width:9px;height:9px;border-radius:50%;flex-shrink:0}
.wk-l{font-size:10px;color:var(--color-text-muted);font-weight:400}
.wk-l.today{color:var(--color-text-action);font-weight:700}
/* Approval requests (06/10) — rows reuse .today-row.qrow; the detail body shows current → new (reqDetailHtml in dashboard-ui.js).
   On a phone the type, status and age drop under the name instead of squeezing it to one letter per line. */
.req-meta{display:flex;align-items:center;gap:8px;flex-shrink:0}
@media(max-width:640px){
  .qrow.req-row{flex-wrap:wrap;row-gap:6px}
  .req-row .req-who{flex:1 1 0}
  .req-row .req-meta{flex:1 1 100%;flex-wrap:wrap;padding-left:44px}
  .req-row .qwait{min-width:0;margin-left:auto}
}
.diff-old{color:var(--color-text-muted);text-decoration:line-through}
.diff-new{font-weight:700;color:var(--color-text)}
/* One-time password hand-off (06/10): /admin/ after creating an account or collecting a password; the Tiếp nhận wizard after creating a profile (P18). */
.cred-pw{display:flex;align-items:center;justify-content:space-between;gap:12px;background:var(--color-surface-sunken);border:1px dashed var(--color-border);border-radius:var(--rs);padding:12px 14px;font-family:var(--font-num);font-variant-numeric:tabular-nums;font-size:var(--text-xl);font-weight:700;letter-spacing:.06em;color:var(--color-text);margin:6px 0 4px}
.cred-pw span{user-select:all;word-break:break-all}

