/* AlphaLabPipet — design tokens + shared components.
   Nguồn chân lý: docs/design/alphalabpipet-design-guidelines.md (mục 3, 5, 6, 7.9, 8, 9).

   Trục cuộn (AP chốt 2026-07-11, test iPhone/iPad thật): TRANG cuộn dọc như trang web
   thường — KHÔNG scroll-trong-scroll (iOS landscape kẹt cuộn trong bảng, mất nội dung
   dưới); .lp-table-scroll CHỈ cuộn ngang. Cột bảng tự co giãn theo nội dung
   (table-layout auto + min-width nhỏ), cỡ chữ số scale theo viewport bằng clamp(). */

@font-face {
  font-family: "Inter";
  src: url("/fonts/InterVariable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/fonts/InterVariable-Italic.woff2") format("woff2");
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Inter Display";
  src: url("/fonts/InterDisplay-SemiBold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  /* App light-only (§6.2 — không dark mode v1): khai báo cho UA biết, để trình duyệt
     dark-mode KHÔNG tự đảo tối form control/scrollbar (select, checkbox, input). */
  color-scheme: light;
  /* iOS Safari tự phóng chữ khi xoay ngang (text inflation) — phá type scale đã tinh
     chỉnh từng px (v3.5/v3.6). 100% (KHÔNG phải none): tắt inflation, GIỮ pinch-zoom (§8.3). */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;

  --lp-ink: #0e1b27;
  --lp-ink-2: #51616f;
  --lp-bg: #f4f6f9;
  --lp-surface: #ffffff;
  --lp-border: #dbe2e9;
  --lp-border-soft: #e7ecf1;   /* kẻ ngang trong bảng — zebra đã gánh nhịp hàng, kẻ chỉ phụ họa */
  --lp-border-strong: #9fb0bf;
  --lp-zebra: #f3f6fa;         /* hàng chẵn bảng pha — chống tra nhầm dòng (AP 2026-07-11 v3.4) */
  --lp-blue: #004c97;
  --lp-blue-bright: #009cde;
  /* NAVY-INK = mực của NỘI DUNG CHÍNH (AP 2026-07-11 v3.8): tên hóa chất, số thể tích
     (ml hóa chất + nước cần thêm), tên công thức/mã màu cốc. KHÔNG copy brand blue
     #004c97 (8,5:1 — thay ink 17,4:1 bị AP chê "mờ", v3.8.1): variant lấy CẢM HỨNG
     brand — giữ đúng hue 210° của $blue landing page, kéo TỐI về phía ink → đọc như
     MỰC có ánh navy, không như link. Đo: 12,0:1 trên trắng / 11,1:1 trên zebra (AAA,
     thỏa luật §6.2 "số thao tác ≥ 7:1"); nằm giữa ramp ink #0e1b27 → blue #004c97,
     và tách rõ khỏi màu nút/link (--lp-blue) nên không mơ hồ "bấm được". Số/chữ THAM
     KHẢO (định mức gốc, mã hóa chất, tổng/vải, tiêu đề cột) giữ ink-2 xám:
     navy = "việc phải làm", xám = "tra cứu". */
  --lp-navy: #083765;
  --lp-dye: #e35205;
  --lp-green: #1a7f37;
  --lp-green-bg: #e7f4ec;
  --lp-amber: #9a6700;
  --lp-amber-bg: #fff4d5;
  --lp-red: #b42318;
  --lp-red-bg: #fdecea;

  --lp-font: "Inter", "Segoe UI", system-ui, sans-serif;
  --lp-font-display: "Inter Display", "Inter", "Segoe UI", system-ui, sans-serif;

  /* 2 cột trái sticky khi cuộn ngang — độ rộng CỐ ĐỊNH bằng CSS (không đo JS: font
     load xong mới đo là nguồn lệch offset sticky). Thứ tự: [Nồng độ gốc][Hóa chất]. */
  --lp-stock-col-w: 104px;
  --lp-chem-col-w: clamp(118px, 22vw, 190px);

  /* Hộp đơn vị cố định bề ngang → mọi ĐƠN VỊ thẳng cột dọc và mọi SỐ thẳng mép phải với
     nhau (ô ml, dòng định mức gốc, footer). Vừa ĐỦ "g/L" ở cỡ chữ dòng phụ — KHÔNG dư,
     hộp rộng để lại slack sau đơn vị nhìn như "padding đôi" bên phải (AP 2026-07-11). */
  --lp-unit-w: 16px;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--lp-font);
  background: var(--lp-bg);
  color: var(--lp-ink);
  font-size: 16px;
  line-height: 1.4;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  /* Render chữ đồng bộ 2 app anh em (AlphaLicense app.css / landing _base.scss) —
     KHÔNG mang theo letter-spacing âm của họ: §3 cấm letter-spacing âm cho số. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-kerning: normal;
}

/* Chữ ký brand Alpha (đồng bộ alpha-landing-page + AlphaLicense): quét chọn chữ =
   ánh cam dye trong mờ. Đây là chi tiết IDENTITY (như logo) — hợp luật §6.1 "dye chỉ
   identity", không phải màu ngữ nghĩa mới; còn giúp thấy rõ select-all khi chạm ô
   nồng độ gốc (mục 7.4 "chạm là gõ đè"). */
::selection { background: rgba(227, 82, 5, 0.22); }

/* Caret nhập liệu màu xanh hành động (§6.2: xanh dương = "bấm được, trung tính") —
   con trỏ nháy tách rõ khỏi mực số navy khi đang gõ đè nồng độ. */
input, select, textarea { caret-color: var(--lp-blue); }

/* Thuộc tính hidden PHẢI thắng mọi display của component (UA stylesheet thua
   .lp-banner{display:flex} → banner "hidden" vẫn hiện — bug thật 2026-07-11). */
[hidden] { display: none !important; }

h1, h2, h3, .lp-heading {
  font-family: var(--lp-font-display);
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0;
}

/* KHÔNG tabular-nums (AP 2026-07-13 v3.12 — lật luật cũ "tabular bắt buộc"): số dùng
   proportional figures mặc định của Inter. Cột số vẫn thẳng nhờ căn PHẢI + hộp đơn vị
   bề ngang cố định (--lp-unit-w) — không dựa vào bề ngang chữ số. */

button, input, select {
  font-family: var(--lp-font);
}

/* Bôi chọn (::selection cam ở trên) CHỈ dành cho NỘI DUNG — số liệu, tên hóa chất, mã màu.
   Control tương tác (nút, menu, label form/checkbox, select) KHÔNG được bôi chọn: chạm-giữ
   hoặc quét trượt bằng găng tay lên nút chỉ tạo highlight cam vô nghĩa (nhìn như trạng thái
   mới) trước khi bấm. Luật ghi tại guidelines §6.2. */
button, select, label { -webkit-user-select: none; user-select: none; }

:focus-visible {
  outline: 3px solid var(--lp-blue-bright);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.001ms !important; animation-duration: 0.001ms !important; }
}

