/* ── Theme Variables ───────────────────────────────────────────── */
:root,[data-theme="dark"]{
  --bg:        #0a0a0f;
  --surface:   #111118;
  --surface2:  #16161f;
  --surface3:  #1c1c28;
  --surface4:  #22222f;
  --border:    rgba(255,255,255,.07);
  --border2:   rgba(255,255,255,.12);
  --text:      #e8e8f0;
  --text2:     #9898b0;
  --text3:     #5a5a78;
  --accent:    #6c63ff;
  --accent2:   #a5a0ff;
  --accent-bg: rgba(108,99,255,.12);
  --accent-border: rgba(108,99,255,.35);
  --green:     #22c55e; --green-bg: rgba(34,197,94,.1);  --green-border: rgba(34,197,94,.25);
  --amber:     #f59e0b; --amber-bg: rgba(245,158,11,.1); --amber-border: rgba(245,158,11,.25);
  --red:       #ef4444; --red-bg:   rgba(239,68,68,.1);  --red-border:   rgba(239,68,68,.25);
  --blue:      #38bdf8; --blue-bg:  rgba(56,189,248,.1); --blue-border:  rgba(56,189,248,.25);
  --teal:      #2dd4bf; --teal-bg:  rgba(45,212,191,.1); --teal-border:  rgba(45,212,191,.25);
  /* User-customizable (Appearance panel, js/ui-prefs.js) — these defaults apply
     until the user picks their own; overridden via inline style on <html> so
     they win regardless of dark/light theme. */
  --user-status-drafted:   #f59e0b;
  --user-status-completed: #38bdf8;
  --user-status-finalized: #22c55e;
  --user-status-printed:   #6c63ff;
  --user-has-history:      #22c55e;
  --sidebar-w: 240px;
  --topbar-h:  56px;
  /* UI Preferences (Settings → UI Preferences, js/ui-prefs.js) — --radius-scale/--pad-scale/
     --ui-zoom default to 1 (no change from the hardcoded values below) until the server-side
     theme is fetched and applied; --r/--r-sm/--r-lg and every padding: calc(...) declaration
     read the scale so the ~20 existing --r* usages and the handful of padding rules tokenized
     for density all move together from one multiplier each, without needing to touch every
     individual rule. */
  --radius-scale: 1;
  --pad-scale:    1;
  --ui-zoom:      1;
  --font-sans:    'Inter', sans-serif;
  --r:         calc(10px * var(--radius-scale));
  --r-sm:      calc(6px  * var(--radius-scale));
  --r-lg:      calc(14px * var(--radius-scale));
  --shadow:    0 4px 24px rgba(0,0,0,.4);
  --shadow-sm: 0 2px 8px rgba(0,0,0,.3);
}
[data-theme="light"]{
  --bg:        #f0f0f8;
  --surface:   #ffffff;
  --surface2:  #f8f8fc;
  --surface3:  #f0f0f8;
  --surface4:  #e8e8f4;
  --border:    rgba(0,0,0,.08);
  --border2:   rgba(0,0,0,.14);
  --text:      #1a1a2e;
  --text2:     #5a5a7a;
  --text3:     #9898b8;
  --accent:    #5b52e8;
  --accent2:   #6c63ff;
  --accent-bg: rgba(91,82,232,.1);
  --accent-border: rgba(91,82,232,.35);
  --green:     #16a34a; --green-bg: rgba(22,163,74,.08);  --green-border: rgba(22,163,74,.3);
  --amber:     #d97706; --amber-bg: rgba(217,119,6,.08);  --amber-border: rgba(217,119,6,.3);
  --red:       #dc2626; --red-bg:   rgba(220,38,38,.08);  --red-border:   rgba(220,38,38,.3);
  --blue:      #0284c7; --blue-bg:  rgba(2,132,199,.08);  --blue-border:  rgba(2,132,199,.3);
  --teal:      #0d9488; --teal-bg:  rgba(13,148,136,.08); --teal-border:  rgba(13,148,136,.3);
  --shadow:    0 4px 24px rgba(0,0,0,.1);
  --shadow-sm: 0 2px 8px rgba(0,0,0,.08);
}

/* ── Reset & Base ──────────────────────────────────────────────── */
*{margin:0;padding:0;box-sizing:border-box}
html,body{height:100%}
body{background:var(--bg);color:var(--text);font-family:var(--font-sans);font-size:14px;display:flex;overflow:hidden;line-height:1.5;transition:background .2s,color .2s}

/* ── Layout Shell ──────────────────────────────────────────────── */
/* Login is compulsory: #app stays hidden and #login-screen stays shown until JS confirms a
   valid session (see auth.js bootAuthGate) and adds body.authed — default-hidden here rather
   than only toggled by JS avoids a flash of the full app before that check completes.
   zoom (not transform:scale) for the UI Preferences font-size setting: scales text AND padding
   AND icons together as one unit, matching what a user means by "make everything bigger" far
   better than resizing text alone — and unlike transform:scale, layout/scrollbars/hit-targets
   stay correct since zoom changes the effective CSS-pixel ratio for this subtree rather than
   visually stretching an already-laid-out box. Only #app (the authenticated shell) is zoomed;
   the login screen itself always renders at 1:1. */
#app{display:none;width:100%;height:100vh;zoom:var(--ui-zoom)}
body.authed #app{display:flex}
body.authed #login-screen{display:none!important}

/* ── Sidebar ───────────────────────────────────────────────────── */
#sidebar{
  width:var(--sidebar-w);flex-shrink:0;
  background:var(--sidebar-bg, var(--surface));
  border-right:1px solid var(--border);
  display:flex;flex-direction:column;height:100vh;
  transition:background .2s,border-color .2s;
}
.sidebar-logo{
  padding:20px 18px 16px;
  border-bottom:1px solid var(--border);
  display:flex;align-items:center;gap:10px;
}
.logo-icon{
  width:38px;height:38px;border-radius:9px;
  display:flex;align-items:center;justify-content:center;
  flex-shrink:0;overflow:hidden;
}
.logo-icon img{width:100%;height:100%;object-fit:cover;display:block}
.logo-text{}
.logo-brand{font-size:17px;font-weight:700;color:var(--sidebar-text, var(--text));letter-spacing:-.02em}
.logo-sub{font-size:10px;color:var(--sidebar-text3, var(--text3));font-family:'JetBrains Mono',monospace;letter-spacing:.06em;text-transform:uppercase}
/* Was an inline style on the element itself (index.html) — moved here as a real, overridable
   rule so body.nav-topbar's own #branch-switcher-holder padding (below) can actually win the
   cascade instead of silently losing to an inline style on the same property. */
#branch-switcher-holder{padding:0 14px 10px}
.sidebar-nav{padding:12px 10px;flex:1;display:flex;flex-direction:column;gap:2px;overflow-y:auto}
.nav-section{
  font-size:10px;font-family:'JetBrains Mono',monospace;
  color:var(--sidebar-text3, var(--text3));letter-spacing:.1em;text-transform:uppercase;
  padding:14px 8px 5px;
}
.nav-item{
  display:flex;align-items:center;gap:10px;
  padding:calc(9px * var(--pad-scale)) calc(10px * var(--pad-scale));border-radius:var(--r-sm);
  cursor:pointer;color:var(--sidebar-text2, var(--text2));font-size:13px;font-weight:500;
  transition:all .15s;border:1px solid transparent;user-select:none;
}
.nav-item:hover{background:var(--sidebar-hover-bg, var(--surface3));color:var(--sidebar-text, var(--text))}
.nav-item.active{
  background:var(--accent-bg);color:var(--accent2);
  border-color:var(--accent-border);
}
.nav-icon{width:20px;height:20px;display:flex;align-items:center;justify-content:center;border-radius:5px;font-size:14px;flex-shrink:0}
/* ── Icon system (js/icons.js) ─────────────────────────────────────────
   Sizing lives here, not on individual icon() calls, so every icon on the page stays visually
   consistent — this was the actual problem with the emoji this replaced (wildly different
   rendered sizes across browsers/OS/fonts for the same "font-size:1em" emoji glyph). */
.icon{width:15px;height:15px;flex-shrink:0}
.nav-icon .icon{width:18px;height:18px}
.form-section-title .icon,.card-title .icon,.modal-title .icon,.form-section-icon .icon{width:16px;height:16px}
.badge .icon{width:11px;height:11px;margin-right:1px}
.metric-icon .icon{width:20px;height:20px}
.login-logo-icon .icon{width:22px;height:22px}
.icon-spin{animation:icon-spin 1s linear infinite}
@keyframes icon-spin{to{transform:rotate(360deg)}}
.nav-item.active .nav-icon{background:rgba(108,99,255,.2)}

/* Collapsible sidebar submenu (Masters) */
.nav-group-toggle{justify-content:space-between}
.nav-group-toggle-label{display:flex;align-items:center;gap:10px}
.nav-chevron{font-size:10px;color:var(--sidebar-text3, var(--text3));transition:transform .15s;flex-shrink:0}
.nav-chevron.open{transform:rotate(90deg)}
/* .sidebar-nav is display:flex;flex-direction:column with a capped, scrollable height
   (overflow-y:auto) — flex items default to flex-shrink:1, and because this item has
   overflow:hidden, its "automatic minimum size" per the flexbox spec is 0, not its content
   size. Without flex-shrink:0, the flex algorithm was squeezing it down to literally 0px
   (confirmed: className had "open" and computed max-height was correctly 400px, but computed
   height was 0px) to keep the rest of the nav fitting, instead of letting .sidebar-nav's own
   overflow-y:auto do its job and scroll. That's what looked like "the dropdown doesn't open." */
.nav-submenu{overflow:hidden;max-height:0;flex-shrink:0;transition:max-height .18s ease}
/* 400px used to be enough for every Masters entry that existed at the time; it no longer is —
   at 13 sub-items (and growing), this cap silently clipped the last couple of rows (Payment
   Types, Discount References, Attachment Types) with no scrollbar of its own to reveal them,
   which looked exactly like "Payment Types is missing" even though it was in the DOM the whole
   time. Bumped well past any realistic list length instead of tuning it to today's exact count
   again — .sidebar-nav's own overflow-y:auto (see the comment above) is what actually makes the
   page scrollable if the whole expanded sidebar now exceeds viewport height, not this value. */
.nav-submenu.open{max-height:800px}
.nav-subitem{padding-left:38px;font-size:12.5px}

/* Hidden per product decision — SCP status/controls, queue chips, and live-connection status
   are internal DICOM-receiver plumbing that front-desk/clinical users never need to see or
   touch; the underlying elements are left in the DOM (not removed) so websocket.js/auth.js's
   existing status-update code keeps working untouched, it just has nothing visible to update. */
.sidebar-footer{display:none;padding:12px 14px 14px;border-top:1px solid var(--border)}
.scp-row{display:flex;align-items:center;gap:8px;margin-bottom:8px}
.status-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0;transition:all .3s}
.dot-green{background:var(--green);box-shadow:0 0 0 2px rgba(34,197,94,.25)}
.dot-red  {background:var(--red);  box-shadow:0 0 0 2px rgba(239,68,68,.25)}
.dot-pulse{animation:pulse 2s ease-in-out infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.35}}
.scp-label{font-size:12px;font-weight:500;color:var(--sidebar-text2, var(--text2))}
.queue-chips{display:flex;gap:6px;margin-bottom:8px;flex-wrap:wrap}
.chip{font-size:10px;font-family:'JetBrains Mono',monospace;padding:3px 8px;border-radius:20px;background:var(--surface3);border:1px solid var(--border2);color:var(--sidebar-text3, var(--text3))}
.ws-indicator{font-size:10px;font-family:'JetBrains Mono',monospace;color:var(--sidebar-text3, var(--text3));display:flex;align-items:center;gap:5px}
.ws-dot{width:5px;height:5px;border-radius:50%;background:var(--text3)}
.ws-dot.connected{background:var(--green)}
.scp-actions{display:flex;gap:4px;margin-bottom:10px}
.scp-actions .btn{flex:1;padding:5px 0;font-size:12px;justify-content:center}
.scp-actions .btn:disabled{opacity:.35;cursor:not-allowed}

