/* ~/EGFR/web/template/styles.css — Roche ONE design system (Navify Light) */
:root{
  /* Roche ONE tokens (verbatim values from @one/design-tokens) */
  --blue:#0b41cd;            /* Roche Blue — primary */
  --blue-500:#1482fa; --blue-200:#bde3ff; --blue-100:#daedfb; --blue-50:#f5f9ff;
  --green:#00874a; --green-200:#cee7d8; --green-100:#e7f3ea;
  --yellow:#d97706; --yellow-bg:#fff9e8; --yellow-bd:#ffedb9;
  --red:#cc0033; --red-600:#7a000f; --red-100:#ffdde1;
  --subbrand:#49b900;
  --ink:#121212;            /* gray-900 */
  --muted:#544f4f;          /* gray-600 */
  --muted-2:#868281;        /* gray-400 */
  --line:#ddd9d5;           /* gray-100 */
  --line-2:#f5f5f2;         /* gray-50 */
  --bg:#f5f5f2;             /* page bg (gray-50) */
  --card:#ffffff;
  --logo-color:var(--blue);
  --radius:14px; --radius-sm:9px;
  --shadow-1:0 4px 20px rgba(18,18,18,.035),0 1px 2px rgba(18,18,18,.03);
  --shadow-2:0 4px 12px rgba(18,18,18,.08),0 2px 4px rgba(18,18,18,.04);
  --font:'Inter','Roche Sans','Helvetica Neue',sans-serif;
  /* high-end refinement tokens */
  --shadow-3:0 14px 34px -12px rgba(18,18,18,.22),0 4px 10px rgba(18,18,18,.06);
  --ease:cubic-bezier(.2,.7,.2,1);
  --grad-blue:linear-gradient(135deg,var(--blue-500),var(--blue));
  --dur-1:.18s; --dur-2:.5s; --dur-3:.9s;
  /* Elegant Technical (round 2) — Roche navy + soft surfaces */
  --navy-2:#022366;        /* Roche blue-800 (deep navy) — page-title */
  --soft:#f8fafc;          /* very light input surface */
  --slate:#64748b;         /* neutral header/label gray */
  --chg-pos:#2e7d32;       /* positive delta — emerald/sage (medical premium) */
  --chg-neg:#d9383a;       /* negative delta — muted crimson (not harsh) */
  --bar-pos:#4caf7d;       /* Δ chart bar — soft emerald (lighter than the text delta) */
  --bar-neg:#e26a78;       /* Δ chart bar — soft crimson */
}
*{box-sizing:border-box;margin:0;padding:0;}
html{font-size:16px;}
body{font-family:var(--font);background:var(--bg);color:var(--ink);
  display:flex;min-height:100vh;-webkit-font-smoothing:antialiased;line-height:1.5;}
.material-symbols-outlined{font-size:20px;line-height:1;vertical-align:middle;
  font-variation-settings:'opsz' 20,'wght' 400,'FILL' 0,'GRAD' 0;}

/* ---------- Sidebar ---------- */
#sidebar{width:264px;background:var(--card);border-right:1px solid var(--line);
  padding:24px 16px;display:flex;flex-direction:column;gap:3px;position:sticky;top:0;height:100vh;}
.brand{display:flex;justify-content:center;padding:8px 12px 22px;
  border-bottom:1px solid var(--line);margin-bottom:16px;}
.brand-logo{display:block;width:150px;max-width:100%;height:auto;}
.nav-item{position:relative;display:flex;align-items:center;gap:12px;margin:0 8px;padding:12px 14px;border-radius:10px;
  color:var(--muted);cursor:pointer;font-weight:500;font-size:14.5px;line-height:1.6;text-decoration:none;
  transition:background var(--dur-1) var(--ease),color var(--dur-1) var(--ease);}
.nav-item:hover{background:var(--blue-50);color:var(--blue);}
/* Linear/Tailwind-UI style active: faint ~5% blue wash + brand-blue text + flush-left rail */
.nav-item.active{background:rgba(11,65,205,.05);color:var(--blue);font-weight:600;}
.nav-item.active::before{content:"";position:absolute;left:0;top:7px;bottom:7px;width:3px;
  border-radius:0 99px 99px 0;background:var(--blue);}
/* Real Roche icons (two-tone #0b41cd + #1482fa, viewBox 0 0 192 192, stroke 8).
   Their colour is baked into the SVG, unlike the Material Symbols font they
   replaced, so the resting state is desaturated to keep the grey-inactive /
   blue-active rhythm the sidebar already had. The active item shows the icon
   in full Roche colour. */
.nav-ico{width:21px;height:21px;flex:0 0 21px;display:block;
  filter:grayscale(1) opacity(.55);
  transition:filter var(--dur-1) var(--ease);}
.nav-item:hover .nav-ico{filter:grayscale(.35) opacity(.85);}
.nav-item.active .nav-ico{filter:none;}
/* The mini actions below the nav (change password, logout) are not page menus;
   they keep the Material Symbols font at its inherited size. */

/* ---------- Layout ---------- */
#content{flex:1;padding:32px 36px;max-width:1480px;width:100%;}
.page{display:none;}
.page.active{display:block;animation:pageIn var(--dur-1) var(--ease);}
.page-head{display:flex;justify-content:space-between;align-items:flex-end;gap:16px;
  flex-wrap:wrap;margin-bottom:24px;}
.page-title{font-size:26px;font-weight:700;letter-spacing:-.025em;color:var(--navy-2);
  display:flex;align-items:center;gap:12px;line-height:1.15;}
.page-title::before{content:"";width:4px;height:25px;border-radius:3px;flex-shrink:0;
  background:linear-gradient(var(--blue-500),var(--blue));box-shadow:0 1px 3px rgba(11,65,205,.35);}
.page-sub{font-size:13.5px;color:var(--muted);margin-top:7px;margin-left:16px;letter-spacing:.01em;}

/* ---------- Filter bar ---------- */
#filter-bar,#audit-filter{display:flex;gap:18px;flex-wrap:wrap;margin-bottom:16px;align-items:flex-end;
  background:transparent;border:none;border-bottom:1px solid var(--line);
  padding:0 0 12px;box-shadow:none;border-radius:0;}
.filter-group{display:flex;flex-direction:column;gap:6px;}
.filter-group label{font-size:11px;color:var(--muted);font-weight:600;letter-spacing:.01em;}
.filter-group select,.filter-group input{padding:7px 10px;border:1px solid transparent;
  border-radius:var(--radius-sm);font-size:14px;font-family:inherit;background:var(--soft);
  color:var(--ink);min-width:130px;transition:border-color var(--dur-1) var(--ease),background var(--dur-1) var(--ease),box-shadow var(--dur-1) var(--ease);cursor:pointer;}
.filter-group select:hover,.filter-group input:hover{background:#fff;border-color:var(--blue-200);
  box-shadow:0 2px 8px rgba(18,18,18,.05);}
.filter-group select:focus,.filter-group input:focus{outline:none;background:#fff;border-color:var(--blue);
  box-shadow:0 0 0 3px var(--blue-100),0 2px 8px rgba(11,65,205,.08);}
/* Datepicker: balanced spacing, faint placeholder, minimalist calendar icon */
.filter-group input[type=date]{padding:7px 12px;}
.filter-group input[type=date]::-webkit-datetime-edit{color:var(--muted-2);}
.filter-group input[type=date]:focus::-webkit-datetime-edit{color:var(--ink);}
.filter-group input[type=date]::-webkit-calendar-picker-indicator{opacity:.4;cursor:pointer;
  transition:opacity var(--dur-1) var(--ease);}
.filter-group input[type=date]:hover::-webkit-calendar-picker-indicator{opacity:.75;}

/* ---------- Cards ---------- */
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow-1);padding:24px;margin-bottom:20px;
  transition:transform var(--dur-1) var(--ease),box-shadow var(--dur-1) var(--ease);}
.card:hover{box-shadow:var(--shadow-2);}

/* Stagger entrance for cards and MMX groups */
.card,.mmx-group{animation:rise var(--dur-2) var(--ease) both;}
#lj-detail .card:nth-child(1){animation-delay:.04s;}
#lj-detail .card:nth-child(2){animation-delay:.10s;}
#lj-detail .card:nth-child(3){animation-delay:.16s;}
#lj-detail .card:nth-child(4){animation-delay:.22s;}
/* LJ chart container — extra depth so it floats above the page bg */
#lj-detail .card{box-shadow:0 10px 30px rgba(0,0,0,.04);border:1px solid #e2e8f0;}
#lj-detail .card:hover{box-shadow:0 14px 36px rgba(0,0,0,.06);}
.mmx-group:nth-child(2){animation-delay:.05s;}
.mmx-group:nth-child(3){animation-delay:.10s;}
.mmx-group:nth-child(4){animation-delay:.15s;}