/* ── Buttons ─────────────────────────────────────────────────────────── */
.btn {
  appearance: none;
  border: none;
  border-radius: 8px;
  font-family: var(--lp-font);
  font-size: 16px;
  font-weight: 600;
  min-height: 48px;
  padding: 0 18px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  transition: transform 120ms ease, background-color 120ms ease;
}
.btn:active { transform: scale(0.97); }
.btn:disabled { cursor: not-allowed; opacity: 0.55; transform: none; }

.btn-primary { background: var(--lp-blue); color: #fff; }
.btn-primary:hover:not(:disabled) { background: #003b73; }

.btn-success { background: var(--lp-green); color: #fff; }
.btn-success:hover:not(:disabled) { background: #14602a; }

.btn-ghost { background: var(--lp-surface); color: var(--lp-ink); border: 1px solid var(--lp-border-strong); }
.btn-ghost:hover:not(:disabled) { background: #eef2f6; }

/* Hành động phá hủy ngữ cảnh (rút cốc khỏi bảng) — đỏ, cùng hệ .lp-dialog-error. */
.btn-danger { background: var(--lp-red); color: #fff; }
.btn-danger:hover:not(:disabled) { background: #a11212; }

.btn-icon {
  min-width: 48px;
  min-height: 48px;
  padding: 0;
  background: transparent;
  color: var(--lp-ink);
  border-radius: 8px;
}
.btn-icon:hover:not(:disabled) { background: #eef2f6; }

/* ── Menu (⋮) ────────────────────────────────────────────────────────── */
.menu-wrap { position: relative; }
.menu-panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  background: var(--lp-surface);
  border: 1px solid var(--lp-border);
  border-radius: 10px;
  box-shadow: 0 8px 28px rgba(14, 27, 39, 0.16);
  min-width: 200px;
  padding: 6px;
  z-index: 40;
  display: none;
}
.menu-panel.open { display: block; }
.menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 48px;
  padding: 0 12px;
  background: none;
  border: none;
  border-radius: 6px;
  font-size: 15px;
  color: var(--lp-ink);
  text-align: left;
  cursor: pointer;
}
.menu-item:hover { background: #eef2f6; }
.menu-item.danger { color: var(--lp-red); }
.menu-sep { height: 1px; background: var(--lp-border); margin: 6px 4px; }

/* ── Header ──────────────────────────────────────────────────────────── */
/* KHÔNG sticky mặc định — màn thấp (điện thoại ngang: browser chrome iOS đã chiếm
   ~20% chiều cao) header phải cuộn đi cùng trang, nhường chỗ cho bảng. Chỉ ghim
   trên màn đủ cao (tablet/desktop) nơi nút Hoàn thành luôn thấy được là đáng giá. */
.lp-header {
  background: var(--lp-surface);
  border-bottom: 1px solid var(--lp-border);
  padding: 8px 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
@media (min-height: 700px) {
  .lp-header { position: sticky; top: 0; z-index: 30; }
}
.lp-header-left { display: flex; align-items: center; gap: 12px; min-width: 0; }
.lp-logo { color: var(--lp-dye); flex-shrink: 0; }
.lp-title-block { min-width: 0; }
.lp-title { font-size: 18px; }
.lp-subtitle { font-size: 13px; color: var(--lp-ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lp-header-right { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.lp-select {
  min-height: 48px;
  padding: 0 12px;
  border: 1px solid var(--lp-border-strong);
  border-radius: 8px;
  font-size: 15px;
  color: var(--lp-ink);
  background: var(--lp-surface);
  cursor: pointer;
  max-width: 220px;
}

/* ── Banners ─────────────────────────────────────────────────────────── */
.lp-banner {
  padding: 8px 14px;
  font-size: 14px;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  text-align: center;
  flex-wrap: wrap;
}
.lp-banner-stale { background: var(--lp-amber-bg); color: var(--lp-amber); }
.lp-banner-offline { background: #eceff2; color: var(--lp-ink-2); }
.lp-banner .btn { min-height: 40px; padding: 0 14px; font-size: 14px; }

/* ── Table / board ───────────────────────────────────────────────────── */
.lp-board-wrap { padding: 10px; }
.lp-table-scroll {
  overflow-x: auto;
  border-radius: 10px;
  box-shadow: 0 2px 10px rgba(14, 27, 39, 0.06);
  background: var(--lp-surface);
  overscroll-behavior-x: contain;
}
.lp-table {
  border-collapse: separate;
  border-spacing: 0;
  background: var(--lp-surface);
  min-width: 100%;
  /* table-layout auto (mặc định): cột rộng theo nội dung thật — số ngắn = cột hẹp. */
}
/* ═══ HỆ KẺ BẢNG PHA — LUẬT CHUNG (AP 2026-07-11 v3.6: "universal fix, không vá lẻ") ═══
   VẤN ĐỀ gốc: `border-collapse: separate` + dùng `border` cho kẻ → tại MỌI góc 2 kẻ khác
   bề rộng/màu gặp nhau, CSS chia góc bằng MITER 45° (đường xéo "không tô kín"); kẻ ô này
   còn vẽ ĐÈ kẻ ô kia theo thứ tự DOM (kẻ mảnh nằm trên kẻ đậm — "thick below light").
   LUẬT: KHÔNG dùng `border` cho kẻ bảng — MỌI kẻ (ngang/dọc, đậm/mảnh) là `box-shadow`
   inset (box-shadow là HÌNH CHỮ NHẬT: không bao giờ miter, góc luôn đầy). Thứ tự trong
   danh sách shadow: ĐẬM đứng TRƯỚC (vẽ TRÊN) kẻ MẢNH → kẻ đậm không bao giờ bị kẻ mảnh cắt.
   Cấu tạo: `--sh-bottom` (kẻ NGANG dưới ô, do R`HÀNG` quyết) + phần DỌC (do CỘT quyết),
   ghép trong `box-shadow` theo đúng thứ tự đậm-trước. Đổi độ đậm 1 hàng → chỉ set
   `--sh-bottom`; đổi kẻ dọc 1 cột → chỉ set box-shadow cột đó. Không vá từng góc. */
.lp-table th, .lp-table td {
  --sh-bottom: inset 0 -1px 0 var(--lp-border-soft);           /* HÀNG: kẻ ngang mảnh mặc định */
  box-shadow: var(--sh-bottom), inset -1px 0 0 var(--lp-border-soft);  /* + kẻ dọc phân cột mảnh (mặc định/stock) */
  padding: 0;
  vertical-align: middle;
}
/* "Tờ giấy in" (AP 2026-07-11 v3.4): zebra hàng chống tra nhầm dòng — bg đặt trên <td>
   (kể cả cột sticky: phải ĐỤC và ĐỒNG MÀU cả hàng để dòng đọc như MỘT dải liền).
   Specificity (0,2,3) thắng .lp-stock-col (0,1,0). Nền warn/error nằm ở div
   .lp-cell-wrap bên trong nên vẫn nổi trên zebra. */
.lp-table tbody tr:nth-child(odd) > td { background: var(--lp-surface); }
.lp-table tbody tr:nth-child(even) > td { background: var(--lp-zebra); }
/* HÀNG đậm (kẻ ngang 2px strong): "đường kẻ tổng" cuối tbody + tiêu đề + hàng Nước — chỉ
   đổi `--sh-bottom`, box-shadow cột tự ghép lại. Kẻ NGOÀI (đáy bảng) = trong suốt (bo góc). */
.lp-table tbody tr:last-child > td { --sh-bottom: inset 0 -2px 0 var(--lp-border-strong); }
.lp-table tfoot tr:last-child > td, .lp-table tfoot tr:last-child > th { --sh-bottom: inset 0 0 0 transparent; }
/* CỘT công thức: kẻ DỌC đậm TRƯỚC mỗi công thức (quy tắc AP v3.5) = box-shadow inset-left
   strong, ĐỨNG TRƯỚC `--sh-bottom` (đậm vẽ trên mảnh). KHÔNG kẻ dọc phải (không cộng dồn ô kế). */
.lp-table td.lp-col-end, .lp-table th.lp-col-end {
  box-shadow: inset 2px 0 0 var(--lp-border-strong), var(--sh-bottom);
}

/* Cột dữ liệu: min-width nhỏ (auto-layout tự nở theo nội dung), dư thì cuộn ngang. */
.lp-th-beaker,
.lp-table tbody td:not(.lp-chem-col):not(.lp-stock-col),
.lp-table tfoot td.lp-footer-val { min-width: 76px; }

/* Header MỘT hàng (khách / mã màu / công thức xếp chồng trong 1 ô) — thấp hơn hẳn
   3 hàng cũ, không cần sticky-top offset, không rowspan. */
.lp-table thead th {
  background: #f1f5f9;   /* MỘT màu xám ngữ cảnh dùng chung header + footer (v3.4 — bớt sắc độ thừa) */
  --sh-bottom: inset 0 -2px 0 var(--lp-border-strong);   /* kẻ ngang đậm dưới tiêu đề (hệ box-shadow) */
  vertical-align: bottom;
  padding: 5px 8px;
}
.lp-th-left { text-align: left; }
/* Nhãn PHẢI wrap được trong bề ngang cột sticky — chữ tràn ra sẽ bị nền đục của cột
   kế bên (z-index cao hơn) che mất, nhìn như bị "cắt" (bug thật EN "Stock
   concentration", AP 2026-07-11). hyphens cần <html lang> — common.js đã set. */
/* Tiêu đề cột màu XÁM đậm, không xanh dương: xanh dương theo §6.2 = "bấm được" —
   header không bấm được thì không được mặc màu đó (Apple-neutral, v3.4). */
.lp-th-left-label {
  font-weight: 700; font-size: 13px; color: var(--lp-ink-2); line-height: 16px;
  overflow-wrap: break-word; -webkit-hyphens: auto; hyphens: auto;
}
/* Đơn vị (g/L) LUÔN ở tiêu đề cột Nồng độ gốc (AP v3.5): đơn vị trong ô bị nút Lưu
   thay chỗ tạm thời — header là chỗ người dùng luôn tra lại được. */
.lp-th-left-unit { font-weight: 600; font-size: 12px; color: var(--lp-ink-2); line-height: 16px; }
/* Nút ✕ (rút cốc) absolute góc trên-phải. MẶC ĐỊNH chừa dải trên cùng cho nút — an
   toàn ở MỌI bề rộng cột: màn nhỏ / nhiều công thức (cột hẹp 76px, chữ canh giữa tràn
   tới mép phải) không đè nút. Phải viết `.lp-table thead th.lp-th-beaker` để THẮNG
   shorthand `.lp-table thead th{padding:5px 8px}` (specificity cao hơn — trước đây
   `.lp-th-beaker{padding-top}` bị nó đè nên dải chừa KHÔNG có tác dụng, bug AP
   2026-07-13). Responsive: desktop rộng bỏ dải bên dưới. */
.lp-th-beaker { text-align: center; position: relative; }
/* Dải chừa = 32px: icon ✕ 16px canh GIỮA nút 44px (v3.12) chiếm ~y14–30, chữ bắt đầu
   dưới đó ~2px. Chữ được phép lấn vào phần dưới hit-area (nút trong suốt, header không
   bấm) nhưng KHÔNG chạm ✕. */
.lp-table thead th.lp-th-beaker { padding-top: 32px; }
/* Màn đủ rộng (≥860px = ngưỡng "màn nhỏ" dùng chung của file, xem @media dưới): cột
   rộng rãi, chữ ngắn canh giữa không chạm nút ở góc — bỏ dải chừa cho gọn (AP: "để vậy
   đẹp rồi"). Dưới 860 (phone + tablet dọc, cột hay bị hẹp) GIỮ dải an toàn. */
@media (min-width: 860px) {
  .lp-table thead th.lp-th-beaker { padding-top: 5px; }
}
/* Nút rút cốc khỏi bảng (AP 2026-07-13; chỉnh v3.12) — góc trên phải header cột.
   Hit area 44×44 (chuẩn tối thiểu cho ngón đeo găng / touchscreen điện thoại nhỏ —
   hành động HIẾM nhưng vùng bấm không được hiếm; dialog xác nhận vẫn chặn bấm nhầm).
   Dấu ✕ canh GIỮA đúng tâm nút (AP v3.12: "center, vừa vặn" — flex-start cũ nhìn lệch);
   hình hover/focus tròn ôm quanh icon. Glyph mờ để không tranh chú ý với mã màu. */
.lp-th-remove {
  position: absolute; top: 0; right: 0;
  width: 44px; height: 44px;
  appearance: none; border: none; background: transparent;
  padding: 0;
  color: var(--lp-ink-2); opacity: 0.55;
  line-height: 1; cursor: pointer;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.lp-th-remove:hover { opacity: 1; background: #e2e8f0; color: var(--lp-red); }
/* Tên dài KHÔNG cắt cụt: khách wrap tối đa 2 dòng (title attr giữ bản đầy đủ),
   mã màu wrap tự do — mã màu là định danh chính, thà 2 dòng còn hơn mất chữ. */
/* Tên khách = ngữ cảnh phụ → Inter THƯỜNG (AP 2026-07-13 v3.12 thu hẹp ngoại lệ v3.11:
   Display CHỈ còn mã màu — mã màu mới là định danh chính người pha tra; tên khách mặc
   Display cạnh nó làm 2 dòng tranh nhau vai "tiêu đề"). */
.lp-th-customer {
  font-size: 12px; font-weight: 600; color: var(--lp-ink-2); line-height: 16px;
  overflow-wrap: break-word; max-width: 150px; margin: 0 auto;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* Mã màu/tên công thức = định danh chính của cốc — nổi bằng CỠ + ĐẬM + mực NAVY brand
   (AP v3.8). Trước v3.4 dùng --lp-dye (cam): vi phạm luật §6.1 "dye CHỈ identity
   logo/marker", lại giành chú ý với cảnh báo hổ phách. Cam giờ chỉ còn ở logo. */
/* Mã màu = định danh CHÍNH duy nhất được Inter Display (ngoại lệ §3, AP v3.11 thu hẹp
   v3.12). Display chỉ có weight 600 tĩnh (file SemiBold duy nhất) — không đặt 700
   (browser giả đậm, nét bẩn). */
.lp-th-color {
  font-family: var(--lp-font-display);
  font-size: 16px; font-weight: 600; color: var(--lp-navy);
  overflow-wrap: break-word; max-width: 170px; margin: 0 auto; line-height: 19px;
}
.lp-th-recipe { font-size: 12px; font-weight: 500; color: var(--lp-ink-2); white-space: nowrap; line-height: 16px; }

/* 2 cột trái sticky khi cuộn ngang. Nền PHẢI đục — cột dữ liệu chui xuống dưới. */
.lp-stock-col, .lp-chem-col { position: sticky; background: #f8fafc; z-index: 5; }
.lp-stock-col {
  left: 0;
  width: var(--lp-stock-col-w);
  min-width: var(--lp-stock-col-w);
  max-width: var(--lp-stock-col-w);
}
.lp-chem-col {
  left: var(--lp-stock-col-w);
  width: var(--lp-chem-col-w);
  min-width: var(--lp-chem-col-w);
  max-width: var(--lp-chem-col-w);
}
/* Mép PHẢI cột Hóa chất = kẻ ghim đậm 2px strong (box-shadow OUTSET 2px, trùng khít kẻ
   dọc inset-left của CT1) — ĐỨNG TRƯỚC `--sh-bottom` (đậm trên mảnh). KHÔNG kẻ dọc mảnh
   như base (cột này chỉ có 1 kẻ ghim đậm bên phải). (0,2,0) thắng base (0,1,1). */
.lp-table .lp-chem-col { box-shadow: 2px 0 0 var(--lp-border-strong), var(--sh-bottom); }
.lp-table thead th.lp-stock-col, .lp-table thead th.lp-chem-col { background: #f1f5f9; z-index: 6; }

/* PHẢI đủ specificity thắng base `.lp-table td{padding:0}` (0,1,1) — nếu không tên hóa
   chất chạm sát mép trái (0 padding, bug thật AP 2026-07-11). Padding NGANG = 8px KHỚP
   tiêu đề cột (`.lp-table thead th{padding:5px 8px}`) → "Hóa chất" thẳng trái với tên
   hóa chất bên dưới (quy tắc AP 2026-07-11: padding cell = padding tiêu đề cột). */
.lp-table td.lp-chem-cell { padding: 8px; }   /* dọc 8px (v3.4 — thêm khoảng thở kiểu giấy in), NGANG giữ 8px khớp header */
/* Tên hóa chất = nội dung chính (navy brand v3.8); mã hóa chất bên dưới là tham khảo → xám. */
.lp-chem-name { font-size: 14px; font-weight: 600; color: var(--lp-navy); overflow-wrap: break-word; line-height: 18px; }
.lp-chem-code { font-size: 12px; color: var(--lp-ink-2); margin-top: 1px; line-height: 15px; }

/* KHÔNG display:flex thẳng lên <td> (mất table-cell layout, vỡ chiều cao hàng) —
   flex nằm ở div .lp-stock-inner bên trong. Đơn vị g/L CHỈ ở header, không lặp/ô. */
.lp-stock-cell { padding: 0; }
.lp-stock-inner { display: flex; align-items: center; gap: 4px; padding: 4px 6px; }
.lp-stock-input {
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  min-height: 44px;
  padding: 6px 8px;
  font-size: 16px;      /* v3.4: nhập nồng độ là việc ĐẦU CA, không được to gần bằng số ml để hút */
  font-weight: 600;
  font-family: var(--lp-font);
  border: 2px solid #b9c6d2;   /* nhạt hơn border-strong — input im lặng khi không dùng tới (v3.4) */
  border-radius: 6px;
  text-align: right;
  color: var(--lp-ink);
}
.lp-stock-input:focus { border-color: var(--lp-blue-bright); }
/* Đỏ input nồng độ gốc khi (AP v3.6): .invalid = trống/0/ngoài dải (tự thân sai —
   recalcRow); .overflow = tham gia công thức có Nước cần thêm < 0 (recalcWaterAll). */
.lp-stock-input.invalid, .lp-stock-input.overflow { border-color: var(--lp-red); background: var(--lp-red-bg); }
.lp-stock-save {
  min-width: 34px; min-height: 34px; padding: 0;
  background: transparent; border: none; border-radius: 6px;
  color: var(--lp-blue); cursor: pointer; display: none;
  flex-shrink: 0;
}
.lp-stock-save.show { display: inline-flex; align-items: center; justify-content: center; }
.lp-stock-save:hover { background: #eef2f6; }
/* Đơn vị g/L cạnh SỐ nồng độ gốc (thay cho đơn vị cũ ở tiêu đề cột — AP 2026-07-11).
   Khi nút Lưu mặc định hiện (.show) nó THAY CHỖ g/L: cùng bề ngang (34px) → không xê
   dịch. `~`: saveBtn đứng TRƯỚC stockUnit trong DOM nên chọn được sibling sau nó. */
.lp-stock-unit {
  flex-shrink: 0; min-width: 34px; text-align: center;
  font-size: 12px; font-weight: 600; color: var(--lp-ink-2);
}
.lp-stock-save.show ~ .lp-stock-unit { display: none; }

/* Ô số: 2 cấp thị giác — số ml ĐỂ HÚT to đậm (scale theo viewport), định mức gốc
   dòng phụ nhỏ mờ bên dưới (giữ cả khi đã có nồng độ — AP 2026-07-11). Không còn
   tick "Đã hút" → ô không phải nút, hàng thấp gọn. */
.lp-cell-wrap { padding: 8px 8px 6px; text-align: right; }   /* dọc nới (v3.4), NGANG giữ 8px khớp header */
/* line-height PIXEL NGUYÊN cho MỌI chữ trong bảng (v3.5): line-height tỉ lệ (1.4×16=22.4)
   làm chiều cao hàng LẺ → phần tĩnh trôi vị trí lẻ, còn cột sticky (compositing layer
   riêng trên iOS) bị snap về pixel nguyên → kẻ ngang/nền cột Hóa chất lệch 1px so với
   phần còn lại ("stitched together" — bug thật iPhone dọc, AP 2026-07-11). Con số 700→600:
   700 đậm quá thiếu tự nhiên (AP v3.5). */
.lp-cell-line { display: block; white-space: nowrap; line-height: 24px; }
/* Số ml = con số ĐỂ HÚT — nội dung chính, mực NAVY brand (AP v3.8). Trạng thái
   warn/hổ phách + error/đỏ vẫn thắng (specificity cao hơn, khối bên dưới). */
.lp-cell-val { font-size: clamp(16px, 1.2vw + 11px, 20px); font-weight: 600; color: var(--lp-navy); }
/* Hộp đơn vị inline-block bề ngang cố định, chữ dồn TRÁI → cột đơn vị thẳng hàng dọc,
   kéo theo mép phải mọi con số (ml / định mức gốc / footer) thẳng nhau (AP 2026-07-11). */
/* MỌI đơn vị = 12px (AP v3.6 "tất cả đơn vị cùng 12px"). ĐỘ ĐẬM đi theo con số bên trái
   (AP v3.5): base 400 KHỚP dòng định mức gốc (số 400); ô ml + footer số 600 → override
   600 bên dưới. Người ta đọc "10 ml" nên đơn vị cùng cỡ-chữ-nhỏ nhưng cùng đậm/màu số. */
.lp-cell-unit {
  display: inline-block; min-width: var(--lp-unit-w); margin-left: 4px; text-align: left;
  font-size: 12px; font-weight: 400; color: var(--lp-ink-2);
}
/* Đơn vị CÙNG MÀU + ĐỘ ĐẬM với con số bên trái nó — người ta đọc "10 ml" chứ không
   đọc "10" (AP 2026-07-11 v3.5). Dòng định mức gốc xám thì đơn vị xám theo (mặc định
   trên đã đúng); số ml đen thì "ml" đen; warn/error thì đơn vị đổi màu theo số. */
.lp-cell-line .lp-cell-unit { color: var(--lp-navy); font-weight: 600; }
.lp-cell-dosing { display: block; font-size: 12px; color: var(--lp-ink-2); margin-top: 1px; white-space: nowrap; line-height: 15px; }
/* Chưa nhập nồng độ: chỉ còn định mức gốc, nhỉnh hơn dòng phụ để đọc được là số tham khảo. */
.lp-cell-unset .lp-cell-dosing { font-size: 13px; margin-top: 0; line-height: 18px; }
/* Dấu "–" (hóa chất không dùng trong công thức) = CÙNG token chữ nhỏ với chem-code/định
   mức gốc: 12px / 400 / ink-2 (#51616f) — AP v3.6 "consistency is key". */
td.lp-cell-na { text-align: center; color: var(--lp-ink-2); font-weight: 400; font-size: 12px; padding: 8px; line-height: 22px; }

.lp-cell-icon { margin-right: 4px; }
.lp-cell-warn { background: var(--lp-amber-bg); }
.lp-cell-warn .lp-cell-val, .lp-cell-warn .lp-cell-icon, .lp-cell-warn .lp-cell-line .lp-cell-unit { color: var(--lp-amber); }
.lp-cell-error { background: var(--lp-red-bg); }
.lp-cell-error .lp-cell-val, .lp-cell-error .lp-cell-icon, .lp-cell-error .lp-cell-line .lp-cell-unit { color: var(--lp-red); }

/* Footer: nhãn nằm cột Hóa chất (SÁT số — AP 2026-07-11), đơn vị đi theo số.
   padding PHẢI qua `.lp-table` (0,2,0) để thắng base `.lp-table td{padding:0}` (0,1,1) —
   nếu không số/nhãn footer chạm sát viền phải (0 padding) VÀ lệch 10px so với ô body
   phía trên (body pad nằm ở div .lp-cell-wrap, footer pad nằm ở td) — bug thật AP 2026-07-11. */
/* Nhãn footer (Nước cần thêm / Tổng thể tích / Khối lượng vải) = 14px KHỚP tên hóa chất
   (AP v3.6): cùng là "nhãn hàng" trong cột trái → cùng cỡ. Nền TRẮNG cho CẢ 3 hàng footer
   (AP 2026-07-11 v3.7): sạch như tờ giấy in, nhất quán với thân bảng; phân cấp giữ ở MÀU CHỮ
   (nước ink đậm = hành động; tổng/vải ink-2 = tham khảo), không dựa vào nền xám nữa. */
.lp-table .lp-footer-label {
  background: var(--lp-surface); font-size: 14px; font-weight: 600; color: var(--lp-ink-2);
  padding: 7px 8px; text-align: right; white-space: nowrap; line-height: 18px;
}
/* Merge ô nhãn footer với ô TRỐNG bên trái (spacer stock-col) — BỎ kẻ dọc mảnh giữa chúng
   để nhãn đọc như một dải liền: box-shadow chỉ còn `--sh-bottom` (0,3,1 thắng base). */
.lp-table td.lp-footer-label.lp-stock-col { box-shadow: var(--sh-bottom); }
/* nowrap: số + hộp đơn vị PHẢI dính nhau (ô body có .lp-cell-line nowrap bọc; footer
   không có wrapper → "234,55" và "ml" tách dòng khi cột hẹp — bug thật phone AP 2026-07-11). */
.lp-table td.lp-footer-val { background: var(--lp-surface); text-align: right; padding: 7px 8px; white-space: nowrap; line-height: 18px; }
/* Phân cấp emphasis (AP 2026-07-11 v3.4): Tổng thể tích & Khối lượng vải là số THAM KHẢO
   → nhỏ + xám trên nền TRẮNG (đơn vị xám theo số — mặc định .lp-cell-unit đã đúng). */
.lp-footer-val .lp-fv { font-size: 13.5px; font-weight: 600; color: var(--lp-ink-2); }
/* Đơn vị footer 600 KHỚP số footer 600 (số ml/g footer đều .lp-fv 600) — AP v3.5/v3.6. */
.lp-table .lp-footer-val .lp-cell-unit { font-weight: 600; }
/* Hàng "Nước cần thêm" = HÀNH ĐỘNG vật lý (rót nước) ngang hàng số ml hóa chất —
   cùng cỡ/đậm/màu với .lp-cell-val, nền trắng như thân bảng (AP 2026-07-11 v3.4).
   Kẻ ĐẬM dưới hàng nước (AP v3.5): khép phần hành-động, tách khỏi 2 dòng tham khảo. */
/* Nhãn "Nước cần thêm" = NAVY như tên hóa chất (v3.8): hàng nước là hàng HÀNH ĐỘNG —
   đọc phải giống hệt một hàng hóa chất (nhãn navy + số navy). Nhãn Tổng thể tích /
   Khối lượng vải giữ xám: tham khảo, không phải thứ để rót. */
.lp-table .lp-footer-water .lp-footer-label { color: var(--lp-navy); }
.lp-table .lp-footer-water td.lp-footer-val { line-height: 24px; }
.lp-table .lp-footer-water > td, .lp-table .lp-footer-water > th { --sh-bottom: inset 0 -2px 0 var(--lp-border-strong); }
.lp-footer-water .lp-fv { font-size: clamp(16px, 1.2vw + 11px, 20px); font-weight: 600; color: var(--lp-navy); }
.lp-table .lp-footer-water td.lp-footer-val .lp-cell-unit { color: var(--lp-navy); }
/* Trạng thái nước ÂM phải THẮNG khối emphasis trên → thêm .lp-table cho specificity (0,4,*). */
.lp-table .lp-footer-water.lp-row-error td.lp-footer-val,
.lp-table .lp-footer-water.lp-row-error .lp-footer-label { background: var(--lp-red-bg); }
.lp-table .lp-footer-water.lp-row-error .lp-footer-label { color: var(--lp-red); }
.lp-table .lp-footer-water td.lp-water-neg .lp-fv,
.lp-table .lp-footer-water td.lp-water-neg .lp-cell-unit { color: var(--lp-red); }

.lp-water-error-msg {
  margin: 8px 0 0;
  padding: 10px 14px;
  background: var(--lp-red-bg);
  color: var(--lp-red);
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
}

/* ── Page states (loading / empty / error) ──────────────────────────── */
.lp-state {
  padding: 60px 24px;
  text-align: center;
  color: var(--lp-ink-2);
}
.lp-state-icon { color: var(--lp-border-strong); margin-bottom: 12px; }
.lp-state-msg { font-size: 16px; max-width: 480px; margin: 0 auto 16px; }

.lp-skeleton-table { padding: 12px; }
.lp-skel-row { display: flex; gap: 8px; margin-bottom: 8px; }
.lp-skel-cell {
  height: 44px; flex: 1; border-radius: 6px;
  background: linear-gradient(90deg, #e9edf1 25%, #f3f5f8 37%, #e9edf1 63%);
  background-size: 400% 100%;
  animation: lp-shimmer 1.4s ease infinite;
}
@keyframes lp-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* ── Dialog ──────────────────────────────────────────────────────────── */
.lp-dialog-overlay {
  position: fixed; inset: 0;
  background: rgba(14, 27, 39, 0.45);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 16px;
}
.lp-dialog-overlay.open { display: flex; }
.lp-dialog-card {
  background: var(--lp-surface);
  border-radius: 12px;
  max-width: 480px;
  width: 100%;
  max-height: 85dvh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 12px 40px rgba(14, 27, 39, 0.28);
}
.lp-dialog-title { font-family: var(--lp-font-display); font-size: 20px; font-weight: 600; padding: 20px 20px 8px; }
.lp-dialog-body { padding: 4px 20px 12px; overflow-y: auto; font-size: 15px; color: var(--lp-ink); }
.lp-dialog-beaker-row { padding: 8px 0; border-bottom: 1px solid var(--lp-border); font-size: 14px; }
.lp-dialog-beaker-row:last-child { border-bottom: none; }
/* Dòng cốc CÓ checkbox (dialog Hoàn thành — AP 2026-07-13): cả dòng là <label>,
   chạm đâu cũng toggle; checkbox to cho găng tay. */
.lp-dialog-beaker-check { display: flex; align-items: center; gap: 12px; cursor: pointer; min-height: 44px; }
.lp-dialog-checkbox { width: 22px; height: 22px; flex: none; accent-color: var(--lp-green); cursor: pointer; }
.lp-dialog-warn { color: var(--lp-amber); font-weight: 600; margin-top: 6px; }
.lp-dialog-error { color: var(--lp-red); font-weight: 600; margin-top: 6px; }
.lp-dialog-actions {
  display: flex; justify-content: space-between; gap: 10px;
  padding: 14px 20px; border-top: 1px solid var(--lp-border);
}

/* ── Toast ───────────────────────────────────────────────────────────── */
.lp-toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  min-width: 220px;
  max-width: calc(100vw - 32px);
  padding: 14px 22px;
  border-radius: 10px;
  font-size: 15px;
  font-weight: 600;
  color: #fff;
  box-shadow: 0 6px 20px rgba(14, 27, 39, 0.25);
  opacity: 0;
  pointer-events: none;
  transition: opacity 180ms ease, transform 180ms ease;
  z-index: 200;
  text-align: center;
}
.lp-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.lp-toast-success { background: var(--lp-green); }
.lp-toast-error { background: var(--lp-red); }

/* ── Login page ──────────────────────────────────────────────────────── */
.lp-login-wrap {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--lp-bg);
  padding: 20px;
}
.lp-login-card {
  background: var(--lp-surface);
  border-radius: 14px;
  box-shadow: 0 4px 24px rgba(14, 27, 39, 0.10);
  padding: 36px 32px;
  width: 100%;
  max-width: 400px;
}
.lp-login-logo { display: flex; align-items: center; gap: 12px; margin-bottom: 26px; }
.lp-login-logo-text { font-size: 19px; }
.lp-login-logo-sub { font-size: 13px; color: var(--lp-ink-2); margin-top: 2px; }
.lp-field-label { display: block; font-size: 14px; font-weight: 600; color: var(--lp-ink); margin: 16px 0 6px; }
.lp-field-input-wrap { position: relative; }
.lp-field-input {
  width: 100%;
  min-height: 48px;
  padding: 12px 14px;
  font-size: 16px;
  color: var(--lp-ink);
  border: 2px solid var(--lp-border-strong);
  border-radius: 8px;
  outline: none;
  transition: border-color 120ms ease;
}
.lp-field-input:focus { border-color: var(--lp-blue-bright); }
.lp-field-input.invalid { border-color: var(--lp-red); }
#tenantCode { text-transform: uppercase; letter-spacing: 0.5px; }
.lp-toggle-secret {
  position: absolute; right: 0; top: 0; bottom: 0;
  min-width: 48px; background: none; border: none; color: var(--lp-blue);
  cursor: pointer; font-size: 13px; font-weight: 700;
  border-radius: 0 8px 8px 0;
}
.lp-toggle-secret:hover { background: #eef2f6; }
.lp-login-submit { width: 100%; margin-top: 24px; }
.lp-login-err {
  margin-top: 16px; padding: 12px 14px; background: var(--lp-red-bg);
  color: var(--lp-red); border-radius: 8px; font-size: 14px; font-weight: 500;
  display: none;
}
.lp-login-err.show { display: block; }
.lp-spinner {
  display: inline-block; width: 16px; height: 16px;
  border: 2px solid rgba(255,255,255,.45); border-top-color: #fff;
  border-radius: 50%; animation: lp-spin 0.7s linear infinite;
}
@keyframes lp-spin { to { transform: rotate(360deg); } }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* ── Responsive ──────────────────────────────────────────────────────── */
/* Tablet dọc / màn hẹp: gọn header, cột trái hẹp lại. */
@media (max-width: 860px) {
  .lp-header { padding: 6px 10px; gap: 8px; }
  .lp-title { font-size: 16px; }
  .lp-subtitle { font-size: 12px; max-width: 40vw; }
  .btn { padding: 0 12px; font-size: 15px; }
  #btnRefreshLabel { display: none; }  /* icon-only, aria-label vẫn đủ */
  .lp-select { max-width: 170px; font-size: 14px; }
  .lp-board-wrap { padding: 8px; }
  :root {
    --lp-stock-col-w: 96px;
    --lp-chem-col-w: clamp(108px, 22vw, 165px);
  }
  .lp-stock-input { font-size: 16px; }
}

/* Điện thoại: header wrap 2 tầng; CHỈ cột Hóa chất ghim (Nồng độ gốc thả trôi —
   nhường bề ngang cho công thức; nó là việc đầu ca, cuộn về 0 là thấy lại). */
@media (max-width: 560px) {
  .lp-header-left { flex: 1 1 100%; }
  /* Select người pha RIÊNG một dòng (tên đầy đủ, không cắt cụt); refresh + Hoàn thành +
     ⋮ tự wrap xuống dòng dưới, canh phải (AP 2026-07-11). Không phình thêm dòng nào. */
  .lp-header-right { flex: 1 1 100%; justify-content: flex-end; }
  .lp-select { flex: 1 1 100%; max-width: none; min-width: 0; }
  .lp-subtitle { max-width: none; }
  :root {
    --lp-stock-col-w: 88px;
    --lp-chem-col-w: clamp(100px, 30vw, 140px);
  }
  .lp-stock-col { position: static; }
  .lp-chem-col { left: 0; }
  .lp-chem-name { font-size: 13px; }
  /* chem-code / th-left-unit KHÔNG hạ xuống 11px nữa (AP v3.6): token chữ nhỏ + đơn vị
     giữ 12px trên MỌI viewport — điện thoại là màn AP soi, phải nhất quán ở đó trước. */
  .lp-th-left-label { font-size: 12px; }
  .lp-stock-inner { gap: 3px; padding: 4px 5px; }
  .lp-stock-input { font-size: 16px; min-height: 40px; }
  .lp-th-beaker,
  .lp-table tbody td:not(.lp-chem-col):not(.lp-stock-col),
  .lp-table tfoot td.lp-footer-val { min-width: 64px; }
  /* padding-right ô số (div .lp-cell-wrap) = padding-right footer (td) — mép phải các
     cột số body & footer mới thẳng nhau. footer PHẢI qua `.lp-table` để thắng base. */
  .lp-cell-wrap { padding: 6px 8px 5px; }
  .lp-table td.lp-footer-val { padding: 6px 8px; }
  /* Nhãn footer theo tên hóa chất: phone chem-name=13px → nhãn footer cũng 13px. */
  .lp-table .lp-footer-label { padding: 6px 8px; font-size: 13px; }
  .lp-dialog-actions { flex-direction: column-reverse; }
  .lp-dialog-actions .btn { width: 100%; }
  .lp-login-card { padding: 28px 20px; }
}

/* Màn THẤP (điện thoại ngang — browser chrome iOS đã ăn ~20% chiều cao):
   nén mọi chrome của app xuống mức tối thiểu, bảng là nhân vật chính. */
@media (max-height: 520px) {
  .lp-header { padding: 4px 10px; gap: 6px; }
  .lp-subtitle { display: none; }
  .lp-title { font-size: 15px; }
  .btn { min-height: 40px; }
  .btn-icon { min-width: 40px; min-height: 40px; }
  .lp-select { min-height: 40px; }
  #btnRefreshLabel { display: none; }
  .lp-banner { padding: 5px 10px; font-size: 13px; }
  .lp-board-wrap { padding: 6px; }
}

/* ── Safe area (Dynamic Island / notch / home indicator) ─────────────── */
/* viewport-fit=cover → app PHẢI tự chừa vùng khuyết (iPhone ngang: island che gần
   hết cột Nồng độ gốc — bug thật iPhone 14 Pro, AP 2026-07-11). Longhand đặt CUỐI
   file để thắng mọi shorthand padding trong các media query phía trên, mọi viewport. */
.lp-header,
.lp-banner {
  padding-left: max(10px, env(safe-area-inset-left));
  padding-right: max(10px, env(safe-area-inset-right));
}
.lp-board-wrap {
  padding-left: max(8px, env(safe-area-inset-left));
  padding-right: max(8px, env(safe-area-inset-right));
  padding-bottom: max(10px, env(safe-area-inset-bottom));
}
.lp-login-wrap {
  padding-left: max(20px, env(safe-area-inset-left));
  padding-right: max(20px, env(safe-area-inset-right));
}

/* CHỈ khi chạy PWA đã cài (standalone): không còn thanh địa chỉ che phần trên → app phải
   tự chừa status bar/notch, nếu không header chui xuống dưới đồng hồ. Trong trình duyệt
   thường inset-top = 0 nên KHÔNG áp ở đây (tránh header dày thêm vô cớ). */
@media (display-mode: standalone) {
  .lp-header    { padding-top: max(8px,  env(safe-area-inset-top)); }
  .lp-login-wrap { padding-top: max(20px, env(safe-area-inset-top)); }
}