/* ── Horizontal Topbar nav layout (My Display Preferences → Main Navigation, default) ──────
   Reflows the SAME #sidebar element and nav-item markup into a horizontal strip above #main
   instead of a vertical column beside it — one nav-item list, one set of module/permission
   gating (applyModuleVisibility()/applyPermVisibility() in auth.js never need to know which
   layout is active), two layouts. Toggled by js/ui-prefs.js's applyNavLayoutPref() via this one
   body class. */
body.nav-topbar #app{flex-direction:column}
body.nav-topbar #sidebar{
  width:100%;height:auto;flex-shrink:0;
  flex-direction:row;flex-wrap:wrap;align-items:stretch;
  border-right:none;border-bottom:1px solid var(--border);
  transform:none; /* overrides the mobile off-canvas transform below — never off-canvas in this mode */
}
/* Row 1: logo + branch switcher (left) and the clock/theme-toggle/user-menu (right — moved in
   here from the app's own .topbar bar by ui-prefs.js's applyNavLayoutPref(), see
   #nav-topbar-controls-slot below). Row 2: nav items — .sidebar-nav's flex-basis:100% forces it
   onto its own line via #sidebar's flex-wrap above, instead of everything crowding one row. */
body.nav-topbar .sidebar-logo{padding:7px 16px;gap:8px;border-bottom:1px solid var(--border);border-right:1px solid var(--border);flex-shrink:0}
body.nav-topbar .logo-icon{width:26px;height:26px;border-radius:6px}
body.nav-topbar .logo-brand{font-size:13.5px}
body.nav-topbar #branch-switcher-holder{padding:6px 14px;flex-shrink:0;display:flex;align-items:center;border-bottom:1px solid var(--border)}
body.nav-topbar #branch-switcher-holder select{margin:4px 0}
body.nav-topbar #nav-topbar-controls-slot{
  margin-left:auto;flex-shrink:0;display:flex;align-items:center;gap:8px;
  padding:6px 16px;border-bottom:1px solid var(--border);min-height:40px;box-sizing:border-box;
}
/* The clock/theme-toggle/user-menu keep their normal (larger) size in the sidebar layout's own
   .topbar — these overrides apply only once they're relocated into the compact row-1 slot. */
body.nav-topbar #nav-topbar-controls-slot .clock{font-size:11px;padding:3px 8px}
body.nav-topbar #nav-topbar-controls-slot .topbar-icon-btn{width:26px;height:26px;font-size:13px}
body.nav-topbar #nav-topbar-controls-slot .user-badge{font-size:11px;padding:3px 8px 3px 3px;gap:5px}
body.nav-topbar .sidebar-nav{
  flex:1 1 100%;
  flex-direction:row;align-items:center;flex-wrap:nowrap;
  overflow-x:auto;overflow-y:visible;padding:6px 8px;gap:2px;
}
body.nav-topbar .nav-item{white-space:nowrap;flex-shrink:0}
/* Section labels ("Role Dashboards", "Reports", "Configuration") don't fit a single-row strip —
   the items themselves stay in the same order, just without the group heading. */
body.nav-topbar .nav-section{display:none}
/* Positioned via inline style at open time (state.js's toggleNavGroup(), which also detaches
   this element to <body>) — a submenu is a DOM *sibling* of its own toggle, not a child, so a
   plain CSS position:absolute here has no correctly-positioned containing block to anchor to.
   While CLOSED it's still an in-flow flex child of the horizontally-scrolling nav row, though —
   width:0 keeps it from silently reserving a 220px-wide gap between every pair of top-level
   items (which is what made the row need horizontal scrolling well before it actually ran out
   of room). The panel's real width only matters once .open takes it out of that row entirely. */
body.nav-topbar .nav-submenu{width:0;flex-basis:0}
body.nav-topbar .nav-submenu.open{
  width:auto;flex-direction:column;
  background:var(--sidebar-bg, var(--surface));border:1px solid var(--border);border-radius:var(--r);
  box-shadow:var(--shadow);min-width:220px;padding:6px;z-index:50;
  max-height:80vh;overflow-y:auto;
}
body.nav-topbar .nav-subitem{padding-left:10px}
/* The vertical-only concepts (off-canvas drawer toggle, width-collapse toggle) have no
   equivalent here — the strip is always "expanded" and just scrolls horizontally instead. */
body.nav-topbar #sidebar-toggle-btn,
body.nav-topbar #sidebar-collapse-btn{display:none}
@media (max-width:1023px){
  /* Cancels the off-canvas drawer's position:fixed further down this file — without this the
     strip would float over #main instead of pushing it down, since fixed positioning takes an
     element out of normal flow. */
  body.nav-topbar #sidebar{position:static;transform:none}
}

/* ── Main ──────────────────────────────────────────────────────── */
#main{flex:1;display:flex;flex-direction:column;height:100vh;overflow:hidden;min-width:0}
.topbar{
  height:var(--topbar-h);flex-shrink:0;
  background:linear-gradient(180deg, var(--topbar-bg, var(--surface)), color-mix(in srgb, var(--topbar-bg, var(--surface)) 90%, var(--topbar-text, var(--text)) 10%));
  border-bottom:1px solid var(--border);
  display:flex;align-items:center;padding:0 22px;gap:12px;
  transition:background .2s;
  box-shadow:0 1px 0 rgba(0,0,0,.02);
}
.page-title{font-size:15px;font-weight:600;letter-spacing:-.02em;color:var(--topbar-text, var(--text))}
.topbar-right{margin-left:auto;display:flex;align-items:center;gap:10px}
.clock{font-size:12px;font-family:'JetBrains Mono',monospace;color:var(--topbar-text3, var(--text3));padding:4px 10px;background:var(--surface3);border-radius:20px}
.user-badge{font-size:12px;color:var(--topbar-text2, var(--text2));padding:4px 10px 4px 4px;background:var(--surface3);border-radius:20px;cursor:pointer;transition:background .15s;display:inline-flex;align-items:center;gap:6px}
.user-badge:hover{background:var(--surface4)}
.user-badge-avatar{
  width:20px;height:20px;border-radius:50%;flex-shrink:0;
  background:linear-gradient(135deg,var(--accent),var(--accent2));color:#fff;
  display:flex;align-items:center;justify-content:center;
  font-size:10px;font-weight:700;line-height:1;
}
.user-menu-wrap{position:relative}
.user-menu{
  position:absolute;top:calc(100% + 6px);right:0;z-index:150;
  min-width:200px;background:var(--surface);border:1px solid var(--border2);
  border-radius:var(--r-sm);box-shadow:var(--shadow);padding:5px;
  animation:slideUp .12s ease;
}
.user-menu-item{
  padding:8px 10px;border-radius:6px;font-size:12.5px;color:var(--text2);
  cursor:pointer;white-space:nowrap;transition:background .1s,color .1s;
}
.user-menu-item:hover{background:var(--surface3);color:var(--text)}

/* Topbar tool group — theme/appearance/refresh icon buttons, visually clustered into one pill */
.topbar-toolgroup{
  display:flex;align-items:center;gap:2px;
  background:var(--surface3);border:1px solid var(--border2);border-radius:var(--r-sm);padding:2px;
}
.topbar-toolgroup .topbar-icon-btn{border:none;background:transparent;box-shadow:none}
.topbar-toolgroup .topbar-icon-btn:hover{background:var(--surface4)}
.topbar-toolgroup .topbar-icon-btn.active{background:var(--accent-bg);color:var(--accent2)}

/* Theme Toggle / generic topbar icon button */
.theme-toggle,.topbar-icon-btn{
  width:32px;height:32px;border-radius:var(--r-sm);
  border:1px solid var(--border2);background:var(--surface3);
  color:var(--topbar-text2, var(--text2));cursor:pointer;display:flex;align-items:center;justify-content:center;
  font-size:15px;transition:all .15s;
}
.theme-toggle:hover,.topbar-icon-btn:hover{background:var(--topbar-hover-bg, var(--surface4));color:var(--topbar-text, var(--text))}

#content{flex:1;overflow-y:auto;padding:22px;scroll-behavior:smooth}

/* ── Buttons ───────────────────────────────────────────────────── */
.btn{
  padding:calc(7px * var(--pad-scale)) calc(14px * var(--pad-scale));border-radius:var(--r-sm);
  border:1px solid var(--border2);background:var(--surface3);
  color:var(--text);cursor:pointer;font-family:var(--font-sans);
  font-size:12px;font-weight:500;transition:all .15s;
  display:inline-flex;align-items:center;gap:5px;white-space:nowrap;
}
.btn:hover{background:var(--btn-hover-bg, var(--surface4));border-color:var(--border2)}
.btn:active{transform:scale(.97)}
.btn-primary{background:var(--accent);border-color:var(--accent);color:#fff;box-shadow:0 2px 8px rgba(108,99,255,.35)}
.btn-primary:hover{opacity:.9;background:var(--accent)}
.btn-success{background:var(--green-bg);border-color:var(--green-border);color:var(--green)}
.btn-success:hover{background:rgba(34,197,94,.15)}
.btn-danger{background:var(--red-bg);border-color:var(--red-border);color:var(--red)}
.btn-danger:hover{background:rgba(239,68,68,.15)}
.btn-teal{background:var(--teal-bg);border-color:var(--teal-border);color:var(--teal)}
.btn-teal:hover{background:rgba(45,212,191,.15)}
.btn-blue{background:var(--blue-bg);border-color:var(--blue-border);color:var(--blue)}
.btn-blue:hover{background:rgba(56,189,248,.15)}
.btn-sm{padding:4px 10px;font-size:11px}
.btn-icon{width:30px;height:30px;padding:0;display:flex;align-items:center;justify-content:center;font-size:14px}
/* Row action buttons (patient/study browser) — bigger glyphs than .btn-icon so
   the icon itself (not just the click target) is easy to read at a glance. */
.btn-action{width:32px;height:32px;padding:0;display:flex;align-items:center;justify-content:center;font-size:16px;flex-shrink:0}
/* td only, not th — .row-actions also marks the header <th> (as a position anchor for
   js/action-column.js), but display:flex there overrides a <th>'s native display:table-cell,
   which silently breaks position:sticky (app.css's .data-table th rule) in every browser tested:
   a sticky table header relies on genuinely being a table cell, not a flex item pretending to be
   one. The header only ever holds a plain text label anyway, so it never needed flex layout. */
td.row-actions{display:flex;gap:6px;flex-wrap:nowrap}
/* History button — filled green once a patient actually has a history note, so its
   presence is visible without opening the modal. Solid-ish (not a faint tint) so it
   reads clearly at a glance; color itself is user-customizable (Appearance panel). */
.btn-action.has-history{background:color-mix(in srgb, var(--user-has-history) 38%, var(--surface3));border-color:var(--user-has-history);color:var(--text)}
.btn-action.has-history:hover{background:color-mix(in srgb, var(--user-has-history) 55%, var(--surface3))}
/* Report button — tinted by the report's own lifecycle stage; each stage's color
   is user-customizable (Appearance panel, js/ui-prefs.js). */
.btn-action.rpt-status-drafted{background:color-mix(in srgb, var(--user-status-drafted) 38%, var(--surface3));border-color:var(--user-status-drafted);color:var(--text)}
.btn-action.rpt-status-completed{background:color-mix(in srgb, var(--user-status-completed) 38%, var(--surface3));border-color:var(--user-status-completed);color:var(--text)}
.btn-action.rpt-status-finalized{background:color-mix(in srgb, var(--user-status-finalized) 38%, var(--surface3));border-color:var(--user-status-finalized);color:var(--text)}
.btn-action.rpt-status-printed{background:color-mix(in srgb, var(--user-status-printed) 38%, var(--surface3));border-color:var(--user-status-printed);color:var(--text)}
.btn-action.rpt-status-drafted:hover{background:color-mix(in srgb, var(--user-status-drafted) 55%, var(--surface3))}
.btn-action.rpt-status-completed:hover{background:color-mix(in srgb, var(--user-status-completed) 55%, var(--surface3))}
.btn-action.rpt-status-finalized:hover{background:color-mix(in srgb, var(--user-status-finalized) 55%, var(--surface3))}
.btn-action.rpt-status-printed:hover{background:color-mix(in srgb, var(--user-status-printed) 55%, var(--surface3))}
.btn-action.rpt-export-disabled{opacity:.35;cursor:not-allowed}
.btn-action.rpt-export-disabled:hover{background:var(--surface3)}
/* Generic disabled look for any row-action icon button (e.g. viewer launch buttons before
   any DICOM images have been received) — same treatment as rpt-export-disabled, reusable name. */
.btn-action:disabled{opacity:.35;cursor:not-allowed}
.btn-action:disabled:hover{background:var(--surface3)}
/* Small "pending" pill for placeholder studies (registration data only, no images received yet) */
.badge-pending{background:var(--surface3);color:var(--text3);border-color:var(--border2)}

/* ── Appearance panel ─────────────────────────────────────────────── */
.uip-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 0;border-bottom:1px solid var(--border)}
.uip-row:last-of-type{border-bottom:none}
.uip-swatch{width:44px;height:30px;padding:0;border:1px solid var(--border2);border-radius:6px;cursor:pointer;background:none}
/* Auto Contrast readout next to a font-color picker's label — see refreshContrastBadge()
   (js/ui-prefs.js). Deliberately uses fixed semantic green/amber, not the user's own configurable
   palette — a status indicator staying legible regardless of what colors are being edited. */