.card-head{display:flex;justify-content:space-between;align-items:center;
  margin-bottom:16px;flex-wrap:wrap;gap:10px;}
.card-title{font-weight:600;font-size:17px;color:var(--ink);}
.mut-badge{display:inline-block;font-weight:700;color:var(--blue);
  background:linear-gradient(180deg,#fff,var(--blue-50));
  border:1px solid var(--blue-200);border-radius:999px;padding:3px 12px;margin-left:2px;
  box-shadow:0 1px 2px rgba(11,65,205,.12),inset 0 1px 0 #fff;letter-spacing:.01em;white-space:nowrap;}
.chips{display:flex;gap:8px;flex-wrap:wrap;}
.chip{background:var(--line-2);border-radius:999px;padding:5px 13px;font-size:13px;
  color:var(--muted);font-weight:500;}
.chip b{color:var(--ink);font-weight:700;}
.n-chip{display:inline-flex;align-items:center;}
.n-chip .dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:6px;}
.n-chip .dot.ok{background:var(--green);} .n-chip .dot.low{background:var(--muted-2);}

/* LJ summary stats as mini-KPI cards (label on top, value bold below) */
.lj-kpis{display:flex;gap:10px;flex-wrap:wrap;align-items:center;}
.lj-kpis .kpi{display:flex;flex-direction:column;align-items:center;gap:3px;min-width:82px;padding:9px 16px;
  border-radius:16px;border:none;background:#eef2f8;text-align:center;}
/* text-indent compensates the trailing letter-spacing so the label sits dead-centre over the value */
.lj-kpis .kpi-label{font-size:10.5px;font-weight:700;letter-spacing:.1em;text-indent:.1em;color:var(--muted-2);text-transform:uppercase;}
.lj-kpis .kpi-val{font-size:18px;font-weight:700;color:var(--blue);letter-spacing:-.01em;line-height:1.05;font-variant-numeric:tabular-nums;}
/* N below CLSI-recommended 20 → de-emphasised value (still a KPI card like the others) */
.lj-kpis .kpi.kpi-low .kpi-val{color:var(--muted-2);}

/* ---------- MMX groups (label + cards on one row) ---------- */
.mmx-group{display:flex;align-items:center;gap:14px;margin-bottom:4px;padding:5px 10px;border-radius:10px;
  transition:background var(--dur-2) var(--ease),box-shadow var(--dur-2) var(--ease);}
/* แถว MMX ที่ถูกเลือก (group view) → พื้นเทาไอซ์ + เงาละมุน ขับกล่องพาสเทลด้านในให้ลอยเด่น */
.mmx-group:has(.mmx-head.active){background:var(--blue-100);
  box-shadow:inset 0 0 0 1px var(--blue-200),0 10px 24px rgba(11,65,205,.18),0 2px 6px rgba(11,65,205,.10);}
.mmx-head{flex-shrink:0;width:62px;font-size:12px;font-weight:700;white-space:nowrap;
  color:var(--blue);text-transform:uppercase;letter-spacing:.04em;cursor:pointer;
  padding:5px 8px;border:1px solid var(--blue-200);border-radius:6px;
  transition:background .15s,border-color .15s,box-shadow .15s;user-select:none;}
.mmx-head:hover{background:var(--blue-50);border-color:var(--blue);box-shadow:var(--shadow-1);}
.mmx-head.active{background:var(--blue);color:#fff;border-color:var(--blue);}
.mmx-head.mmx-static{cursor:default;border-color:var(--line);}
.mmx-head.mmx-static:hover{background:none;border-color:var(--line);box-shadow:none;}
.unc-card.unc-empty{opacity:.5;}
.unc-footer{margin-top:8px;padding:14px 18px;background:var(--card);border:1px solid var(--line);
  border-radius:var(--radius);font-size:13px;color:var(--ink);}
.unc-footer .unc-note{margin-top:8px;font-size:12px;color:var(--muted);line-height:1.55;}
.unc-footer .unc-note b{color:var(--ink);font-weight:600;}
.all-row{margin-bottom:6px;}
.all-head{display:inline-block;width:auto;padding:6px 16px;border:1px solid var(--line);}
.all-head:hover{border-color:var(--blue-200);}
.all-head.active{border-color:var(--blue);}
.group-banner{font-size:13px;font-weight:600;color:var(--blue);background:var(--blue-50);
  border-radius:var(--radius-sm);padding:10px 16px;margin-bottom:16px;}

/* ---------- Mini-card grid ---------- */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(185px,1fr));gap:10px;
  margin-bottom:24px;}
.mmx-group .grid{flex:1;margin-bottom:0;}
/* LJ overview: แถวกว้าง "พอดี" กับเนื้อหา เพื่อให้กรอบ active ไม่ลากยาวเกินการ์ด */
#page-lj .mmx-group{width:fit-content;max-width:100%;}
#page-lj .mmx-group .grid{display:flex;flex-wrap:wrap;flex:0 1 auto;gap:10px;}
#page-lj .mini-card{flex:0 0 180px;}
/* การ์ด mutation = โทนเทา/ฟ้าสไตล์ Roche (กลาง ๆ) ; สถานะหลุด Westgard บอกด้วยจุดแดงเล็ก */
.mini-card{background:#fbfcfe;border:1px solid #eceef3;border-radius:var(--radius-sm);
  padding:11px 16px;cursor:pointer;
  transition:box-shadow var(--dur-1) var(--ease),border-color var(--dur-1) var(--ease),transform var(--dur-1) var(--ease),background var(--dur-1) var(--ease);
  display:flex;align-items:center;justify-content:space-between;gap:8px;}
.mini-card:hover{background:var(--blue-50);box-shadow:var(--shadow-2);border-color:var(--blue-200);transform:translateY(-2px);}
/* กล่องที่ถูกเลือก (single view) → ขอบ/เรืองแสงน้ำเงิน Roche (กันขนาดขยับด้วย inset ring) */
.mini-card.selected{border-color:var(--blue);box-shadow:inset 0 0 0 2px var(--blue),0 4px 14px rgba(11,65,205,.18);}
.mini-mut{font-weight:600;font-size:13px;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.status-dot{width:8px;height:8px;border-radius:50%;background:var(--red);flex-shrink:0;}

/* ---------- Badges ---------- */
.badge{display:inline-flex;align-items:center;gap:4px;font-size:12px;padding:3px 10px;
  border-radius:999px;font-weight:600;width:fit-content;}
.badge.ok{background:var(--green-100);color:var(--green);}        /* upload */
.badge.del{background:#fdecea;color:#c0392b;}                     /* delete */
.badge.warn{background:#fff4e0;color:#b9770e;}                    /* outlier */
.badge.neutral{background:#eef1f5;color:#5b6b7f;}                 /* other */

/* ---------- Buttons ---------- */
.btn{display:inline-flex;align-items:center;gap:7px;padding:9px 16px;border-radius:var(--radius-sm);
  border:1px solid transparent;background:var(--grad-blue);color:#fff;cursor:pointer;
  font-size:14px;font-weight:600;font-family:inherit;
  box-shadow:0 6px 14px -6px rgba(11,65,205,.5);transition:transform var(--dur-1) var(--ease),box-shadow var(--dur-1) var(--ease);}
.btn:hover{transform:translateY(-2px);box-shadow:0 10px 22px -6px rgba(11,65,205,.55);}
.btn.secondary{background:#fff;color:var(--blue);}
.btn.secondary:hover{background:var(--blue-50);}
.btn .material-symbols-outlined{font-size:18px;}
.export-bar{display:flex;gap:10px;}
.btn.ghost{background:#fff;border:1.5px solid var(--blue-200);color:var(--blue);font-weight:600;box-shadow:none;}
.btn.ghost .material-symbols-outlined{color:var(--blue);}
.btn.ghost:hover{background:var(--blue-50);border-color:var(--blue);color:var(--blue);
  box-shadow:0 4px 12px rgba(11,65,205,.12);transform:translateY(-1px);}

/* ---------- Uncertainty cards ---------- */
.unc-card{display:flex;flex-direction:column;gap:8px;margin-bottom:0;}
.unc-mut{font-weight:600;font-size:15px;color:var(--ink);}
.unc-value{font-size:30px;font-weight:800;letter-spacing:-.02em;color:var(--blue);
  font-variant-numeric:tabular-nums;display:flex;flex-direction:column;align-items:center;gap:2px;line-height:1.1;}
.unc-num{background:var(--grad-blue);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;}
.unc-unit{font-size:13px;font-weight:500;color:var(--muted-2);}
.unc-meta{font-size:12px;color:var(--muted);display:flex;flex-direction:column;gap:2px;align-items:center;text-align:center;}
.unc-range{font-size:13px;font-weight:700;color:var(--navy-2);background:var(--blue-100);
  border-radius:8px;padding:8px 10px;font-variant-numeric:tabular-nums;text-align:center;line-height:1.45;}
/* card header + N/lot/date tooltip */
.unc-cardhead{display:flex;justify-content:space-between;align-items:flex-start;gap:8px;}
.unc-info{position:relative;display:inline-flex;color:var(--muted-2);cursor:help;}
.unc-info .material-symbols-outlined{font-size:18px;}
.unc-info:hover{color:var(--blue);}
.unc-tip{position:absolute;top:24px;right:0;z-index:30;width:max-content;max-width:230px;
  background:var(--ink);color:#fff;font-size:11.5px;font-weight:500;line-height:1.6;
  padding:9px 11px;border-radius:8px;box-shadow:var(--shadow-2);text-align:left;white-space:normal;
  opacity:0;visibility:hidden;transform:translateY(-4px);transition:opacity var(--dur-1) var(--ease),transform var(--dur-1) var(--ease);}
.unc-info:hover .unc-tip,.unc-info:focus .unc-tip{opacity:1;visibility:visible;transform:translateY(0);}
/* MU cards: equal fixed width across all groups (like LJ mini-cards), wide enough for IC (Ex28) MMX1 */
#page-unc .mmx-group{width:fit-content;max-width:100%;}
#page-unc .mmx-group .grid{display:flex;flex-wrap:wrap;flex:0 1 auto;gap:12px;}
#page-unc .unc-card{flex:0 0 240px;}
.unc-formula{font-size:12px;color:var(--muted-2);line-height:1.5;margin-top:10px;padding-top:10px;border-top:1px solid var(--line);}

/* ---------- Lot comparison ---------- */
/* lot selectors live IN the column headers (no top card) — label on top, premium dropdown below */
.cmp-table th.cmp-th{vertical-align:bottom;padding-top:14px;padding-bottom:14px;}
.cmp-th-label{display:block;font-size:11.5px;font-weight:600;color:var(--slate);
  text-transform:none;letter-spacing:.01em;margin-bottom:8px;line-height:1.2;}
/* high specificity so the column header aligns with its CT values (beats the base th text-align) */
.cmp-table thead th.cmp-th-base{text-align:right;}
.cmp-table thead th.cmp-th-cmp{text-align:left;position:relative;}
/* thin flow arrow sitting on the border between Baseline → Compared (Previous → Current) */
.cmp-th-cmp .cmp-flow{position:absolute;left:0;bottom:11px;transform:translateX(-50%);
  color:#cbd5e1;display:flex;align-items:center;pointer-events:none;}
.cmp-th-cmp .cmp-flow svg{width:22px;height:22px;}
/* compared CT values mirror left so both CT columns hug the centre arrow */
.cmp-table td.cmp-ct-l{text-align:left;font-variant-numeric:tabular-nums;font-feature-settings:"tnum";}
/* premium in-table dropdown */
.lot-dd{position:relative;display:inline-block;text-align:left;}
.lot-dd-btn{display:inline-flex;align-items:center;gap:6px;cursor:pointer;background:#fff;
  border:1px solid #E2E8F0;border-radius:6px;padding:6px 10px;font:inherit;line-height:1;
  text-transform:none;letter-spacing:0;
  transition:border-color var(--dur-1) var(--ease),box-shadow var(--dur-1) var(--ease);}
.lot-dd-btn:hover{border-color:var(--blue);}
.lot-dd.open .lot-dd-btn{border-color:var(--blue);box-shadow:0 0 0 3px var(--blue-100);}
.lot-dd .lot-name{color:var(--blue);font-weight:600;font-size:13px;}
.lot-dd .lot-n{color:var(--muted-2);font-weight:400;font-size:12px;}
.lot-dd-caret{width:14px;height:14px;color:var(--muted-2);margin-left:1px;flex:none;
  transition:transform var(--dur-1) var(--ease);}
.lot-dd.open .lot-dd-caret{transform:rotate(180deg);}
.lot-dd-menu{position:absolute;top:calc(100% + 7px);left:0;z-index:40;min-width:max(100%,150px);
  background:#fff;border:1px solid var(--line);border-radius:10px;padding:6px;
  box-shadow:0 14px 34px rgba(15,23,42,.16);
  opacity:0;visibility:hidden;transform:translateY(-5px);
  transition:opacity var(--dur-1) var(--ease),transform var(--dur-1) var(--ease),visibility var(--dur-1) var(--ease);}
.cmp-th-cmp .lot-dd-menu{left:auto;right:0;}   /* keep menu inside the table on the right column */
.lot-dd.open .lot-dd-menu{opacity:1;visibility:visible;transform:translateY(0);}
.lot-dd-opt{display:flex;align-items:center;gap:10px;width:100%;cursor:pointer;background:none;
  border:0;border-radius:6px;padding:8px 10px;text-align:left;font:inherit;
  text-transform:none;letter-spacing:0;white-space:nowrap;
  transition:background var(--dur-1) var(--ease);}
.lot-dd-opt:hover{background:var(--blue-50);}
.lot-dd-opt.sel{background:var(--blue-100);}
.lot-dd-opt .lot-n{margin-left:auto;}
.lot-dd-check{width:14px;height:14px;color:var(--blue);flex:none;}
.cmp-note{font-size:12px;color:var(--muted-2);line-height:1.5;margin-top:14px;padding-top:12px;border-top:1px solid var(--line);}
/* in-table diverging Δ chart: continuous zero axis, left=decrease(red), right=increase(green) */
.cmp-table th.cmp-viz-h{min-width:180px;text-align:center;}   /* legend centers over the zero axis */
.cmp-table td.cmp-viz{min-width:180px;padding:10px 16px;position:relative;}
/* one continuous Zero Axis line through the whole column (per-cell, full height → cells abut) */
.cmp-table td.cmp-viz::before{content:"";position:absolute;left:50%;top:0;bottom:0;width:1px;
  margin-left:-.5px;background:#cdd5e0;}
.cmp-diverge{position:relative;height:16px;}
.cmp-dbar{position:absolute;top:50%;transform:translateY(-50%);height:8px;
  transition:width var(--dur-2) var(--ease);}   /* flush at axis, rounded outer tip */
.cmp-dbar.pos{left:50%;background:var(--bar-pos);border-radius:0 4px 4px 0;}
.cmp-dbar.neg{right:50%;background:var(--bar-neg);border-radius:4px 0 0 4px;}
.cmp-key{display:inline-block;width:9px;height:9px;border-radius:2px;vertical-align:middle;margin-right:3px;}
.cmp-key.pos{background:var(--bar-pos);}
.cmp-key.neg{background:var(--bar-neg);}
.cmp-table{width:100%;border-collapse:collapse;font-size:14px;}
.cmp-table thead th{color:var(--slate);font-weight:600;font-size:11px;letter-spacing:.05em;
  text-transform:uppercase;text-align:left;padding:10px 16px;border-bottom:2px solid var(--line);}
.cmp-table th.num{text-align:right;}
.cmp-table .th-sub{display:block;font-size:11px;font-weight:600;color:var(--blue);
  text-transform:none;letter-spacing:0;margin-top:3px;}
.cmp-table tbody tr{transition:background var(--dur-1) var(--ease);}
.cmp-table tbody td{padding:13px 16px;border-bottom:1px solid var(--line-2);color:var(--ink);}
.cmp-table tbody tr:nth-child(even){background:#f9fafb;}
.cmp-table tbody tr:hover{background:var(--blue-50);}
.cmp-table .mut-cell{font-weight:600;letter-spacing:-.01em;}
.cmp-table .num{text-align:right;font-variant-numeric:tabular-nums;font-feature-settings:"tnum";}
.cmp-table .chg-pos{color:var(--chg-pos);font-weight:600;}
.cmp-table .chg-neg{color:var(--chg-neg);font-weight:600;}
.cmp-table .chg-zero{color:var(--muted-2);}
.cmp-table .chg-ico{font-size:9px;margin-right:5px;vertical-align:middle;line-height:1;}

/* ---------- Tables ---------- */
table{width:100%;border-collapse:collapse;font-size:14px;}
thead th{color:var(--muted);font-weight:600;font-size:12px;letter-spacing:.03em;
  text-transform:uppercase;text-align:left;padding:10px 14px;border-bottom:2px solid var(--line);}
tbody td{padding:11px 14px;border-bottom:1px solid var(--line-2);color:var(--ink);}
/* Scoped to .dash-t's clickable data rows only — the "No runs for this
   selection" / "From date is after To date" message rows in the same table
   are not .dash-row and must not light up on hover, since hovering them does
   nothing. */
.dash-t tbody tr.dash-row:hover{background:var(--blue-50);}
.empty-note{color:var(--muted-2);padding:14px;font-style:italic;}
.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;
  padding:46px 20px;color:var(--muted-2);text-align:center;}
.empty-state .material-symbols-outlined{font-size:42px;color:var(--blue-200);
  font-variation-settings:'opsz' 48,'wght' 300,'FILL' 0,'GRAD' 0;}
.empty-state p{font-size:14px;color:var(--muted);max-width:340px;}

/* ---------- LJ chart ---------- */
.lj-chart-wrap{position:relative;height:400px;width:100%;}

/* custom LJ tooltip (QCloud-style card) */
.lj-tooltip{position:absolute;z-index:50;pointer-events:none;opacity:0;transition:opacity .12s;
  transform:translate(-50%,-115%);background:#fff;border:1px solid var(--line);
  border-radius:var(--radius);box-shadow:var(--shadow-2);padding:14px 18px;font-size:13px;
  line-height:1.75;min-width:190px;white-space:nowrap;}
.lj-tooltip .tt-row{color:var(--muted);} .lj-tooltip .tt-row b{color:var(--ink);font-weight:600;}
.lj-tooltip .tt-rule{margin-top:6px;padding-top:6px;border-top:1px solid var(--line-2);font-weight:700;}
.lj-tooltip .tt-rule.reject{color:var(--red);} .lj-tooltip .tt-rule.warn{color:var(--yellow);}

/* Westgard event rows */
.wg-list{display:flex;flex-direction:column;gap:8px;margin-top:12px;}
.wg-row{display:flex;align-items:center;gap:10px;font-size:14px;}
.wg-badge{display:inline-flex;align-items:center;gap:5px;border-radius:999px;padding:4px 13px;
  font-weight:600;font-size:13px;white-space:nowrap;border:1px solid transparent;}
.wg-badge.reject{background:var(--red-100);color:var(--red-600);border-color:#f6b7be;}
.wg-badge.warn{background:var(--yellow-bg);color:var(--yellow);border-color:var(--yellow-bd);}
.wg-detail{color:var(--ink);}

/* ---------- Skeleton loading ---------- */
.sk{background:linear-gradient(90deg,var(--line-2) 25%,#ececec 37%,var(--line-2) 63%);
  background-size:900px 100%;animation:shimmer 1.4s infinite linear;border-radius:var(--radius-sm);}
.sk-head{display:flex;justify-content:space-between;margin-bottom:24px;}
.sk-line{height:26px;} .sk-head .sk-line:last-child{height:36px;}
.sk-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(185px,1fr));gap:10px;margin-bottom:24px;}
.sk-chip{height:34px;} .sk-chart{height:400px;border-radius:var(--radius);}

/* ---------- Mobile ---------- */
#menu-toggle{display:none;position:fixed;top:16px;left:16px;z-index:30;background:var(--blue);
  color:#fff;border:none;border-radius:var(--radius-sm);width:44px;height:44px;cursor:pointer;
  box-shadow:var(--shadow-2);align-items:center;justify-content:center;}
#backdrop{display:none;position:fixed;inset:0;z-index:15;background:rgba(18,18,18,.38);
  opacity:0;transition:opacity var(--dur-1) var(--ease);}
#backdrop.show{opacity:1;}
@media(max-width:1024px){
  #sidebar{width:220px;} #content{padding:28px 24px;}
}
@media(max-width:768px){
  #sidebar{position:fixed;left:-300px;z-index:20;width:280px;
    transition:left var(--dur-1) var(--ease);box-shadow:var(--shadow-3);}
  #sidebar.open{left:0;} #menu-toggle{display:flex;} #backdrop{display:block;}
  #content{padding:72px 16px 28px;}
  .grid{grid-template-columns:repeat(2,1fr);}
  .page-head{flex-direction:column;align-items:flex-start;}
  .mmx-group{flex-direction:column;align-items:stretch;gap:8px;}
  #page-lj .mmx-group{width:auto;} #page-lj .mini-card{flex:1 1 auto;}
  #page-unc .mmx-group{width:auto;} #page-unc .unc-card{flex:1 1 200px;}
  .cmp-table,table{display:block;overflow-x:auto;white-space:nowrap;}
}
@media(max-width:460px){ .grid{grid-template-columns:1fr;} }

/* ---------- Print / PDF ---------- */
#print-header{display:none;}
/* Paper-only elements. These must be declared BEFORE @media print: both rules
   are one class deep, so the later one in the file wins, and a `display:none`
   sitting after the print block silently blanks them on paper. */
.unc-print-tbl{display:none;width:100%;border-collapse:collapse;font-size:10.5px;margin-top:4px;}
.unc-print-tbl th{text-align:left;padding:5px 6px;border-bottom:1.5px solid var(--line);
  font-size:8.5px;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--slate);}
.unc-print-tbl td{padding:5px 6px;border-bottom:1px solid var(--line-2);color:var(--ink);}
.unc-print-tbl .num{text-align:right;font-variant-numeric:tabular-nums;}
.unc-print-tbl td.mut{font-weight:600;}
.unc-print-tbl td.b{font-weight:700;color:var(--blue);}
.print-foot{display:none;}
/* Overview: the scope line and the exclusion list restate on paper what the
   controls and the "(n excluded)" hover carry on screen. */
.dash-print-scope,.dash-print-exc{display:none;}

@media print{
  /* State the paper. Without size, the page follows the browser/printer default,
     which is Letter in a US locale — the LJ layout is tuned to fit one MMX group
     per A4 sheet, and on Letter the last chart of a group can spill. */
  @page{size:A4 portrait;margin:10mm;}
  *{-webkit-print-color-adjust:exact;print-color-adjust:exact;}
  /* body is display:flex for the sidebar layout. _fillPrintHeader() inserts
     #print-header as body's first child, which made it a flex sibling of
     #content — the header sat in a column on the left and every chart was
     squeezed into the right-hand strip. Print stacks instead. */
  body{background:#fff;display:block;}
  #content{padding:0;max-width:none;width:auto;}
  /* Cards animate in with `rise`. Print can capture them mid-animation, which
     leaves them half-transparent on paper. Nothing should animate on paper. */
  *,*::before,*::after{animation:none!important;transition:none!important;opacity:1!important;}
  .page:not(.active){display:none;}
  #sidebar,#menu-toggle,#filter-bar,#audit-filter,.export-bar,#backdrop,
  .de-pager,#de-bulkbar,#de-drop,#de-progress,.page-head{display:none!important;}
  #print-header{display:block;margin-bottom:8px;border-bottom:2px solid var(--blue);padding-bottom:6px;}
  #print-header .print-logo{height:28px;width:auto;}
  #print-header .print-h-title{font-size:14px;font-weight:700;color:var(--navy-2);margin-top:4px;}
  #print-header .print-h-ctx{font-size:10px;color:#444;margin-top:2px;}
  /* A4 portrait leaves a ~718px content box, which is under the 768px mobile
     breakpoint — so the phone rules apply on paper. The one that does damage:
     tables become `display:block; overflow-x:auto`, and a scroll container
     cannot be scrolled on a sheet of paper. Reagent Lots Variation lost its
     whole Δ trend column off the right edge, scrollbar and all. */
  .cmp-table,table{display:table!important;overflow:visible!important;white-space:normal!important;}
  /* Audit Trail wraps its table in an inline `overflow-x:auto` div, which the
     rule above cannot reach. Same clipping risk, so open it too. */
  #page-audit .card,#page-audit .card>div,.de-table-wrap,.de-batch-body{overflow:visible!important;}
  .card,.mini-card{box-shadow:none;border:1px solid var(--line);break-inside:avoid;}
  table tr,.mmx-group{break-inside:avoid;}
  /* The two lot pickers are controls; on paper they are just the lot numbers. */
  #page-lot .lot-dd-btn{border:none;background:none;padding:0;box-shadow:none;}
  #page-lot .lot-dd-caret,#page-lot .lot-dd-menu{display:none!important;}
  #page-lot .card{padding:10px 12px;}
  #page-lot .cmp-table{font-size:11px;}
  #page-lot .cmp-table th.cmp-th{padding-top:4px;padding-bottom:8px;}
  #page-lot .cmp-table tbody td{padding:7px 10px;}
  #page-lot .cmp-table td.cmp-viz{padding:7px 10px;}
  #page-lot .lot-dd .lot-name{font-size:11px;}
  #page-lot .lot-dd .lot-n{font-size:10px;}
  #page-lot .cmp-note{font-size:9px;margin-top:10px;padding-top:8px;}
  /* Overview. The Test dropdown and the two date inputs are controls — hidden
     on paper, and .dash-print-scope states their values instead. The exclusion
     reasons live in a title= hover, which paper cannot show, so they print as
     a list under the table. */
  #page-dash .dash-ctl,#page-dash .dash-win{display:none!important;}
  .dash-print-scope{display:block;margin-top:8px;font-size:10px;color:var(--muted);
    font-variant-numeric:tabular-nums;}
  .dash-print-exc{display:block;margin-top:8px;padding-top:7px;border-top:1px solid var(--line-2);
    font-size:9px;color:var(--muted);line-height:1.5;}
  .dash-print-exc b{color:var(--ink);font-weight:600;}
  #page-dash .dash-exc{border-bottom:none;}
  /* Two instruments side by side: A4 portrait is under the 900px breakpoint
     that stacks them, and stacked cards spill onto a second sheet. */
  #page-dash .dash-grid{display:grid!important;grid-template-columns:1fr 1fr!important;gap:10px;}
  #page-dash .dash-card{padding:10px;break-inside:avoid;}
  #page-dash .dash-img{width:74px;flex:0 0 74px;}
  #page-dash .dash-sn{font-size:12px;}
  #page-dash .dash-role{font-size:10px;}
  #page-dash .dash-kpis{margin:9px 0 8px;gap:18px;}
  #page-dash .dash-kpi-v{font-size:17px;}
  #page-dash .dash-kpi-l{font-size:9px;}
  #page-dash .dash-t{font-size:10px;}
  #page-dash .dash-t th{font-size:8.5px;padding:5px 4px;}
  #page-dash .dash-t td{padding:6px 4px;}
  #page-dash .dash-range{font-size:9px;}
  #page-dash .dash-pill{font-size:8.5px;padding:1px 6px;}
  /* One MMX group per sheet. The break goes on groups that FOLLOW a group, not
     on every group with an exception for the first: `:first-of-type` counted
     the display:none .group-banner as the first div, so the real first group
     never matched it and every print started with a blank page. */
  .lj-print-group{break-inside:avoid;}
  .lj-print-group + .lj-print-group{break-before:page;}
  .group-banner{display:none;}
  .lj-chart-wrap{height:200px;}
  .lj-overview{display:none!important;}
  /* Tighten LJ card chrome so 4 cards fit one A4 page */
  .lj-print-group .card{padding:4px 10px;margin-bottom:3px;break-inside:auto;}
  .lj-print-group .card-head{margin-bottom:2px;gap:4px;}
  .lj-print-group .lj-kpis{gap:4px;}
  .lj-print-group .lj-kpis .kpi{padding:1px 6px;min-width:44px;border-radius:4px;gap:0px;}
  .lj-print-group .lj-kpis .kpi-val{font-size:10px;line-height:1;}
  .lj-print-group .lj-kpis .kpi-label{font-size:7.5px;}
  .lj-print-group .card-title{font-size:11px;}
  .lj-print-group .lj-chart-wrap{height:130px;overflow:hidden;}
  .lj-print-group .lj-chart-wrap canvas{height:130px!important;width:100%!important;display:block;}
  [id^="wg-events-"]{margin-top:4px!important;font-size:9px;}
  [id^="wg-events-"] .wg-list{margin-top:1px;gap:1px;}
  [id^="wg-events-"] .wg-row{font-size:9px;}
  [id^="wg-events-"] .wg-badge{padding:1px 5px;font-size:8px;}
  .lj-print-group .wg-list{margin-top:1px;gap:1px;}
  .lj-print-group .wg-row{font-size:9px;}
  .lj-print-group .wg-badge{padding:1px 5px;font-size:8px;}
  /* Uncertainty prints as a table, not as the card grid. See renderUnc(): the
     cards hide N, lot count, uRW and U behind a hover tooltip that paper
     cannot show, and ten cards ran onto a second sheet. */
  #page-unc .mmx-group{display:none!important;}
  .unc-print-tbl{display:table;}
  .unc-footer{margin-top:12px;padding:10px 0 0;background:none;border:none;border-top:1px solid var(--line);}
  .unc-footer .unc-note,.unc-footer .unc-formula{font-size:9px;line-height:1.45;margin-top:5px;padding-top:0;border:none;}
  /* Signature line + page number, appended per sheet by _fillPrintFooters(). */
  .print-foot{display:block;margin-top:16px;padding-top:9px;border-top:1px solid var(--line);
    break-inside:avoid;}
  .pf-sign{display:flex;justify-content:space-between;gap:20px;font-size:10.5px;color:var(--ink);}
  .pf-page{text-align:center;font-size:9px;color:var(--muted-2);margin-top:9px;}
}

/* ---------- High-end motion primitives ---------- */
@keyframes rise{from{opacity:0;transform:translateY(10px);}to{opacity:1;transform:none;}}
@keyframes fade{from{opacity:0;}to{opacity:1;}}
@keyframes pageIn{from{opacity:0;transform:translateY(6px);}to{opacity:1;transform:none;}}
@keyframes shimmer{from{background-position:-450px 0;}to{background-position:450px 0;}}
@keyframes deBounce{0%,100%{transform:translateY(0);}50%{transform:translateY(-7px);}}

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;scroll-behavior:auto!important;}
}

/* ---------- Data Entry ---------- */
#page-de .page-head{margin-bottom:22px;}
/* Drop zone — soft slate dashes, lift on hover, pastel + bouncing cloud on dragover */
.de-drop{border:2px dashed #cbd5e1;border-radius:14px;padding:38px 32px;text-align:center;
  color:var(--slate);cursor:pointer;background:var(--soft);
  transition:border-color var(--dur-1) var(--ease),background var(--dur-1) var(--ease),box-shadow var(--dur-1) var(--ease);}
.de-drop:hover{border-color:var(--blue-200);background:#fff;box-shadow:var(--shadow-1);}
.de-drop.over{border-color:var(--blue);background:var(--blue-50);box-shadow:0 0 0 4px var(--blue-100);}
.de-drop .material-symbols-outlined{font-size:44px;display:block;margin-bottom:10px;color:var(--blue);
  font-variation-settings:'opsz' 48,'wght' 300,'FILL' 0,'GRAD' 0;transition:transform var(--dur-1) var(--ease);}
.de-drop.over .material-symbols-outlined{animation:deBounce .65s var(--ease) infinite;}
.de-drop p{font-size:14px;color:var(--slate);}
.de-pick{color:var(--blue);font-weight:600;cursor:pointer;border-bottom:1px solid var(--blue-200);
  transition:border-color var(--dur-1) var(--ease);}
.de-pick:hover{border-bottom-color:var(--blue);}
.de-progress{margin:14px 0;font-size:13px;line-height:1.7}
.de-line{padding:2px 0;border-bottom:1px solid #f0f2f5}
.de-table-wrap{margin-top:18px;overflow:auto}
/* Specimen filter control */
.de-tbl-ctl{margin:10px 0 16px;font-size:13px;color:var(--muted);display:flex;align-items:center;gap:14px;flex-wrap:wrap;}
.de-ctl-group{display:inline-flex;align-items:center;gap:7px;}
.de-tbl-ctl select,.de-tbl-ctl input[type=date]{padding:6px 11px;border:1px solid var(--line);border-radius:8px;background:var(--soft);
  font-family:inherit;font-size:13px;color:var(--ink);cursor:pointer;
  transition:border-color var(--dur-1) var(--ease),box-shadow var(--dur-1) var(--ease);}
.de-tbl-ctl select:hover,.de-tbl-ctl input[type=date]:hover{border-color:var(--blue-200);}
.de-tbl-ctl select:focus,.de-tbl-ctl input[type=date]:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 3px var(--blue-100);}
.de-tbl-ctl input[type=date]::-webkit-calendar-picker-indicator{opacity:.45;cursor:pointer;transition:opacity var(--dur-1) var(--ease);}
.de-tbl-ctl input[type=date]:hover::-webkit-calendar-picker-indicator{opacity:.8;}
.de-date-clear{display:inline-flex;align-items:center;gap:4px;border:1px solid var(--line);background:#fff;
  border-radius:8px;padding:6px 11px 6px 8px;font-size:12px;color:var(--muted);cursor:pointer;font-family:inherit;
  transition:border-color var(--dur-1) var(--ease),color var(--dur-1) var(--ease);}
.de-date-clear:hover{border-color:var(--blue-200);color:var(--blue);}
.de-date-clear .material-symbols-outlined{font-size:16px;}
/* Batch card + header — more breathing room */
.de-batch{border:1px solid var(--line);border-radius:10px;margin-bottom:14px;overflow:hidden;background:var(--card);}
.de-batch-h{display:flex;align-items:center;gap:10px;padding:13px 16px;background:#f9fafb;cursor:default;
  font-size:13px;color:var(--ink);line-height:1.5;transition:background var(--dur-1) var(--ease);}
.de-excluded-h{cursor:pointer;}
.de-excluded-h:hover{background:#f3f5f9;}
.de-batch-h b{font-weight:600;}
.de-batch-h .de-del{margin-left:auto}
.de-caret{transition:transform var(--dur-1) var(--ease);color:var(--muted-2);}
.de-batch.collapsed .de-caret{transform:rotate(-90deg)}
.de-batch.collapsed .de-batch-body{display:none}
.de-batch-body{overflow-x:auto}
/* Dense table — horizontal rules only, breathable rows, quiet uppercase headers */
.de-grid{border-collapse:collapse;width:100%;font-size:12.5px}
.de-grid th,.de-grid td{padding:9px 14px;white-space:nowrap;text-align:left;border-bottom:1px solid var(--line-2)}
.de-grid th{background:#fafbfc;position:sticky;top:0;z-index:1;text-transform:uppercase;font-size:11px;
  font-weight:600;letter-spacing:.05em;color:var(--slate);border-bottom:2px solid var(--line)}
.de-grid tbody tr{transition:background var(--dur-1) var(--ease)}
.de-grid tbody tr:hover{background:var(--blue-50)}
.de-grid td.ct{text-align:right;font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}
/* Specimen badges — Plasma (blue) / Tissue (green), instant visual sort */
.de-spec-badge{display:inline-flex;align-items:center;font-size:11px;font-weight:600;letter-spacing:.02em;
  padding:2px 10px;border-radius:999px;line-height:1.6;white-space:nowrap;}
.de-spec-plasma{background:var(--blue-100);color:var(--blue);}
.de-spec-tissue{background:var(--green-100);color:var(--green);}
.de-spec-other{background:#eef1f5;color:var(--slate);}
/* Muted delete — text+icon, soft until hover */
.de-del{border:1px solid transparent;background:transparent;color:#b4434f;border-radius:8px;
  padding:5px 10px;cursor:pointer;font-size:12px;font-weight:600;display:inline-flex;align-items:center;gap:5px;
  transition:background var(--dur-1) var(--ease),color var(--dur-1) var(--ease);}
.de-del:hover{background:var(--red-100);color:var(--red-600);}
.de-empty{color:#8a97a8;padding:20px;text-align:center}
/* Privacy reassurance — quiet line at the very bottom of the page */
.de-privacy{display:flex;align-items:center;justify-content:center;gap:6px;margin:26px 2px 6px;
  font-size:12px;color:var(--muted-2);line-height:1.5;text-align:center;}
.de-privacy .material-symbols-outlined{font-size:15px;color:var(--muted-2);
  font-variation-settings:'opsz' 20,'wght' 400,'FILL' 0,'GRAD' 0;}
/* Pagination bar — 3 zones: rows-per-page · summary · page nav */
.de-pager{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin:16px 2px 4px;font-size:13px;color:var(--muted);}
.de-pager-left{display:flex;align-items:center;gap:8px;flex:1 1 200px;}
.de-pager-left label{color:var(--muted);white-space:nowrap;}
.de-pager-left select{padding:6px 11px;border:1px solid var(--line);border-radius:8px;background:var(--soft);
  font-family:inherit;font-size:13px;color:var(--ink);cursor:pointer;
  transition:border-color var(--dur-1) var(--ease),box-shadow var(--dur-1) var(--ease);}
.de-pager-left select:hover{border-color:var(--blue-200);}
.de-pager-left select:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 3px var(--blue-100);}
.de-pager-mid{flex:0 1 auto;text-align:center;color:var(--muted-2);font-size:12.5px;white-space:nowrap;}
.de-pager-mid b{color:var(--ink);font-weight:600;font-variant-numeric:tabular-nums;}
.de-pager-right{display:flex;align-items:center;gap:4px;flex:1 1 200px;justify-content:flex-end;}
.de-pg-btn{min-width:32px;height:32px;padding:0 6px;display:inline-flex;align-items:center;justify-content:center;
  border:1px solid transparent;background:transparent;color:var(--muted);border-radius:8px;cursor:pointer;
  font-family:inherit;font-size:13px;font-weight:600;font-variant-numeric:tabular-nums;
  transition:background var(--dur-1) var(--ease),color var(--dur-1) var(--ease);}
.de-pg-btn:hover:not(:disabled):not(.active){background:var(--blue-50);color:var(--blue);}
.de-pg-btn.active{background:var(--blue);color:#fff;cursor:default;}
.de-pg-btn:disabled{color:var(--muted-2);opacity:.4;cursor:not-allowed;}
.de-pg-btn .material-symbols-outlined{font-size:20px;}
.de-pg-ellipsis{min-width:22px;text-align:center;color:var(--muted-2);user-select:none;}
/* Sticky pinned checkbox column — stays left while CT columns scroll under */
.de-grid input[type=checkbox]{width:15px;height:15px;accent-color:var(--blue);cursor:pointer;vertical-align:middle;margin:0;}
.de-col-check{width:42px;text-align:center;padding-left:16px;padding-right:6px;
  position:sticky;left:0;z-index:2;background:#fff;box-shadow:9px 0 14px -10px rgba(18,18,18,.18);}
.de-grid thead .de-col-check{z-index:3;background:#fafbfc;}
.de-grid tbody tr:hover .de-col-check{background:var(--blue-50);}
.de-excl-row .de-col-check{background:#fcfcfd;}

/* Floating bulk-action bar — slides up when rows are selected */
#de-bulkbar{position:fixed;left:50%;bottom:-90px;transform:translateX(-50%);z-index:900;
  display:flex;align-items:center;gap:16px;background:var(--ink);color:#fff;
  padding:11px 12px 11px 22px;border-radius:14px;box-shadow:var(--shadow-3);
  opacity:0;visibility:hidden;
  transition:bottom var(--dur-2) var(--ease),opacity var(--dur-2) var(--ease),visibility var(--dur-2) var(--ease);}
#de-bulkbar.show{bottom:28px;opacity:1;visibility:visible;}
.de-bb-count{font-size:13.5px;color:#cdd6e4;letter-spacing:.01em;white-space:nowrap;}
.de-bb-count b{color:#fff;font-weight:700;}
.de-bb-actions{display:flex;gap:8px;}
#de-bulkbar button{display:inline-flex;align-items:center;gap:6px;border:none;cursor:pointer;
  font-family:inherit;font-size:13px;font-weight:600;border-radius:9px;padding:8px 14px;
  transition:background var(--dur-1) var(--ease);}
#de-bulkbar .material-symbols-outlined{font-size:18px;}
.de-bb-excl,.de-bb-rest{background:rgba(255,255,255,.14);color:#fff;}
.de-bb-excl:hover,.de-bb-rest:hover{background:rgba(255,255,255,.24);}
.de-bb-del{background:var(--red);color:#fff;}
.de-bb-del:hover{background:#e11d48;}
.de-bb-clear{background:transparent;color:#9aa6b8;padding:8px;}
.de-bb-clear:hover{background:rgba(255,255,255,.12);color:#fff;}
/* ---------- Delete confirm modal ---------- */
.de-modal-ov{position:fixed;inset:0;background:rgba(15,23,42,.4);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);
  display:flex;align-items:center;justify-content:center;z-index:1000;animation:fade var(--dur-1) var(--ease);}
.de-modal{background:#fff;border-radius:16px;width:min(440px,92vw);padding:24px;box-shadow:var(--shadow-3);
  animation:modalPop var(--dur-2) var(--ease);}
@keyframes modalPop{from{opacity:0;transform:translateY(8px) scale(.985);}to{opacity:1;transform:none;}}
.de-modal-h{display:flex;align-items:center;gap:9px;font-size:17px;font-weight:700;color:#c0392b;letter-spacing:-.01em}
.de-modal-h .material-symbols-outlined{font-size:22px}
/* Users/auth modals: charcoal title + brand-blue icon (not the danger red) */
.um .de-modal-h{color:#1e293b;}
.um .de-modal-h .material-symbols-outlined{color:var(--blue);}
.de-modal-msg{margin:10px 0 16px;font-size:13px;color:#3a4759;line-height:1.5;white-space:pre-line}
.de-modal-label{font-size:13px;font-weight:600;color:#2a3441;margin-bottom:8px}
.de-req{color:#c0392b}
.de-reasons{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:10px}
.de-reason-chip{border:1px solid #d3dbe6;background:#f7f9fc;color:#3a4759;border-radius:14px;padding:4px 10px;font-size:12px;cursor:pointer;transition:.12s}
.de-reason-chip:hover{border-color:#0b41cd;color:#0b41cd}
.de-reason-chip.sel{background:#0b41cd;border-color:#0b41cd;color:#fff}
.de-reason-tx{width:100%;box-sizing:border-box;border:1px solid #d3dbe6;border-radius:8px;padding:8px 10px;font-size:13px;font-family:inherit;resize:vertical}
.de-reason-tx:focus{outline:none;border-color:#0b41cd}
.de-modal-btns{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}
.de-btn-cancel{border:none;background:transparent;color:var(--muted);border-radius:8px;padding:9px 16px;font-size:13px;font-weight:600;font-family:inherit;cursor:pointer;transition:background var(--dur-1) var(--ease),color var(--dur-1) var(--ease)}
.de-btn-cancel:hover{background:var(--line-2);color:var(--ink)}
.de-btn-confirm{border:none;background:#c0392b;color:#fff;border-radius:8px;padding:9px 18px;font-size:13px;font-weight:600;font-family:inherit;cursor:pointer;transition:background var(--dur-1) var(--ease)}
.de-btn-confirm:hover{background:#a93226}
.de-btn-confirm:disabled{background:#e0a9a3;cursor:not-allowed}
/* Primary modal button (users/auth) — was unstyled (default browser look) */
.de-btn-ok{border:none;background:var(--blue);color:#fff;border-radius:8px;padding:9px 18px;font-size:13px;font-weight:600;font-family:inherit;cursor:pointer;display:inline-flex;align-items:center;gap:6px;transition:background var(--dur-1) var(--ease),box-shadow var(--dur-1) var(--ease)}
.de-btn-ok:hover{background:#0934a6;box-shadow:0 4px 12px rgba(11,65,205,.25)}
.de-btn-ok:disabled{background:#9db4ec;cursor:not-allowed}
.de-btn-ok .material-symbols-outlined{font-size:18px}
.de-name-tx{width:100%;box-sizing:border-box;border:1px solid #d3dbe6;border-radius:8px;padding:8px 10px;font-size:13px;font-family:inherit}
.de-name-tx:focus{outline:none;border-color:#0b41cd}
.de-modal-info .de-modal-h{color:#0b41cd}
.de-btn-info{background:#0b41cd}
.de-btn-info:hover{background:#0934a6}
.de-btn-info:disabled{background:#9db4ec}
.de-excluded .de-batch-h{background:#fbf7ef}
.de-excl-row{color:#7a8699;background:#fcfcfd}
.de-excl-meta{font-size:11px;color:#8a94a6;white-space:normal;max-width:220px}
.de-excl-by{color:#aab2c0}

/* ---- App-level auth (light-mode premium: off-white DNA bg + glassmorphic card) ---- */
#auth-gate{position:fixed;inset:0;z-index:1000;background:#eef3fa;overflow:auto;}
#auth-gate .auth-fs{position:relative;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:44px 20px;
  background:linear-gradient(160deg,#f6f9fd 0%,#eaf1f9 55%,#e4ecf6 100%);}
/* faint pastel DNA — clean & clinical, ~13% so the logo's true colours read perfectly */
#auth-gate .auth-fs::before{content:"";position:absolute;inset:0;background:url(auth-dna.jpg) center/cover no-repeat;opacity:.13;}

#auth-gate .auth-stack{position:relative;z-index:1;width:100%;max-width:416px;display:flex;flex-direction:column;align-items:center;}
#auth-gate .auth-toplogo{width:228px;max-width:72%;margin-bottom:16px;filter:drop-shadow(0 4px 12px rgba(20,40,90,.10));}
#auth-gate .auth-hero-slogan{font-size:11.5px;font-weight:300;letter-spacing:.15em;line-height:1.6;text-transform:uppercase;color:rgba(2,35,102,.6);white-space:nowrap;margin-bottom:30px;}

/* Glassmorphic card (Apple / Win11 style) */
#auth-gate .auth-card{width:100%;display:flex;flex-direction:column;
  background:rgba(255,255,255,.85);-webkit-backdrop-filter:blur(12px) saturate(1.25);backdrop-filter:blur(12px) saturate(1.25);
  border:1px solid rgba(255,255,255,.4);border-radius:18px;padding:38px 36px;
  box-shadow:0 24px 56px -18px rgba(20,40,90,.22),0 2px 10px rgba(20,40,90,.08),inset 0 1px 0 rgba(255,255,255,.85);}
#auth-gate .auth-welcome{font-size:24px;font-weight:700;color:var(--navy-2);text-align:center;letter-spacing:-.01em;}
#auth-gate .auth-sub{font-size:14px;color:var(--muted);text-align:center;margin:6px 0 26px;}
/* The sign-in card has no sub-line, so the heading carries the gap the
   sub-line used to hold open before the first field. */
#auth-gate .auth-welcome-solo{margin-bottom:26px;}

/* Floating-label fields with leading icon + focus glow (radius unified at 10px) */
#auth-gate .auth-field2{margin-top:16px;}
#auth-gate .auth-field2 .fld-label{display:block;font-size:12.5px;font-weight:600;color:#33415c;letter-spacing:.01em;margin-bottom:7px;}
#auth-gate .auth-field2 .fld-box{position:relative;}
#auth-gate .auth-field2 .fld-ic{position:absolute;left:14px;top:50%;transform:translateY(-50%);color:var(--muted-2);font-size:21px;pointer-events:none;transition:color var(--dur-1) var(--ease);}
#auth-gate .auth-field2 input{width:100%;box-sizing:border-box;height:50px;padding:0 44px;border:1.5px solid var(--line);border-radius:10px;background:#fff;font-size:15px;color:var(--ink);outline:none;transition:border-color var(--dur-1) var(--ease),box-shadow var(--dur-1) var(--ease);}
#auth-gate .auth-field2 input:focus{border-color:var(--blue);box-shadow:0 0 0 4px rgba(11,65,205,.13);}
#auth-gate .auth-field2 .fld-box:focus-within .fld-ic{color:var(--blue);}
#auth-gate .auth-eye{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;color:var(--muted-2);display:flex;padding:5px;border-radius:8px;transition:color var(--dur-1) var(--ease);}
#auth-gate .auth-eye:hover:not(:disabled){color:var(--blue);}
/* Disabled until the field is typed into — an autofilled password must not be
   revealable by anyone who walks up to the machine. Faded rather than hidden so
   the control does not appear and disappear as you type. */
#auth-gate .auth-eye:disabled{opacity:.35;cursor:default;}
#auth-gate .auth-eye .material-symbols-outlined{font-size:20px;}
#auth-gate .auth-err{color:var(--red);font-size:13px;min-height:18px;margin:10px 2px 0;}

/* Gradient Sign-In button — radius unified at 10px to match inputs */
#auth-gate .auth-btn{margin-top:16px;display:flex;align-items:center;justify-content:center;gap:9px;color:#fff;border:none;border-radius:10px;padding:13px;font-size:15px;font-weight:600;cursor:pointer;letter-spacing:.01em;
  background:linear-gradient(135deg,#1e50e6 0%,var(--blue) 55%,#072e9e 100%);box-shadow:0 8px 20px -6px rgba(11,65,205,.55);transition:transform var(--dur-1) var(--ease),box-shadow var(--dur-1) var(--ease),filter var(--dur-1) var(--ease);}
#auth-gate .auth-btn .material-symbols-outlined{font-size:20px;transition:transform var(--dur-1) var(--ease);}
#auth-gate .auth-btn:hover{filter:brightness(1.05);transform:translateY(-1px);box-shadow:0 12px 26px -6px rgba(11,65,205,.6);}
#auth-gate .auth-btn:hover .material-symbols-outlined{transform:translateX(3px);}
#auth-gate .auth-btn:active{transform:translateY(0);}
#auth-gate .auth-link{margin-top:14px;display:block;width:100%;background:none;border:none;color:var(--blue);font-size:13px;cursor:pointer;text-align:center;}
#auth-gate .auth-link:hover{text-decoration:underline;}
#auth-gate .auth-foot{margin-top:24px;text-align:center;font-size:11.5px;color:rgba(2,35,102,.42);letter-spacing:.02em;}

@media (max-width:520px){
  #auth-gate .auth-card{padding:30px 22px;}
  #auth-gate .auth-toplogo{width:190px;}
}
@media (prefers-reduced-motion:reduce){
  #auth-gate .auth-btn,#auth-gate .auth-btn .material-symbols-outlined,
  #auth-gate .auth-field2 input,#auth-gate .auth-field2 label,#auth-gate .auth-field2 .fld-ic{transition:none;}
}

/* ---- Users admin page ---- */
.users-head{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:20px;}
.users-head .de-btn-ok{border-radius:999px;padding:10px 20px;}   /* capsule primary CTA */
.users-table{width:100%;border-collapse:collapse;font-size:14px;}
.users-table thead th{text-align:left;padding:11px 14px;border-bottom:2px solid var(--line);
  text-transform:uppercase;font-size:11px;font-weight:600;letter-spacing:.05em;color:var(--slate);}
.users-table tbody td{text-align:left;padding:12px 14px;border-bottom:1px solid var(--line-2);color:var(--ink);}
.users-table tbody tr{transition:background var(--dur-1) var(--ease);}
.users-table tbody tr:hover{background:var(--blue-50);}
.users-table tbody tr.u-inactive{opacity:.55;}
/* borderless icon / text action buttons */
.u-actions{display:flex;align-items:center;gap:2px;}
.u-act{border:none;background:transparent;cursor:pointer;border-radius:8px;font-family:inherit;font-size:13px;font-weight:600;
  color:var(--muted);display:inline-flex;align-items:center;gap:5px;padding:6px 10px;
  transition:background var(--dur-1) var(--ease),color var(--dur-1) var(--ease);}
.u-act .material-symbols-outlined{font-size:19px;}
.u-act-icon{padding:6px;}
.u-act-icon:hover{background:var(--blue-50);color:var(--blue);}
.u-act-text:hover{background:var(--line-2);color:var(--ink);}
.u-act.u-danger{color:#b4434f;}
.u-act.u-danger:hover{background:var(--red-100);color:var(--red-600);}
/* in-table role select (superadmin) — custom chevron */
.users-table select.u-role{appearance:none;-webkit-appearance:none;padding:6px 30px 6px 11px;border:1px solid var(--line);
  border-radius:8px;background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") no-repeat right 8px center;background-size:14px;
  font-family:inherit;font-size:13px;color:var(--ink);cursor:pointer;transition:border-color var(--dur-1) var(--ease),box-shadow var(--dur-1) var(--ease);}
.users-table select.u-role:hover{border-color:var(--blue-200);}
.users-table select.u-role:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 3px var(--blue-100);}
.nav-foot{margin-top:auto;padding:12px;border-top:1px solid #e5e7eb;}
.nav-foot .who{display:flex;align-items:center;gap:6px;font-size:13px;font-weight:600;margin-bottom:8px;}
.nav-foot .who-role{font-weight:500;color:#6b7280;font-size:12px;}
.nav-mini{display:flex;align-items:center;gap:6px;font-size:13px;color:#374151;cursor:pointer;padding:6px 0;}
.temp-pw{display:flex;align-items:center;gap:10px;margin:12px 0;}
.temp-pw code{font-size:16px;background:#f3f4f6;padding:6px 12px;border-radius:6px;letter-spacing:1px;}

/* eye-toggle works in modals too (not just #auth-gate) */
.de-modal .auth-field{position:relative;}
.de-modal .auth-field input{width:100%;box-sizing:border-box;padding:10px 38px 10px 12px;border:1px solid #d1d5db;border-radius:8px;background:#f9fafb;font-size:14px;
  transition:border-color var(--dur-1) var(--ease),box-shadow var(--dur-1) var(--ease);}
.de-modal .auth-field input:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 3px var(--blue-100);background:#fff;}
.de-modal .auth-eye{position:absolute;right:6px;top:50%;transform:translateY(-50%);background:none;border:none;cursor:pointer;color:#6b7280;display:flex;padding:4px;}
.de-modal .auth-eye .material-symbols-outlined{font-size:20px;}
/* Modal field label + role dropdown (matches Username input height, rounded, SVG chevron) */
.de-modal .auth-label{font-size:12.5px;font-weight:600;color:var(--slate);margin:14px 0 7px;}
.de-modal .auth-label:first-of-type{margin-top:4px;}
.de-modal select{width:100%;box-sizing:border-box;appearance:none;-webkit-appearance:none;
  padding:10px 38px 10px 12px;border:1px solid #d1d5db;border-radius:8px;
  background:#f9fafb url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") no-repeat right 12px center;background-size:16px;
  font-family:inherit;font-size:14px;color:var(--ink);cursor:pointer;
  transition:border-color var(--dur-1) var(--ease),box-shadow var(--dur-1) var(--ease);}
.de-modal select:hover{border-color:var(--blue-200);}
.de-modal select:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 3px var(--blue-100);background-color:#fff;}

/* ---- Overview ---------------------------------------------- */
/* Usage reporting, not QC health: this page stays in neutral greys/blues.
   Green and red carry pass/fail meaning elsewhere in the app. */
.dash-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;}
.dash-card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:16px;}
.dash-head{display:flex;gap:16px;align-items:center;}
.dash-img{width:104px;flex:0 0 104px;border-radius:8px;}
.dash-id{flex:1;min-width:0;}
.dash-sn{font-size:16px;font-weight:700;color:var(--ink);}
.dash-role{font-size:12.5px;color:var(--muted);margin-top:3px;}
/* Filters sit on their own row: the instrument photo is large enough that
   tucking the controls into the header would crowd both. Wraps rather than
   squashing when the card is narrow. */
.dash-ctl{display:flex;flex-wrap:wrap;gap:10px;margin-top:14px;align-items:center;}
/* The Test select takes only what it needs so the two date fields — which
   carry a whole date each — get the rest of the row. */
.dash-dd{font-family:inherit;font-size:13px;padding:6px 10px;border:1px solid var(--line);
  border-radius:8px;background:var(--card);color:var(--ink);cursor:pointer;
  flex:0 1 130px;min-width:0;}
.dash-dates{display:flex;align-items:center;gap:8px;flex:1 1 300px;}
.dash-dl{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;}
.dash-date{font-family:inherit;font-size:13px;padding:5px 8px;border:1px solid var(--line);
  border-radius:8px;background:var(--card);color:var(--ink);cursor:pointer;
  flex:1 1 0;min-width:0;font-variant-numeric:tabular-nums;}
/* An inverted range is the user's typo, not a data problem — mark the inputs
   so the cause is visible next to the message in the table. */
.dash-dates-bad .dash-date{border-color:var(--muted-2);}
/* Echoes the picked window in the app's date format, because the native input
   shows it in the browser locale (mm/dd/yyyy here) and that is ambiguous. */
.dash-win{margin-top:9px;font-size:12px;color:var(--muted);
  font-variant-numeric:tabular-nums;}
.dash-win-bad{color:var(--ink);font-weight:600;}
.dash-kpis{display:flex;gap:24px;margin:14px 0 12px;}
.dash-kpi{display:flex;flex-direction:column;}
.dash-kpi-v{font-size:24px;font-weight:700;color:var(--ink);line-height:1;
  font-variant-numeric:tabular-nums;}
.dash-kpi-l{font-size:12px;color:var(--muted);text-transform:uppercase;
  letter-spacing:.05em;margin-top:5px;}
/* Dotted underline + help cursor: the exclusion reasons are on the hover, and
   nothing else signals that this text carries more than the count. */
.dash-exc{text-transform:none;letter-spacing:0;cursor:help;
  border-bottom:1px dotted var(--muted-2);}
/* Fixed layout with percentage columns. Each table used to size itself from
   its own content, so the two cards' columns landed up to 44px apart and the
   eye could not run straight across from one instrument to the other.
   Percentages, not pixels, so the columns still track the card width. */
.dash-t{width:100%;border-collapse:collapse;font-size:14px;table-layout:fixed;}
.dash-t th{text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:.05em;
  color:var(--muted);font-weight:600;padding:7px 6px;border-bottom:1px solid var(--line);}
.dash-t td{padding:9px 6px;border-bottom:1px solid var(--line);vertical-align:top;
  overflow-wrap:break-word;}
.dash-t th:nth-child(1){width:52%;}
.dash-t th:nth-child(2){width:33%;}
.dash-t th:nth-child(3){width:15%;}
.dash-lot{font-weight:600;}
.dash-range{font-size:12px;color:var(--muted);margin-top:3px;
  font-variant-numeric:tabular-nums;}
.dash-num{text-align:right;font-variant-numeric:tabular-nums;}
/* The Runs header carries .dash-num too, but `.dash-t th` outranks a bare
   class, so the heading sat left while its numbers sat right. */
.dash-t th.dash-num{text-align:right;}
.dash-none{color:var(--muted);text-align:center;padding:20px 6px;}
.dash-pill{display:inline-block;font-size:11px;padding:2px 8px;border-radius:9px;
  background:var(--blue-50);color:var(--muted);margin-right:4px;}
.dash-pill-test{font-weight:600;color:var(--navy-2);}
/* Specimen pills share the Data Entry palette (.de-spec-*) so the same type
   reads the same colour on both pages. Declared after .dash-pill to win on order. */
.dash-pill-plasma{background:var(--blue-100);color:var(--blue);}
.dash-pill-tissue{background:var(--green-100);color:var(--green);}
.dash-pill-other{background:#eef1f5;color:var(--slate);}
@media (max-width:900px){
  .dash-grid{grid-template-columns:1fr;}
}

/* Lot rows open the LJ Chart. styles.css:312 already hovers every tbody row,
   so before this the rows looked clickable and were not; the pointer cursor and
   focus ring are what make the affordance honest. */
.dash-row{cursor:pointer;}
.dash-row:focus-visible{outline:2px solid var(--blue);outline-offset:-2px;}
/* Deep-link arrival: wash the filter bar once so the changed values get noticed.
   Neutral blue — nothing here reports QC status. */
@keyframes fbFlash{from{background:var(--blue-100);}to{background:transparent;}}
#filter-bar.fb-flash{animation:fbFlash 1.2s var(--ease);}
/* prefers-reduced-motion: same signal, no animation — a plain background held
   for the same window (removed by dashboard.js's timeout) instead of a fade. */
#filter-bar.fb-flash-static{background:var(--blue-100);}