.uip-contrast-badge{
  display:inline-block;margin-left:6px;padding:1px 6px;border-radius:20px;
  font-size:9.5px;font-weight:700;font-family:'JetBrains Mono',monospace;
  letter-spacing:.02em;text-transform:none;vertical-align:middle;cursor:help;
}
.uip-contrast-badge.ok{background:rgba(34,197,94,.15);color:#22c55e}
.uip-contrast-badge.warn{background:rgba(245,158,11,.18);color:#f59e0b}
.uip-preset-chip{display:inline-flex;align-items:center;gap:6px}
.uip-preset-del{
  border:none;background:none;color:var(--text3);cursor:pointer;font-size:12px;line-height:1;
  padding:2px 4px;border-radius:4px;
}
.uip-preset-del:hover{color:var(--red);background:var(--red-bg)}

/* ── Table Style preview (Settings → UI Preferences) ──────────────────────
   Purely illustrative dummy tables — deliberately its own tsp-* class family, never table-wrap/
   data-table, so table-enhance.js's #content scanner never tries to enhance these mockups. */
.tsp-option{display:block;border:1px solid var(--border2);border-radius:var(--r);padding:10px;cursor:pointer;width:230px;transition:border-color .15s}
.tsp-option:hover{border-color:var(--accent-border)}
.tsp-option.selected{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}
.tsp-option-head{display:flex;align-items:center;gap:7px;font-size:13px;margin-bottom:2px}
.tsp-option-sub{font-size:10.5px;color:var(--text3);margin:0 0 8px 21px}
.tsp-preview{border:1px solid var(--border);border-radius:var(--r-sm);overflow:hidden;background:var(--surface)}
.tsp-preview-bar{display:flex;justify-content:flex-end;gap:5px;padding:4px 6px;background:var(--surface2);border-bottom:1px solid var(--border)}
.tsp-preview-bar:last-child{border-bottom:none;border-top:1px solid var(--border)}
.tsp-chip{font-size:9px;padding:2px 6px;border-radius:10px;background:var(--surface3);color:var(--text3);border:1px solid var(--border2);white-space:nowrap}
.tsp-preview-scrollbar{height:6px;background:var(--surface2);border-bottom:1px solid var(--border);position:relative}
.tsp-preview-scrollbar::after{content:'';position:absolute;left:20%;top:1.5px;width:40%;height:3px;background:var(--border2);border-radius:3px}
.tsp-preview-table{width:100%;border-collapse:collapse;font-size:9.5px}
.tsp-preview-table th{background:var(--surface2);color:var(--text3);text-transform:uppercase;font-size:8px;padding:4px 6px;text-align:left;border-bottom:1px solid var(--border)}
.tsp-preview-table td{padding:4px 6px;border-bottom:1px solid var(--border);color:var(--text2)}
.tsp-preview-table tr:last-child td{border-bottom:none}

/* ── Tabs (folder-tab style — Settings, Appointment Slots, and any future
   sectioned page) ──────────────────────────────────────────────────────
   Rounded-top tabs sitting on a shared baseline; the active tab lifts off
   the others using the app's accent color — same --accent-bg/--accent2/
   --accent-border tint already used for .nav-item.active and the topbar's
   active icon buttons — so a user's custom accent (Settings → General →
   Appearance) drives every tab strip in the app consistently, not just this
   one. Inactive tabs sit muted (--text3) and recede on a transparent
   background until hovered, echoing a classic connected folder-tab look. */
.tab-bar{display:flex;gap:3px;border-bottom:1px solid var(--border);margin-bottom:16px;flex-wrap:wrap}
.tab-btn{
  appearance:none;background:transparent;cursor:pointer;font-family:inherit;
  /* Bottom border is always 1px, transparent by default — active state below only changes its
     *color* to blend with the tab's own background, never its width, so the active tab's box is
     never a pixel taller than its neighbors (that mismatch used to visibly misalign the active
     tab against the inactive tabs' shared baseline line). */
  border:1px solid transparent;
  padding:9px 18px;font-size:13px;font-weight:600;color:var(--text3);
  border-radius:var(--r-sm) var(--r-sm) 0 0;
  margin-bottom:-1px;
  transition:background .15s,color .15s,border-color .15s;
}
.tab-btn:hover:not(.active){background:var(--surface3);color:var(--text2)}
.tab-btn.active{
  background:var(--accent-bg);color:var(--accent2);
  border-color:var(--accent-border) var(--accent-border) var(--accent-bg) var(--accent-border);
  box-shadow:inset 0 2px 0 0 var(--accent);
}
.tab-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* ── Cards ─────────────────────────────────────────────────────── */
.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);padding:calc(18px * var(--pad-scale));transition:background .2s,border-color .2s}
.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}
.card-title{font-size:12px;font-family:'JetBrains Mono',monospace;color:var(--text3);letter-spacing:.07em;text-transform:uppercase}
/* A card that directly wraps a .table-wrap — zeroes the card's own padding so the table's border
   and rounded corners read as the card's edge, instead of every such page repeating
   style="padding:0;overflow:hidden" inline (the same override appeared on 6+ pages). */
.card.card-table{padding:0;overflow:hidden}

/* ── Metric Cards ──────────────────────────────────────────────── */
.metrics-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:12px;margin-bottom:18px}
@media (max-width:1400px){.metrics-grid{grid-template-columns:repeat(3,1fr)}}
@media (max-width:760px){.metrics-grid{grid-template-columns:repeat(2,1fr)}}
.metric-card{
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-lg);padding:16px 18px;
  position:relative;overflow:hidden;transition:all .2s;cursor:default;
}
.metric-card::before{
  content:'';position:absolute;top:0;left:0;right:0;height:3px;
  background:var(--accent-color,var(--accent));opacity:.75;
  box-shadow:0 0 10px 0 var(--accent-color,var(--accent));
}
.metric-card:hover{border-color:var(--border2);transform:translateY(-2px);box-shadow:var(--shadow-sm)}
.metric-icon{position:absolute;top:14px;right:16px;font-size:20px;opacity:.5;line-height:1}
.metric-card.c-blue  {--accent-color:var(--blue)}
.metric-card.c-teal  {--accent-color:var(--teal)}
.metric-card.c-green {--accent-color:var(--green)}
.metric-card.c-red   {--accent-color:var(--red)}
.metric-card.c-amber {--accent-color:var(--amber)}
.metric-card.c-purple{--accent-color:var(--accent)}
.metric-label{font-size:10px;font-family:'JetBrains Mono',monospace;color:var(--text3);letter-spacing:.07em;text-transform:uppercase;margin-bottom:8px;padding-right:22px}
.metric-value{font-size:30px;font-weight:600;letter-spacing:-.04em;font-family:'JetBrains Mono',monospace;line-height:1}
.metric-card.c-blue   .metric-value{color:var(--blue)}
.metric-card.c-teal   .metric-value{color:var(--teal)}
.metric-card.c-green  .metric-value{color:var(--green)}
.metric-card.c-red    .metric-value{color:var(--red)}
.metric-card.c-amber  .metric-value{color:var(--amber)}
.metric-card.c-purple .metric-value{color:var(--accent2)}
.metric-sub{font-size:11px;color:var(--text3);margin-top:5px}

/* ── Badges ─────────────────────────────────────────────────────── */
.badge{display:inline-flex;align-items:center;gap:5px;padding:3px 9px;border-radius:20px;font-size:10px;font-family:'JetBrains Mono',monospace;font-weight:700;letter-spacing:.03em;border:1px solid transparent;white-space:nowrap}
.badge-green {background:var(--green-bg);color:var(--green);border-color:var(--green-border)}
.badge-red   {background:var(--red-bg);  color:var(--red);  border-color:var(--red-border)}
.badge-amber {background:var(--amber-bg);color:var(--amber);border-color:var(--amber-border)}
.badge-blue  {background:var(--blue-bg); color:var(--blue); border-color:var(--blue-border)}
.badge-teal  {background:var(--teal-bg); color:var(--teal); border-color:var(--teal-border)}
.badge-purple{background:var(--accent-bg);color:var(--accent2);border-color:var(--accent-border)}
.badge-dot{width:5px;height:5px;border-radius:50%;background:currentColor;flex-shrink:0}
.badge-live .badge-dot{animation:pulse 1.4s ease-in-out infinite}

/* ── Collection Report summary panel ──────────────────────────────
   Deliberately fixed navy/white (not var(--surface)/var(--text)) — a self-contained "important
   numbers" block that reads the same in light or dark mode, same idea as the printed bill's
   letterhead using fixed black-on-white regardless of the app theme around it. */
.coll-summary{display:grid;grid-template-columns:1fr 1fr 1fr;gap:0;background:#0f2138;border:1px solid #1c3a5e;border-radius:var(--r-lg);padding:16px 22px;margin-bottom:16px;color:#dbe7f5}
.coll-summary-col{padding:0 20px;border-left:1px solid rgba(255,255,255,.12)}
.coll-summary-col:first-child{padding-left:0;border-left:none}
.coll-summary-title{font-size:10px;font-family:'JetBrains Mono',monospace;text-transform:uppercase;letter-spacing:.08em;color:#8fb3d9;margin-bottom:10px;display:flex;align-items:center;gap:6px}
.coll-summary-title .icon{width:13px;height:13px}
.coll-summary-row{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:3px 0;font-size:12.5px}
.coll-summary-row b{font-family:'JetBrains Mono',monospace;font-weight:700}
.coll-summary-row.total b{font-size:16px;color:#4ade80}
.coll-mode-dot{width:8px;height:8px;border-radius:2px;display:inline-block;margin-right:7px;flex-shrink:0}
.coll-summary-legend{font-size:11px;color:#8fa8c7;line-height:1.7}
.coll-summary-legend b{color:#dbe7f5}
.coll-badge-current{background:rgba(74,222,128,.15);color:#4ade80;border:1px solid rgba(74,222,128,.35);border-radius:20px;padding:2px 8px;font-size:9.5px;font-family:'JetBrains Mono',monospace;font-weight:700}
.coll-badge-balance{background:rgba(251,191,36,.15);color:#fbbf24;border:1px solid rgba(251,191,36,.35);border-radius:20px;padding:2px 8px;font-size:9.5px;font-family:'JetBrains Mono',monospace;font-weight:700}
@media (max-width:900px){
  .coll-summary{grid-template-columns:1fr}
  .coll-summary-col{padding:10px 0;border-left:none;border-top:1px solid rgba(255,255,255,.12)}
  .coll-summary-col:first-child{border-top:none;padding-top:0}
}

/* ── Dashboard 2-col ───────────────────────────────────────────── */
.dash-grid{display:grid;grid-template-columns:1fr 280px;gap:14px}
.dash-grid>.card{min-width:0}

/* ── Single-page Registration (js/registration-single.js) ───────────────
   Own equal-column grid rather than reusing .dash-grid's asymmetric 1fr/280px split — needs a
   plain CSS class (not an inline grid-template-columns) so the mobile override below can actually
   win; an inline style always beats a stylesheet rule regardless of the media query it's in. */
.rs-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;align-items:start}
/* Registration page only (rs-grid-6-4, added alongside rs-grid on that page's own grid div) —
   patient/visit info needs more room than the compact Select Tests/Selected Tests/Billing Summary
   column next to it. Visit Details (visit-view.js) keeps the shared plain .rs-grid 1fr/1fr split. */
.rs-grid.rs-grid-6-4{grid-template-columns:6fr 4fr}
/* auto-fit/minmax instead of a fixed repeat(5,1fr) — the Billing Summary sits in the rs-grid-6-4
   split's narrower right-hand column (~40% of the page), which isn't wide enough to fit all 5
   fields on one line at that fixed ratio; each field now claims only as much width as it needs
   and the row wraps onto a second line by itself instead of squeezing every input unreadably
   narrow. */
.rs-billing-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:12px}
@media (max-width:900px){
  .rs-grid{grid-template-columns:1fr}
  .rs-grid.rs-grid-6-4{grid-template-columns:1fr}
  .rs-billing-row{grid-template-columns:1fr 1fr}
}

/* ── Activity Feed ─────────────────────────────────────────────── */
/* One-row-per-study, image counter increments in place */
.feed-table{width:100%;border-collapse:collapse;font-size:12px;table-layout:fixed}
.feed-table th{
  font-size:10px;font-family:'JetBrains Mono',monospace;
  color:var(--text3);letter-spacing:.07em;text-transform:uppercase;
  padding:8px 10px;text-align:left;border-bottom:1px solid var(--border);
  background:var(--surface2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  /* Every other table page's header stays pinned via .data-table th's sticky positioning —
     .feed-table is bespoke (its own column-width classes, table-layout:fixed) and had been
     missing this, so its header alone scrolled away with the body. Same mechanism, same
     scroll ancestor (#content), so it behaves identically to .data-table th now. */
  position:sticky;top:0;z-index:1;
}
.feed-table td{padding:8px 10px;border-bottom:1px solid var(--border);vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.feed-table tr:hover td{background:var(--surface2)}
.feed-table tr.flash td{animation:rowflash .5s ease}
@keyframes rowflash{from{background:rgba(108,99,255,.14)}to{background:transparent}}
/* column widths */
.feed-table .c-time{width:150px}
.feed-table .c-event{width:110px}
.feed-table .c-patient{width:150px}
.feed-table .c-pid{width:92px}
.feed-table .c-mod{width:55px;text-align:center}
.feed-table .c-dest{width:110px}
.feed-table .c-ser{width:64px;text-align:center}
.feed-table .c-img{width:65px;text-align:center}
.feed-table .c-total{width:70px;text-align:center}
.feed-table .c-recv{width:82px;text-align:center}
.feed-table .c-comp{width:98px;text-align:center}
.feed-table .c-sentn{width:70px;text-align:center}
.feed-table .c-start{width:150px}
.feed-table .c-end{width:150px}
.feed-table .c-dur{width:90px;text-align:center}
.feed-table .c-status{width:70px}
.feed-table .c-msg{width:auto}

.img-counter{
  font-family:'JetBrains Mono',monospace;font-size:12px;font-weight:600;
  color:var(--blue);
  transition:color .2s;
}
.img-counter.updated{animation:counterpop .3s ease}
@keyframes counterpop{0%{transform:scale(1.4);color:var(--amber)}100%{transform:scale(1);color:var(--blue)}}
.count-cell{font-family:'JetBrains Mono',monospace;font-size:12px;font-weight:600;transition:color .2s}
.count-cell.recv{color:var(--blue)}
.count-cell.comp{color:var(--teal)}
.count-cell.sentn{color:var(--green)}
.count-cell.total{color:var(--text2)}
.count-cell.ser{color:var(--text2)}
.count-cell.dur{color:var(--amber)}
.count-cell.bump{animation:counterpop .3s ease}

/* ── Sender Status Cards ───────────────────────────────────────── */
.sender-card{
  padding:12px 14px;border:1px solid var(--border);
  border-radius:var(--r);background:var(--surface2);
  margin-bottom:8px;transition:all .15s;
}
.sender-card:hover{border-color:var(--border2)}
.sender-card.ok{border-left:3px solid var(--green)}
.sender-card.err{border-left:3px solid var(--red)}
.sender-card.idle{border-left:3px solid var(--border2)}

/* ── Tables ─────────────────────────────────────────────────────── */
.table-wrap{overflow-x:auto;border-radius:var(--r);border:1px solid var(--border)}
/* ── Table enhancement experiment (js/table-enhance.js) ───────────────────
   Applied automatically to every .table-wrap in the main content area (not inside the wizard
   or a modal — those stay as they were), UNLESS Settings → UI Preferences → Table Style is set
   to Classic (body.table-style-classic), in which case every table stays exactly as it always
   was — see js/table-enhance.js's unenhance(). Turns the page-level scroll a long table used to
   force into a self-contained, height-bounded scroll region with a mirrored top scrollbar, the
   page's own pagination controls pulled up into the table's own footer, and a per-table column
   show/hide dropdown (top toolbar opens it downward, bottom toolbar opens it upward, so it's
   never offscreen at either end).
   To fully remove this feature outright (not just switch everyone to Classic): delete the
   <script src="js/table-enhance.js"> tag in index.html — every table reverts to plain
   full-page-scroll with no other change needed anywhere. */
.table-wrap.tbl-enhanced{overflow:hidden;position:relative;border:none}
.tbl-toolbar{
  display:flex;justify-content:space-between;align-items:center;gap:8px;
  padding:6px 10px;background:var(--surface2);min-height:34px;
}
.tbl-toolbar-top{border-bottom:1px solid var(--border)}
.tbl-toolbar-bottom{border-top:1px solid var(--border)}
/* When a table's content is short enough that neither scrollbar is needed, the top/bottom
   toolbars sit directly against the header row / last data row — .tbl-scroll-top collapses to
   0 height itself (see below) and .tbl-scroll-body never carries extra margin, so there's no
   leftover gap in that case beyond the toolbars' own padding. */
/* Deliberately NEVER display:none, even with zero pagination buttons inside (a single page of
   results) — .tbl-toolbar's justify-content:space-between only keeps .tbl-toolbar-right pinned
   to the right edge if this stays a real (if visually empty) flex item; collapsing it out of
   the layout entirely used to leave .tbl-toolbar-right as the ONLY flex child, and
   space-between renders a lone child at the flex-START instead — the Columns button visibly
   drifting to the left the moment a table had only one page of results. */
.tbl-pager-slot{display:flex;gap:6px;flex-wrap:wrap;min-width:0}
.tbl-toolbar-right{display:flex;align-items:center;gap:10px;flex-shrink:0}
.tbl-cols-btn{padding:4px 10px;font-size:11px;flex-shrink:0}
/* flex-shrink:0 here (not just on the <select> nested inside it) is the actual fix — without
   it, .tbl-toolbar-right's flex layout could compute a SHRUNK width for this whole label under
   space pressure, while the native <select> inside it still paints/hit-tests at its full
   natural width regardless of what the layout algorithm decided — the mismatch let the
   adjacent Columns button's flex box start before the select's rendered content visually
   ended, so clicks in what looked like the tail end of the dropdown actually landed on
   Columns instead (confirmed via elementFromPoint, not just a cosmetic overlap). */
/* NOT display:flex — a nested flex container as a flex item of .tbl-toolbar-right measured
   consistently wrong in testing: this label's own flex-basis:auto sizing came out equal to the
   <select>'s width alone, as though the "Rows" text contributed nothing, regardless of whether
   that text was a bare text node or a properly wrapped <span> — a real nested-flex sizing quirk,
   not a markup issue. Plain inline flow (a <span> then a <select>, both naturally inline-level)
   sidesteps the whole nested-flex-basis calculation and sizes exactly to its visible content. */
.tbl-pagesize{white-space:nowrap;flex-shrink:0;color:var(--text3);font-size:11.5px}
.tbl-pagesize span{margin-right:6px}
/* select.tbl-pagesize-select (type+class), not just .tbl-pagesize-select — the <select> also
   carries .form-select (for consistent input styling), and .form-select{width:100%} is declared
   later in this file. Both selectors were equal specificity (a single class each), so cascade
   ORDER decided the winner: .form-select's width:100% always beat this rule's width:auto,
   silently stretching the select to fill its containing block and overlap the Columns button
   next to it — this, not flex-basis sizing, was the actual cause of that overlap. Bumping this
   selector's specificity above .form-select's makes the override reliable regardless of
   declaration order. */
select.tbl-pagesize-select{width:auto;padding:3px 22px 3px 8px;font-size:11.5px;flex-shrink:0;vertical-align:middle}
/* position:fixed (not absolute) and appended to document.body, not to .table-wrap — the wrap
   itself is overflow:hidden (needed to keep the mirrored scrollbar's rounded corners correct),
   which would otherwise clip this dropdown. Top/bottom/right are set inline by table-enhance.js
   from the trigger button's actual on-screen position each time it opens (the bottom toolbar's
   button opens it upward instead of down, since down would usually run off the viewport there). */
.tbl-cols-dropdown{
  display:none;position:fixed;z-index:200;
  min-width:200px;max-width:260px;
  background:var(--surface);border:1px solid var(--border2);border-radius:var(--r-sm);
  box-shadow:var(--shadow);overflow:hidden;
}
.tbl-cols-dropdown.open{display:flex;flex-direction:column}
.tbl-cols-dropdown-header{
  display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:7px 6px 7px 10px;border-bottom:1px solid var(--border);flex-shrink:0;
}
.tbl-cols-dropdown-title{font-size:11px;font-weight:700;color:var(--text3);text-transform:uppercase;letter-spacing:.05em}
.tbl-cols-dropdown-close{
  border:none;background:none;color:var(--text3);cursor:pointer;
  width:22px;height:22px;border-radius:4px;font-size:13px;line-height:1;
  display:flex;align-items:center;justify-content:center;flex-shrink:0;
}
.tbl-cols-dropdown-close:hover{background:var(--surface3);color:var(--text)}
.tbl-cols-dropdown-list{overflow-y:auto;max-height:260px;padding:6px}
.tbl-cols-item{display:flex;align-items:center;gap:7px;padding:5px 6px;font-size:12.5px;color:var(--text2);cursor:pointer;border-radius:4px}
.tbl-cols-item:hover{background:var(--surface3);color:var(--text)}

/* Mobile/tablet "dropdown" Action Panel style (Settings → UI Preferences → js/action-column.js)
   — a row's action buttons collapse behind a single ⋮ trigger; tapping it opens this menu.
   Same fixed-position-appended-to-body precedent as .tbl-cols-dropdown above, for the same
   reason (the table's own overflow:hidden/scroll containers would otherwise clip it). */
.row-menu-trigger{margin:0 auto}
.row-menu{
  display:flex;flex-direction:column;position:fixed;z-index:200;
  min-width:160px;max-width:240px;max-height:300px;overflow-y:auto;
  background:var(--surface);border:1px solid var(--border2);border-radius:var(--r-sm);
  box-shadow:var(--shadow);padding:6px;
}
.row-menu-item{
  display:flex;align-items:center;gap:8px;width:100%;
  padding:8px 8px;font-size:13px;color:var(--text2);
  background:none;border:none;border-radius:4px;text-align:left;cursor:pointer;
}
.row-menu-item:hover{background:var(--surface3);color:var(--text)}
.row-menu-item.disabled{opacity:.4;cursor:not-allowed}
.row-menu-icon{width:18px;text-align:center;flex-shrink:0;font-size:14px}
/* Mirrored top scrollbar — a11y/UX convenience so the horizontal scrollbar for a tall table
   doesn't only appear at the very bottom, past every row. Purely a scroll-position mirror of
   .tbl-scroll-body below; carries no content of its own beyond a same-width spacer div. Hidden
   entirely (table-enhance.js toggles this) whenever the table doesn't actually overflow
   horizontally, rather than always reserving dead space for it. Thickness matches
   .tbl-scroll-body's own scrollbars exactly (both below) so all three scrollbars in this
   component — top mirror, native bottom, native right — read as one consistent design. */
.tbl-scroll-top{overflow-x:auto;overflow-y:hidden;height:12px;border-bottom:1px solid var(--border)}
.tbl-scroll-top-inner{height:1px}
.tbl-scroll-body{overflow:auto}
.tbl-scroll-body .data-table th{top:0}
.tbl-scroll-top::-webkit-scrollbar,.tbl-scroll-body::-webkit-scrollbar{width:12px;height:12px}
.tbl-scroll-top::-webkit-scrollbar-track,.tbl-scroll-body::-webkit-scrollbar-track{background:var(--surface2)}
.tbl-scroll-top::-webkit-scrollbar-thumb,.tbl-scroll-body::-webkit-scrollbar-thumb{background:var(--border2);border-radius:6px;border:3px solid var(--surface2)}
.tbl-scroll-top::-webkit-scrollbar-thumb:hover,.tbl-scroll-body::-webkit-scrollbar-thumb:hover{background:var(--text3)}
.data-table{width:100%;border-collapse:collapse;font-size:13px}
.data-table th{
  background:var(--surface2);
  font-size:11px;font-family:'JetBrains Mono',monospace;
  color:var(--text3);letter-spacing:.06em;text-transform:uppercase;
  padding:calc(10px * var(--pad-scale)) calc(14px * var(--pad-scale));text-align:left;border-bottom:1px solid var(--border);
  white-space:nowrap;position:sticky;top:0;z-index:1;
}
.data-table td{padding:calc(11px * var(--pad-scale)) calc(14px * var(--pad-scale));border-bottom:1px solid var(--border);vertical-align:middle;white-space:nowrap}
.data-table tr:last-child td{border-bottom:none}
.data-table tbody tr{transition:background .1s;cursor:default}
.data-table tbody tr:hover td{background:var(--surface2)}
.data-table .clickable{cursor:pointer;color:var(--accent2);font-weight:600}
.data-table .clickable:hover{text-decoration:underline}

/* Patient drill-down */
.breadcrumb{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--text3);margin-bottom:14px;font-family:'JetBrains Mono',monospace;flex-wrap:wrap}
.breadcrumb .crumb{color:var(--accent2);cursor:pointer}
.breadcrumb .crumb:hover{text-decoration:underline}
.breadcrumb .sep{color:var(--text3)}

/* ── Forms ──────────────────────────────────────────────────────── */
.form-group{margin-bottom:14px}
.form-label{display:block;font-size:11px;font-family:'JetBrains Mono',monospace;color:var(--text2);letter-spacing:.05em;text-transform:uppercase;margin-bottom:6px}
.form-input,.form-select,.form-textarea{
  width:100%;padding:calc(9px * var(--pad-scale)) calc(12px * var(--pad-scale));
  background:var(--surface2);border:1px solid var(--border2);
  border-radius:var(--r-sm);color:var(--text);
  font-family:var(--font-sans);font-size:13px;
  outline:none;transition:border-color .15s,box-shadow .15s;
}
.form-input:focus,.form-select:focus,.form-textarea:focus{
  border-color:var(--accent);
  box-shadow:0 0 0 3px rgba(108,99,255,.15);
}
.form-select option{background:var(--surface2)}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.form-row-3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px}
.form-row-4{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:12px}

/* ── Form Section ──────────────────────────────────────────────────
   Generalizes .report-info-panel's bordered-card idiom (see Reporting
   section below) into a reusable "grouped block within a long form"
   component — a modal that stacks several conceptually-distinct sections
   (Edit User: Roles, Branches, Sharing, etc.) gets a bordered card with a
   header per section instead of everything reading as one undifferentiated
   list of .form-group rows. Non-collapsible by default; add .collapsible
   for the longest sections, reusing the same chevron/expand mechanics as
   .report-info-panel so there's only one "collapsible card" pattern in
   the app, not two. */
.form-section{border:1px solid var(--border);border-radius:var(--r);margin-bottom:16px;overflow:hidden;background:var(--surface)}
.form-section:last-child{margin-bottom:0}
.form-section-header{
  display:flex;align-items:center;gap:8px;padding:calc(10px * var(--pad-scale)) calc(14px * var(--pad-scale));
  background:var(--surface2);border-bottom:1px solid var(--border);
}
.form-section-icon{flex:0 0 auto;font-size:14px;line-height:1;opacity:.85}
.form-section-title{font-size:11.5px;font-weight:700;color:var(--text2);text-transform:uppercase;letter-spacing:.05em;font-family:'JetBrains Mono',monospace}
.form-section-desc{font-size:11px;color:var(--text3);margin-top:2px;font-weight:400;text-transform:none;letter-spacing:0;font-family:var(--font-sans)}
.form-section-meta{margin-left:auto;font-size:11px;font-family:'JetBrains Mono',monospace;color:var(--text3);background:var(--surface3);border:1px solid var(--border2);border-radius:20px;padding:2px 10px;white-space:nowrap;flex-shrink:0}
.form-section-body{padding:calc(14px * var(--pad-scale))}
.form-section-body .form-group:last-child{margin-bottom:0}
.form-section.collapsible .form-section-header{cursor:pointer;user-select:none}
.form-section.collapsible .form-section-header:hover{background:var(--surface3)}
.form-section-chevron{font-size:10px;color:var(--text3);transition:transform .15s;flex-shrink:0;margin-left:auto}
.form-section.collapsible.open .form-section-chevron{transform:rotate(90deg)}
.form-section.collapsible .form-section-meta{margin-left:8px}
.form-section-body{display:block}
.form-section.collapsible .form-section-body{display:none}
.form-section.collapsible.open .form-section-body{display:block}
/* A dynamic add/remove list (mapped doctors, share rules, permitted radiologists) inside a
   form-section body shouldn't grow unbounded — caps at ~5 visible rows, scrolls beyond that. */
.form-section-list{max-height:190px;overflow-y:auto}
.toggle-wrap{display:flex;align-items:center;gap:10px}
.toggle{position:relative;width:36px;height:20px;flex-shrink:0}
.toggle input{opacity:0;position:absolute;width:100%;height:100%;cursor:pointer;margin:0}
.toggle-slider{position:absolute;inset:0;background:var(--surface3);border:1px solid var(--border2);border-radius:20px;transition:.2s}
.toggle-slider::before{content:'';position:absolute;width:14px;height:14px;left:2px;top:2px;background:var(--text3);border-radius:50%;transition:.2s}
.toggle input:checked+.toggle-slider{background:var(--accent);border-color:var(--accent)}
.toggle input:checked+.toggle-slider::before{transform:translateX(16px);background:#fff}
.toggle-label{font-size:13px;color:var(--text2)}

/* ── Modals ─────────────────────────────────────────────────────── */
.modal-overlay{
  position:fixed;inset:0;background:rgba(0,0,0,.6);
  display:flex;align-items:center;justify-content:center;
  z-index:1000;backdrop-filter:blur(8px);
  animation:fadeIn .15s ease;
}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
.modal{
  background:var(--surface);border:1px solid var(--border2);
  border-radius:var(--r-lg);padding:24px;
  width:520px;max-width:90vw;max-height:88vh;overflow-y:auto;
  box-shadow:var(--shadow);animation:slideUp .2s ease;
}
/* Wider tier for content-heavy modals (e.g. Edit User, which can stack up to 8 .form-section
   blocks) — the default 520px is kept for every simple single-topic modal. */
.modal.modal-lg{width:760px}
/* Widest tier — a two-column layout (filters + a live Jodit preview pane) needs real horizontal
   room, unlike modal-lg's stacked-sections use case. */
.modal.modal-xl{width:1100px}

/* Load Template modal (js/reports.js) — filter column + live template preview, side by side. */
.ltm-modal-cols{display:flex;gap:20px;align-items:flex-start}
.ltm-modal-filters{width:280px;flex-shrink:0}
.ltm-modal-preview{flex:1;min-width:0}
@media (max-width:760px){
  .ltm-modal-cols{flex-direction:column}
  .ltm-modal-filters{width:100%}
}
@keyframes slideUp{from{transform:translateY(10px);opacity:0}to{transform:translateY(0);opacity:1}}
.modal-title{font-size:16px;font-weight:600;letter-spacing:-.02em;margin-bottom:20px;display:flex;align-items:center;gap:10px}
.modal-footer{display:flex;gap:8px;justify-content:flex-end;margin-top:20px;padding-top:16px;border-top:1px solid var(--border)}

/* Role & Permissions dialog (js/config-roles.js) — one section per resource, one row per
   permission with its longer description underneath the label. Needs .modal-lg's extra width
   (760px) to keep the description text from wrapping too tightly. */
.rp-section{margin-bottom:18px;padding-bottom:14px;border-bottom:1px solid var(--border)}
.rp-section:last-child{border-bottom:none;margin-bottom:0;padding-bottom:0}
.rp-section-header{margin-bottom:8px}
.rp-section-title{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--text2)}
.rp-section-desc{font-size:12px;color:var(--text3);line-height:1.5;margin-top:2px}
.rp-perm-list{display:flex;flex-direction:column;gap:2px}
.rp-perm-row{display:flex;align-items:flex-start;gap:9px;padding:6px 8px;border-radius:var(--r-sm);cursor:pointer}
.rp-perm-row:hover{background:var(--surface2)}
.rp-perm-row input[type="checkbox"]{margin-top:3px;flex-shrink:0}
.rp-perm-label{display:block;font-size:12.5px;color:var(--text);font-weight:500}
.rp-perm-desc{display:block;font-size:11.5px;color:var(--text3);line-height:1.5;margin-top:1px}

/* ── Compression Rules ───────────────────────────────────────────── */
.rule-row{
  display:grid;grid-template-columns:82px 1fr auto;
  gap:12px;align-items:center;padding:11px 0;
  border-bottom:1px solid var(--border);
}
.rule-row:last-child{border-bottom:none}
.modality-badge{
  font-family:'JetBrains Mono',monospace;font-size:11px;font-weight:700;
  padding:4px 10px;border-radius:var(--r-sm);
  background:var(--accent-bg);border:1px solid var(--accent-border);
  color:var(--accent2);text-align:center;letter-spacing:.05em;
}

/* ── Settings ───────────────────────────────────────────────────── */
.setting-row{
  display:grid;grid-template-columns:1fr 220px;
  gap:16px;align-items:center;padding:14px 0;
  border-bottom:1px solid var(--border);
}
.setting-row:last-child{border-bottom:none}
.setting-key{font-size:13px;font-weight:500;color:var(--text);margin-bottom:3px}
.setting-desc{font-size:11px;color:var(--text3)}

/* ── Reporting ──────────────────────────────────────────────────── */
.report-header-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.report-info-panel{border:1px solid var(--border);border-radius:var(--r-sm);margin-bottom:14px;overflow:hidden;background:var(--surface)}
.report-info-header{
  display:flex;align-items:center;gap:8px;padding:10px 12px;cursor:pointer;
  background:var(--surface2);user-select:none;transition:background .15s;
}
.report-info-header:hover{background:var(--surface3)}
.report-info-chevron{font-size:10px;color:var(--text3);display:inline-block;transition:transform .15s;flex-shrink:0}
.report-info-panel.expanded .report-info-chevron{transform:rotate(90deg)}
.report-info-title{font-size:11px;font-weight:600;color:var(--text2);text-transform:uppercase;letter-spacing:.05em;font-family:'JetBrains Mono',monospace;flex-shrink:0}
.report-info-summary{font-size:12px;color:var(--text3);margin-left:8px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.report-info-panel.expanded .report-info-summary{display:none}
.report-info-body{display:none;padding:14px;border-top:1px solid var(--border)}
.report-info-panel.expanded .report-info-body{display:block}
.img-preview-box{
  display:flex;align-items:center;justify-content:center;
  border:1px dashed var(--border2);border-radius:var(--r-sm);
  background:var(--surface2);min-height:70px;padding:8px;margin-bottom:10px;overflow:hidden;
}
.img-preview-box img{max-width:100%;max-height:90px}
.img-preview-box.empty{color:var(--text3);font-size:12px}
.export-checks{display:flex;gap:16px;flex-wrap:wrap;margin:14px 0}
.export-checks label{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--text2);cursor:pointer}
.report-toolbar{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:14px}
.report-status-select{width:auto;padding:6px 10px;font-size:12px}
.jodit-row{display:flex;gap:12px;align-items:stretch;margin-bottom:14px}
.jodit-row .jodit-wrap{flex:1;min-width:0;margin-bottom:0}
/* Takes the exact same flex slot as .jodit-wrap (only one of the two is ever visible at a
   time — see previewOrDownloadAttachment()/closeAttachmentViewer() in history.js) so the
   editor row's overall width/height never jumps when swapping between them. */
.attachment-viewer{flex:1;min-width:0;display:flex;flex-direction:column;border:1px solid var(--border2);border-radius:var(--r-sm);overflow:hidden;background:var(--surface)}
.attachment-viewer-header{display:flex;justify-content:space-between;align-items:center;gap:8px;padding:8px 12px;background:var(--surface2);border-bottom:1px solid var(--border);font-size:12.5px;font-weight:600;flex-shrink:0}
.attachment-viewer-body{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;background:var(--surface3)}
.attachment-viewer-body iframe{width:100%;height:100%;border:none}
.attachment-viewer-body img{max-width:100%;max-height:100%;object-fit:contain}
#history-toggle-btn.active{background:var(--accent-bg);border-color:var(--accent-border);color:var(--accent2)}
#study-toggle-btn.active{background:var(--accent-bg);border-color:var(--accent-border);color:var(--accent2)}
/* Jodit's editing area isn't rendered inside an iframe by default, so — unlike
   its own toolbar chrome, which ships its own colors — the WYSIWYG content div
   has no text color of its own and inherits ours (near-white, for our dark
   theme) over Jodit's own near-white editing background: unreadable. Force a
   normal dark, readable color regardless of our page's theme. */
.jodit-wysiwyg, .jodit-wysiwyg *{color:#222!important}
.jodit-wysiwyg a{color:#2563eb!important}

/* ── RadiSpeak.AI panel ──────────────────────────────────────────── */
#rs-toggle-btn.active{background:var(--accent-bg);border-color:var(--accent-border);color:var(--accent2)}
.radispeak-panel{
  flex:0 0 30%;width:30%;min-width:0;display:flex;flex-direction:column;
  border:1px solid var(--border);border-radius:var(--r);background:var(--surface2);overflow:hidden;
}
.radispeak-panel.collapsed{display:none}
.rs-header{
  display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:10px 12px;background:var(--surface3);border-bottom:1px solid var(--border);flex-shrink:0;
}
.rs-header-title{font-size:12px;font-weight:600;color:var(--text)}
.rs-header-sub{font-size:10px;font-weight:400;color:var(--text3);margin-left:4px}
.rs-conn-pill{display:flex;align-items:center;gap:5px;font-size:10px;color:var(--text2);white-space:nowrap}
.rs-conn-dot{width:7px;height:7px;border-radius:50%;background:var(--red);flex-shrink:0}
.rs-conn-dot.connected{background:var(--green)}
.rs-body{padding:12px;display:flex;flex-direction:column;gap:12px;overflow-y:auto;flex:1;min-height:0}
.rs-connect-row{display:flex;align-items:center;justify-content:space-between;gap:8px}
.rs-user-label{font-size:12px;color:var(--text2)}

.mic-section{background:var(--accent-bg);border:1px solid var(--accent-border);border-radius:var(--r-sm);padding:12px;display:flex;align-items:center;gap:12px}
.mic-wrap{flex-shrink:0;text-align:center;width:64px}
.mic-ripple{position:relative;width:56px;height:56px;cursor:pointer;margin:0 auto}
.mic-ring{display:none;position:absolute;border-radius:50%;border:2px solid;pointer-events:none}
.mic-ring1{inset:-9px;border-color:rgba(56,189,248,.4);animation:micRipple 1.8s ease-out infinite}
.mic-ring2{inset:-17px;border-color:rgba(56,189,248,.22);animation:micRipple 1.8s ease-out infinite .5s}
.mic-circle{position:absolute;inset:0;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:20px;border:3px solid rgba(255,255,255,.15);transition:background .3s}
.mic-circle-idle{background:var(--surface4)}
.mic-circle-ready{background:linear-gradient(135deg,#0ea5e9,#0284c7);box-shadow:0 3px 14px rgba(14,165,233,.5)}
.mic-circle-rec{background:linear-gradient(135deg,#dc2626,#b91c1c);box-shadow:0 3px 14px rgba(220,38,38,.5)}
.mic-circle-paused{background:linear-gradient(135deg,#d97706,#b45309);box-shadow:0 3px 14px rgba(217,119,6,.5)}
.mic-state{margin-top:6px;font-size:9px;font-weight:700;color:var(--text2);text-transform:uppercase;letter-spacing:.4px;text-align:center;line-height:1.3}
.mic-timer{display:none;font-size:11px;font-weight:700;color:var(--red);text-align:center}
.mic-instructions{flex:1;min-width:0}
.mic-pill{display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:20px;font-size:10px;font-weight:600;margin-bottom:6px;background:var(--surface4);color:var(--text2)}
.mic-pill-dot{width:6px;height:6px;border-radius:50%;background:var(--text3);flex-shrink:0}
.mic-pill-dot-ready{background:#38bdf8}
.mic-pill-dot-rec{background:#ef4444}
.mic-pill-dot-paused{background:#f59e0b}
.mic-live-dot{color:#ef4444;font-weight:700}
.mic-steps{font-size:10px;color:var(--text2);line-height:1.8;display:flex;flex-direction:column;gap:1px}
.mic-step{display:flex;align-items:center;gap:6px}
.step-n{border-radius:50%;width:14px;height:14px;display:inline-flex;align-items:center;justify-content:center;font-size:8px;font-weight:700;flex-shrink:0;color:#0a0a0f}
.step-n-green{background:#86efac}
.step-n-amber{background:#fcd34d}
.step-n-blue{background:#7dd3fc}

.rs-dictation-wrap{display:flex;flex-direction:column;flex:1;min-height:120px}
.rs-sec-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.4px;color:var(--text3);display:flex;align-items:center;margin-bottom:5px}
.rs-char-count{margin-left:auto;font-weight:400;text-transform:none}
.rs-textarea{
  width:100%;border:1px solid var(--border2);border-radius:var(--r-sm);padding:9px 11px;
  font-size:12px;font-family:var(--font-sans);resize:none;outline:none;line-height:1.7;flex:1;min-height:0;
  background:var(--surface);color:var(--text);
}
.rs-textarea:focus{border-color:var(--accent)}
.rs-error{padding:8px 10px;background:var(--red-bg);border:1px solid var(--red-border);border-radius:var(--r-sm);font-size:11px;color:var(--red)}
.rs-footer{padding:10px 12px;background:var(--surface3);border-top:1px solid var(--border);flex-shrink:0;display:flex;align-items:center;gap:7px}
.rs-gen-btn{flex:1;justify-content:center}

@keyframes micRipple{0%{transform:scale(1);opacity:1}100%{transform:scale(1.6);opacity:0}}

/* Narrow host (e.g. the OHIF side-panel iframe) — each iframe has its own
   viewport, so this media query fires independently of the outer window. */
@media (max-width:640px){
  .report-header-grid{grid-template-columns:1fr}
  .report-toolbar{flex-direction:column;align-items:stretch}
  .report-toolbar>span{display:none}
  .report-status-select{width:100%}
  .jodit-row{flex-direction:column}
  .radispeak-panel{width:100%;flex-basis:auto}
  .attachment-viewer{width:100%}
  .attachment-viewer-body{min-height:300px}
}

/* ── Empty states ──────────────────────────────────────────────── */
.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;padding:44px 20px;color:var(--text3);text-align:center}
.empty-state-icon{font-size:30px;opacity:.55;line-height:1}
.empty-state-text{font-size:13px;color:var(--text3)}
.empty-state-sub{font-size:11.5px;color:var(--text3);opacity:.75}

/* ── Skeleton loading placeholders ────────────────────────────────── */
.skeleton-cell{padding:11px 14px}
.skeleton-bar{height:12px;border-radius:4px;background:linear-gradient(90deg,var(--surface3) 25%,var(--surface4) 37%,var(--surface3) 63%);background-size:400% 100%;animation:skeleton-shimmer 1.4s ease-in-out infinite}
@keyframes skeleton-shimmer{0%{background-position:100% 50%}100%{background-position:0 50%}}

/* ── Search bar ─────────────────────────────────────────────────── */
.search-input{
  flex:1;padding:calc(9px * var(--pad-scale)) 14px;
  background:var(--surface);border:1px solid var(--border2);
  border-radius:var(--r-sm);color:var(--text);
  font-family:var(--font-sans);font-size:13px;outline:none;
  transition:border-color .15s,box-shadow .15s;
}
.search-input:focus{border-color:var(--accent);box-shadow:0 0 0 3px rgba(108,99,255,.12)}

/* ── Filter row ─────────────────────────────────────────────────────
   The one shared shape for every page's filter/search bar: a row of fields that ends at a common
   baseline (align-items:flex-end) so a labeled .form-group sits flush with an unlabeled search
   input or a button beside it, without every page repeating style="margin-bottom:0" on each
   .form-group or style="display:flex;gap:10px;align-items:flex-end..." on the container inline —
   both of those were the dominant copy-pasted pattern across Worklist/Accounts/Referrals/
   Appointment Slots before this rule existed. */
.filter-row{display:flex;gap:10px;margin-bottom:14px;align-items:flex-end;flex-wrap:wrap}
.filter-row .form-group{margin-bottom:0}
/* The one legitimate "naked label" case (e.g. a date-range's "–" / mid-row separator label) —
   replaces the inline style="margin:0;white-space:nowrap" that appeared ad hoc for this. */
.filter-row-label{font-size:11px;font-family:'JetBrains Mono',monospace;color:var(--text2);letter-spacing:.05em;text-transform:uppercase;white-space:nowrap;padding-bottom:calc(9px * var(--pad-scale))}
.filter-row-check{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--text2);cursor:pointer;white-space:nowrap;padding-bottom:calc(9px * var(--pad-scale))}
.filter-row-spacer{margin-left:auto}

/* ── Toast ───────────────────────────────────────────────────────── */
#toasts{position:fixed;bottom:22px;right:22px;display:flex;flex-direction:column;gap:8px;z-index:9999}
.toast{
  background:var(--surface);border:1px solid var(--border2);
  border-radius:var(--r);padding:11px 16px;font-size:13px;
  display:flex;gap:10px;align-items:center;max-width:360px;
  box-shadow:var(--shadow);animation:slideInToast .3s ease;
}
@keyframes slideInToast{from{transform:translateX(100%);opacity:0}to{transform:translateX(0);opacity:1}}
.toast.success{border-color:var(--green-border)}
.toast.error  {border-color:var(--red-border)}
.toast.info   {border-color:var(--blue-border)}
.toast-icon{font-size:15px}

/* ── Send Dialog (patient) ───────────────────────────────────────── */
.sender-option{
  padding:12px 14px;border:1px solid var(--border);
  border-radius:var(--r);cursor:pointer;transition:all .15s;
  display:flex;align-items:center;justify-content:space-between;
  margin-bottom:8px;
}
.sender-option:hover{border-color:var(--accent-border);background:var(--accent-bg)}
.sender-option.selected{border-color:var(--accent);background:var(--accent-bg)}
.sender-option-name{font-weight:600;font-size:13px;color:var(--text)}
.sender-option-host{font-size:11px;font-family:'JetBrains Mono',monospace;color:var(--text3)}

/* ── Misc ───────────────────────────────────────────────────────── */
.mono{font-family:'JetBrains Mono',monospace;font-size:11px}
.hidden{display:none!important}
.page{display:none}
.page.active{display:block}
.divider{height:1px;background:var(--border);margin:12px 0}
::-webkit-scrollbar{width:5px;height:5px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--border2);border-radius:4px}
::-webkit-scrollbar-thumb:hover{background:var(--text3)}
/* ── Login Screen ──────────────────────────────────────────────────── */
#login-screen{
  position:fixed;inset:0;z-index:9000;
  background:var(--bg);
  display:flex;
}
/* Branding banner — left ~58% on desktop, hidden below the tablet breakpoint (see media query)
   so the sign-in form always gets the full, uncramped width on a phone. object-fit:cover crops
   rather than squashes the banner at aspect ratios other than its own. */
.login-banner{
  flex:1 1 58%;min-width:0;
  background:#0a1628;
  overflow:hidden;
}
.login-banner img{width:100%;height:100%;object-fit:cover;display:block}
.login-form-panel{
  flex:1 1 42%;min-width:380px;
  display:flex;align-items:center;justify-content:center;
  background:#f4f7fb;
}
/* The credential box is deliberately a fixed light "brand surface" — navy/green pulled from the
   banner image's own DCMS logo and swoosh — rather than following the user's dark/light app
   theme like every other card in the product. The banner is a fixed-color graphic; a card that
   swung to near-black in dark mode looked disconnected from it, which was the actual complaint.
   Theming resumes as normal the moment you're past this screen. */
.login-card{
  --dcms-blue:#1a3f7a; --dcms-blue2:#2f5fa8; --dcms-green:#1f9955; --dcms-green2:#34b96f;
  background:#fff;border:1px solid #e3e8f0;
  border-radius:18px;width:400px;overflow:hidden;
  box-shadow:0 24px 60px -12px rgba(15,40,80,.28),0 2px 8px rgba(15,40,80,.08);
}
.login-card-topbar{height:5px;background:linear-gradient(90deg,var(--dcms-blue),var(--dcms-green))}
.login-card-body{padding:34px 38px 38px}
.login-logo{
  display:flex;align-items:center;gap:12px;margin-bottom:26px;
}
.login-logo-icon{
  width:44px;height:44px;border-radius:12px;
  display:flex;align-items:center;justify-content:center;
  overflow:hidden;flex-shrink:0;
  box-shadow:0 4px 14px rgba(26,63,122,.4);
}
.login-logo-icon img{width:100%;height:100%;object-fit:cover;display:block}
.login-title{font-size:20px;font-weight:700;color:#152a4d;letter-spacing:-.03em}
.login-subtitle{font-size:12px;color:#6b7a90;margin-top:2px}
.login-error{
  background:var(--red-bg);border:1px solid var(--red-border);
  color:var(--red);border-radius:var(--r-sm);
  padding:9px 12px;font-size:13px;margin-bottom:14px;
  display:none;
}
/* Scoped overrides of the app-wide .form-label/.form-input — this box stays on the fixed light
   brand surface above regardless of dark/light app theme, so it needs its own explicit colors
   rather than the var(--text)/var(--surface2) tokens those rules normally read (which flip to
   near-black/near-white and would go invisible against this always-white card in dark mode). */
.login-card .form-label{color:#3a5a8a}
.login-card .form-input{
  background:#f6f8fb;border:1px solid #dbe2ec;color:#152a4d;
}
.login-card .form-input:focus{
  border-color:var(--dcms-blue2);
  box-shadow:0 0 0 3px rgba(47,95,168,.15);
}
/* Keyboard-focus outline (app.css's global input:focus-visible rule) stays — just recolored to
   match this card's brand blue instead of the app's default purple accent. */
.login-card .form-input:focus-visible{outline-color:var(--dcms-blue2)}
.login-btn{
  width:100%;padding:11px;border-radius:var(--r-sm);
  background:linear-gradient(135deg,var(--dcms-blue2),var(--dcms-green2));border:none;color:#fff;
  font-family:"Inter",sans-serif;font-size:14px;font-weight:600;
  cursor:pointer;transition:all .15s;margin-top:10px;
  box-shadow:0 6px 18px -4px rgba(26,63,122,.45);
}
.login-btn:hover{opacity:.92;box-shadow:0 8px 22px -4px rgba(26,63,122,.55)}
.login-btn:disabled{opacity:.5;cursor:not-allowed;box-shadow:none}

/* ── Export Progress Bar (CD/ISO/USB) ─────────────────────────────── */
.progress-track{
  height:8px;border-radius:4px;background:var(--border);
  overflow:hidden;position:relative;
}
.progress-fill{
  height:100%;border-radius:4px;width:0%;
  background:linear-gradient(135deg,var(--accent),var(--accent2));
  transition:width .3s ease;
}
.progress-fill.indeterminate{
  width:35%!important;position:absolute;
  animation:progress-indeterminate 1.1s ease-in-out infinite;
}
.progress-fill.failed{background:var(--red)}
@keyframes progress-indeterminate{
  0%{left:-35%}
  100%{left:100%}
}
.progress-label{
  display:flex;justify-content:space-between;font-size:12px;
  color:var(--text2);margin-top:8px;
}

/* ── Registration wizard — step tracker (StepWizard.jpg reference) ────────── */
.wiz-tracker{display:flex;align-items:center;margin-bottom:22px}
.wiz-track-step{flex:1;display:flex;flex-direction:column;align-items:center;text-align:center;min-width:0;padding:0 2px}
.wiz-track-row{display:flex;align-items:center;width:100%}
.wiz-track-line{flex:1;height:2px;background:var(--border2);transition:background .2s ease}
.wiz-track-line.done{background:var(--green)}
.wiz-track-line.spacer{visibility:hidden}
.wiz-track-circle{
  flex:0 0 auto;width:36px;height:36px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  font-size:13px;font-weight:700;font-family:'JetBrains Mono',monospace;
  background:var(--surface3);border:2px solid var(--border2);color:var(--text3);
  transition:all .18s ease;margin:0 2px;
}
.wiz-track-circle.done{background:var(--green);border-color:var(--green);color:#fff}
.wiz-track-circle.active{background:var(--accent);border-color:var(--accent);color:#fff;width:42px;height:42px;box-shadow:0 0 0 4px var(--accent-bg)}
.wiz-track-circle svg{width:15px;height:15px}
.wiz-track-circle.active svg{width:18px;height:18px}
.wiz-track-title{margin-top:9px;font-size:12.5px;font-weight:600;color:var(--text2);white-space:nowrap}
.wiz-track-step.active .wiz-track-title{color:var(--accent2)}
.wiz-track-step.done .wiz-track-title{color:var(--text)}
.wiz-track-desc{font-size:10.5px;color:var(--text3);margin-top:2px;line-height:1.3}

.wiz-panel-header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-bottom:14px;margin-bottom:16px;border-bottom:1px solid var(--border)}
.wiz-panel-title-wrap{display:flex;align-items:center;gap:12px;min-width:0}
.wiz-panel-icon{flex:0 0 auto;width:38px;height:38px;border-radius:10px;background:var(--accent-bg);color:var(--accent2);display:flex;align-items:center;justify-content:center}
.wiz-panel-icon svg{width:20px;height:20px}
.wiz-panel-title{font-size:16px;font-weight:700;color:var(--text)}
.wiz-panel-sub{font-size:12px;color:var(--text3);margin-top:2px}
.wiz-panel-count{flex:0 0 auto;font-size:11px;font-family:'JetBrains Mono',monospace;color:var(--text3);background:var(--surface3);border:1px solid var(--border2);border-radius:20px;padding:4px 12px;white-space:nowrap}

.wiz-content-box{border:1px solid var(--border);border-radius:12px;padding:20px}

.wiz-nav{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-top:22px;padding-top:16px;border-top:1px solid var(--border)}
.wiz-nav-side{display:flex;align-items:center;gap:10px}
.wiz-nav-btn{
  display:flex;align-items:center;gap:10px;padding:9px 16px;border-radius:10px;border:1px solid var(--accent-border);
  background:var(--accent-bg);color:var(--accent2);cursor:pointer;font-family:inherit;transition:all .15s ease;
}
.wiz-nav-btn:hover{background:var(--accent);color:#fff}
.wiz-nav-btn.primary{background:var(--accent);color:#fff;border-color:var(--accent);box-shadow:0 2px 8px rgba(108,99,255,.3)}
.wiz-nav-btn.primary:hover{opacity:.9}
.wiz-nav-btn svg{width:16px;height:16px;flex:0 0 auto}
.wiz-nav-btn-text{display:flex;flex-direction:column;align-items:flex-start;line-height:1.25}
.wiz-nav-btn.next .wiz-nav-btn-text{align-items:flex-end}
.wiz-nav-btn-action{font-size:12.5px;font-weight:700}
.wiz-nav-btn-sub{font-size:10.5px;opacity:.85;font-weight:500}

/* ══════════════════════════════════════════════════════════════════
   RESPONSIVE DESIGN SYSTEM
   Breakpoints: large desktop ≥1440px · desktop 1024–1439px (default,
   rules above this section) · tablet 768–1023px · mobile ≤767px.
   ══════════════════════════════════════════════════════════════════ */

/* ── Accessibility / readability polish ───────────────────────────── */
/* Only .form-input had a visible focus ring before; keyboard users tabbing
   through nav items, buttons and badges had no indication of focus at all. */
a:focus-visible,button:focus-visible,.btn:focus-visible,.nav-item:focus-visible,
.theme-toggle:focus-visible,.data-table .clickable:focus-visible,
input:focus-visible,select:focus-visible,textarea:focus-visible{
  outline:2px solid var(--accent);outline-offset:2px;border-radius:4px;
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}
}

/* ── Searchable combobox (registration wizard: Referring Physician / PRO) ── */
.wiz-searchsel{position:relative}
.wiz-searchsel-list{
  display:none;position:absolute;left:0;right:0;top:100%;margin-top:2px;z-index:40;
  max-height:220px;overflow-y:auto;background:var(--surface);border:1px solid var(--border2);
  border-radius:var(--r-sm);box-shadow:var(--shadow);
}
.wiz-searchsel-item{padding:8px 12px;font-size:13px;cursor:pointer}
.wiz-searchsel-item:hover{background:var(--surface3)}

/* ── Wizard result card (patient search, test search) ────────────────────
   .wiz-searchsel-list above is a compact combobox dropdown (one line per item, floats over the
   field) — right for Referring Physician/PRO, but patient-search and test-search results are
   richer (title + subtitle + action buttons) and were each hand-rolling a near-identical
   `.card` with inline flex styling. One shared card component for both instead. */
.wiz-result-card{
  display:flex;justify-content:space-between;align-items:center;gap:10px;
  padding:10px 14px;border:1px solid var(--border);border-radius:var(--r-sm);
  background:var(--surface);margin-top:6px;transition:border-color .15s;
}
.wiz-result-card:first-child{margin-top:0}
.wiz-result-card:hover{border-color:var(--border2)}
.wiz-result-main{min-width:0}
.wiz-result-title{font-weight:600;font-size:13px;color:var(--text)}
.wiz-result-sub{color:var(--text3);font-size:12px;margin-top:2px}
.wiz-result-actions{display:flex;align-items:center;gap:8px;flex-shrink:0}
.wiz-result-empty{color:var(--text3);padding:10px 4px;font-size:12.5px}

/* ── Registration wizard: totals row + highlighted payment summary panel ── */
.wiz-totals-row td{font-weight:600;border-top:2px solid var(--border2)!important;background:var(--surface3)}
.wiz-payment-summary{
  display:flex;gap:28px;margin:14px 0;padding:14px 18px;font-size:14px;
  background:var(--accent-bg);border:1px solid var(--accent);border-radius:var(--r);
}
.wiz-payment-summary span{color:var(--text3);font-size:12px}
.wiz-refund-row td{background:var(--red-bg);color:var(--text3)}

/* ── Sidebar toggle (hamburger) + backdrop — hidden on desktop ─────── */
/* Despite the "sidebar-" prefix, this button renders inside .topbar (it's the hamburger that
   CONTROLS the sidebar, not part of it) — colored from the topbar font-color variables. */
.sidebar-toggle{
  display:none;width:34px;height:34px;border-radius:var(--r-sm);
  border:1px solid var(--border2);background:var(--surface3);
  color:var(--topbar-text2, var(--text2));cursor:pointer;align-items:center;justify-content:center;
  font-size:17px;transition:all .15s;flex-shrink:0;
}
.sidebar-toggle:hover{background:var(--topbar-hover-bg, var(--surface4));color:var(--topbar-text, var(--text))}
.sidebar-backdrop{
  display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);
  z-index:190;backdrop-filter:blur(2px);animation:fadeIn .15s ease;
}

/* ── Sidebar collapse (desktop) ──────────────────────────────────────
   Distinct from .sidebar-toggle above (the mobile off-canvas hamburger) — this button only
   shows at desktop widths, mirroring .sidebar-toggle's mobile-only visibility in reverse. */
.sidebar-collapse-btn{
  display:flex;width:34px;height:34px;border-radius:var(--r-sm);
  border:1px solid var(--border2);background:var(--surface3);
  color:var(--topbar-text2, var(--text2));cursor:pointer;align-items:center;justify-content:center;
  font-size:13px;transition:all .15s;flex-shrink:0;
}
.sidebar-collapse-btn:hover{background:var(--topbar-hover-bg, var(--surface4));color:var(--topbar-text, var(--text))}
@media (max-width:1023px){ .sidebar-collapse-btn{display:none} }

@media (min-width:1024px){
  #sidebar{transition:width .18s ease,background .2s,border-color .2s}
  body.sidebar-collapsed #sidebar{width:64px}
  body.sidebar-collapsed .sidebar-logo{justify-content:center;padding:20px 0}
  body.sidebar-collapsed .logo-text,
  body.sidebar-collapsed #branch-switcher-holder,
  body.sidebar-collapsed .nav-section,
  body.sidebar-collapsed .nav-chevron,
  body.sidebar-collapsed .nav-submenu{display:none}
  body.sidebar-collapsed .nav-item{overflow:hidden;white-space:nowrap;justify-content:flex-start}

  /* SCP status panel: full labels/buttons replaced with a compact icon-only stack — the
     colored dots still carry the running/connected state, and native title="" tooltips
     (kept in sync in dashboard.js/websocket.js) cover the rest on hover. */
  body.sidebar-collapsed .sidebar-footer{padding:12px 6px 14px}
  body.sidebar-collapsed .scp-row{justify-content:center;margin-bottom:10px}
  body.sidebar-collapsed .scp-label{display:none}
  body.sidebar-collapsed .scp-actions{flex-direction:column;gap:6px}
  body.sidebar-collapsed .scp-actions .btn{flex:none;width:100%;padding:6px 0}
  body.sidebar-collapsed .scp-text{display:none}
  body.sidebar-collapsed .queue-chips{flex-direction:column;align-items:center;gap:5px}
  body.sidebar-collapsed .chip{
    width:22px;height:22px;padding:0;
    display:flex;align-items:center;justify-content:center;border-radius:50%;
  }
  body.sidebar-collapsed .chip-text{display:none}
  body.sidebar-collapsed .ws-indicator{justify-content:center}
  body.sidebar-collapsed #ws-status{display:none}
}
.sidebar-flyout{
  display:none;position:fixed;z-index:250;padding:7px 12px;font-size:13px;font-weight:500;
  background:var(--surface3);border:1px solid var(--border2);border-radius:var(--r-sm);
  box-shadow:var(--shadow);color:var(--text);white-space:nowrap;pointer-events:none;
}
.sidebar-flyout.show{display:block;animation:fadeIn .1s ease}

/* ── Documentation pages (User/Admin Documentation) ──────────────────
   Two-column layout: sticky left TOC (built + scroll-spied by js/docs.js
   from the fetched content's own h2/h3 headings) + a scrollable content
   column styled like a readable article, not a data screen. */
.doc-layout{display:flex;align-items:flex-start;gap:26px}
.doc-toc{
  position:sticky;top:14px;flex:0 0 240px;width:240px;max-height:calc(100vh - var(--topbar-h) - 28px);
  overflow-y:auto;background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);
  padding:calc(14px * var(--pad-scale));font-size:12.5px;
}
.doc-toc-title{font-size:10px;font-family:'JetBrains Mono',monospace;color:var(--text3);letter-spacing:.08em;text-transform:uppercase;margin-bottom:10px;padding:0 8px}
.doc-toc a{
  display:block;padding:6px 8px;border-radius:var(--r-sm);color:var(--text2);text-decoration:none;
  line-height:1.35;transition:background .12s,color .12s;border-left:2px solid transparent;
}
.doc-toc a.doc-toc-h3{padding-left:20px;font-size:12px;color:var(--text3)}
.doc-toc a:hover{background:var(--surface3);color:var(--text)}
.doc-toc a.active{background:var(--accent-bg);color:var(--accent2);border-left-color:var(--accent)}
.doc-content{flex:1;min-width:0;max-width:860px}
.doc-loading{color:var(--text3);font-size:13px;padding:40px 0;text-align:center}
.doc-content h1{font-size:24px;font-weight:700;letter-spacing:-.02em;margin:0 0 6px}
.doc-content .doc-intro{color:var(--text2);font-size:13.5px;line-height:1.6;margin-bottom:28px;max-width:70ch}
.doc-content section{margin-bottom:38px;scroll-margin-top:14px}
.doc-content h2{
  font-size:18px;font-weight:650;letter-spacing:-.01em;margin:0 0 4px;padding-top:6px;
  border-top:1px solid var(--border);padding-top:20px;display:flex;align-items:center;gap:8px;
}
.doc-content section:first-of-type h2{border-top:none;padding-top:0}
.doc-content h3{font-size:14.5px;font-weight:650;color:var(--text2);margin:22px 0 8px}
.doc-content p{font-size:13.5px;line-height:1.65;color:var(--text2);margin:0 0 12px;max-width:72ch}
.doc-content ul,.doc-content ol{margin:0 0 14px;padding-left:22px;font-size:13.5px;line-height:1.65;color:var(--text2)}
.doc-content li{margin-bottom:5px}
.doc-content li b,.doc-content p b,.doc-content li strong,.doc-content p strong{color:var(--text)}
.doc-content code{
  background:var(--surface3);border:1px solid var(--border);border-radius:4px;
  padding:1px 6px;font-family:'JetBrains Mono',monospace;font-size:12px;color:var(--accent2);
}
.doc-steps{list-style:none;margin:0 0 18px;padding:0;counter-reset:docstep}
.doc-steps>li{
  counter-increment:docstep;position:relative;padding:0 0 18px 34px;margin-bottom:4px;
  border-left:2px solid var(--border);
}
.doc-steps>li:last-child{border-left-color:transparent;padding-bottom:0}
.doc-steps>li::before{
  content:counter(docstep);position:absolute;left:-13px;top:0;width:24px;height:24px;
  border-radius:50%;background:var(--accent-bg);border:1px solid var(--accent-border);color:var(--accent2);
  font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;
  font-family:'JetBrains Mono',monospace;
}
.doc-shot{
  display:block;max-width:100%;margin:10px 0 4px;border:1px solid var(--border);border-radius:var(--r);
  box-shadow:var(--shadow-sm);cursor:zoom-in;background:var(--surface2);
}
.doc-shot-cap{font-size:11.5px;color:var(--text3);margin:0 0 14px;font-style:italic}
.doc-callout{
  display:flex;gap:10px;background:var(--surface2);border:1px solid var(--border);
  border-left:3px solid var(--accent);border-radius:var(--r);padding:calc(12px * var(--pad-scale)) 14px;
  margin:14px 0;font-size:13px;line-height:1.6;color:var(--text2);
}
.doc-callout.warn{border-left-color:var(--amber);background:var(--amber-bg)}
.doc-callout.tip{border-left-color:var(--green);background:var(--green-bg)}
.doc-callout-icon{flex:0 0 auto;font-size:15px;line-height:1.5}
.doc-btn-table{width:100%;border-collapse:collapse;margin:8px 0 16px;font-size:12.5px}
.doc-btn-table th,.doc-btn-table td{text-align:left;padding:7px 10px;border-bottom:1px solid var(--border);vertical-align:top}
.doc-btn-table th{color:var(--text3);font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;font-family:'JetBrains Mono',monospace}
.doc-btn-table td:first-child{white-space:nowrap;font-weight:600;color:var(--text)}
.doc-lightbox{
  display:none;position:fixed;inset:0;z-index:400;background:rgba(0,0,0,.78);
  align-items:center;justify-content:center;padding:30px;cursor:zoom-out;
}
.doc-lightbox.open{display:flex}
.doc-lightbox img{max-width:100%;max-height:100%;border-radius:var(--r);box-shadow:var(--shadow)}

/* ── HL7 sample messages (Settings → HL7) ─────────────────────────── */
.hl7-sample{border:1px solid var(--border);border-radius:var(--r);margin-bottom:10px;overflow:hidden}
.hl7-sample summary{
  padding:10px 14px;cursor:pointer;font-size:13px;font-weight:600;color:var(--text);
  background:var(--surface2);display:flex;align-items:center;gap:10px;list-style:none;
}
.hl7-sample summary::-webkit-details-marker{display:none}
.hl7-sample summary::before{content:'▸';color:var(--text3);font-size:11px;transition:transform .15s}
.hl7-sample[open] summary::before{transform:rotate(90deg)}
.hl7-dir{font-size:10px;font-family:'JetBrains Mono',monospace;text-transform:uppercase;letter-spacing:.05em;
  padding:2px 7px;border-radius:10px;font-weight:700}
.hl7-dir.in{background:var(--blue-bg);color:var(--blue);border:1px solid var(--blue-border)}
.hl7-dir.out{background:var(--green-bg);color:var(--green);border:1px solid var(--green-border)}
.hl7-sample-body{padding:14px}
.hl7-msg{
  background:var(--surface2);border:1px solid var(--border);border-radius:var(--r);
  padding:12px 14px;font-family:'JetBrains Mono',monospace;font-size:11.5px;line-height:1.8;
  white-space:pre-wrap;word-break:break-all;color:var(--text2);margin:0 0 10px;
}
.hl7-msg .seg-id{color:var(--accent2);font-weight:700}

/* ── Large desktop (≥1440px): a little extra breathing room ────────── */
@media (min-width:1440px){
  #content{padding:28px 34px}
  .metrics-grid{grid-template-columns:repeat(6,1fr);gap:14px}
}

/* ── Tablet and below (≤1023px): sidebar becomes an off-canvas drawer ─ */
@media (max-width:1023px){
  .sidebar-toggle{display:flex}
  #sidebar{
    position:fixed;top:0;left:0;z-index:200;
    transform:translateX(-100%);
    box-shadow:var(--shadow);
    transition:transform .22s ease;
  }
  body.sidebar-open #sidebar{transform:translateX(0)}
  body.sidebar-open .sidebar-backdrop{display:block}
  #main{width:100%}
  .metrics-grid{grid-template-columns:repeat(3,1fr)}
  .dash-grid{grid-template-columns:1fr}
  .report-header-grid{grid-template-columns:1fr}

  .doc-layout{flex-direction:column}
  .doc-toc{position:static;width:100%;max-height:none;order:-1}
  .doc-content{max-width:100%}
}

/* ── Mobile (≤767px) ───────────────────────────────────────────────── */
@media (max-width:767px){
  #content{padding:14px}
  .topbar{padding:0 14px;gap:8px}
  .page-title{font-size:14px}
  .clock{display:none}
  #user-badge{display:none}
  .topbar-right{gap:6px}

  .metrics-grid{grid-template-columns:repeat(2,1fr);gap:10px}
  .metric-value{font-size:24px}
  .form-row{grid-template-columns:1fr}
  .setting-row{grid-template-columns:1fr;gap:6px}
  .rule-row{grid-template-columns:1fr;gap:6px}

  /* Touch targets — mouse-tuned padding is too tight for a fingertip. Still routed through
     --pad-scale (UI Preferences → Spacing Density) like every other padding: in this file, so
     "Compact" means compact on mobile too rather than silently doing nothing here — min-height
     is deliberately a fixed floor, NOT scaled, so a tap target never shrinks below a usable size
     even at the most compact setting. */
  .btn{padding:calc(10px * var(--pad-scale)) calc(14px * var(--pad-scale));font-size:13px;min-height:40px}
  .btn-sm{padding:calc(8px * var(--pad-scale)) calc(12px * var(--pad-scale));font-size:12px;min-height:36px}
  .btn-icon,.btn-action{width:38px;height:38px}
  .form-input,.form-select,.form-textarea{padding:calc(11px * var(--pad-scale)) calc(12px * var(--pad-scale));font-size:14px}
  .nav-item{padding:calc(12px * var(--pad-scale)) calc(10px * var(--pad-scale));font-size:14px}

  .modal-overlay{padding:0}
  .modal,.modal.modal-lg,.modal.modal-xl{
    width:100vw;max-width:100vw;height:100vh;max-height:100vh;
    border-radius:0;padding:18px 16px calc(18px + env(safe-area-inset-bottom));
  }

  .wiz-tracker{overflow-x:auto;padding-bottom:4px;-webkit-overflow-scrolling:touch}
  .wiz-tracker::-webkit-scrollbar{height:4px}
  .wiz-track-step{min-width:64px}
  .wiz-track-desc{display:none}
  .wiz-panel-header{flex-wrap:wrap}
  .wiz-nav{flex-direction:column;align-items:stretch}
  .wiz-nav-side{width:100%;justify-content:space-between}
  .wiz-nav-btn{flex:1;justify-content:center}

  .table-wrap{-webkit-overflow-scrolling:touch}
  .data-table th,.data-table td{padding:calc(9px * var(--pad-scale)) calc(10px * var(--pad-scale));font-size:12.5px}

  .login-banner{display:none}
  .login-form-panel{flex:1 1 100%;min-width:0}
  .login-card{width:92vw}
  .login-card-body{padding:26px 22px 30px}

  .doc-content h1{font-size:20px}
  .doc-content h2{font-size:16px}
  .doc-steps>li{padding-left:28px}
}
