/* GENERATED FILE — KHÔNG SỬA TRỰC TIẾP.
   Nguồn: styles/manifest.json · SHA-256 1d9227c0d311f518cae6351d56bba22c37f7dbfb637cbd9bf8f851aa3a647343
   Tạo lại bằng: npm run build:styles */

/* ===== SOURCE: styles/foundation.css ===== */
/* ============================================================
   VLXD THANH HIỀN — phần mềm bán hàng
   Bảng màu: xanh da trời (chủ đạo) · cam sáng (điểm nhấn) · trắng
   ============================================================ */

:root{
  /* XÁM THAN trung tính (b105 — chủ tiệm chọn 05/08/2026):
     nền lùi lại để màu CAM một mình nổi bật. Tên biến giữ nguyên --sky-*
     cho đỡ phải sửa hàng trăm chỗ — hiểu là "thang màu chủ đạo". */
  --sky-900:#181B20;
  --sky-800:#22262E;
  --sky-700:#2E333D;
  --sky-600:#3B424F;
  --sky-500:#4E5766;
  --sky-400:#8791A0;
  --sky-300:#BBC2CC;
  --sky-100:#E7EAEE;
  --sky-50:#F4F5F7;
  /* cam sáng — CHỈ cho hành động chính và số cần chú ý */
  --or:#F97316;
  --or-6:#EA6A0B;
  --or-7:#C25706;
  --or-safe:#A94704;
  --or-safe-hover:#873801;
  --or-50:#FFF2E4;
  /* trung tính */
  --ink:#1B1E24;
  --ink-2:#2C313A;
  --slate:#61697A;
  --slate-2:#61697A;
  --line:#D8DCE2;
  --line-2:#EBEDF1;
  --paper:#FFFFFF;
  --bg:#ECEEF1;
  --green:#0C7A57;
  --green-soft:#E1F4ED;
  --red:#C6342A;
  --red-soft:#FCEBE9;

  --r:8px;
  --r-lg:12px;
  --r-sm:6px;
  --shadow:0 1px 2px rgba(24,27,32,.05), 0 2px 8px rgba(24,27,32,.05);
  --shadow-md:0 2px 6px rgba(24,27,32,.07), 0 8px 24px rgba(24,27,32,.08);
  --shadow-lg:0 12px 48px rgba(24,27,32,.24);

  /* Nhịp giao diện b157: một nguồn duy nhất cho khoảng cách, chiều cao điều
     khiển và chuyển động. Giữ nguyên hệ font và thang chữ của app cũ. */
  --space-1:4px;
  --space-2:8px;
  --space-3:12px;
  --space-4:16px;
  --space-5:24px;
  --control-h:40px;
  --motion-fast:120ms;
  --motion-base:180ms;
  --focus-ring:0 0 0 3px rgba(249,115,22,.2);

  --f-ui:"Be Vietnam Pro", ui-sans-serif, system-ui, "Segoe UI", Roboto, sans-serif;
  --f-mono:"TH Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  /* b225 · font cho SỐ. Cùng bộ với --f-mono (mỗi chữ số một bề ngang nên
     số thẳng cột), nhưng số 0 KHÔNG có dấu chấm ở giữa — anh Đạt soi phiếu
     bán thấy chấm giữa số 0 rối mắt. Xem fonts/TH-MONO-GHI-CHU.txt. */
  --f-num:var(--f-mono);

  --rail:56px;   /* b242 · thanh bên CHỈ CÒN BIỂU TƯỢNG, chữ hiện khi rê chuột */
  --head:56px;
}

*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0; font-family:var(--f-ui); background:var(--bg); color:var(--ink);
  font-size:14px; line-height:1.45; -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale; overflow:hidden;
  font-feature-settings:"cv05","ss01";
}

button,input,select,textarea{font:inherit;color:inherit}
button{cursor:pointer;border:0;background:none}
input,select,textarea{
  background:var(--paper); border:1px solid var(--line); border-radius:var(--r);
  padding:8px 10px; width:100%; outline:none; transition:border-color .12s, box-shadow .12s;
}
input:focus,select:focus,textarea:focus{border-color:var(--sky-500);box-shadow:0 0 0 3px var(--sky-100)}
input[readonly]{background:var(--sky-50);color:var(--slate)}
:focus-visible{outline:2.5px solid var(--or);outline-offset:2px;border-radius:4px}
input:focus-visible,select:focus-visible,textarea:focus-visible{outline-offset:0}
button:focus-visible,a:focus-visible,[tabindex]:focus-visible{box-shadow:var(--focus-ring)}
.num{font-variant-numeric:tabular-nums;font-family:var(--f-mono)}
.mut{color:var(--slate)}

/* ---------- đăng nhập & tài khoản (b154) ----------
   Giữ nguyên hệ font cũ: tất cả thành phần kế thừa --f-ui/--f-mono. */
.authgate{
  position:fixed;inset:0;z-index:10000;display:grid;place-items:center;padding:20px;
  background:radial-gradient(circle at 50% 15%,#3B424F 0,#22262E 42%,#181B20 100%);
}
.authgate[hidden]{display:none}
.auth-card{width:min(410px,100%);background:var(--paper);border:1px solid rgba(255,255,255,.15);
  border-radius:var(--r-lg);box-shadow:var(--shadow-lg);padding:28px}
.auth-logo{width:52px;height:52px;margin:0 auto 10px;border-radius:12px;background:var(--or);
  color:#fff;display:grid;place-items:center}
.auth-logo svg{width:30px;height:30px}
.auth-title{text-align:center;font-size:24px;font-weight:800;letter-spacing:-.3px}
.auth-sub{text-align:center;color:var(--slate);font-size:12.5px;margin:2px 0 22px}
.auth-card form{display:grid;gap:12px}
.auth-go{width:100%;height:42px;margin-top:2px}
.auth-err{padding:9px 11px;border-radius:var(--r-sm);background:var(--red-soft);color:var(--red);
  font-size:12.5px;font-weight:600}
.auth-err[hidden]{display:none}
.auth-first{margin-top:16px;padding-top:14px;border-top:1px solid var(--line-2);color:var(--slate);
  font-size:11.5px;line-height:1.65;text-align:center}
.auth-who{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:12px;border:1px solid var(--line);
  border-radius:var(--r);background:var(--sky-50)}
.auth-who>span:not(.tag){color:var(--slate);font-size:12px}
.auth-actions{display:grid;gap:8px;margin-top:14px}
.auth-actions .btn{justify-content:center}
.auth-table .mut{font-size:11.5px;margin-top:2px}
.auth-user-chip{display:flex;align-items:center;gap:6px;max-width:180px}
.auth-user-chip span{max-width:112px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
body.auth-locked>.app{filter:blur(2px);pointer-events:none;user-select:none}

/* ---------- khung ---------- */
.app{display:grid;grid-template-columns:var(--rail) 1fr;height:100vh}

.rail{
  background:linear-gradient(180deg,#2E333D 0%,#1F232B 100%);
  display:flex; flex-direction:column; padding:10px 8px 8px; gap:1px; overflow-y:auto;
  box-shadow:inset -1px 0 0 rgba(255,255,255,.06);
}
.rail::-webkit-scrollbar{width:0}
.brand{
  display:flex;flex-direction:column;align-items:center;gap:7px;
  padding:8px 4px 16px; color:#fff;
}
.brand-mark{
  width:40px;height:40px;border-radius:11px;background:#fff;
  display:grid;place-items:center;color:#fff;font-weight:800;font-size:16px;
  letter-spacing:-.4px;box-shadow:0 3px 10px rgba(0,0,0,.22);
}
.brand-mark.logo{padding:4px}
.brand-mark svg{width:100%;height:100%;display:block}
.brand-name{
  font-size:11px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;
  color:#fff;text-align:center;line-height:1.4;
}
.brand-name .brand-sub{
  font-size:8.5px;font-weight:600;letter-spacing:.1em;color:var(--sky-300);
}

.navbtn{
  position:relative;display:flex;flex-direction:column;align-items:center;gap:5px;
  padding:10px 4px;border-radius:var(--r);color:#9AA3B2;
  font-size:10.5px;font-weight:600;text-align:center;line-height:1.25;letter-spacing:.01em;
  transition:background .12s,color .12s;
}
.navbtn svg{width:20px;height:20px;stroke-width:1.75;opacity:.92}
.navbtn:hover{background:rgba(255,255,255,.07);color:#fff}
.navbtn.on{background:rgba(255,255,255,.12);color:#fff}
.navbtn.on svg{opacity:1}
.navbtn.on::before{
  content:'';position:absolute;left:-8px;top:10px;bottom:10px;width:3px;border-radius:0 3px 3px 0;
  background:var(--or);
}
.rail-sp{flex:1}
.rail-line{height:1px;background:var(--sky-600);margin:6px 14px 4px}
.rail-ft{
  color:#8B95A6;font-size:9.5px;text-align:center;padding:8px 2px 2px;
  letter-spacing:.06em;line-height:1.4;
}

/* ══════════ b242 · THANH BÊN GỌN — chỉ biểu tượng, chữ hiện khi rê chuột ══════════
   Anh Đạt 16/09, gửi kèm ảnh thanh bên của app Claude: *"làm theo ảnh t gửi.
   V gọn app hơn, đỡ nguy cơ nhấn nhầm. Logo cũng để đúng kích thước lại"*.

   VÌ SAO GIỮ THANH chứ không giấu hẳn (anh hỏi 16/09, em đã đo và trả lời):
   thanh này là đường đi DUY NHẤT giữa các màn. Giấu đi thì mỗi lần đổi màn tốn
   2 cú bấm thay vì 1, và người mới — nhất là tiệm lạ sắp mời dùng thử — mở app
   lên không thấy đường nào mà đi. Thu còn biểu tượng giữ nguyên MỘT cú bấm.

   ĐO ĐƯỢC (245 tên hàng thật, 16/09): 92px → 48px trả lại chỗ cho lưới hàng,
   tên vừa một dòng 78% → 82% ở màn 1920, và 30% → 39% ở màn 1600.
   Chọn 56px chứ không 48px: vùng bấm phải đủ 40px (token --control-h) cộng lề
   8px mỗi bên. 48px thì nút chỉ còn 32px — nhỏ hơn ngưỡng bấm nhầm.

   CHỈ ÁP CHO MÁY TÍNH. Điện thoại (≤880px) thanh này nằm DƯỚI ĐÁY và VẪN CÓ
   CHỮ — `responsive-core.css` đặt --rail:0 rồi `mobile.css` dựng lại thành
   thanh đáy. Đụng vào đây mà quên chặn theo bề ngang là mất chữ ở đáy điện
   thoại, đúng cái tiệm đang dùng hằng ngày. */
@media (min-width:881px){
  /* Ô chữ hiện khi rê chuột phải THOÁT ra ngoài thanh, nên thanh không được
     cắt. Chỉ bỏ cắt khi cửa sổ đủ cao để 9 nút + logo + chân nằm gọn — đo được
     490px là đủ, lấy 640px cho rộng tay. Cửa sổ thấp hơn thì thanh cuộn lại
     như cũ và ô chữ bị cắt, nhưng đó là cảnh hiếm trên máy bàn. */
  .rail{overflow:hidden}
  @media (min-height:600px){ .rail{overflow:visible} }

  /* ---- logo: ngang hàng với thanh tiêu đề ----
     🔴 Anh Đạt 16/09 (lần hai): "vẫn lệch mà", gửi kèm ảnh cắt logo đặt cạnh
     chữ "Bán hàng" trên thanh tiêu đề. Lần trước em chỉnh lệch MÉP NGANG, còn
     cái anh thấy là lệch DỌC: thanh tiêu đề cao 56px nên tâm chữ ở y=28, mà
     logo nằm ở y 16→56, tâm 36 — thấp hơn đúng 8px. Nhìn dọc xuống thì logo
     và dòng chữ đầu màn không cùng một đường.
     Vá: khối logo cao ĐÚNG bằng `--head` và căn giữa trong đó, nên tâm logo
     luôn bằng tâm thanh tiêu đề, kể cả khi đổi `--head` sau này. */
  .rail{padding-top:0}
  .brand{height:var(--head);justify-content:center;margin-bottom:8px}

  /* ---- khung logo BẰNG ĐÚNG bề ngang nút ----
     🔴 Anh Đạt 16/09: "logo chỉnh cho cân với hàng ngang luôn, hiện tại lệch".
     Đo ra thì cả hai đều đúng tâm 28px — lệch không phải ở tâm mà ở MÉP: nút
     rộng 40px (x 8→48), khung logo 36px (x 10→46), thụt vào 2px mỗi bên. Ô
     trắng tương phản mạnh nên 2px đó nhìn ra ngay. Nay khung logo = 40px, mép
     trùng khít mép nền nút — cùng một cột thẳng từ trên xuống. */
  .brand{padding:0;gap:0}
  .brand-mark{width:40px;height:40px;border-radius:11px}
  .brand-name{display:none}

  /* ---- nút: chỉ còn biểu tượng ---- */
  .navbtn{padding:9px 4px;gap:0;min-height:40px;justify-content:center}
  .navbtn svg{width:21px;height:21px}

  /* ---- chữ thành ô chỉ dẫn nổi bên phải ----
     Giữ nguyên thẻ <span> làm tên đọc được của nút (trình đọc màn hình vẫn
     đọc đúng), chỉ đổi cách vẽ. Đừng thay bằng display:none — làm thế là nút
     mất tên, người khiếm thị nghe thành "nút" trống. */
  .navbtn>span{
    position:absolute;left:calc(100% + 9px);top:50%;
    transform:translateY(-50%) translateX(-4px);
    background:#1B1F26;color:#fff;padding:7px 11px;border-radius:9px;
    font-size:12.5px;font-weight:600;letter-spacing:0;line-height:1;
    white-space:nowrap;text-transform:none;
    opacity:0;pointer-events:none;z-index:90;
    box-shadow:0 8px 24px rgba(0,0,0,.30);
    transition:opacity .12s ease,transform .12s ease;
  }
  .navbtn:hover>span,
  .navbtn:focus-visible>span{opacity:1;transform:translateY(-50%) translateX(0)}
  @media (prefers-reduced-motion:reduce){
    .navbtn>span{transition:none}
  }

  /* ---- chân thanh: xếp dọc cho vừa 56px ---- */
  .rail-line{margin:6px 10px 4px}
  .rail-ft{display:flex;flex-direction:column;align-items:center;gap:3px;padding:8px 0 2px}
}

/* Cỡ chữ lớn: thanh rộng hơn một chút và biểu tượng to hơn — người dùng chế độ
   này nhìn kém, biểu tượng 21px là nhỏ. Chữ vẫn chỉ hiện khi rê chuột. */
@media (min-width:881px){
  body.big{--rail:64px}
  body.big .navbtn svg{width:24px;height:24px}
  body.big .navbtn{min-height:46px}
  body.big .brand-mark{width:48px;height:48px;border-radius:13px}   /* = bề ngang nút ở cỡ chữ lớn */
  body.big .navbtn>span{font-size:14px;padding:8px 12px}
}

.main{display:flex;flex-direction:column;min-width:0;overflow:hidden}
.head{
  height:var(--head);flex:0 0 var(--head);background:var(--paper);
  border-bottom:1px solid var(--line);display:flex;align-items:center;
  gap:10px;padding:0 16px;
}
.head h1{margin:0;font-size:16px;font-weight:750;letter-spacing:-.35px;white-space:nowrap;line-height:1.2}
.head .sub{font-size:11.5px;color:var(--slate);font-weight:500;white-space:nowrap;line-height:1.2}
/* Đầu màn Bán hàng (anh Đạt chốt 03/09): tên màn và số hóa đơn cùng độ cao
   chữ, không cái nào bị đẩy lên. Tên tiệm là thông tin PHỤ — chữ thường,
   nhạt, tách bằng một vạch đứng chứ không dính thành một chuỗi nặng. */
.pos-head-invoice{display:inline-flex;align-items:baseline;gap:9px;padding-left:2px}
.pos-head-invoice b{font-family:var(--f-mono);font-size:13px;color:var(--ink-2);font-weight:700;letter-spacing:-.01em}
.pos-head-shop{font-style:normal;font-size:11px;font-weight:500;color:var(--slate-2);letter-spacing:.01em;
  padding-left:9px;border-left:1px solid var(--line-2)}
.head-sp{flex:1}
@media (max-width:1240px){.pos-head-shop{display:none}}
.pill{
  display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:100px;
  font-size:11.5px;font-weight:600;background:var(--sky-50);color:var(--sky-700);
  white-space:nowrap;
}
.pill .dot{width:7px;height:7px;border-radius:50%;background:var(--green)}
.pill.or{background:var(--or-50);color:var(--or-7)}
.pill.or .dot{background:var(--or)}
.pill.warn{background:var(--red-soft);color:var(--red)}
.pill.warn .dot{background:var(--red)}

.view{flex:1;overflow:auto;padding:18px}
.view.pos{padding:0;overflow:hidden}

/* ---------- nút ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:7px;
  min-height:var(--control-h);padding:9px 15px;border-radius:var(--r);font-weight:600;font-size:13.5px;
  background:var(--paper);border:1px solid var(--line);color:var(--ink);
  white-space:nowrap;transition:background .08s ease-out,border-color .08s ease-out;
  -webkit-tap-highlight-color:transparent;touch-action:manipulation;
}
.btn:hover{background:var(--sky-50);border-color:var(--sky-300)}
.btn:active{transform:translateY(1px)}
.btn svg{width:16px;height:16px;stroke-width:2}
.btn.pri{background:var(--sky-600);border-color:var(--sky-600);color:#fff}
.btn.pri:hover{background:var(--sky-700);border-color:var(--sky-700)}
.btn.acc{
  background:var(--or);border-color:var(--or);color:#fff;
  box-shadow:0 1px 2px rgba(194,87,6,.2);
}
.btn.acc:hover{background:var(--or-6);border-color:var(--or-6)}
.btn.ink{background:var(--sky-900);border-color:var(--sky-900);color:#fff}
.btn.ink:hover{background:var(--sky-800)}
.btn.dg{color:var(--red);border-color:#EDD3D0}
.btn.dg:hover{background:var(--red-soft);border-color:#E3B9B4}
.btn.sm{min-height:34px;padding:6px 11px;font-size:12.5px}
.btn.big{padding:13px 20px;font-size:15px;font-weight:700;width:100%;letter-spacing:.01em}
.btn[disabled]{opacity:1;cursor:not-allowed;box-shadow:none;background:#F1F3F5;
  border-color:#DEE1E6;color:#9097A2}
.btn.pri[disabled]{background:#D9DDE2;border-color:#D9DDE2;color:#7D858F}
.btn.acc[disabled]{background:#F6E7DA;border-color:#EED8C5;color:#A47D64}
.btn[disabled]:hover{background:#F1F3F5;border-color:#DEE1E6;color:#9097A2}
.btn.pri[disabled]:hover{background:#D9DDE2;border-color:#D9DDE2;color:#7D858F}
.btn.acc[disabled]:hover{background:#F6E7DA;border-color:#EED8C5;color:#A47D64}
.btn[disabled]:active{transform:none}

/* Một hành động chính, các công cụ ít dùng nằm trong menu theo ngữ cảnh. */
.head-actions{position:relative;z-index:12}
.head-actions>summary{list-style:none;cursor:pointer}
.head-actions>summary::-webkit-details-marker{display:none}
.head-actions[open]>summary{background:var(--sky-50);border-color:var(--sky-300)}
.head-actions-menu{
  position:absolute;right:0;top:calc(100% + 8px);width:300px;padding:6px;
  background:var(--paper);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow-md);display:grid;gap:2px
}
.head-actions-menu button{display:flex;align-items:center;gap:10px;width:100%;padding:10px;
  border-radius:var(--r);text-align:left;color:var(--ink)}
.head-actions-menu button:hover{background:var(--sky-50)}
.head-actions-menu button>svg{width:18px;height:18px;flex:0 0 auto;color:var(--slate)}
.head-actions-menu button>span{display:flex;flex-direction:column;min-width:0}
.head-actions-menu strong{font-size:13px;font-weight:700}
.head-actions-menu small{font-size:11px;color:var(--slate);margin-top:1px}
/* Nút icon 33px -> 40px cho đạt vùng bấm (sổ tay mục 1, đồng bộ .icobtn.lg b130).
   RIÊNG nút bỏ dòng trong phiếu (.item .xoa, b229) 26px (cỡ lớn 28px): nó nằm ở đầu
   dòng, ngang dòng đầu của tên — to hơn là dòng hàng cao thêm, vỡ chuẩn b107. */
/* 🔴 `display:grid` là KHỐI — hai nút icon cạnh nhau tự xếp CHỒNG DỌC, dù ô
   chứa đã khai `white-space:nowrap` (nowrap chỉ lo chữ, không lo khối). Bảng
   thiết bị cho thuê vì thế có bút chì nằm trên thùng rác, dòng cao gấp đôi và
   hai đích bấm dính nhau. `inline-grid` giữ nguyên cách xếp bên trong, chỉ đổi
   cách nút đứng với nút bên cạnh. */
.icobtn{
  width:40px;height:40px;border-radius:var(--r);display:inline-grid;place-items:center;vertical-align:middle;
  color:var(--slate);transition:background .12s,color .12s;
  -webkit-tap-highlight-color:transparent;touch-action:manipulation;
}
.icobtn svg{width:18px;height:18px}
.icobtn:hover{background:var(--sky-100);color:var(--sky-700)}
.icobtn svg{width:18px;height:18px;stroke-width:2}
.icobtn.xl{width:33px;height:33px}
.icobtn.xl svg{width:16px;height:16px}
.icobtn.dg:hover{background:var(--red-soft);color:var(--red)}

/* ===== SOURCE: styles/pos.css ===== */
/* ---------- màn bán hàng ---------- */
/* Bố cục màn Bán hàng:
   tab hóa đơn trên cùng · thanh quét · phiếu bán hàng ở giữa · bán chạy bên phải
   Kết quả tìm chỉ bung ra khi gõ/nói, không chiếm chỗ thường trực. */
/* Bố cục màn Bán hàng: hàng hóa bên trái · phiếu bán hàng bên phải, cả hai cùng nhìn thấy.
   Cột trái là một vùng cuộn: gõ tìm thì kết quả chèn lên trên, hàng bán chạy tụt xuống. */
.pos3{display:grid;grid-template-columns:minmax(0,1fr) 440px;gap:18px;height:100%;min-height:0;padding:12px 14px 14px}
.pos3-main{display:flex;flex-direction:column;min-width:0;min-height:0;gap:10px;overflow:hidden}
/* Khu trên cuộn được (hàng trong kho / kết quả tìm),
   dải Hàng bán chạy ghim cứng ở đáy — không xê dịch khi tìm hàng. */
.pane{flex:1;min-height:0;display:flex;flex-direction:column;contain:layout paint;
  padding:9px 10px 10px;background:#EEF3F7;border:1px solid #C8D4DC;border-radius:var(--r-lg)}
.results{overflow:auto;min-height:0;padding-right:2px}
.results::-webkit-scrollbar{width:8px}
.results::-webkit-scrollbar-thumb{background:var(--line);border-radius:8px}
.tabsbar:empty{display:none}
.results[hidden]{display:none}
.results,.quick{display:block}

.scanner{
  background:var(--paper);border:1.5px solid var(--sky-600);
  border-radius:var(--r-lg);padding:11px 14px;
  display:flex;align-items:center;gap:12px;box-shadow:0 2px 12px rgba(24,27,32,.08);
  transition:border-color .12s, box-shadow .12s;
}
.led{
  width:9px;height:9px;border-radius:50%;background:#42D39B;flex:0 0 auto;
  box-shadow:0 0 0 3px rgba(66,211,155,.22);animation:pulse 2.2s ease-in-out infinite;
}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.35}}
@media (prefers-reduced-motion:reduce){.led{animation:none}}
.scan-field{flex:1;min-width:0}
.scan-field label{
  display:block;font-size:10.5px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--slate-2);margin-bottom:3px;
}
.scan-field input{
  background:transparent;border:0;padding:0;color:var(--ink);font-family:var(--f-mono);
  font-size:19px;font-weight:700;letter-spacing:.04em;
}
.scan-field input:focus{box-shadow:none}
/* Ô quét lúc nào cũng đang chờ gõ — vẽ khung cam quanh input thành cái hộp thô.
   Bỏ khung ở riêng ô này; thay bằng cả THANH QUÉT sáng nhẹ lên khi có con trỏ. */
#scan:focus-visible{outline:none}
.scanner:focus-within{border-color:var(--ink-2);box-shadow:0 0 0 3px rgba(59,66,79,.14), 0 2px 12px rgba(24,27,32,.08)}
.scan-field input::placeholder{color:var(--slate);font-weight:400;letter-spacing:0}
.scan-cam{
  width:40px;height:40px;border-radius:var(--r);background:var(--sky-50);border:1px solid var(--line);
  display:grid;place-items:center;color:var(--sky-700);flex:0 0 auto;transition:background .12s,color .12s;
}
.scan-cam:hover{background:var(--or);border-color:var(--or);color:#fff}
.scan-cam svg{width:19px;height:19px;stroke-width:1.8}

/* thẻ sản phẩm */

.grid-p>.pcard{content-visibility:auto;contain-intrinsic-size:118px}

/* khóa cứng 3 cột — màn rộng thì thẻ TO ra chứ không đẻ thêm cột (chủ tiệm chốt) */
.grid-p{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}
.pcard{
  background:var(--paper);border:1.5px solid #173247;border-radius:var(--r-lg);
  padding:11px 13px;text-align:left;display:flex;flex-direction:column;gap:4px;
  min-height:104px;
  transition:border-color .08s ease-out, background-color .08s ease-out;
  position:relative;overflow:hidden;
  contain:layout style paint;              /* trình duyệt khỏi tính lại cả trang */
  -webkit-tap-highlight-color:transparent;
  touch-action:manipulation;               /* bỏ 300ms chờ bấm đúp trên cảm ứng */
}
.pcard{box-shadow:0 1px 3px rgba(7,31,49,.10)}
.pcard:hover{border-color:#071F31;background:#F5FAFD;box-shadow:0 3px 10px rgba(7,31,49,.13)}
/* kết quả khớp nhất: viền cam + nhãn góc — chỉ dán cho ĐÚNG MỘT thẻ đầu khi khớp đủ chữ */
.pcard.best{border:2px solid var(--or);padding:11px 12px}
.pcard.best:hover{background:var(--or-50)}
/* dấu tích cam nhỏ ở góc — không che tên hàng (tên chừa sẵn chỗ bên phải) */
.best-tick{position:absolute;top:6px;right:6px;width:20px;height:20px;border-radius:50%;
  background:var(--or);color:#fff;display:grid;place-items:center}
.best-tick svg{width:12px;height:12px;stroke-width:3}
.pcard.best .pn{padding-right:24px}
.res-more{text-align:center;font-size:12px;color:var(--slate);padding:10px 0 4px}
.res-more b{color:var(--ink-2)}
.pcard:active,.pcard.tapped{border-color:var(--or);background:var(--or-50)}
.pcard .pn{
  font-weight:700;font-size:15px;line-height:1.3;color:var(--ink);padding-right:46px;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;
}
.pcard .pmeta{font-size:11.5px;color:var(--slate);font-family:var(--f-mono);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.pcard.wide{min-height:126px}
.pcard .pwhole{
  font-size:11px;color:var(--sky-700);background:var(--sky-50);
  border-radius:5px;padding:3px 6px;line-height:1.35;
}
.pcard .pwhole b{font-family:var(--f-mono);font-size:11.5px}
.pcard .pwhole .mut{font-size:10px}
.plv{
  font-size:10px;font-weight:700;padding:1px 5px;border-radius:4px;margin-left:5px;
  background:var(--sky-100);color:var(--sky-700);vertical-align:1px;
}
.pcard .prow{display:flex;align-items:baseline;gap:6px;margin-top:auto;padding-right:51px}
.pcard .pp{font-weight:800;font-size:17px;color:var(--ink);font-family:var(--f-mono);letter-spacing:-.02em}
.pcard .pu{font-size:12px;color:var(--slate);font-weight:500}
.stk{
  position:absolute;right:9px;top:8px;font-size:11px;font-weight:800;padding:3px 7px;border-radius:999px;
  background:var(--green-soft);color:var(--green);font-family:var(--f-mono)
}
.pcard.best .stk{top:34px}
.stk.low{background:var(--or-50);color:var(--or-safe)}
.stk.zero{background:var(--red-soft);color:var(--red)}

/* b183 · Dải danh mục ở quầy (anh Đạt chốt 03/09): không tiêu đề, không khung
   bao, không nút Quản lý. Chỉ còn những ô LỚN tô đặc màu xanh than — khác hẳn
   thẻ hàng màu trắng bên trên nên nhìn một cái là biết đâu là bộ lọc, đâu là
   hàng. Ô đang chọn đổi sang cam, chữ đen (6,35:1). */
.pos-quick{flex:0 0 auto;padding:0;background:transparent;border:0}
.pos-quick[hidden]{display:none}
.res-sp{flex:1}
/* Máy tính: ô xuống dòng thay vì trốn sang phải — cuộn ngang bằng chuột khó, mà ô bị cắt nửa thì không ai bấm. */
.pos-qcats{display:flex;flex-wrap:wrap;gap:var(--space-3);padding:2px 2px 4px}
.pos-qcat{flex:1 1 150px;min-width:0;min-height:64px;display:flex;flex-direction:column;justify-content:center;gap:2px;
  padding:var(--space-2) var(--space-4);text-align:left;background:#173247;border:2px solid #173247;border-radius:var(--r-lg);color:#fff;
  transition:background-color var(--motion-fast),border-color var(--motion-fast),transform var(--motion-fast)}
.pos-qcat:hover{background:#071F31;border-color:#071F31}
.pos-qcat:active{transform:scale(.98)}
.pos-qcat.on{background:var(--or);border-color:var(--or-6);color:var(--ink)}
.pos-qcat.on:hover{background:var(--or-6)}
.pos-qcat strong,.pos-qcat small{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pos-qcat strong{font-size:16px;font-weight:700;line-height:1.25}
.pos-qcat small{font-size:12.5px;font-weight:400}

/* Trình quản lý danh mục: chỉ sửa bản nháp. posQuickSave mới ghi cấu hình. */
.posq-manager{display:grid;grid-template-columns:290px minmax(0,1fr);gap:14px;min-height:430px}
.posq-side,.posq-edit{min-width:0;border:1px solid var(--line);border-radius:var(--r);padding:10px;background:var(--bg)}
.posq-side{display:flex;flex-direction:column;gap:9px}.posq-side-hd{display:flex;justify-content:space-between;color:var(--slate);font-size:11px}
.posq-catlist{display:flex;flex-direction:column;gap:6px;overflow:auto;max-height:340px}
.posq-note{margin:0 0 var(--space-3);font-size:12.5px;color:var(--slate)}
.posq-catrow{display:grid;grid-template-columns:minmax(0,1fr) 40px 30px 30px 30px;gap:4px;align-items:center;padding:3px;border:1px solid transparent;border-radius:8px}
.posq-catrow.off .posq-catpick strong{color:var(--slate);text-decoration:line-through}
/* công tắc bật/tắt danh mục — xanh than = đang hiện ở quầy */
.posq-toggle{width:36px;height:20px;border-radius:999px;background:#AEBFCB;border:0;position:relative;justify-self:center;
  transition:background-color var(--motion-fast)}
.posq-toggle i{position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:#fff;transition:left var(--motion-fast)}
.posq-toggle.on{background:#173247}.posq-toggle.on i{left:18px}
.posq-catrow.on{border-color:#173247;background:#EAF3F8}.posq-catpick{text-align:left;min-width:0;padding:5px}
.posq-catpick strong,.posq-catpick small{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.posq-catpick strong{font-size:12px}.posq-catpick small{font-size:10px;color:var(--slate)}
.posq-edit{background:#fff}.posq-picked{display:flex;justify-content:space-between;align-items:center;gap:var(--space-2);flex-wrap:wrap;font-size:11px;color:var(--slate);margin:7px 0}
.posq-picked-act{display:flex;gap:var(--space-3)}.posq-picked-act .text-action{font-size:12px}.posq-picked-act .text-action.dgr{color:var(--red)}
.posq-products{display:grid;grid-template-columns:1fr 1fr;gap:7px;max-height:326px;overflow:auto;padding-right:3px}
.posq-product{display:grid;grid-template-columns:24px minmax(0,1fr);align-items:center;gap:7px;text-align:left;
  padding:8px;border:1px solid var(--line);border-radius:8px;background:#fff}
.posq-product.on{border-color:#173247;background:#EAF3F8}.posq-check{width:20px;height:20px;display:grid;place-items:center;
  border:1px solid #9EB1BE;border-radius:5px;color:#fff;background:#fff;font-weight:800}
.posq-product.on .posq-check{background:#173247;border-color:#173247}
.posq-product strong,.posq-product small{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.posq-product strong{font-size:11.5px}.posq-product small{font-size:9.5px;color:var(--slate)}
.posq-none,.posq-empty{padding:20px;text-align:center;color:var(--slate);font-size:12px}.posq-products>.posq-none{grid-column:1/-1;padding:8px 4px 10px;text-align:left}.posq-empty{display:grid;place-content:center;gap:5px;height:100%}

/* Một popup duy nhất, không nhận chuột, nên rê ảnh không bao giờ cướp cú bấm
   của thẻ sản phẩm. JavaScript tự đặt nó bên trái khi bên phải là phiếu. */
.pos-img-preview{position:fixed;z-index:120;width:270px;pointer-events:none;filter:drop-shadow(0 12px 25px rgba(7,31,49,.24))}
.pos-img-preview[hidden]{display:none}.pos-img-frame{padding:10px;background:#fff;border:2px solid #173247;border-radius:12px}
.pos-img-frame img{display:block;width:246px;height:222px;object-fit:contain;background:#F7FAFC;border-radius:8px}
.pos-img-frame strong,.pos-img-frame small,.pos-img-frame b{display:block;margin-top:6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pos-img-frame strong{font-size:14px;color:var(--ink)}.pos-img-frame small{font-size:11px;color:var(--slate)}
.pos-img-frame b{font-size:16px;color:#173247}

/* ---------- hóa đơn đang bán ---------- */
.tape-col{position:relative;display:grid;grid-template-rows:1fr;min-height:0;min-width:0;overflow:hidden}
/* Khung phiếu dùng lưới 3 hàng: đầu phiếu · danh sách hàng (co giãn) · phần
   thanh toán. Phần thanh toán luôn dính đáy, không bao giờ bị đẩy khỏi màn hình. */
.tape{
  background:var(--paper);display:grid;grid-template-rows:auto 1fr auto;min-height:0;
  position:relative;border-radius:8px;overflow:hidden;
  /* Tách hẳn khỏi khu giữa: viền xanh đậm + bóng đổ sâu.
     Trước đây nền #F4F5F7 và phiếu #FFFFFF chỉ chênh 1,07 lần — mắt không tách được. */
  border:2px solid var(--sky-600);
  box-shadow:0 4px 16px rgba(8,51,79,.14), 0 1px 3px rgba(8,51,79,.10);
}

/* Thanh tiêu đề phiếu — dải màu đậm để nhận ra ngay đây là phiếu bán hàng */
.tape-bar{
  background:linear-gradient(135deg,#3B424F,#22262E);
  color:#fff;padding:9px 16px;margin:0 -16px;display:flex;align-items:center;justify-content:space-between;gap:10px;
}
.tape-bar .tt{
  font-size:12px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;
  display:flex;align-items:center;gap:7px;white-space:nowrap;
}
.tape-bar .tt svg{width:15px;height:15px;opacity:.85}
.tape-bar .no{
  font-family:var(--f-mono);font-size:12.5px;font-weight:700;color:#AEB6C2;white-space:nowrap;
}
.tape-no{display:flex;flex-direction:column;align-items:flex-end;gap:2px;line-height:1}
.tape-date{font-family:var(--f-mono);font-size:9.5px;font-weight:500;letter-spacing:.02em;color:#AEB6C2;white-space:nowrap}

.zig{height:7px;flex:0 0 7px;background-color:transparent;
  background-image:
    linear-gradient(45deg, var(--paper) 50%, transparent 50%),
    linear-gradient(-45deg, var(--paper) 50%, transparent 50%);
  background-size:10px 7px;background-repeat:repeat-x;
}
.zig.top{transform:rotate(180deg)}
/* 4 hàng: thanh tiêu đề / đầu phiếu / danh sách hàng / thanh toán.
   Đệm ngang đặt ở khung; phần nào cần tràn hết bề ngang thì kéo margin âm ra. */
.tape-in{display:grid;grid-template-rows:auto auto 1fr auto;min-height:0;min-width:0;overflow:hidden;padding:0 16px}

.tape-shopline{display:flex;align-items:center;justify-content:space-between;gap:10px}
.tape-hd .shop{font-weight:800;font-size:14px;letter-spacing:-.2px;color:var(--sky-800)}
.tape-items{font-size:10.5px;color:var(--slate);white-space:nowrap}
.tape-hd .meta{
  display:flex;justify-content:space-between;gap:8px;margin-top:3px;
  font-size:11px;color:var(--slate);font-family:var(--f-mono)
}
.cust-band{margin-top:7px;padding:6px 7px;background:#EEF5F8;border-left:3px solid #315C73;border-radius:8px}
.cust-row{display:grid;grid-template-columns:minmax(0,1fr) 134px 34px;gap:6px}
.cust-row input{padding:7px 9px;font-size:13px;background:#fff;border-color:#C8D8E1}
.cbtn{
  display:grid;place-items:center;border:1px solid var(--line);border-radius:var(--r);
  background:#fff;color:var(--sky-700);
}
.cbtn svg{width:15px;height:15px;stroke-width:2}
.cbtn:hover{background:var(--sky-100);border-color:var(--sky-400)}
.cbtn.on{background:var(--sky-600);border-color:var(--sky-600);color:#fff}
.custline{
  display:flex;align-items:center;gap:6px;margin-top:5px;font-size:12px;font-weight:600;color:var(--ink-2);
}
/* --giu-day: đệm đáy tạm sau khi bỏ dòng (xem GIU_DAY trong pos.js) */
.items{overflow-y:auto;overflow-x:hidden;min-height:0;padding:5px 8px calc(5px + var(--giu-day, 0px)) 0}
.items::-webkit-scrollbar{width:7px}
.items::-webkit-scrollbar-thumb{background:var(--line);border-radius:7px}
/* b229 · DÒNG PHIẾU BỐN CỘT: [X] [tên] [giá] [bút] — anh Đạt 11/09, ba lần soi:
   ① "10 sản phẩm, bấm nhanh chuột cùng 1 vị trí thì thấy dấu X có di chuyển" ⇒ X ở cột
      RIÊNG rộng cố định, canh giữa DÒNG ĐẦU của tên (--dong1): tên dài mấy dòng thì X
      vẫn cách mép trên thẻ đúng một khoảng; bỏ một dòng thì dòng kế trồi lên đúng chỗ.
   ② soi bản thử 21:43: X để bên phải thì lúc ẩn cột phải trống, "số bị đẩy sang trái quá
      nhiều, mất cân đối" ⇒ chọn phương án C: X ở ĐẦU dòng, CHỈ hiện khi rê vào dòng.
   ③ "dấu X và cây bút nên dịch ra 2 bên tý để nội dung chính rõ ràng" ⇒ X và bút ở hai
      cột ngoài cùng, lấn vào lề thẻ đúng bằng lề thẻ (6px); tên–số nằm giữa.
   Nguyên tắc tham khảo: NN/g 2021 — nút xóa phải XA nút thao tác thường (cây bút). */
.item{
  --cot-xoa:20px;--xoa:26px;--cot-but:16px;--dong1:18px;
  padding:6px 0;border-bottom:1px dashed var(--line-2);display:grid;
  grid-template-columns:var(--cot-xoa) minmax(0,1fr) auto var(--cot-but);gap:3px 8px;
}
.item .nm{grid-column:2;grid-row:1;font-size:12.5px;font-weight:600;line-height:var(--dong1);padding-right:8px}   /* + khe cột 8px = tên cách giá 16px — anh Đạt 11/09: "không sát giá, sát giá sẽ bị nhiễu" */
/* b223 · CỤM TIỀN của một dòng: đúng MỘT con số (thành tiền) + cây bút (từ b229 cây bút
   ở cột riêng ngoài cùng bên phải, cách số 8px).
   Trước b223 dòng phiếu có hai con số bằng nhau — thành tiền ở trên và ô
   "ĐƠN GIÁ" ở dưới — anh Đạt 10/09: "nhìn nhiều, đầy quá". */
/* Giá cũng canh DÒNG ĐẦU của tên (tên 2 dòng thì giá không trôi xuống giữa nữa):
   cụm cao 22px = cây bút, canh giữa --dong1 bằng lề âm. */
.item .tt{
  grid-column:3;grid-row:1;
  display:flex;align-items:center;justify-content:flex-end;gap:4px;flex-wrap:wrap;
  align-self:start;margin-block:calc((var(--dong1) - 22px) / 2);
  font-weight:800;font-family:var(--f-mono);text-align:right;white-space:nowrap;
}
.item .tt b{font-weight:800;line-height:22px}
.item .tt.over b,.item .tt.over .ttin{color:var(--or-7)}
.item .ttbut{
  grid-column:4;grid-row:1;align-self:start;justify-self:end;
  margin:calc((var(--dong1) - 22px) / 2) -6px calc((var(--dong1) - 22px) / 2) 0;
  display:grid;place-items:center;width:22px;height:22px;flex:0 0 22px;border-radius:5px;
  color:var(--slate-2);font-size:12px;line-height:1;opacity:.4;transition:opacity .12s,color .12s,background .12s;
}
.item .ttbut svg{width:12px;height:12px;stroke-width:2.4}
/* Cây bút MỜ THƯỜNG TRỰC chứ không ẩn hẳn: anh Đạt 10/09 chốt "sửa giá thì bấm
   cây bút kế bên giá" — ẩn đi thì không ai biết là bấm được. Rê vào mới đậm. */
.item:hover .ttbut,.item:focus-within .ttbut,.item .ttbut.over{opacity:1}
.item .ttbut:hover{background:var(--sky-100);color:var(--sky-700)}
.item .ttbut.over{color:var(--or-7)}
/* Ô nhập đơn giá mở ra ĐÚNG chỗ con số vừa đứng — mắt không phải đi tìm. */
.item .ttin{
  width:7em;min-width:7em;height:22px;padding:0 5px;text-align:right;
  font-family:var(--f-mono);font-size:inherit;font-weight:800;color:var(--ink);
  border:1px solid var(--sky-400);border-radius:5px;background:var(--sky-50);
}
.item .ttin:focus{box-shadow:none;background:#fff}
/* Số lượng khác 1 thì mới cần nhắc đơn giá — bỏ hẳn là mất thông tin, để
   thường trực là lại thành hai số như cũ. */
.item .ttx{
  flex:0 0 100%;font-size:10.5px;font-weight:500;color:var(--slate-2);
  font-family:var(--f-mono);letter-spacing:0;
}
.item .ln{
  grid-column:2/-1;display:flex;align-items:center;gap:5px;flex-wrap:wrap;row-gap:3px;
  font-size:11px;color:var(--slate);font-family:var(--f-mono)
}
.item .icobtn.xoa{
  grid-column:1;grid-row:1;align-self:start;justify-self:start;width:var(--xoa);height:var(--xoa);
  margin:calc((var(--dong1) - var(--xoa)) / 2) 0 calc((var(--dong1) - var(--xoa)) / 2) -6px;
}
.item .icobtn.xoa svg{width:16px;height:16px}
/* ĐƠN GIÁ THẲNG HÀNG GIỮA CÁC DÒNG (anh Đạt yêu cầu 09/08):
   khung số lượng không co (co là nút + bị cắt), ô đơn vị rộng CỐ ĐỊNH
   để cột đơn giá bắt đầu cùng một mép ở mọi dòng. */
.item .ln .qty{flex:0 0 auto}
/* b223 · ô đơn vị KHÔNG còn rộng cố định 60px. Chiều rộng đó sinh ra chỉ để
   cột "ĐƠN GIÁ" của mọi dòng bắt đầu cùng một mép — nay không còn cột đó nữa,
   giữ lại chỉ tổ chừa một khoảng trắng vô nghĩa giữa số lượng và đơn vị. */
.item .ln .uplain,.item .ln .umode{
  flex:0 0 auto;max-width:96px;justify-content:flex-start;
  overflow:hidden;text-overflow:ellipsis;
}
.item .ln .uplain{display:inline-block}
.qty{display:inline-flex;align-items:center;border:1px solid var(--line);border-radius:5px;overflow:hidden;background:var(--paper)}
/* Nút +/- là nút bấm nhiều nhất màn bán hàng. 23px cũ dưới cả mức tối thiểu
   24px của WCAG (Apple đòi 44) — nâng lên 28px, ô số nới theo (sổ tay mục 1). */
.qty button{width:28px;height:28px;display:grid;place-items:center;color:var(--sky-700);font-weight:700;font-size:15px}
.qty button:hover{background:var(--sky-100)}
.qty input{
  width:48px;border:0;border-left:1px solid var(--line);border-right:1px solid var(--line);
  border-radius:0;text-align:center;padding:2px;font-family:var(--f-mono);font-size:13px;font-weight:700;
}
.qty input:focus{box-shadow:none;background:var(--sky-50)}
.umode{
  display:inline-flex;align-items:center;gap:2px;height:25px;padding:0 6px;flex:0 0 auto;
  border:1px solid var(--line);border-radius:5px;background:var(--paper);
  font-size:11.5px;font-weight:700;color:var(--ink-2);white-space:nowrap;
}
.umode i{font-style:normal;font-size:9px;color:var(--slate-2)}
.umode:hover{border-color:var(--sky-400);background:var(--sky-50)}
.umode.whole{background:var(--sky-100);color:var(--sky-700);border-color:var(--sky-300)}
.umode.whole i{color:var(--sky-600)}
.uplain{flex:0 0 auto;white-space:nowrap;font-size:11.5px}
/* b225 · CHỌN DUNG TÍCH ngay trên dòng hàng sơn. Anh Đạt 10/09: "phần này chủ
   động thay đổi được số lít vì có sơn 15L, 17L". Dùng <select> chứ không dựng
   hộp riêng: trên điện thoại nó mở bằng bánh xe sẵn có của máy, một chạm là
   xong, và không cần thêm một lớp nổi nào nữa trong phiếu. */
.litsel{
  /* `width:auto` KHÔNG thừa: luật nền cho mọi select là width:100%, để nguyên
     thì ô dung tích chiếm trọn một dòng và đẩy hàng màu xuống — đúng cái ảnh
     chụp 10/09. Sổ lỗi #121. */
  flex:0 0 auto;width:auto;min-width:62px;height:26px;padding:0 2px 0 6px;
  border:1px solid var(--line);border-radius:6px;
  background:var(--paper);font-family:var(--f-num);font-variant-numeric:tabular-nums;
  font-size:11.5px;font-weight:700;color:var(--ink-2);cursor:pointer;
}
.litsel:hover{border-color:var(--sky-400);background:var(--sky-50)}
.litsel:focus{outline:2px solid var(--sky-400);outline-offset:1px}
/* Chưa chọn dung tích thì nổi màu cam: chưa có số lít là chưa tính được tiền màu. */
.litsel.chua{border-color:#F3C9A2;background:var(--or-50);color:var(--or-safe)}
.empty-tape{
  display:grid;place-content:center;text-align:center;gap:8px;color:var(--slate);
  padding:30px 10px;
}
.empty-tape svg{width:34px;height:34px;stroke-width:1.4;margin:0 auto;color:var(--sky-300)}
.empty-tape p{margin:0;font-size:12.5px;max-width:220px}
.empty-tape .kbd-hint{font-size:11px;color:var(--slate-2)}

/* Phần thanh toán: nền riêng, viền rõ để không lẫn với danh sách hàng */

.tape-ft .trow{color:var(--ink-2)}
.tape-ft .trow .num{color:var(--ink)}
.tape-ft input,.tape-ft select{background:var(--paper)}

.trow input{width:92px;text-align:right;padding:3px 7px;font-size:12px;font-family:var(--f-mono);font-weight:700}
.trow select{width:auto;padding:3px 6px;font-size:11.5px;font-weight:700;color:var(--sky-700);background:var(--sky-50);border-color:var(--sky-300)}
.trow .lb{display:inline-flex;align-items:center;gap:6px}
.trow.tot{
  font-size:12px;font-weight:700;color:var(--sky-700);padding-top:7px;margin-top:5px;
  border-top:1px solid #D2D7DE;letter-spacing:.08em;text-transform:uppercase;
}
.trow.tot .num{font-size:21px;color:var(--or-safe);letter-spacing:-.5px;white-space:nowrap}   /* b229 · chữ "đ" không rớt xuống dòng riêng trên điện thoại */
.tape-acts{display:grid;gap:5px;margin-top:5px}
.acts-2{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.kbd{
  font-family:var(--f-mono);font-size:10px;font-weight:700;padding:1px 5px;border-radius:4px;
  background:var(--sky-50);border:1px solid var(--line);color:var(--slate);
}
.btn.acc .kbd,.btn.pri .kbd,.btn.ink .kbd{background:rgba(255,255,255,.22);border-color:rgba(255,255,255,.3);color:#fff}
/* Phím tắt in trên nút cam: mảng trắng mờ .22 làm nền sáng lên, chữ trắng chỉ
   còn 3,84. Đổi sang mảng TỐI mờ — nền đậm lại, chữ trắng lên 6,3
   (đo bằng tests/browser/pos-do.js). */
.tape-acts .btn.acc .kbd{background:rgba(0,0,0,.16);border-color:rgba(255,255,255,.34);color:#fff}

/* ===== SOURCE: styles/components.css ===== */
/* ---------- bảng ---------- */
.panel{background:var(--paper);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden}
.panel-hd{
  padding:13px 16px;border-bottom:1px solid var(--line);display:flex;
  align-items:center;gap:12px;flex-wrap:wrap;background:var(--paper);
}
.panel-hd h2{margin:0;font-size:14px;font-weight:700;display:inline-flex;align-items:center;gap:7px}
.panel-hd h2 svg{width:17px;height:17px;stroke-width:2;flex:0 0 auto}
input[type=file]{padding:6px 8px;font-size:12.5px;cursor:pointer}
input[type=file]::file-selector-button{
  font:inherit;font-weight:600;font-size:12.5px;margin-right:9px;padding:5px 11px;cursor:pointer;
  border:1px solid var(--sky-300);border-radius:5px;background:var(--sky-50);color:var(--sky-700);
}
input[type=file]::file-selector-button:hover{background:var(--sky-100)}
details summary::marker{color:var(--sky-500)}
.panel-hd .head-sp{flex:1}
.panel-bd{padding:16px}

table{width:100%;border-collapse:collapse;font-size:13px}
thead th{
  position:sticky;top:0;background:var(--paper);z-index:1;text-align:left;
  padding:10px 12px;font-size:10px;font-weight:700;letter-spacing:.1em;
  text-transform:uppercase;color:var(--slate);border-bottom:1.5px solid var(--line);
  white-space:nowrap;
}
tbody td{padding:9px 12px;border-bottom:1px solid var(--line-2);vertical-align:middle}
tbody tr:hover{background:var(--sky-50)}
tbody tr:last-child td{border-bottom:0}
.tbl-wrap{overflow:auto;max-height:calc(100vh - 210px);contain:layout paint}
tbody tr{content-visibility:auto;contain-intrinsic-size:41px}
tbody tr.clk{cursor:pointer}
td.r,th.r{text-align:right}
td.c,th.c{text-align:center}
.tag{
  display:inline-block;padding:2px 7px;border-radius:4px;font-size:11px;font-weight:600;
  background:var(--sky-100);color:var(--sky-700);white-space:nowrap;
}
.tag.bp{background:var(--sky-100);color:var(--sky-700)}
.tag.gn{background:var(--green-soft);color:var(--green)}
.tag.rd{background:var(--red-soft);color:var(--red)}
.tag.am{background:var(--or-50);color:var(--or-7)}
.tag.gy{background:#EEF0F3;color:var(--slate)}
.status-tag{display:inline-flex;align-items:center;gap:5px}
.status-tag svg{width:13px;height:13px;stroke-width:2.1;flex:0 0 auto}

.toolbar{display:flex;gap:9px;align-items:center;flex-wrap:wrap;margin-bottom:14px}
.toolbar input,.toolbar select{width:auto;min-width:150px}
.toolbar label{font-size:12px;font-weight:600;color:var(--slate)}
.toolbar-sp{flex:1}
.resource-toolbar{min-height:40px}
.resource-toolbar .resource-search{max-width:420px}
/* 🔴 Ô TÌM CÓ SÀN, KHÔNG CHỈ CÓ TRẦN. Trước đây chỉ khai `max-width:340px`; trên
   thanh công cụ đông nút (màn Sản phẩm có 7 điều khiển) `flex:1` bóp nó xuống
   **176px** — đo được — và chữ mờ nào cũng cụt. Trần lo lúc rộng, sàn lo lúc chật. */
.search-in{position:relative;flex:1 1 220px;min-width:180px;max-width:340px}
.search-in input{padding-left:32px}
.search-in svg{
  position:absolute;left:10px;top:50%;transform:translateY(-50%);
  width:15px;height:15px;color:var(--slate-2);stroke-width:2;pointer-events:none
}

/* ---------- KPI ---------- */
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(184px,1fr));gap:12px;margin-bottom:16px}
.kpi{
  background:var(--paper);border:1px solid var(--line);border-radius:var(--r-lg);
  padding:13px 15px 14px;position:relative;overflow:hidden;
}
.kpi::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--sky-500)}
.kpi .k{
  font-size:10px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;
  color:var(--slate);margin-bottom:6px
}
.kpi .v{font-size:23px;font-weight:800;font-family:var(--f-mono);letter-spacing:-.8px;line-height:1.1}
.kpi .n{font-size:11.5px;color:var(--slate);margin-top:3px}
.kpi.gn::before{background:var(--green)}  .kpi.gn .v{color:var(--green)}
.kpi.rd::before{background:var(--red)}     .kpi.rd .v{color:var(--red)}
.kpi.bp::before{background:var(--sky-600)} .kpi.bp .v{color:var(--sky-700)}
.kpi.am::before{background:var(--or)}      .kpi.am .v{color:var(--or-7)}

/* ---------- hộp thoại ---------- */
.ov{
  position:fixed;inset:0;background:rgba(6,43,68,.45);display:grid;place-items:center;
  padding:20px;z-index:80;backdrop-filter:blur(2px);
}
.ov[hidden]{display:none}
.modal{
  /* b175: min-width:0 — modal là con của lưới .ov, không có nó thì một hàng
     nowrap bên trong (thanh mục Cài đặt) đẩy modal RỘNG HƠN màn điện thoại. */
  background:var(--paper);border-radius:var(--r-lg);width:100%;max-width:660px;min-width:0;
  max-height:90vh;display:flex;flex-direction:column;box-shadow:var(--shadow-lg);
}
.modal.wide{max-width:880px}
.modal.narrow{max-width:440px}
.ov.drawer-host{place-items:stretch end;padding:0;background:rgba(24,27,32,.38)}
.modal.drawer{
  width:min(680px,calc(100vw - 88px));height:100vh;max-width:680px;max-height:100vh;
  border-radius:var(--r-lg) 0 0 var(--r-lg);animation:drawerIn .18s ease-out
}
.modal.drawer.wide{max-width:760px}
.modal.drawer .m-hd{border-radius:var(--r-lg) 0 0 0;position:sticky;top:0;z-index:2}
.modal.drawer .m-ft{position:sticky;bottom:0;background:var(--paper);z-index:2}
.modal.focus{max-width:960px;max-height:94vh}
@keyframes drawerIn{from{transform:translateX(24px);opacity:.7}to{transform:none;opacity:1}}
@media (prefers-reduced-motion:reduce){.modal.drawer{animation:none}}
.m-hd{
  padding:15px 18px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:10px;
  background:var(--paper);border-radius:var(--r-lg) var(--r-lg) 0 0;
}
.m-hd h3{margin:0;font-size:15.5px;font-weight:700;color:var(--ink);letter-spacing:-.2px}
.m-bd{padding:18px;overflow:auto;flex:1}
.m-ft{padding:13px 18px;border-top:1px solid var(--line);display:flex;gap:9px;justify-content:flex-end;flex-wrap:wrap}
.fgrid{display:grid;grid-template-columns:1fr 1fr;gap:13px}
.fgrid .full{grid-column:1/-1}
.f label{
  display:block;font-size:11px;font-weight:700;color:var(--slate);margin-bottom:4px;
  letter-spacing:.02em
}
.f .hint{font-size:11px;color:var(--slate-2);margin-top:3px}
.sect{
  font-size:10.5px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;
  color:var(--sky-700);margin:20px 0 11px;padding-bottom:6px;border-bottom:1px solid var(--line);
  grid-column:1/-1
}
.sect:first-child{margin-top:0}
/* Tiêu đề khối có KÈM NÚT — nút thêm dòng đứng ngay trên danh sách, không trôi
   xuống dưới theo số dòng (xem chú thích ở `rentals.js`). Nút giữ cỡ chữ thường
   của nó, không bị hút theo cỡ 10.5px in hoa của tiêu đề. */
.sect-act{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding-bottom:8px;
}
.sect-act>button{
  font-size:12px;font-weight:600;letter-spacing:0;text-transform:none;
  flex:0 0 auto;
}
.note{
  background:var(--sky-50);border:1px solid var(--line);border-left:3px solid var(--sky-500);
  border-radius:var(--r);padding:11px 13px;font-size:12.5px;color:var(--ink-2);
}
.note.am{background:var(--or-50);border-color:#F6D9BC;border-left-color:var(--or)}
.note strong{color:var(--ink)}
/* b238 · khối "lúc mất mạng thì việc gì phải đợi" trong hộp bật bán dự phòng.
   Có lớp riêng để không phải nhét style thẳng vào thẻ — cùng cỡ chữ với danh sách ngay trên nó. */
.note-ds{margin-top:12px}
.note-ds ul{font-size:13px;line-height:1.65;margin:6px 0 0;padding-left:20px}
.cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:8px 16px;font-size:12.5px}

/* ---------- thông báo ---------- */
.toasts{position:fixed;bottom:18px;left:50%;transform:translateX(-50%);z-index:99;display:grid;gap:8px;justify-items:center;pointer-events:none}
.toast{
  background:var(--sky-900);color:#fff;padding:10px 16px;border-radius:100px;font-size:13px;
  font-weight:600;box-shadow:var(--shadow-lg);animation:up .22s ease-out;max-width:88vw;text-align:center;
}
.toast.ok{background:var(--green)}
.toast.err{background:var(--red)}
@keyframes up{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}

/* Dải sau bán: phản hồi + hành động tiếp theo, không khóa màn Bán hàng. */
.sale-follow{
  position:fixed;left:calc(var(--rail) + 18px);right:18px;bottom:18px;z-index:70;
  min-height:64px;padding:10px 12px;display:flex;align-items:center;gap:10px;
  background:var(--sky-900);color:#fff;border:1px solid rgba(255,255,255,.14);
  border-radius:14px;box-shadow:var(--shadow-lg);overflow:hidden
}
.sale-follow[hidden]{display:none}
.sale-follow:not([hidden]) + .toasts{bottom:96px}
.sale-follow.on{animation:followIn .18s ease-out}
.sf-state{width:38px;height:38px;flex:0 0 38px;border-radius:11px;background:var(--green);
  display:grid;place-items:center}
.sf-state svg{width:21px;height:21px;stroke-width:2.5}
.sf-copy{display:flex;align-items:baseline;gap:7px;min-width:0;flex:1;flex-wrap:wrap}
.sf-copy strong{font-size:13.5px;white-space:nowrap}
.sf-copy span{font-size:12px;color:#C9CFD8;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sf-copy .num{font-size:14px;font-weight:800;color:#fff}
.sf-actions{display:flex;align-items:center;gap:5px;flex:0 0 auto}
.sf-actions button{min-height:40px;padding:8px 11px;border-radius:9px;color:#fff;
  border:1px solid rgba(255,255,255,.18);display:inline-flex;align-items:center;gap:6px;
  font-size:12px;font-weight:700}
.sf-actions button:hover{background:rgba(255,255,255,.12)}
.sf-actions button svg{width:15px;height:15px}
.sf-actions .sf-close{width:40px;padding:0;justify-content:center;color:#C9CFD8}
.sf-life{position:absolute;left:0;bottom:0;height:3px;background:var(--or);width:100%;
  transform-origin:left;animation:followLife 15s linear forwards}
@keyframes followIn{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
@keyframes followLife{to{transform:scaleX(0)}}
@media (prefers-reduced-motion:reduce){.sale-follow.on,.sf-life{animation:none}}

/* ---------- mã vạch / tem ---------- */
.bc svg{display:block;max-width:100%;height:auto}
.labels{display:grid;grid-template-columns:repeat(3,1fr);gap:5px}
.label{
  border:1px dashed var(--line);padding:7px;text-align:center;
  display:flex;flex-direction:column;gap:3px;align-items:center;break-inside:avoid;
}
.label .lc{font-size:9.5px;font-weight:700;font-family:var(--f-mono);align-self:flex-start}
.label .lp{font-size:11px;font-weight:800;font-family:var(--f-mono)}
.label .ln2{font-size:9px;line-height:1.2}
.label .bcn{font-size:8px;font-family:var(--f-mono);letter-spacing:.06em}

.empty{
  text-align:center;padding:48px 20px;color:var(--slate);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
}
.empty svg{width:38px;height:38px;stroke-width:1.4;color:var(--sky-300);margin-bottom:10px}
.empty h3{margin:0 0 5px;font-size:15px;color:var(--ink);font-weight:700}
.empty p{margin:0 auto 14px;font-size:13px;max-width:420px;line-height:1.55}
.empty-actions{display:flex;align-items:center;justify-content:center;gap:var(--space-3);flex-wrap:wrap}
.text-action{min-height:40px;padding:8px 6px;color:var(--sky-700);font-size:12.5px;font-weight:700;
  text-decoration:underline;text-decoration-color:var(--sky-300);text-underline-offset:3px;border-radius:var(--r-sm)}
.text-action:hover{color:var(--ink);text-decoration-color:var(--or)}
.empty-note{margin-top:4px;padding:9px 12px;border-radius:var(--r);background:var(--sky-50);
  color:var(--slate);font-size:12px;font-weight:600}
.onboard-empty{min-height:360px;padding:36px 24px}
.onboard-empty>svg{width:44px;height:44px}
.empty-steps{display:flex;align-items:center;justify-content:center;gap:10px;margin:2px 0 20px;
  width:min(620px,100%)}
.empty-steps>span{flex:1;min-width:0;display:flex;align-items:center;gap:8px;padding:9px 11px;
  background:var(--paper);border:1px solid var(--line);border-radius:var(--r)}
.empty-steps b{width:24px;height:24px;flex:0 0 24px;border-radius:50%;display:grid;place-items:center;
  background:var(--sky-900);color:#fff;font:700 11px var(--f-mono)}
.empty-steps em{font-style:normal;color:var(--ink);font-size:11.5px;font-weight:650;white-space:nowrap}
.empty-steps>i{font-style:normal;color:var(--sky-400);font-size:22px;font-weight:300}

.cam-box{position:relative;background:#000;border-radius:var(--r);overflow:hidden;aspect-ratio:4/3}
.cam-box video{width:100%;height:100%;object-fit:cover;display:block}
.cam-line{
  position:absolute;left:8%;right:8%;top:50%;height:2px;background:var(--or);
  box-shadow:0 0 12px var(--or);animation:sweep 2s ease-in-out infinite;
}
@keyframes sweep{0%,100%{top:26%}50%{top:74%}}
@media (prefers-reduced-motion:reduce){.cam-line{animation:none}}
/* b229 · B5 · dải đỏ BẢN THỬ (máy chủ THU.cmd chạy trên sổ CHÉP từ sổ thật) — viền đỏ quanh màn + nhãn giữa đỉnh.
   pointer-events:none: không chặn bấm; không in ra giấy. */
.ban-thu{position:fixed;top:0;left:50%;transform:translateX(-50%);z-index:2147483000;background:#b71c1c;color:#fff;
  font-weight:700;font-size:12px;line-height:1.5;padding:3px 12px;border-radius:0 0 8px 8px;pointer-events:none;
  box-shadow:0 2px 6px rgba(0,0,0,.35);white-space:nowrap;max-width:96vw;overflow:hidden;text-overflow:ellipsis}
html.co-ban-thu::after{content:"";position:fixed;inset:0;border:4px solid #b71c1c;pointer-events:none;z-index:2147483000}
@media print{.ban-thu{display:none}html.co-ban-thu::after{display:none}}

/* b229 · B8: chốt ngày nói Thừa/Thiếu/Khớp có màu; chừa khoảng giữa hai dòng số máy chủ và ô nhập */
#rc_diff.lech { color: var(--red); font-weight: 700; }
#rc_diff.khop { color: var(--green); font-weight: 700; }
.fgrid:has(#rc_open) { margin-top: 12px; }

/* b229 · B8 (soi ảnh điện thoại): bảng Quản lý tài khoản rộng hơn màn 390px — nút "Cấp mật khẩu tạm" bị giấu bên phải,
   phải vuốt ngang mới thấy. Lên b229 chủ PHẢI cấp mật khẩu tạm cho từng người (000000 bị khóa), có khi làm từ điện thoại
   ⇒ màn hẹp xếp mỗi tài khoản thành một thẻ: tên + nhóm + trạng thái bên trái, hai nút bên phải. */
@media (max-width: 560px) {
  .auth-table thead { display: none; }
  .auth-table tr { display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; padding: 10px 0; border-bottom: 1px solid var(--line); }
  .auth-table td { display: block; padding: 0; border: 0; }
  .auth-table td:nth-child(2), .auth-table td:nth-child(3) { grid-column: 1; font-size: 13px; color: var(--slate); }
  .auth-table td.r { grid-column: 2; grid-row: 1 / span 3; align-self: center; display: flex; flex-direction: column; gap: 6px; }
}

/* ===== SOURCE: styles/print.css ===== */
/* ---------- in ấn ---------- */
#print{display:none}
#print.measure{display:block !important;position:absolute;left:-10000px;top:0;background:#fff}
/* .p-80 đặt NGOÀI @media print để app đo được chiều dài phiếu trước khi in
   (in vẫn đúng vì trên màn hình #print luôn ẩn) */
/* hóa đơn khổ 80mm (máy in nhiệt) — bố cục kiểu UNIQLO, chốt b114 */
.p-80{width:72mm;box-sizing:border-box;padding:2.5mm 4mm 3mm;font-size:9pt;line-height:1.4;color:#000}
.p-80 tr,.p-80 .nm,.p-80 .chuyen,.p-80 .ft,.p-80 .rvq{break-inside:avoid;page-break-inside:avoid}
.p-80 .c{text-align:center}
.p-80 .b{font-weight:700}
.p-80 .lk{display:flex;align-items:center;justify-content:center;gap:2.5mm}
.p-80 .lk-m{width:15mm;height:10mm}
.p-80 .lk-t{text-align:left}
.p-80 .lk-tag{font-size:6.3pt;font-weight:700;letter-spacing:1.6pt;white-space:nowrap}
.p-80 .lk-w{width:33mm;height:6.6mm;display:block}
.p-80 .lk-ad{font-size:8.5pt;line-height:1.45;margin-top:1.2mm;text-align:center}
.p-80 h1{font-size:12pt;margin:2.2mm 0 .5mm;text-align:center;letter-spacing:2pt;font-weight:800}
.p-80 .mt{font-size:8.5pt;margin-bottom:.8mm}
.p-80 hr{border:0;border-top:1px dashed #000;margin:1.8mm 0}
.p-80 table{width:100%;border-collapse:collapse;font-size:9pt}
.p-80 td{padding:.4mm 0;vertical-align:top}
.p-80 .r{text-align:right;white-space:nowrap}
.p-80 .nm{font-weight:600}
.p-80 .sb{font-size:8.5pt}
.p-80 .inote{font-size:8pt;font-style:italic;padding-left:2.5mm;line-height:1.25}
.p-80 .ct{text-align:center}
.p-80 .sum td{padding:.5mm 0}
.p-80 .tot td{font-weight:800;font-size:12pt;padding-top:1.2mm;border-top:1px solid #000}
.p-80 .words{font-size:8pt;font-style:italic;margin-top:.8mm}
.p-80 .chuyen{font-size:8pt;text-align:center;line-height:1.5}
.p-80 .chuyen b{font-weight:800}
.p-80 .ft{text-align:center;font-size:8.5pt;line-height:1.5}
/* VietQR trên bill nhiệt: 30mm cho dễ quét (b132, anh Đạt góp ý — mốc tối
   thiểu của sổ tay là 20mm), viền trắng 4 mô-đun nằm sẵn trong SVG.
   Chữ chỉ một dòng ngắn, SỐ TIỀN tách riêng in to — không để chữ rớt dòng. */
.p-80 .vqr{text-align:center;margin:1.5mm 0 .5mm}
.p-80 .vqr svg{width:30mm;height:30mm}
.p-80 .vqr .t{font-size:8pt;line-height:1.4}
.p-80 .vqr .vamt{font-size:12pt;font-weight:800;margin:.2mm 0 .4mm}
/* Tài khoản dưới mã QR (sửa b147): ngân hàng + số tài khoản một dòng, TÊN CHỦ
   một dòng riêng. Trước đây ba thứ nối bằng dấu chấm giữa nên tên công ty dài
   bị bẻ ngang, nhìn như lỗi in. Tên chừa lề hai bên 3mm để nếu có xuống dòng
   thì cũng gãy ở giữa từ chứ không sát mép giấy. */
.p-80 .vqr .vbank{font-size:8.5pt;font-weight:700;line-height:1.35;margin-top:.3mm}
.p-80 .vqr .vstk{letter-spacing:.35pt}
.p-80 .vqr .vown{font-size:7.5pt;line-height:1.3;letter-spacing:.1pt;padding:0 3mm}
/* Mã vạch số HĐ ở chân bill: cao ~7mm, vạch mảnh ~0.4mm, hai bên trống rộng */
.p-80 .bchd{text-align:center;margin-top:1.6mm}
.p-80 .bchd svg{width:40mm;height:auto}


@media print{
  body{overflow:visible;background:#fff}
  .app,.toasts,.ov{display:none !important}
  #print{display:block !important}

  /* hóa đơn A4/A5 */
  .p-inv{max-width:100%;font-size:11pt;color:#000}
  .p-inv .p-shop{text-align:center;margin-bottom:4mm;font-size:9.5pt;line-height:1.4}
  .p-inv h1{font-size:16pt;margin:0 0 1mm;text-align:center;letter-spacing:.5pt}
  .p-inv .p-sub{text-align:center;font-size:9pt;margin-bottom:5mm}
  .p-inv table{width:100%;border-collapse:collapse;font-size:10pt}
  .p-inv th,.p-inv td{border:1px solid #000;padding:1.6mm 2mm}
  .p-inv th{background:#eee;font-size:9pt;text-transform:uppercase}
  /* Trên màn hình dòng cuối bảng bỏ viền dưới cho thoáng (tbody tr:last-child td),
     nhưng khi IN thì bảng bị hở đáy — trả lại viền cho phiếu in (b123). */
  .p-inv tbody tr:last-child td,.p-list tbody tr:last-child td{border-bottom:1px solid #000}
  .p-inv .p-meta td{border:0;padding:0 0 1mm}
  /* Cột phải của phần thông tin đầu phiếu: trước canh phải nên chữ dí sát mép
     giấy. Nay là một cột rộng cố định, canh trái (b126). */
  .p-inv .p-meta td.rt{width:46%;text-align:left;padding-left:8mm}
  /* Phiếu giao hàng: nhãn thành cột riêng, giá trị có gạch chân để điền tay.
     Trước đây ĐT/Số xe canh phải nên bị dí sát rìa giấy (b123). */
  .p-inv .p-dl{table-layout:fixed}
  .p-inv .p-dl td{padding:0 0 2mm;vertical-align:bottom}
  .p-inv .p-dl .lb{width:26mm;font-weight:700;white-space:nowrap}
  .p-inv .p-dl .lb2{width:18mm;font-weight:700;white-space:nowrap;padding-left:6mm}
  .p-inv .p-dl .vl,.p-inv .p-dl .vl2{border-bottom:1px dotted #999;padding:0 4mm 1mm 2mm}
  .p-inv .p-dl .vl2{width:40mm;padding-right:1mm}
  /* Khối tiền thu hộ khi giao (COD) — b131 thêm ô VietQR bên phải */
  .p-inv .p-cod{border:1.6pt solid #000;padding:2.5mm 3mm;margin-top:4mm;text-align:center;
    display:flex;align-items:center;justify-content:center;gap:5mm}
  .p-inv .p-cod .cod-main{flex:1;min-width:0}
  .p-inv .p-cod .cod-qr{flex:0 0 auto;font-size:7.5pt;line-height:1.35;text-align:center}
  .p-inv .p-cod .cod-qr svg{width:22mm;height:22mm;display:block;margin:0 auto .5mm}
  .p-inv .p-cod .cod-hd{font-size:9.5pt;font-weight:700;letter-spacing:.6pt}
  .p-inv .p-cod .cod-amt{font-size:19pt;font-weight:800;line-height:1.15;margin:.6mm 0}
  .p-inv .p-cod .cod-w{font-size:9pt;font-style:italic}
  .p-inv .p-cod .cod-note{font-size:9pt;margin-top:1.4mm}
  .p-inv .p-cod .cod-tick{margin-left:3mm;white-space:nowrap}
  .p-inv .p-cod.none{border:1pt dashed #666;font-size:9.5pt;font-weight:700;padding:2mm 3mm}
  .p-inv .p-sum{width:74mm;margin-left:auto;margin-top:3mm}
  .p-inv .p-sum td{border:0;padding:.8mm 0;font-size:10pt}
  .p-inv .p-sum tr.g td{border-top:1px solid #000;font-weight:700;font-size:11.5pt;padding-top:1.4mm}
  .p-inv .p-words{margin-top:3mm;font-size:9.5pt;font-style:italic}
  .p-sign{display:flex;justify-content:space-around;margin-top:14mm;font-size:10pt;text-align:center}
  .p-ft{margin-top:8mm;text-align:center;font-size:9pt;font-style:italic}

  /* bảng giá / báo cáo */
  .p-list table{width:100%;border-collapse:collapse;font-size:9.5pt}
  .p-list th,.p-list td{border:1px solid #999;padding:1.4mm 2mm}
  .p-list th{background:#eee}
  .p-list tr,.p-list .label{page-break-inside:avoid}
  .labels{display:grid;grid-template-columns:repeat(3,1fr);gap:2mm}
  .label{border:1px dashed #999;padding:2mm}
  .p-h{font-size:14pt;font-weight:800;margin:0 0 4mm}
  @page{size:A4;margin:11mm}
}
@media print{
  body.k80 .p-inv{display:none}
  body:not(.k80) .p-80{display:none}
}

/* ===== SOURCE: styles/responsive-core.css ===== */
/* ---------- màn nhỏ ---------- */
@media (max-width:1240px){ .pos3{grid-template-columns:minmax(0,1fr) 400px} }
@media (max-width:1024px){ .pos3{grid-template-columns:minmax(0,1fr) 360px} }
@media (max-width:880px){
  :root{--rail:0px}
  .app{grid-template-columns:1fr}
  .rail{
    position:fixed;bottom:0;left:0;right:0;z-index:60;flex-direction:row;
    padding:4px 2px;gap:0;overflow-x:auto;box-shadow:0 -2px 14px rgba(8,51,79,.2);
  }
  .brand,.rail-sp,.rail-ft,.rail-line{display:none}
  .navbtn{flex:1 0 auto;min-width:68px;padding:7px 3px;font-size:9.5px}
  .navbtn svg{width:19px;height:19px}
  .navbtn.on::before{left:12%;right:12%;top:0;bottom:auto;width:auto;height:3px;border-radius:0 0 3px 3px}
  .view{padding:12px 12px 78px}
  .pos3{grid-template-columns:1fr;padding:10px 10px 78px;height:auto}
  .pane{overflow:visible}
  .tape-col{border-left:0;padding:0;min-height:340px}
  .tape{min-height:300px}
  .results{overflow:visible}
  .fgrid{grid-template-columns:1fr}
  .head{padding:0 12px;gap:9px}
  .head h1{font-size:14.5px}
  .head .sub{display:none}
  .mobile-account{margin-left:auto;flex:0 0 40px;border:1px solid var(--line);background:var(--sky-50)}
  .tbl-wrap{max-height:none}
  .kpi .v{font-size:19px}
  .m-ft .btn{flex:1}
  .ov.drawer-host{padding:0;place-items:stretch}
  .modal.drawer,.modal.drawer.wide{width:100vw;max-width:none;height:100dvh;max-height:100dvh;border-radius:0}
  .modal.drawer .m-hd{border-radius:0}
  .resource-toolbar .resource-search{max-width:none;flex:1 0 100%}
  .resource-toolbar .toolbar-sp{display:none}
  .sale-follow{left:8px;right:8px;bottom:66px;padding:9px;gap:8px;min-height:60px}
  .sale-follow:not([hidden]) + .toasts{bottom:138px}
  .sf-state{width:34px;height:34px;flex-basis:34px}
  .sf-copy{display:block}
  .sf-copy strong,.sf-copy span{display:block;max-width:100%}
  .sf-copy span:not(.num){display:none}
  .sf-actions button{width:40px;padding:0;justify-content:center}
  .sf-actions button span{display:none}
  .sf-actions .sf-close{display:none}
}

@media (max-width:560px){
  .onboard-empty{min-height:0;padding:28px 14px}
  .empty-steps{gap:6px;margin-bottom:17px}
  .empty-steps>span{display:block;padding:8px 5px;text-align:center}
  .empty-steps b{margin:0 auto 4px}
  .empty-steps em{font-size:10px;white-space:normal}
  .empty-steps>i{font-size:17px}
  .empty-actions{flex-direction:column;width:100%}
  .empty-actions .btn{width:100%;max-width:320px}
}

/* ---------- bán hàng bằng giọng nói ---------- */
.scan-mic{
  width:40px;height:40px;border-radius:var(--r);background:var(--or);
  display:grid;place-items:center;color:#fff;flex:0 0 auto;transition:background .12s,color .12s;
}
.scan-mic:hover{background:var(--or-6)}
.scan-mic svg{width:19px;height:19px;stroke-width:1.8}
.scan-mic.on{background:var(--or);color:#fff;box-shadow:0 0 0 0 rgba(249,115,22,.6);animation:mic 1.6s ease-out infinite}
@keyframes mic{0%{box-shadow:0 0 0 0 rgba(249,115,22,.55)}70%{box-shadow:0 0 0 12px rgba(249,115,22,0)}100%{box-shadow:0 0 0 0 rgba(249,115,22,0)}}
@media (prefers-reduced-motion:reduce){.scan-mic.on{animation:none}}

.vpanel{
  background:var(--paper);border:1px solid var(--line);border-left:4px solid var(--or);
  border-radius:var(--r-lg);padding:11px 13px;box-shadow:var(--shadow);
}
.vhead{display:flex;align-items:center;gap:9px;font-size:12.5px;color:var(--sky-800)}
.vdot{width:9px;height:9px;border-radius:50%;background:var(--or);animation:pulse 1.4s ease-in-out infinite}
@media (prefers-reduced-motion:reduce){.vdot{animation:none}}
.vtts{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:600;color:var(--slate);white-space:nowrap}
.vtts input{width:auto;margin:0}
.vheard{
  margin-top:8px;font-size:16px;font-weight:600;color:var(--ink);min-height:24px;line-height:1.35;
}
.vmsg{
  margin-top:8px;padding:8px 11px;border-radius:var(--r);font-size:13px;
  background:var(--sky-50);color:var(--ink-2);border:1px solid var(--line);
}
.vmsg.ok{background:var(--green-soft);border-color:#BFE3D5;color:#0B5F44}
.vmsg.err{background:var(--red-soft);border-color:#EDD3D0;color:var(--red)}
.vmsg.ask{background:var(--or-50);border-color:#F6D9BC;color:var(--or-7)}
.vchoices{display:grid;gap:6px;margin-top:8px}
.vch{
  display:flex;align-items:center;gap:9px;text-align:left;width:100%;
  border:1px solid var(--line);border-radius:var(--r);padding:8px 11px;background:var(--paper);
  font-size:13px;transition:border-color .12s,background .12s;
}
.vch:hover{border-color:var(--or);background:var(--or-50)}
.vch b{
  width:22px;height:22px;border-radius:5px;background:var(--sky-600);color:#fff;
  display:grid;place-items:center;font-size:12px;flex:0 0 auto;
}
.vch span:nth-of-type(1){flex:1;font-weight:600}
.vcmds{margin-top:9px;font-size:11px;color:var(--slate-2);line-height:1.5}

/* ---------- cho thuê ---------- */
.eqrow{display:grid;grid-template-columns:1fr 78px 110px 108px 34px;gap:8px;align-items:center;margin-bottom:7px}
.eqrow input,.eqrow select{padding:7px 9px;font-size:13px}
/* Số tiền canh phải để hàng nghìn thẳng cột — đo 17/09 thấy "9000" canh trái,
   không dấu chấm, trong khi cả app dùng money() ra "9.000". */
.eqrow input.num{text-align:right}
.eqrow .eqtt{text-align:right;font-weight:700;font-size:13px;color:var(--ink);padding-right:2px}
.eqrow.eqhd{
  font-size:10px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--slate);
  margin-bottom:3px;
}
.eqrow.eqhd span{padding-left:2px}
.eqrow.eqhd span.r{text-align:right;padding-left:0;padding-right:2px}
/* .eqo chỉ là cái bọc để MÀN HÌNH HẸP có nhãn riêng cho từng ô — trên máy bàn
   nó tàng hình (display:contents) nên ô con vẫn là ô lưới, hàng tiêu đề vẫn thẳng. */
.eqrow .eqo{display:contents}
.eqrow .eqo>span{display:none}
@media (max-width:880px){
  .eqrow{grid-template-columns:1fr 62px 90px 92px 30px;gap:5px}
  .eqrow.eqhd{font-size:10px}
}
/* 🔴 Đo 17/09 trên 390px: ô chọn thiết bị bị ép còn 28px — KHÔNG ĐỌC ĐƯỢC đang
   cho thuê cái gì. Màn hẹp thì mỗi thiết bị là một thẻ: tên chiếm trọn dòng
   trên, ba con số nằm dòng dưới, mỗi con số có nhãn của nó. */
@media (max-width:560px){
  .eqrow.eqhd{display:none}
  .eqrow{
    grid-template-columns:1fr 1fr minmax(72px,auto) 30px;
    gap:6px 8px;align-items:end;
    border:1px solid var(--line);border-radius:10px;
    padding:9px 10px;margin-bottom:9px;background:var(--paper);
  }
  .eqrow>select{grid-column:1/-1;grid-row:1;min-width:0}   /* tên thiết bị chiếm trọn dòng, không bị cắt */
  .eqrow>.icobtn{grid-column:4;grid-row:2;justify-self:end}
  .eqrow .eqo{display:block;grid-row:2;min-width:0}
  /* nhãn phải nằm gọn MỘT dòng, nếu không "GIÁ THUÊ / NGÀY" xuống hai dòng
     làm ba nhãn so le nhau (đo 17/09) */
  .eqrow .eqo>span{
    display:block;font-size:9.5px;font-weight:700;letter-spacing:0;
    text-transform:uppercase;color:var(--slate);margin-bottom:2px;
    white-space:nowrap;
  }
  .eqrow .eqo>input{width:100%}
  .eqrow .eqo:last-of-type{text-align:right}
  .eqrow .eqtt{line-height:38px}
}

/* b223 · khối .pin (ô ĐƠN GIÁ trong hàng dưới) đã BỎ: anh Đạt 10/09 thấy hai
   con số giá trùng nhau trên cùng một dòng. Nay chỉ còn một số — thành tiền —
   và cây bút cạnh nó (.tt / .ttin / .ttbut ở pos.css). */
.pin button{
  width:19px;height:19px;border-radius:4px;display:grid;place-items:center;
  font-size:12px;color:#fff;background:var(--or);border:0;
}
.pin button:hover{background:var(--or-7)}
@media (max-width:1240px){ .pin b{display:none} }
@media (max-width:880px){ .pin input{width:82px;min-width:82px;flex:0 0 82px} }

/* bộ lọc bảng giá */
.chips{display:flex;gap:7px;flex-wrap:wrap}
.chip{
  display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:100px;
  background:var(--sky-100);color:var(--sky-700);font-size:12px;font-weight:600;
  border:1px solid var(--sky-300);
}
.chip i{font-style:normal;font-size:11px;opacity:.7}
.chip:hover{background:var(--sky-300);color:var(--sky-900)}
.pickbar{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:9px 11px;margin-bottom:12px;
  background:var(--or-50);border:1px solid #F6D9BC;border-radius:var(--r);
}
@media print{ .pickbar{display:none} .p-list input[type=checkbox]{display:none} }

/* ===== SOURCE: styles/filters.css ===== */
/* hàng thẻ chọn nhiều mục */
.chiprow:empty{display:none}
.chiprow{margin-top:10px}

.chiprow-lb{
  font-size:10px;font-weight:700;letter-spacing:.11em;text-transform:uppercase;
  color:var(--slate);flex:0 0 auto;margin-right:2px;
}
.chiprow-hint{font-size:11.5px;color:var(--slate-2)}
.chip2{
  display:inline-flex;align-items:center;gap:5px;padding:4px 11px;border-radius:999px;
  border:1px solid var(--line);background:var(--paper);color:var(--ink-2);
  font-size:12.5px;font-weight:600;white-space:nowrap;
}
.chip2 i{
  font-style:normal;font-size:10.5px;font-weight:700;font-family:var(--f-mono);
  color:var(--slate-2);background:var(--bg);padding:0 5px;border-radius:999px;
}
.chip2:hover{border-color:var(--sky-400);background:var(--sky-50)}
.chip2.on{background:var(--sky-900);border-color:var(--sky-900);color:#fff}
.chip2.on i{background:rgba(255,255,255,.22);color:#fff}
.chip2.clr{border-style:dashed;color:var(--slate);font-weight:500}
.chip2.lv2{font-size:11.5px;font-weight:500;color:var(--slate);border-style:dashed}
.chip2.lv2.on{color:#fff;border-style:solid}
.chip2.more{border-style:dashed;color:var(--sky-700);border-color:var(--sky-300);background:var(--sky-50);font-weight:600}
.chip2.more:hover{background:var(--sky-100)}
.chiprow-in{display:flex;align-items:center;gap:6px;flex-wrap:wrap;row-gap:6px}

/* ===== SOURCE: styles/commerce.css ===== */
/* ============ b175 · ngăn Bộ lọc + Cài đặt chia mục + kho tài khoản ============ */

.fpanel{
  background:var(--bg);border:1px solid var(--line);border-radius:var(--r);
  padding:4px 12px 12px;margin-top:10px;
}
.fpanel .chiprow{margin-top:8px}
.btn.fbtn .fn{
  font-family:var(--f-mono);font-size:10.5px;font-weight:700;background:var(--sky-900);
  color:#fff;border-radius:999px;padding:0 6px;margin-left:2px;
}
.btn.fbtn .caret{margin-left:4px;font-size:10px;color:var(--slate)}
.btn.fbtn.on{border-color:var(--sky-400);background:var(--sky-50)}

.set-nav{
  display:flex;gap:6px;flex-wrap:wrap;margin-bottom:16px;
  border-bottom:1px solid var(--line);padding-bottom:12px;
}
.set-nav button{
  border:1px solid var(--line);background:var(--paper);color:var(--ink-2);
  border-radius:999px;padding:6px 14px;font-size:12.5px;font-weight:600;cursor:pointer;
}
.set-nav button:hover{background:var(--sky-50);border-color:var(--sky-300)}
.set-nav button.on{background:var(--sky-900);border-color:var(--sky-900);color:#fff}

.bk-list{display:flex;flex-direction:column;gap:8px}
.bk-row{
  display:flex;align-items:center;gap:10px;justify-content:space-between;
  border:1px solid var(--line);border-radius:var(--r);padding:9px 12px;background:var(--paper);
}
.bk-info{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;min-width:0}
.bk-info .num{font-family:var(--f-mono);font-weight:700}
.bk-ten{font-size:12.5px;color:var(--slate)}
.bk-act{display:flex;gap:6px;flex:0 0 auto}
.bk-edit{
  border:1px solid var(--sky-300);border-radius:var(--r);padding:12px;background:var(--sky-50);
  display:grid;grid-template-columns:1fr 1fr;gap:10px;
}
.bk-edit .f{margin:0}
.bk-edit-bar{grid-column:1/-1;display:flex;justify-content:flex-end}
@media (max-width:880px){
  .bk-edit{grid-template-columns:1fr}
  .bk-row{flex-wrap:wrap}
  .set-nav{overflow-x:auto;flex-wrap:nowrap;padding-bottom:10px}
  .set-nav button{white-space:nowrap}
}

.lrn{
  font-size:10px;font-weight:700;padding:1px 5px;border-radius:4px;
  background:var(--green-soft);color:var(--green);white-space:nowrap;
}
.navbtn.lockbtn{margin-top:6px;border-top:1px solid rgba(255,255,255,.14);padding-top:12px}
.navbtn.lockbtn.on{background:var(--or);color:#fff}
.navbtn.lockbtn.on::before{display:none}
.navbtn.lockbtn.on:hover{background:var(--or-6)}

/* ============ nhiều hóa đơn cùng lúc ============ */

.tabs::-webkit-scrollbar{height:0}

.tab:hover{background:var(--sky-50);color:var(--ink)}
.tab.on{
  background:var(--sky-900);color:#fff;border-color:var(--sky-900);
}
.tab.on .ts{color:#9AA3B2}
.tab.on i{opacity:.6;color:#fff}
.tab.on i:hover{background:rgba(255,255,255,.18);color:#fff}
.tab .tn{
  font-size:11px;font-weight:800;min-width:19px;height:19px;padding:0 5px;border-radius:10px;
  background:var(--or);color:#fff;display:grid;place-items:center;
}
.tab .ts{font-size:12.5px;color:var(--slate);font-weight:700}

.tab i{font-style:normal;font-size:13px;opacity:.4;padding:2px 4px;border-radius:4px;margin:-2px -4px -2px 0}
.tab i:hover{opacity:1;color:var(--red);background:var(--red-soft)}
.tab.add{
  background:var(--sky-50);border:1.5px dashed var(--sky-300);color:var(--sky-700);
  font-size:13.5px;font-weight:700;padding:9px 14px 9px 11px;gap:6px;
}
.tab.add b{
  font-size:17px;font-weight:700;line-height:1;width:22px;height:22px;border-radius:6px;
  background:var(--sky-600);color:#fff;display:grid;place-items:center;
}
.tab.add:hover{background:var(--sky-100);border-color:var(--sky-500);border-style:solid}
.tab.add:hover b{background:var(--or)}

/* ============ tiền khách đưa · tiền thối ============ */
.cashbox{
  margin-top:7px;padding:7px 9px;border-radius:var(--r);
  background:var(--paper);border:1px solid #D2D7DE;
}
.cashrow{display:flex;align-items:center;gap:10px;min-width:0;flex-wrap:wrap;margin-top:4px}
.cashrow .lb{font-size:12.5px;color:var(--slate);flex:0 0 auto}
.cashbox input{
  width:106px;flex:0 0 106px;text-align:right;font-family:var(--f-mono);font-size:14px;font-weight:700;
  padding:3px 8px;background:var(--paper);
}
.cashrow .chg{
  margin-left:auto;font-size:12px;font-weight:700;color:var(--green);white-space:nowrap;
}
.cashrow .chg b{font-family:var(--f-mono);font-size:15.5px;letter-spacing:-.3px;margin-left:3px}
.cashrow .chg.short{color:var(--red)}
.quickcash{display:flex;gap:5px;margin:9px 0 0;overflow-x:auto;min-width:0;scrollbar-width:none}
.quickcash::-webkit-scrollbar{height:0}
.quickcash button{
  flex:0 0 auto;padding:3px 8px;border-radius:5px;border:1px solid var(--line);background:var(--paper);
  font-family:var(--f-mono);font-size:11px;font-weight:700;color:var(--sky-700);
}
.quickcash button:hover{background:var(--sky-600);border-color:var(--sky-600);color:#fff}
.quickcash button.clr{font-family:var(--f-ui);color:var(--slate-2);border-style:dashed}
.quickcash button.clr:hover{background:var(--red-soft);border-color:#EDD3D0;color:var(--red)}

/* ============ kiểm kho bằng máy quét ============ */
.ck-scan{border-radius:var(--r-lg)}
.ck-step{display:flex;gap:3px;flex:0 0 auto}
.ck-step button{
  padding:6px 9px;border-radius:var(--r-sm);font-size:12px;font-weight:700;
  background:rgba(255,255,255,.12);color:#C9CFD8;
}
.ck-step button:hover{background:rgba(255,255,255,.2);color:#fff}
.ck-step button.on{background:var(--or);color:#fff}
.ck-last:empty{display:none}
.ck-last{margin-bottom:11px}
.ck-last-in{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.ck-lb{
  font-size:10px;font-weight:700;letter-spacing:.11em;text-transform:uppercase;color:var(--slate);
}
.ck-chip{
  display:inline-flex;align-items:baseline;gap:5px;padding:4px 9px;border-radius:100px;
  background:var(--sky-50);border:1px solid var(--line);font-size:12px;color:var(--ink-2);
}
.ck-chip.new{background:var(--green-soft);border-color:#BFE3D5;color:#0B5F44}
.ck-chip b{font-family:var(--f-mono);font-size:12.5px}
.ck-chip em{font-style:normal;font-size:10.5px;color:var(--slate-2);font-family:var(--f-mono)}

/* thanh tab xuống dòng thay vì cuộn ngang */
.tabs{display:flex;gap:5px;overflow-x:auto;padding-bottom:0;flex-wrap:wrap;overflow:visible;row-gap:5px}
.tab{display:inline-flex;align-items:center;gap:8px;flex:0 0 auto;padding:10px 14px;border-radius:var(--r);min-height:40px;background:var(--paper);border:1px solid var(--line);color:var(--ink-2);font-size:14px;font-weight:600;white-space:nowrap;transition:background .12s,color .12s,border-color .12s;max-width:180px}
.tab .tl{overflow:hidden;text-overflow:ellipsis}

/* khối kết quả tìm nằm ngay trên hàng bán chạy */

.res-x{
  width:27px;height:27px;border-radius:7px;display:grid;place-items:center;
  background:var(--red);color:#fff;font-size:14px;font-weight:800;box-shadow:0 1px 3px rgba(180,35,35,.24);
}
.res-x:hover{background:#9F1D1D;color:#fff}
/* Tiêu đề khu hàng là MỘT Ô SÁNG bên trái, không phải dải xám vắt ngang cả
   hàng (anh Đạt chốt 03/09). Đệm đều trên dưới nên chữ nằm giữa ô, không bị
   đẩy lên. Số lượng nằm trong huy hiệu cam đặc để đọc được từ xa. */
.res-head{display:flex;align-items:center;gap:8px;margin-bottom:9px;padding:0 0 8px;position:sticky;top:0;background:#EEF3F7;z-index:2}
.res-title{display:inline-flex;align-items:center;gap:7px;min-width:0;padding:7px 12px;border-radius:999px;
  background:var(--paper);border:1.5px solid var(--or);box-shadow:0 1px 4px rgba(249,115,22,.16);
  color:var(--or-safe);font-size:11px;font-weight:800;letter-spacing:.11em;text-transform:uppercase;line-height:1;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.res-count{display:inline-grid;place-items:center;min-width:21px;height:21px;padding:0 6px;border-radius:999px;
  background:var(--or);color:var(--ink);font-size:11.5px;font-weight:800;letter-spacing:0}
.res-actions{margin-left:auto;display:flex;align-items:center;justify-content:flex-end;min-width:27px}
.res-head svg{width:14px;height:14px;stroke-width:2.2;color:var(--or)}
/* phiếu bán hàng ở giữa: chữ to hơn cho dễ soát */
.tape-hd{padding:9px 0 8px;border-bottom:1.5px dashed var(--line)}
.tape-hd .shop{font-size:15px}
.item .nm{font-size:13.5px;min-width:0;overflow-wrap:anywhere}
.item .icode{
  font-family:var(--f-mono);font-size:10px;font-weight:500;color:var(--slate-2);
  margin-left:6px;letter-spacing:.02em;
}
.item .tt{font-size:16px}   /* b229 · anh Đạt 11/09: "giá tiền nhìn to hơn 1 chút" — 14 → 16 */
.tape-ft{border-top:2px solid var(--sky-600);padding:6px 16px 8px;margin:0 -16px;background:#F7F9FB}
/* hàng đôi: hai cặp nhãn+ô trên cùng một dòng cho đỡ tốn chiều cao */
/* lưới 2x2: nhãn thẳng cột trái, ô nhập thẳng mép phải, cùng cỡ */
.ftgrid{display:grid;grid-template-columns:1fr 1fr;gap:4px 14px;margin:0}
.fcell{display:flex;align-items:center;justify-content:space-between;gap:8px;
  font-size:13px;color:var(--slate);white-space:nowrap;min-width:0}
.fcell input,.fcell select{width:112px;min-height:29px;flex:none;text-align:right;padding:3px 8px;
  font-size:12.5px;font-weight:700;font-family:var(--f-mono)}
.fcell select{text-align:left;font-family:var(--f-ui);color:var(--ink-2)}
/* Hình thức thanh toán: 3 nút liền nhau thay ô chọn xổ xuống (đối chiếu
   KiotViet, sổ tay mục 1b) — nhìn phát thấy đang chọn gì, bấm 1 nhịp.
   Nút đang chọn nền THAN (cam để dành cho Thanh toán & số tiền — ý đã chốt). */
.fcell.payseg{justify-content:stretch;gap:0}
.pseg{flex:1;min-height:29px;padding:4px;font-size:12px;font-weight:700;text-align:center;
  border:1px solid var(--line);background:var(--paper);color:var(--slate);
  white-space:nowrap;cursor:pointer;transition:background .1s,color .1s,border-color .1s}
.pseg:first-child{border-radius:8px 0 0 8px}
.pseg:last-child{border-radius:0 8px 8px 0}
.pseg+.pseg{border-left:0}
.pseg:hover:not(.on){background:var(--sky-50);color:var(--ink)}
.pseg.on{background:var(--sky-900);border-color:var(--sky-900);color:#fff}
body.big .pseg{font-size:13.5px;padding:7px 4px}
.chgline{display:flex;justify-content:flex-end;align-items:center;gap:7px;
  font-size:12.5px;font-weight:600;color:var(--green);padding:2px 0}
.chgline.short{color:var(--red)}
.chgline b{font-size:15px}
.chgline .chgclr{width:20px;height:20px;border-radius:5px;display:grid;place-items:center;
  color:var(--slate-2);font-size:13px;font-weight:700;border:1px solid var(--line)}
.chgline .chgclr:hover{background:var(--red-soft);color:var(--red);border-color:#E3B9B4}
/* gợi ý mệnh giá khách hay đưa — bấm là điền, điền xong tự ẩn */
.cashsug{display:flex;justify-content:flex-end;gap:6px;padding:3px 0 1px;flex-wrap:nowrap}
.cashsug button{font-size:11.5px;font-weight:700;padding:3px 9px;border-radius:6px;
  background:var(--paper);border:1px solid var(--line);color:var(--ink-2);white-space:nowrap}
.cashsug button:hover{border-color:var(--or);color:var(--or-6)}
.trow{display:flex;justify-content:space-between;align-items:center;font-size:13px;padding:2px 0;color:var(--slate);gap:8px}
/* dòng hàng vừa thêm: sáng lên một nhịp cho dễ thấy */
.item.fresh{
  /* KHÔNG kéo lề âm — khung cắt phần tràn làm mất chữ cái đầu ("Vòi" thành "òi") */
  background:linear-gradient(90deg,var(--or-50),transparent 70%);
  animation:freshIn 1.1s ease-out;
  border-radius:5px;
}
@keyframes freshIn{0%{background-color:#FFE3C6}100%{background-color:transparent}}
@media (prefers-reduced-motion:reduce){.item.fresh{animation:none}}

/* ============ nhận diện bằng ảnh ============ */
/* b254 · `.scan-eye` đã gỡ cùng cái nút của nó (xem `pos.js`). Khung camera
   `.campane` bên dưới VẪN DÙNG — nó là khung quét mã vạch. */
.campane{
  display:flex;flex-direction:column;gap:10px;min-height:0;overflow:auto;
  background:var(--paper);border:1px solid var(--line);border-radius:var(--r-lg);padding:11px 12px 12px;
}
.campane[hidden]{display:none}
.cam-hd{display:flex;align-items:center;gap:8px;font-size:13.5px;color:var(--ink)}
.cam-hd svg{width:16px;height:16px;stroke-width:2;color:var(--or)}
.cam-hd .ph-ai{margin:0}
.ph-wrap{display:grid;grid-template-columns:1fr minmax(230px,300px);gap:12px;min-height:0}
.ph-cam{position:relative;background:#000;border-radius:var(--r);overflow:hidden;aspect-ratio:4/3;max-height:46vh}
.ph-cam video{width:100%;height:100%;object-fit:cover;display:block}
.ph-box{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:62%;aspect-ratio:1;border:2px dashed rgba(255,255,255,.75);border-radius:12px;
  box-shadow:0 0 0 2000px rgba(0,0,0,.28);
}
.ph-side{min-height:180px;overflow:auto}
.ph-lb{font-size:10px;font-weight:700;letter-spacing:.11em;text-transform:uppercase;color:var(--slate);margin-bottom:7px}
.ph-empty{color:var(--slate-2);font-size:13px;padding:16px 0;text-align:center}
.ph-shot{width:100%;border-radius:var(--r);border:1px solid var(--line)}
.ph-list{display:grid;gap:5px;max-height:38vh;overflow:auto}
.ph-hit{
  display:flex;align-items:center;gap:9px;text-align:left;width:100%;
  padding:6px 8px;border:1px solid var(--line);border-radius:var(--r);background:var(--paper);
}
.ph-hit:hover{border-color:var(--sky-400);background:var(--sky-50)}
.ph-hit img,.ph-noimg{width:38px;height:38px;border-radius:6px;object-fit:cover;flex:0 0 auto;background:var(--line-2)}
.ph-n{flex:1;min-width:0;font-size:12.5px;font-weight:600;line-height:1.3}
.ph-n em{display:block;font-style:normal;font-size:10.5px;font-weight:500;color:var(--slate-2);font-family:var(--f-mono)}
.ph-hit b{font-family:var(--f-mono);font-size:13px;color:var(--slate)}
.ph-hit.hi{border-color:#BFE3D5;background:var(--green-soft)}
.ph-hit.hi b{color:var(--green)}
.ph-hit.mid{border-color:#F6D9BC;background:var(--or-50)}
.ph-hit.mid b{color:var(--or-7)}
.ph-acts{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}
.ph-acts .btn.acc{min-width:180px}
.ph-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px}
.ph-card{border:1px solid var(--line);border-radius:var(--r-lg);padding:8px;text-align:center}
.ph-card img{width:100%;aspect-ratio:1;object-fit:cover;border-radius:var(--r-sm);margin-bottom:6px}
.ph-cn{font-size:12px;font-weight:600;line-height:1.3;margin-bottom:2px}
.ph-cm{font-size:10.5px;color:var(--slate-2);font-family:var(--f-mono);margin-bottom:6px}
@media (max-width:900px){ .ph-wrap{grid-template-columns:1fr} }
.ph-tog{
  display:inline-flex;align-items:center;gap:6px;padding:7px 10px;font-size:12px;border-radius:var(--r);
  border:1px solid var(--line);background:var(--paper);font-size:12.5px;font-weight:600;color:var(--ink-2);
}
.ph-tog input{width:auto;margin:0}
.ph-tog:hover{border-color:var(--sky-400);background:var(--sky-50)}
.ph-badge-wrap{position:absolute;left:0;right:0;bottom:10px;display:flex;justify-content:center;pointer-events:none}
.ph-badge{
  padding:7px 14px;border-radius:100px;font-size:13px;font-weight:700;
  background:rgba(6,43,68,.82);color:#fff;backdrop-filter:blur(4px);
}
.ph-badge.ok{background:var(--green);animation:pop .25s ease-out}
@keyframes pop{from{transform:scale(.9);opacity:.6}to{transform:scale(1);opacity:1}}
@media (prefers-reduced-motion:reduce){.ph-badge.ok{animation:none}}
.ph-ai{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:10px}
.ph-i{
  width:19px;height:19px;border-radius:5px;flex:0 0 auto;display:grid;place-items:center;
  background:var(--sky-100);color:var(--sky-700);font-size:10.5px;font-weight:800;font-family:var(--f-mono);
}
.ph-hit.hi .ph-i{background:var(--green);color:#fff}
.ph-hit.mid .ph-i{background:var(--or);color:#fff}
.ph-cam.mirror video{transform:scaleX(-1)}
.ph-tools{position:absolute;top:8px;right:8px;display:flex;gap:6px}
.ph-tools button{
  width:34px;height:34px;border-radius:8px;display:grid;place-items:center;
  background:rgba(6,43,68,.62);color:#fff;backdrop-filter:blur(4px);
}
.ph-tools button:hover{background:var(--or)}
.ph-tools button svg{width:17px;height:17px;stroke-width:2}
.ph-tools button[hidden]{display:none}
.ph-badge.pick{background:var(--or);animation:pop .25s ease-out}

.ph-badge.look{background:rgba(6,43,68,.78)}

/* cảnh báo bán vượt tồn ngay trên dòng hàng */
.item .over{
  font-size:9.5px;font-weight:700;padding:1px 5px;border-radius:4px;margin-left:6px;
  background:var(--red-soft);color:var(--red);white-space:nowrap;vertical-align:1px;
}

/* bảng tra nhanh */
.hgrid{display:grid;grid-template-columns:1fr 1fr;gap:22px}
.hlb{
  font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--or-7);margin-bottom:7px;padding-bottom:5px;border-bottom:1px solid var(--line);
}
.htab{font-size:12.5px;width:100%}
.htab td{padding:5px 8px 5px 0;border:0;vertical-align:top;line-height:1.45}
.htab td:first-child{width:150px;color:var(--ink)}
.htab tr:hover{background:transparent}
.htab .kbd{font-size:11px}
@media (max-width:880px){ .hgrid{grid-template-columns:1fr;gap:14px} }

/* b248 · Bảng "Cột đọc được" trong hộp nhập Excel — kể ra cột nào thành trường
   nào, cột nào bị bỏ qua. Gấp lại mặc định: người nhập file của chính mình thì
   không cần xem, người nhập file KiotViet/MISA thì mở ra soi. */
.fold.khopcot{margin-bottom:var(--space-3)}
.khopbang{width:100%;border-collapse:collapse;font-size:12.5px}
.khopbang td{padding:4px 8px;border-bottom:1px solid var(--line);vertical-align:top}
.khopbang td:first-child{font-weight:600;color:var(--ink);width:50%}
.khopbang td:last-child{color:var(--slate-2)}
.khopbang i{color:var(--slate-2);font-style:normal;opacity:.75}
/* ---- phiếu cho thuê: đọc lại ngày + dòng tổng dính đáy (17/09) ---- */
/* Ô ngày của trình duyệt in mm/dd/yyyy, anh Đạt đọc dd/mm — dòng này đọc lại
   bằng dd/mm và nói luôn số ngày, vì số ngày CHÍNH LÀ số tiền. */
/* ---- form MỘT CỘT, bề rộng ô theo nội dung ----
   Lưới hai cột cho cả phiếu là thứ Baymard nói "never recommended" và NN/g nói
   "multiple columns interrupt the vertical momentum". Ngoại lệ duy nhất được
   phép: 2–3 ô cùng một khối khái niệm — ở đây là cặp ngày giao / ngày hẹn trả. */
.fgrid.mot-cot{grid-template-columns:1fr}
/* Trần chung cho ô chữ dài: modal mở ở chế độ focus rộng 960px, để ô địa chỉ
   kéo hết 924px thì một dòng chữ dài quá tầm mắt. Bảng thiết bị bên dưới vẫn
   dùng trọn bề rộng vì nó là BẢNG, không phải ô nhập. */
.fgrid.mot-cot .f>input,.fgrid.mot-cot .f>select{width:100%;max-width:560px}
/* Bề rộng bằng độ dài chữ sẽ gõ vào (NN/g §6 · GOV.UK text input · Carbon).
   Trước đây 12/13 ô đều rộng 456px — ô CCCD 12 số bằng ô địa chỉ công trình. */
.fgrid.mot-cot .o-ten>input{max-width:340px}
.fgrid.mot-cot .o-so>input{max-width:190px}
.fgrid.mot-cot .o-tien>input{max-width:190px}
.fgrid.mot-cot .o-ma>input{max-width:150px}
.fgrid.mot-cot .o-chon>select{max-width:290px}
.fgrid.mot-cot .o-ht>select{max-width:210px}
.fgrid.mot-cot .ngaydoi{display:flex;gap:13px;flex-wrap:wrap}
.fgrid.mot-cot .ngaydoi>.f{flex:0 0 190px}
/* Một cột thì hướng dẫn hiện thường xuyên, không đợi bấm vào ô mới hiện
   (Carbon: helper text "should remain visible"). Luật ẩn cũ chỉ dành cho
   lưới hai cột chật chỗ. */
.fgrid.mot-cot .f .hint{display:block}
/* Báo lỗi ngay cạnh ô: nhiều dấu hiệu cùng lúc — viền, màu, chữ (NN/g §10). */
.f.loi>input,.f.loi>select{border-color:var(--rd,#dc2626);background:var(--rose-50,#fef2f2)}
.f.loi>label{color:var(--rd,#dc2626)}
.f .loi-chu{margin-top:3px;font-size:11.5px;font-weight:600;color:var(--rd,#dc2626)}
@media (max-width:880px){
  .fgrid.mot-cot .f>input,.fgrid.mot-cot .f>select{max-width:100%}
  .fgrid.mot-cot .ngaydoi>.f{flex:1 1 150px}
}
.ngayxem{
  font-size:12.5px;color:var(--slate);background:var(--sky-50);
  border-left:3px solid var(--sky-2,#94a3b8);
  padding:var(--space-2) var(--space-3);border-radius:var(--r-2,8px);
}
.ngayxem strong{color:var(--ink);font-weight:700}
.ngayxem.xau{background:var(--rose-50,#fef2f2);border-left-color:var(--rd,#dc2626);color:var(--rd,#dc2626)}
.ngayxem.xau strong{color:var(--rd,#dc2626)}
/* Trước đây dòng tổng nằm cuối phần cuộn: đo được 302px bị giấu dưới mép,
   muốn xem tiền phải cuộn. Dính đáy thì nhìn đâu cũng thấy. */
/* Dòng tổng nằm ở CHÂN phiếu, cạnh nút "Lưu & in phiếu" — phần chân không
   cuộn nên con số này không bao giờ bị giấu, và cũng không che ô nào. */
/* Dòng tiền chiếm trọn MỘT dòng riêng phía trên hai nút. Để nó chen cùng dòng
   với nút thì ở khung 660px hai nút bị đẩy xuống, nút chính rơi xuống dưới nút
   Hủy — sai thứ tự (Carbon: nút chính ở cuối form, hộp thoại thì canh phải). */
.m-ft .rsum{
  flex:1 1 100%;order:-1;min-width:0;
  display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--space-1) var(--space-4);
  padding-bottom:var(--space-2);border-bottom:1px solid var(--line);
}
.rsum .rs-a{font-size:12.5px;color:var(--slate)}
.rsum .rs-b{font-size:12.5px;color:var(--slate)}
.rsum strong{font-size:16px;font-weight:800;color:var(--ink)}
.rsum .rs-b i{display:block;font-style:normal;font-size:11px;color:var(--slate-2)}
@media (max-width:880px){ .m-ft .rsum{gap:var(--space-1) var(--space-3)} }

/* ---- phiếu cho thuê: hai VÙNG để vừa một màn máy bán hàng (17/09) ----
   Đo b267 trên 1366×768: phiếu một cột cao 1411px, khung chỉ thấy 496px —
   phải cuộn 915px. Đứng ở quầy với khách mà cuộn ba lượt mới thấy tiền.
   Chia hai vùng: hàng bên trái, người thuê + ngày + tiền bên phải — đúng bố cục
   màn Bán hàng của chính app này. Mỗi vùng BÊN TRONG vẫn một cột, nên không
   phạm luật Baymard (thứ bị cấm là ô nhập xen kẽ trái–phải). */
.modal:has(.phieuthue){max-width:1120px}
/* Cột trái ôm bảng thiết bị + khối tiền; cột phải ôm người thuê + ngày + khối
   gấp. Chia vậy hai cột cao xấp xỉ nhau — để cả khối tiền bên phải thì cột trái
   trống 440px trong khi cột phải tràn xuống dưới mép. */
.phieuthue{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);gap:0 24px;align-items:start}
.phieuthue .fgrid{gap:11px}
/* dòng Cộng của bảng thiết bị — chỉ vẽ khi có từ 2 dòng trở lên */
.eqrow.eqcong{margin-top:2px;padding-top:6px;border-top:1px solid var(--line);align-items:center}
.eqrow.eqcong span.r{font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--slate)}
.eqrow.eqcong .eqtt{font-size:14px;font-weight:800}
/* 🔴 Bọc trong min-width: quy tắc này (0,2,0) đè lên quy tắc thẻ điện thoại
   ≤560px (0,1,0) nếu để trần — đo 390px thấy bảng vẫn giữ 5 cột cứng và ĐẨY
   CẢ PHIẾU TRÀN NGANG 22px, ở 360px là 52px. Chỉ áp khi hai vùng thật sự bày ra. */
@media (min-width:1101px){
  /* Cột trái hẹp hơn máy bàn một cột, nên thu ba cột số của bảng thiết bị lại
     cho TÊN HÀNG đủ chỗ — "Giàn giáo khung 1,53m (Bộ)" cần 200px, ô cho 223px. */
  .phieuthue .eqrow{grid-template-columns:1fr 66px 116px 96px 30px;gap:6px}
  /* nhãn cột nằm gọn MỘT dòng — "GIÁ THUÊ / NGÀY" xuống hai dòng thì ba nhãn so le */
  .phieuthue .eqrow.eqhd span{white-space:nowrap}
}
.phieuthue .sect:first-child{margin-top:0}
.phieuthue #r_parts{margin-top:9px}
/* ô đứng chung hàng khi chúng là MỘT thực thể (tên+điện thoại, hai ngày,
   công+tiền vận chuyển) — ngoại lệ Baymard cho phép, không phải lưới hai cột */
.fgrid.mot-cot .dong{display:flex;gap:12px;flex-wrap:wrap;align-items:flex-start}
.fgrid.mot-cot .dong>.f{flex:1 1 150px;min-width:0}
.fgrid.mot-cot .dong>.f>input,.fgrid.mot-cot .dong>.f>select{max-width:none}
.fgrid.mot-cot .dong>.o-ten{flex:2 1 190px}
/* khối gấp: bốn ô ít dùng, chiếm 272px chiều cao mà phần lớn phiếu không cần */
.pt-them{grid-column:1/-1;border-top:1px solid var(--line);padding-top:var(--space-2)}
.pt-them>summary{
  cursor:pointer;list-style:none;font-size:12px;font-weight:700;color:var(--slate);
  display:flex;align-items:center;gap:6px;padding:3px 0;
}
.pt-them>summary::-webkit-details-marker{display:none}
.pt-them>summary::before{content:'▸';font-size:11px;color:var(--slate-2)}
.pt-them[open]>summary::before{content:'▾'}
.pt-them>summary:hover{color:var(--ink)}
.pt-them>.fgrid{margin-top:var(--space-2)}
/* Phiếu mở 1120px thì chân đủ chỗ cho dòng tiền đứng CÙNG HÀNG với hai nút —
   tiết kiệm 44px chiều cao, đúng 44px đang thiếu để vừa màn 1366×768. */
.modal:has(.phieuthue) .m-ft .rsum{flex:1 1 auto;order:0;margin-right:auto;border-bottom:0;padding-bottom:0}
@media (max-width:1100px){
  .modal:has(.phieuthue){max-width:660px}
  .modal:has(.phieuthue) .m-ft .rsum{flex:1 1 100%;order:-1;margin-right:0;
    border-bottom:1px solid var(--line);padding-bottom:var(--space-2)}
  .phieuthue{grid-template-columns:1fr;gap:0}
  .phieuthue .pt-hang{order:2}
}

/* ---- màn Báo lỗi (b271) ----
   Chỉ còn một ô gõ + một ô chọn lúc. Bảng sáu dòng của b270 đã bỏ: anh Đạt
   *"Mn có đọc hết đâu"* — đúng, người đang gặp lỗi không đọc bảng. */
.fgrid.mot-cot textarea{width:100%;max-width:560px;font-family:inherit;font-size:14px;padding:9px 11px;
  border:1px solid var(--line);border-radius:var(--r-2,8px);background:var(--paper);color:var(--ink);resize:vertical}

.bl-khong{font-size:11.5px;color:var(--slate-2);line-height:1.5}

/* ===== SOURCE: styles/large-ui.css ===== */
/* ============================================================
   CỠ CHỮ LỚN — bấm nút "A" ở góc phải để bật
   Ưu tiên: chữ trên phiếu > nút bấm > thẻ hàng > ô nhập
   ============================================================ */
.bigbtn strong{font-size:16px;font-weight:800}
.bigbtn.on{background:var(--or);color:#fff}
.bigbtn.on:hover{background:var(--or-6);color:#fff}

/* ---- 1. Chữ và số tiền trên phiếu bán hàng ---- */
body.big .tape-hd .shop{font-size:18px}
body.big .item .nm{font-size:14px;font-weight:700}   /* b229 · 15,5 → 14: anh Đạt 11/09 "tên sp cũng không nên to quá" — giá 18px mới là thứ nổi */
body.big .item .icode{font-size:12px}
body.big .item .tt{font-size:18px;font-weight:800}
body.big .trow{font-size:14.5px;padding:3px 0}
body.big .fcell{font-size:14px}
body.big .fcell input,body.big .fcell select{width:118px;font-size:14px}
body.big .chgline{font-size:14px}
body.big .cashsug button{font-size:13px;padding:5px 11px}
body.big .chgline b{font-size:17px}
body.big .trow.tot{font-size:14px;letter-spacing:.06em}
body.big .trow.tot .num{font-size:25px}
body.big .cashrow .lb{font-size:15px}
body.big .cashrow .chg{font-size:15px}
body.big .cashrow .chg b{font-size:20px}
body.big .cust-row input{font-size:14.5px;padding:7px 10px}
body.big .custline{font-size:14px}

/* ---- 2. Nút bấm ---- */
body.big .btn{font-size:15px;padding:11px 18px}
body.big .btn.sm{font-size:13.5px;padding:8px 13px}
body.big .btn.big{padding:12px 18px;font-size:17px}
body.big .qbtn{width:29px;height:29px;font-size:17px}
body.big .item .del{width:28px;height:28px;font-size:16px}
body.big .icobtn{width:32px;height:32px}
body.big .icobtn svg{width:19px;height:19px}
body.big .quickcash button{font-size:13.5px;padding:6px 11px}
body.big .umode{font-size:13px;padding:4px 9px}

/* ---- 3. Thẻ hàng bán chạy ---- */
body.big .grid-p{grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}
body.big .pcard{min-height:132px;padding:14px 15px}
body.big .pcard .pn{font-size:17.5px;-webkit-line-clamp:3}
body.big .pcard .pmeta{font-size:13.5px}
body.big .pcard .pp{font-size:20px}
body.big .pcard .pu{font-size:13px}
body.big .pcard .stk{font-size:13px;padding:3px 8px}

/* ---- 4. Ô nhập số lượng và đơn giá ---- */
/* LỖI CŨ: width:62px bóp khung số lượng làm nút + bị CẮT MẤT ở cỡ chữ lớn
   (đo Playwright: nút chỉ còn 20-21px). Bỏ width cứng, nút nở theo con. */
body.big .item .qty{width:auto;font-size:15px;padding:0}
body.big .qty button{width:32px;height:32px;font-size:17px}
body.big .qty input{width:52px;font-size:14px}
body.big .item .ln .uplain,body.big .item .ln .umode{flex:0 0 auto}
body.big .item .ttx{font-size:12px}
body.big input,body.big select{font-size:15px}

/* ---- các phần khác vừa phải ---- */
body.big{font-size:15px}
body.big .scan-field input{font-size:19px}
body.big .scan-field label{font-size:11.5px}
body.big .head h1{font-size:17.5px}
body.big .navbtn{font-size:11.5px;padding:12px 4px}
body.big .navbtn svg{width:23px;height:23px}
body.big .tab{font-size:15.5px;min-height:46px;padding:11px 16px}
body.big .tab .ts{font-size:14px}
body.big .tab.add{font-size:15px}
body.big table{font-size:14.5px}
body.big thead th{font-size:11px}
body.big .kpi .v{font-size:26px}
body.big .kpi .k{font-size:12.5px}
body.big .m-hd h3{font-size:17px}
body.big .empty h3{font-size:17px}
body.big .empty p{font-size:14.5px}
body.big .res-title{font-size:12.5px;padding:8px 13px}
body.big .res-count{min-width:23px;height:23px;font-size:13px}
body.big .hint,body.big .note{font-size:13.5px}
body.big .pill{font-size:12.5px}

/* cột phiếu rộng thêm khi chữ to, để tên hàng không bị cắt */
body.big .tape{border-width:3px}
body.big .tape-in{padding:0 18px}
body.big .tape-bar{padding:13px 18px;margin:0 -18px}
body.big .tape-ft{padding:9px 18px 11px;margin:0 -18px}
/* b229 · lề ngang 6px như cỡ thường: thẻ dòng có viền khi rê chuột (b127), lề 0 là chữ và
   khung số lượng dính sát viền thẻ */
body.big .item{padding:12px 6px;--cot-xoa:22px;--xoa:28px;--dong1:20px}
body.big .tape-bar .tt{font-size:14px}
body.big .tape-bar .no{font-size:15px}
body.big .tape-date{font-size:10.5px}
body.big .pos3{grid-template-columns:minmax(0,1fr) 520px}
body.big .tape-in{padding:0 16px}
@media (max-width:1500px){ body.big .pos3{grid-template-columns:minmax(0,1fr) 470px} }
@media (max-width:1200px){ body.big .pos3{grid-template-columns:minmax(0,1fr) 420px} }

/* ============ đo & đếm bằng camera ============ */
.mz-wrap{display:grid;grid-template-columns:1fr 300px;gap:14px}
.mz-stage{position:relative;background:#0b1b26;border-radius:var(--r-lg);overflow:hidden;aspect-ratio:4/3}
.mz-stage video,.mz-stage canvas{width:100%;height:100%;object-fit:contain;display:block}
.mz-stage canvas{display:none}
.mz-stage.shot video{display:none}
.mz-stage.shot canvas{display:block}
.mz-stage.shot .mz-hint-live{display:none}
.mz-hint-live{
  position:absolute;left:0;right:0;bottom:10px;text-align:center;
  font-size:12.5px;color:#fff;text-shadow:0 1px 4px rgba(0,0,0,.7);pointer-events:none;
}
.mz-acts{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
.mz-side{min-width:0}
.mz-range{width:100%;margin:2px 0 4px}
.mz-count{
  font-family:var(--f-mono);font-size:34px;font-weight:800;color:var(--or-7);line-height:1;
}
.mz-count span{display:block;font-family:var(--f-ui);font-size:11.5px;font-weight:600;color:var(--slate-2);margin-top:3px}
.mz-tab{width:100%;font-size:12.5px}
.mz-tab td{padding:4px 6px 4px 0;border-bottom:1px solid var(--line-2)}
.mz-tab tr:hover{background:transparent}
@media (max-width:900px){ .mz-wrap{grid-template-columns:1fr} }

/* ---------- ảnh sản phẩm ---------- */
.pcard .pimg{
  position:absolute;right:9px;bottom:8px;top:auto;width:39px;height:39px;object-fit:contain;
  background:#fff;border:1px solid #AEBFCB;border-radius:7px;padding:2px;cursor:zoom-in;
}
.pcard.wide .pimg{width:46px;height:46px}
/* b202 · MÀU ĐỘ DÀY nằm ở VIỀN Ô ẢNH — anh Đạt 05/09: "ý t chỉ cần đổi màu phần viền
   nhỏ này thôi". Chỉ thẻ hàng sắt mới mang `data-ly`, xem lySat() trong catalog-core.js.
   Viền dày lên 2px và bớt padding 1px để ô ảnh không đổi kích thước.
   Quy ước: xám 0,8–0,9ly · xanh lá 1ly · đỏ 1,1–1,2ly · vàng 1,3–1,4ly (và 2ly). */
.pcard[data-ly] .pimg{border-color:var(--ly);border-width:2px;padding:1px}
.pcard[data-ly="08"]{--ly:#8A939F}
.pcard[data-ly="10"]{--ly:#0B8A34}
.pcard[data-ly="12"]{--ly:#D42A20}
.pcard[data-ly="14"]{--ly:#F5C400}
.pimg-prog{height:8px;border-radius:8px;background:var(--sky-100);overflow:hidden;margin:6px 0}
.pimg-prog>div{height:100%;background:var(--sky-600);transition:width .2s}
body.big .pcard .pimg{width:48px;height:48px;bottom:9px}
body.big .pcard .pn{padding-right:58px}
body.big .pcard .prow{padding-right:60px}
.ph-badge.warn{background:#B45309;color:#fff}

/* thấy nhiều món trong khung */
.ph-many{
  text-align:center;padding:22px 16px;border:2px dashed var(--or);border-radius:var(--r-lg);
  background:var(--or-50);
}
.ph-many .n{font-family:var(--f-mono);font-size:42px;font-weight:800;color:var(--or-7);line-height:1}
.ph-many .t{font-size:13px;color:var(--slate);margin-top:2px;font-weight:600}

/* nút Tiếp tục — to, dễ bấm */
.btn-next{
  width:100%;margin-top:12px;padding:16px 18px;border-radius:var(--r-lg);
  background:linear-gradient(180deg,var(--or),var(--or-6));color:#fff;
  font-size:16px;font-weight:800;letter-spacing:.01em;
  display:flex;flex-direction:column;align-items:center;gap:3px;
  box-shadow:0 3px 10px rgba(249,115,22,.30);transition:transform .1s,box-shadow .12s;
  border:0;cursor:pointer;
}
.btn-next:hover{box-shadow:0 5px 16px rgba(249,115,22,.42)}
.btn-next:active{transform:translateY(1px)}
.btn-next svg{width:19px;height:19px}
.btn-next em{font-size:11.5px;font-weight:600;font-style:normal;opacity:.9}
body.big .btn-next{padding:20px;font-size:19px}
body.big .btn-next em{font-size:13px}

/* báo đã thêm xong */
.ph-done{
  text-align:center;padding:20px 14px;border-radius:var(--r-lg);
  background:var(--green-soft);color:var(--green);font-size:14.5px;font-weight:700;
}
.ph-done svg{width:32px;height:32px;stroke-width:2.4;margin-bottom:6px}

/* ============================================================
   ẢNH HÀNG TRONG THẺ CHỌN — KHỐI NÀY PHẢI NẰM CUỐI TỆP
   ============================================================
   15/09 · anh Đạt: ảnh sang trái, phủ kín dải, mã sát tên, số lượng góc dưới
   phải. Bề rộng dải chốt 29% bề ngang thẻ, viết bằng PHẦN TRĂM để đổi màn là
   tỷ lệ vẫn đúng.

   29% đo được, không phải con số cho đẹp: 245 tên hàng THẬT của tiệm (ổ điện
   Điện Quang, gạch cắt đá, băng keo Tô Nga Dũng, Luxta, Sopoka) dựng đúng phông
   Be Vietnam Pro 700 cỡ 15px của thẻ — trung vị cần 235px một dòng, 3/4 cần
   279px. Ở thẻ 431px, dải 41% chỉ cho 45% số tên nằm gọn một dòng; hạ xuống 29%
   thì lên 77%. Qua 29% là hết lời — 26% chỉ thêm 4 điểm mà ảnh nhỏ đi thấy rõ.

   🔴 VÌ SAO KHỐI NÀY PHẢI Ở CUỐI TỆP — lỗi thật, 16/09:
   `body.big .pcard .pimg{width:48px;height:48px}` nằm giữa tệp, đặc tả BẰNG
   `.pcard:has(.pimg) .pimg` (cùng 0,3,0) nên ai đứng sau thì thắng. Khối này
   viết ở TRÊN nó, thành ra ở chế độ CHỮ TO ảnh mất `width:29%` và `height:100%`,
   chỉ còn `left:0;top:0` của `inset` → co về 48px dính góc trên-trái, ĐÈ LÊN
   tên và mã hàng. Bản thường nhìn đúng, bản chữ to hỏng — không ai thấy cho tới
   khi anh Đạt mở bằng chế độ chữ to.
   ⇒ Khối ở cuối tệp, VÀ có bản riêng cho `body.big`, không trông vào thứ tự.
   ⇒ `tests/kiem-giao-dien.js` có cổng cấm mọi dòng đặt cỡ `.pimg` nằm sau khối
      này — thêm một dòng như vậy là bài kiểm đỏ ngay.

   16/09 · object-fit ĐỔI TỪ cover SANG contain. Anh Đạt: "ảnh bị chèn mất đầu
   đuôi, không còn nguyên sản phẩm". cover lấp đầy dải nhưng xén hai rìa — cái
   van mất hai đầu ren, cây ống mất hai đầu. Ảnh hàng của tiệm chụp nền trắng,
   nên contain chỉ thêm lề TRẮNG trên nền thẻ cũng trắng: lề không lộ ra, mà món
   hàng còn nguyên. Đo kho ảnh 16/09: tệp gốc 682–1333 px (BM là 1333×1042),
   thu về khung 125–186 px — tức đang lấy ảnh TO thu nhỏ, không phóng ảnh nhỏ.

   border-width:0 chứ không bỏ hẳn border: viền này là chỗ hiện MÀU ĐỘ DÀY hàng
   sắt (b202, anh Đạt chốt 05/09). Thẻ mang data-ly vẫn tô màu được như cũ.

   Ngưỡng 1600px, không thấp hơn: ở 1440px thẻ chỉ rộng 271px, dải ảnh ăn 78px
   là tên hàng vỡ ba dòng — tệ hơn bản cũ.
   Thẻ KHÔNG có ảnh giữ nguyên hoàn toàn — 4/5 mã trong sổ chưa có ảnh. */
@media (min-width:1600px){
  /* 16/09 · Ô ẢNH CHỪA SẴN CHO MỌI THẺ, kể cả mã chưa có ảnh — anh Đạt chốt:
     "để sẵn ô, sản phẩm chưa có ảnh thì để ô trắng, sau này có ảnh chỉ thay".
     Trước đó chỉ thẻ CÓ ảnh mới lùi chữ, nên lưới so le: thẻ có ảnh chữ bắt đầu
     ở 29%, thẻ không ảnh chữ sát mép trái. 4/5 mã trong sổ chưa có ảnh nên lưới
     so le là cảnh thường gặp, không phải hiếm.
     Chừa chỗ bằng `padding-left` trên MỌI thẻ; nền thẻ vốn trắng nên chỗ chừa
     tự là ô trắng, không cần vẽ thêm gì. Thêm ảnh sau này là nó lấp đúng ô đó,
     lưới không nhảy một pixel nào.
     Bỏ luôn `:has()` ở đây — `.pimg` chỉ tồn tại khi có ảnh, nên `:has` là thừa,
     mà bỏ được thì trình duyệt cũ không hỗ trợ `:has` cũng ra đúng bố cục. */
  .pcard,
  body.big .pcard{min-height:118px;padding-left:calc(29% + 14px)}
  .pcard .pimg,
  .pcard.wide .pimg,
  body.big .pcard .pimg{
    inset:0 auto 0 0;width:29%;height:100%;
    object-fit:contain;padding:0;border-width:0;border-color:transparent;
    background:transparent;border-radius:11px 0 0 11px;
  }
  /* 16/09 · CHẾ ĐỘ CHỮ TO hạ dải ảnh 29% → 25% (anh Đạt chốt "24% là ổn, hoặc 25%").
     Lý do dùng 25% chứ không 24%: đo 245 tên hàng thật ở 1920px, cỡ chữ 17.5px
     của chế độ chữ to — 29% cho 51% tên vừa MỘT dòng, 25% cho 59%, 24% cho 60%.
     Chênh 24 với 25 đúng 1 điểm phần trăm (2 mã trong 245), mà 25% cho ảnh rộng
     hơn 5px. Chỉ hạ ở chế độ chữ to; chữ thường giữ 29% như anh Đạt chốt 15/09,
     vì ở cỡ 15px thì 29% đã cho 74% tên một dòng. Cả hai cỡ đều 100% tên vừa
     trong HAI dòng, nên không có mã nào bị cắt ba chấm.
     Hai dòng này phải đứng SAU khối 29% ở trên: cùng đặc tả 0,3,0 nên ai sau thắng. */
  body.big .pcard{padding-left:calc(25% + 14px)}
  body.big .pcard .pimg,
  body.big .pcard.wide .pimg{width:25%}
  /* Tên và mã thôi chừa chỗ bên phải — ảnh đã sang trái, nhãn tồn đã xuống đáy. */
  .pcard .pn,
  body.big .pcard .pn{padding-right:0}
  /* Nhãn tồn xuống góc dưới phải, cùng hàng với giá, trên MỌI thẻ.
     `.pcard.best .stk` phải viết ra: nó có `top:34px` với đặc tả cao hơn, không
     kể tên vào đây thì thẻ khớp-nhất vẫn để nhãn ở trên, lại lệch tiếp. */
  .pcard .prow,
  body.big .pcard .prow{padding-right:76px;flex-wrap:wrap}
  .pcard .stk,
  .pcard.best .stk,
  body.big .pcard .stk,
  body.big .pcard.best .stk{top:auto;bottom:10px;right:13px}
}

/* ===== SOURCE: styles/management.css ===== */
/* ---------- THẺ CHUYỂN MỤC kiểu mới (b121) — có biểu tượng, tương phản mạnh ----------
   Dùng ở: Sản phẩm, Công nợ, Báo cáo. Thẻ đang chọn nền THAN chữ trắng;
   bên nào có khoản quá hạn thì nền ĐỎ SẪM + huy hiệu. */
.tabs2{display:flex;gap:9px;margin-bottom:16px;flex-wrap:wrap}
.tb{flex:1;min-width:210px;display:flex;align-items:center;gap:11px;cursor:pointer;text-align:left;
  border:1.5px solid var(--line);background:#fff;border-radius:13px;padding:11px 14px;font:inherit;color:var(--ink)}
.tb-ic{width:36px;height:36px;flex:0 0 36px;border-radius:10px;background:var(--sky-50);
  display:flex;align-items:center;justify-content:center}
.tb-ic svg{width:19px;height:19px;stroke:var(--slate);fill:none;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.tb-tx{display:flex;flex-direction:column;min-width:0}
.tb .t{font-size:14.5px;font-weight:800;line-height:1.25}
.tb .n{font-size:12px;font-weight:600;color:var(--slate);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tb:hover:not(.on){border-color:var(--sky-300);background:var(--sky-50)}
.tb.on{background:var(--sky-900);border-color:var(--sky-900);color:#fff}
.tb.on .tb-ic{background:rgba(255,255,255,.14)}
.tb.on .tb-ic svg{stroke:#fff}
.tb.on .n{color:#C5CBD4}
.tb.on.warn{background:#6E1E19;border-color:#6E1E19}
.tb-bg{margin-left:auto;flex:0 0 auto;background:var(--red);color:#fff;font-size:11px;font-weight:800;
  border-radius:99px;padding:2px 9px;white-space:nowrap}
@media (max-width:820px){ .tb{min-width:100%} }

/* Trung tâm Quản lý b157: số cần quyết định trước, lối vào công cụ sau.
   b229 · anh Đạt 11/09: "chỉ có 8 mục cho gọn trong 1 trang k phải cuộn" — ba tầng: dòng trạng thái · việc chờ chủ
   (chỉ khi có) · số hôm nay + công cụ 4 × 2. Khối chữ giới thiệu đầu màn (~100px) bỏ: tiêu đề màn đã nói điều đó. */
.smart-section{max-width:1120px;margin:0 auto}
.mg-top{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);margin:0 2px var(--space-3)}
.mg-status{margin:0;font-size:12.5px;color:var(--slate);display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap}
.mg-link{min-height:32px}
.mg-viec{display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-2);margin:0 0 var(--space-3);
  padding:var(--space-2) var(--space-3);background:var(--paper);border:1px solid var(--line);border-radius:var(--r-lg)}
.mg-viec-t{font-size:12.5px;font-weight:700;margin-right:var(--space-1)}
.viec-chip{display:inline-flex;align-items:center;gap:var(--space-1);min-height:40px;padding:0 var(--space-3);border-radius:999px;
  border:1px solid var(--line);background:var(--sky-50);color:var(--ink);font:inherit;font-size:12.5px;font-weight:600;
  cursor:pointer;transition:border-color var(--motion-fast),box-shadow var(--motion-fast)}
.viec-chip b{font-size:14px;font-weight:800}
.viec-chip.rd{background:var(--red-soft);border-color:transparent;color:var(--red)}
.viec-chip.am{background:var(--or-50);border-color:transparent;color:var(--or-safe)}
.viec-chip:hover{border-color:currentColor;box-shadow:var(--shadow)}
.mg-h{margin:0 2px var(--space-2);font-size:12.5px;font-weight:700}
.ops-overview{display:grid;grid-template-columns:repeat(auto-fit,minmax(205px,1fr));gap:var(--space-3);margin-bottom:var(--space-4)}
.ops-stat{position:relative;min-height:84px;display:flex;flex-direction:column;align-items:flex-start;
  justify-content:center;padding:var(--space-3) var(--space-4);text-align:left;background:var(--paper);border:1px solid var(--line);
  border-radius:var(--r-lg);color:var(--ink);overflow:hidden;transition:border-color var(--motion-fast),box-shadow var(--motion-fast)}
button.ops-stat:hover{border-color:var(--sky-300);box-shadow:var(--shadow)}
.ops-stat::before{content:'';position:absolute;inset:0 auto 0 0;width:3px;background:var(--sky-500)}
.ops-stat.am::before{background:var(--or)}
.ops-stat.rd::before{background:var(--red)}
.ops-label{font-size:10px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--slate)}
.ops-value{margin-top:5px;font-size:22px;font-weight:800;letter-spacing:-.6px;line-height:1.15;color:var(--ink)}
.ops-note{margin-top:4px;max-width:100%;font-size:11px;color:var(--slate);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ops-open{position:absolute;right:13px;top:12px;color:var(--sky-400);font-size:22px;font-weight:300}
.smart-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-3)}
.smart-tile{
  min-height:86px;width:100%;display:grid;grid-template-columns:44px minmax(0,1fr) auto 18px;
  align-items:center;gap:12px;padding:14px;text-align:left;background:var(--paper);
  border:1px solid var(--line);border-radius:var(--r-lg);color:var(--ink);
  transition:border-color .12s,background .12s,box-shadow .12s
}
.smart-tile:hover{background:var(--sky-50);border-color:var(--sky-300);box-shadow:var(--shadow)}
.smart-icon{width:44px;height:44px;border-radius:12px;background:var(--sky-50);color:var(--slate);
  display:grid;place-items:center}
.smart-icon svg{width:21px;height:21px;stroke-width:1.9}
.smart-icon.am{background:var(--or-50);color:var(--or-safe)}
.smart-icon.bp{background:var(--sky-100);color:var(--sky-700)}
.smart-icon.rd{background:var(--red-soft);color:var(--red)}
.smart-copy{display:flex;flex-direction:column;min-width:0}
.smart-copy strong{font-size:14px;font-weight:750}
.smart-copy span{font-size:11.5px;color:var(--slate);margin-top:3px;line-height:1.45}
.smart-count{min-width:27px;height:27px;padding:0 7px;border-radius:99px;display:grid;place-items:center;
  background:var(--sky-100);color:var(--sky-700);font-size:11px;font-weight:800}
.smart-count.am{background:var(--or-50);color:var(--or-safe)}
.smart-count.rd{background:var(--red-soft);color:var(--red)}
.smart-arrow{font-size:25px;line-height:1;color:var(--sky-400);font-weight:300}
/* Công cụ 4 × 2: ô thấp, chữ phụ tối đa hai dòng (đủ chữ thì rê chuột đọc ở title), số đếm góc phải. */
.smart-grid.cong-cu{grid-template-columns:repeat(4,minmax(0,1fr));grid-auto-rows:1fr}
.cong-cu .smart-tile{min-height:76px;grid-template-columns:36px minmax(0,1fr) auto;gap:var(--space-3);padding:var(--space-3)}
.cong-cu .smart-icon{width:36px;height:36px;border-radius:var(--r)}
.cong-cu .smart-icon svg{width:19px;height:19px}
.cong-cu .smart-copy span{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
@media (max-width:1120px){ .smart-grid.cong-cu{grid-template-columns:repeat(2,minmax(0,1fr))} }
@media (max-width:760px){
  .smart-grid,.smart-grid.cong-cu{grid-template-columns:1fr}.smart-section{max-width:none}
  .ops-overview{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin-bottom:var(--space-4)}
  .ops-stat{min-height:84px;padding:12px}.ops-value{font-size:19px}.ops-note{white-space:normal}
  .mg-top{align-items:flex-start}.viec-chip{min-height:44px}
}

/* ---------- bảng hóa đơn gọn + nút hành động nằm ngang (b121) ---------- */
/* Dòng phụ là chữ nhỏ nhất màn hình — --slate-2 chỉ đạt tương phản 3.35:1,
   đổi sang --slate cho đạt 5.51:1 (WCAG 4.5:1, sổ tay mục 1). */
.cell-sub{font-size:11.5px;color:var(--slate);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rowacts{display:flex;gap:5px;justify-content:flex-end;flex-wrap:nowrap}
/* Cao ~40px cho đạt vùng bấm (padding dọc 10px, sổ tay mục 1) */
.actbtn{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--line);background:#fff;
  border-radius:9px;padding:10px 12px;font:inherit;font-size:12.5px;font-weight:600;color:var(--ink);cursor:pointer;white-space:nowrap}
.actbtn svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.actbtn:hover{background:var(--sky-50);border-color:var(--sky-300)}
/* chữ #A34A05 thay --or-7: qua mốc tương phản 4.5:1 trên nền cam nhạt */
.actbtn.key{background:var(--or-50);border-color:#F5C89A;color:#A34A05}
.actbtn.key:hover{background:#FFE7CE}
.actbtn.dg{color:var(--red);border-color:#F0D2D0}
.actbtn.dg:hover{background:#FDF2F2}
.inv-tbl td,.prod-tbl td,.sup-tbl td{vertical-align:middle}
/* Dòng hóa đơn / phiếu giao để THOÁNG hơn — mỗi trang chỉ 8 dòng, dưới còn
   trống nhiều mà chữ lại nhỏ, nhìn mỏi mắt (b125). */
.inv-tbl td{padding:18px 12px;font-size:14px}
.inv-tbl thead th{padding-top:12px;padding-bottom:12px;font-size:11.5px}
.inv-tbl td strong{font-size:14.5px}
.inv-tbl .cell-sub{font-size:12.5px;margin-top:4px}
.inv-tbl .tag{font-size:12px;padding:4px 9px}
.inv-tbl .actbtn{padding:10px 12px;font-size:13px;border-radius:10px}
.inv-tbl .actbtn svg{width:16px;height:16px}
.inv-tbl .rowacts{gap:6px}
.prod-tbl td strong{font-size:13.5px}
.prod-tbl .cell-sub{max-width:340px}
/* Ảnh thu nhỏ 28px trước tên hàng (đối chiếu KiotViet, sổ tay mục 1b) —
   hàng VLXD tên na ná nhau, cái ảnh nhận ra nhanh hơn đọc chữ. */
.pcell{display:flex;align-items:center;gap:10px;min-width:0}
.pcell>div{min-width:0}
.ptimg{width:28px;height:28px;flex:0 0 28px;object-fit:cover;border-radius:6px;
  border:1px solid var(--line-2);background:#fff}
.ptimg.none{background:var(--sky-50);border-style:dashed}

/* ---------- dòng TỔNG tách hẳn khỏi dòng cuối (b122) ----------
   Trước đây dòng tổng chỉ khác nền một chút nên nhìn như một dòng dữ liệu nữa. */
tfoot.tf-sum tr td{
  border-top:2px solid var(--sky-300);
  background:var(--sky-50);
  padding-top:13px;padding-bottom:13px;
  font-weight:800;font-size:12px;letter-spacing:.4px;color:var(--sky-600);
}
tfoot.tf-sum tr td.big{font-size:15.5px;letter-spacing:-.3px;color:var(--ink)}
tfoot.tf-sum tr td.num{font-family:var(--f-mono)}

/* ---------- chuyển trang (b122) ---------- */
.pgbar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;justify-content:space-between;
  padding:11px 14px;border-top:1px solid var(--line)}
.pgi{font-size:12.5px;color:var(--slate)}
.pgi strong{color:var(--ink);font-family:var(--f-mono)}
.pgn-wrap{display:flex;align-items:center;gap:5px;flex-wrap:wrap}
.pgn{min-width:40px;height:40px;padding:0 9px;border:1px solid var(--line);background:#fff;border-radius:8px;
  font:inherit;font-size:13px;font-weight:700;color:var(--ink);cursor:pointer;font-family:var(--f-mono)}
.pgn.nav{font-family:var(--f-ui);font-size:12.5px;font-weight:600;color:var(--slate)}
.pgn:hover:not(:disabled){background:var(--sky-50);border-color:var(--sky-300)}
.pgn.on{background:var(--sky-900);border-color:var(--sky-900);color:#fff}
.pgn:disabled{opacity:.38;cursor:default}
.pgd{color:var(--slate-2);padding:0 2px}

/* ---------- chip lọc nhanh (b122) ---------- */
.fchips{display:flex;gap:6px;flex-wrap:wrap}
.fchip{border:1px solid var(--line);background:#fff;border-radius:999px;padding:5px 12px;
  font:inherit;font-size:12.5px;font-weight:600;color:var(--slate);cursor:pointer}
.fchip:hover{background:var(--sky-50);border-color:var(--sky-300);color:var(--ink)}
.fchip.on{background:var(--sky-900);border-color:var(--sky-900);color:#fff}
.fchip .fn{font-family:var(--f-mono);opacity:.75;margin-left:2px}
.actbtn.done{background:var(--green-soft);border-color:#A9D8C6;color:var(--green)}
/* ô tick trong form (b123) */
.chk{display:flex;align-items:center;gap:8px;min-height:40px;font-size:13px;cursor:pointer}
.chk input{width:17px;height:17px;flex:none;accent-color:var(--or-6);cursor:pointer}

/* Trả hàng trong màn Sửa hóa đơn */
.ei-ret{display:flex;align-items:center;gap:14px;justify-content:space-between;flex-wrap:wrap;
  border:1px solid var(--line);border-radius:11px;padding:11px 14px;margin-bottom:12px;background:var(--sky-50)}
.ei-ret .btn{white-space:nowrap}

/* ---------- thẻ chuyển mục cũ (Dữ liệu) ---------- */
.dtabs{display:flex;gap:4px;background:var(--sky-100);border-radius:12px;padding:4px;margin-bottom:16px;flex-wrap:wrap}
.dtab{flex:1;min-width:150px;border:0;background:transparent;border-radius:9px;padding:9px 12px;cursor:pointer;
  font:inherit;font-size:14px;font-weight:700;color:var(--sky-500);text-align:center;line-height:1.25}
.dtab small{display:block;font-size:11.5px;font-weight:600;color:var(--sky-400);margin-top:2px}
.dtab.on{background:#fff;color:var(--sky-900);box-shadow:0 1px 3px rgba(0,0,0,.12)}
.dtab.on small{color:var(--or-6)}
.dtab:hover:not(.on){background:rgba(255,255,255,.55)}
.dtab .bg{display:inline-block;background:var(--red);color:#fff;border-radius:99px;font-size:10.5px;padding:0 6px;margin-left:5px;vertical-align:1px}

/* ---------- BÁO CÁO: biểu đồ cột, thanh ngang, dòng tiền, tuổi nợ (b120) ---------- */
.rgrid2{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px}
@media (max-width:1100px){ .rgrid2{grid-template-columns:1fr} }
.delta{display:inline-block;font-size:11.5px;font-weight:800;border-radius:99px;padding:1px 7px;margin-left:6px}
.delta.up{background:#E7F6EC;color:#177245}
.delta.dn{background:#FDECEC;color:#B3261E}

/* Kiểu A (anh Đạt chọn 17/09): cột ngày + đường trung bình 7 ngày phủ lên.
   `.rchart` thành khung định vị; SVG nằm đúng chồng lên vùng cột (cao 180px như
   `.rcols`), không chiếm chỗ nên hàng cột và nhãn ngày không xê dịch một pixel. */
.rchart{padding:2px 0 0;position:relative}
.rtb{
  /* 🔴 PHẢI KHAI `width` CHO SVG. `left:0;right:0` là đủ cho thẻ thường, nhưng
     SVG là phần tử THAY THẾ: có tỉ lệ nội tại từ `viewBox`. viewBox 100×100 +
     `height:180px` ⇒ trình duyệt tự tính bề rộng 180px, và đường trung bình chỉ
     vẽ trên 1/6 bề ngang rồi dừng. Đo mới thấy: svg rộng 180 trong khi có 28 cột.
     Nhìn ảnh thì tưởng vẽ hụt số liệu — thật ra khung vẽ bị bóp. */
  position:absolute;left:0;top:2px;width:100%;height:180px;
  pointer-events:none;overflow:visible;
  /* 🔴 PHẢI NẰM TRÊN CỘT. Bản đầu không khai z-index: đường trung bình bị CỘT
     che mất, nên nó chỉ hiện ở đoạn đầu kỳ — chỗ cột thấp hơn đường — rồi biến
     mất. Nhìn ảnh thì tưởng đường vẽ hụt, thật ra nó nằm dưới. */
  z-index:var(--z-noi,1);
}
.rtb polyline{fill:none;stroke:var(--or-safe);stroke-width:2;stroke-linejoin:round;stroke-linecap:round}
.rcols{display:flex;align-items:flex-end;gap:3px;height:180px}
.rcol{flex:1;display:flex;flex-direction:column;justify-content:flex-end;align-items:center;height:100%;min-width:6px}
.rcol i{display:block;width:100%;background:#FDBA74;border-radius:4px 4px 0 0;transition:background .12s}
.rcol.hi i{background:var(--or-7)}
.rcol:hover i{background:var(--or)}
.rcol b{font-size:11px;font-weight:800;color:var(--slate);margin-bottom:3px;white-space:nowrap}
.rxax{display:flex;gap:3px;margin-top:6px}
.rxax span{flex:1;text-align:center;font-size:10.5px;color:var(--slate-2);min-width:6px;overflow:hidden}

.hbar{display:grid;grid-template-columns:130px 1fr 96px;align-items:center;gap:10px;margin-bottom:8px}
.hbar .hb-n{font-size:13px;font-weight:600;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hbar .hb-t{height:15px;background:var(--sky-100);border-radius:5px;overflow:hidden}
.hbar .hb-t i{display:block;height:100%;background:#FDBA74;border-radius:5px}
.hbar.top .hb-t i{background:var(--or-7)}
.hbar .hb-v{font-size:13px;font-weight:700;text-align:right;font-variant-numeric:tabular-nums}

.stkbar{display:flex;height:36px;border-radius:9px;overflow:hidden;gap:2px}
.stkbar div{display:flex;align-items:center;justify-content:center;color:#fff;font-size:12.5px;font-weight:700;white-space:nowrap;overflow:hidden}
.stkbar .s1{background:var(--or-7)}
.stkbar .s2{background:#8791A0}
.stklg{display:flex;gap:18px;flex-wrap:wrap;font-size:12.5px;color:var(--slate);font-weight:600;margin-top:8px}
.stklg i{display:inline-block;width:10px;height:10px;border-radius:3px;margin-right:6px;vertical-align:-1px}
.stklg i.c1{background:var(--or-7)} .stklg i.c2{background:#8791A0}
.cashline{display:flex;gap:26px;flex-wrap:wrap;margin-top:12px;padding-top:12px;border-top:1px solid var(--line);font-size:13px}

.ages{display:grid;grid-template-columns:repeat(3,1fr);gap:9px}
.agec{border:1px solid var(--line);border-radius:10px;padding:10px 12px}
.agec .t{font-size:12px;font-weight:700;color:var(--ink)}
.agec .m{font-size:19px;font-weight:800;margin-top:3px;font-variant-numeric:tabular-nums}
.agec .c{font-size:11.5px;color:var(--slate);margin-top:2px}
.agec.gn{background:#F1FAF4;border-color:#CBE9D6} .agec.gn .m{color:#177245}
.agec.am{background:#FFF8EC;border-color:#F5E0B8} .agec.am .m{color:#9A6200}
.agec.rd{background:#FDF2F2;border-color:#F3CFCC} .agec.rd .m{color:#B3261E}

.minibar{height:5px;background:var(--sky-100);border-radius:3px;margin:4px 0 2px;max-width:280px}
.minibar i{display:block;height:100%;background:#FDBA74;border-radius:3px}
@media print{ .rchart,.hbar,.stkbar,.ages{break-inside:avoid} }


/* chấm cam đánh dấu tab khách đang mở (b121 — tab không còn hiện số món/tiền) */
.tab .tdot{width:7px;height:7px;border-radius:99px;background:var(--or);flex:0 0 7px}
/* KPI có viền màu bên trái cho dễ phân biệt (b121) */
.kpi{border-left:4px solid var(--line)}
.kpi.gn{border-left-color:#2E9E63} .kpi.rd{border-left-color:#D8524A}
.kpi.am{border-left-color:#E3A008} .kpi.bp{border-left-color:#5A7BA6}
.kpi.or,.kpis .kpi:first-child{border-left-color:var(--or)}

/* ---------- Khóa khi app mở ở cửa sổ khác (b127) ---------- */
#tablock{position:fixed;inset:0;z-index:9000;background:rgba(24,27,32,.72);
  display:grid;place-items:center;padding:24px;backdrop-filter:blur(3px)}
#tablock .tl-box{background:#fff;border-radius:16px;max-width:460px;width:100%;
  padding:26px 26px 22px;text-align:center;box-shadow:var(--shadow-lg)}
#tablock .tl-ic{width:52px;height:52px;margin:0 auto 12px;border-radius:14px;
  background:var(--or-50);display:grid;place-items:center}
#tablock .tl-ic svg{width:28px;height:28px;stroke:var(--or-7);fill:none;stroke-width:1.9}
#tablock h2{font-size:18px;margin:0 0 10px;color:var(--ink)}
#tablock p{font-size:13.5px;color:var(--slate);margin:0 0 10px;line-height:1.55}
#tablock .tl-sub{font-size:12.5px;color:var(--slate-2)}
#tablock .btn{margin-top:6px;padding:11px 20px;font-size:14px}

/* ---------- Ghi chú từng món trong phiếu bán + dòng nổi lên (b127) ---------- */
.item{border:1px solid transparent;border-radius:10px;padding:6px 6px;
  transition:box-shadow .12s, border-color .12s, background .12s}
.item:hover,.item:focus-within{
  border-color:#B9D4F5;background:#fff;
  box-shadow:0 2px 4px rgba(24,27,32,.06), 0 8px 20px rgba(24,27,32,.10)}
/* b229 · ô ghi chú nằm NGAY TRONG hàng số lượng (bên phải) và chỉ hiện/ẩn bằng ĐỘ
   MỜ. Trước đây nó là một hàng riêng bung ra khi rê chuột (0 → 22px), đẩy mọi dòng
   bên dưới xuống: rê từ dòng trên xuống bấm X dòng dưới thì X chạy lên 22px đúng lúc
   con trỏ tới (anh Đạt 11/09: "thấy dấu X có di chuyển"). Dòng ĐÃ có ghi chú thì ô
   chiếm trọn một hàng để đọc đủ chữ — cái đó cố định, không đổi theo con trỏ. */
.item .ntrow{flex:1 1 120px;min-width:0;display:flex;align-items:center;gap:5px;
  font-family:var(--f-ui);opacity:0;transition:opacity .12s}
.item .ntrow.has{flex-basis:100%}
.item:hover .ntrow,.item:focus-within .ntrow,.item .ntrow.has{opacity:1}
.item .ntrow svg{width:12px;height:12px;stroke:var(--slate-2);fill:none;stroke-width:1.9;flex:0 0 auto}
.item .ntin{flex:1;min-width:0;border:0;border-bottom:1px dashed var(--line);border-radius:0;
  background:transparent;font:inherit;font-size:11.5px;color:var(--ink);padding:2px 0}
.item .ntin::placeholder{color:var(--slate-2);font-style:italic}
.item .ntin:focus{border-bottom-color:var(--or);box-shadow:none;background:var(--or-50)}
.item .ntrow.has .ntin{color:var(--sky-600);font-style:italic}
/* b222 · hàng PHA MÀU của dòng sơn — b224 dựng lại theo ba ý anh Đạt 10/09:
   ô màu TO như ảnh sản phẩm · chỗ tiền chỉ có SỐ, không chữ thừa · không được
   tràn ra rìa (ảnh anh gửi: ô màu đè lên viền trái, "/lon" bị cắt).
   Chống tràn bằng ba thứ: cột giữa `min-width:0` (mặc định của flex là auto,
   chính nó làm hàng phình ra), `flex-wrap`, và ô nhập co được. */
/* b225 · Hàng màu là MỘT PHẦN của dòng sơn, không phải một dòng hàng nữa.
   Vạch đứt cũ trông y hệt vạch ngăn giữa hai món, nên trên ảnh 10/09 hàng màu
   như đang thuộc về món kế tiếp. Nay: nền xanh nhạt bo góc, thụt vào — mắt
   thấy ngay nó dính với dòng bên trên.
   `padding-right` chừa đúng cột cây bút sửa giá (b229: --cot-but + 8px khe cột) để
   tiền màu THẲNG CỘT với thành tiền của dòng. Hàng màu bắt đầu ở cột tên (cột 2), cột
   nút X bên trái để trống cho thẳng mép với tên và khung số lượng. */
.item .maurow{
  grid-column:2/-1;display:flex;align-items:center;gap:8px;flex-wrap:wrap;row-gap:4px;
  margin-top:5px;padding:5px calc(var(--cot-but) + 8px) 5px 6px;border-radius:8px;
  background:var(--sky-50);min-width:0;
}
/* Ô màu bằng đúng cỡ ảnh sản phẩm ở thẻ hàng (39px) — anh Đạt: "muốn màu nhìn
   to như ảnh sản phẩm luôn, không phải chỉ nhỏ như vậy". Rê vào phóng 2,4× và
   NỔI LÊN TRÊN (z-index) chứ không đẩy chữ, vì transform không chiếm chỗ. */
.item .mauo{
  width:39px;height:39px;flex:0 0 39px;border-radius:7px;border:1px solid #AEBFCB;
  background:var(--mau,#fff);cursor:zoom-in;
  transition:transform .12s cubic-bezier(.2,.7,.3,1), box-shadow .12s;
  transform-origin:left center;
}
.item .mauo:hover{transform:scale(2.4);box-shadow:0 6px 22px rgba(24,27,32,.3);position:relative;z-index:6}
/* Chưa có mẫu màu thì GẠCH CHÉO — không tô một màu đoán. Ô trắng trơn dễ bị
   hiểu là "màu trắng"; vạch chéo nói rõ "chưa biết". */
.item .mauo.trong{background:repeating-linear-gradient(45deg,#fff 0 5px,var(--line) 5px 6px);cursor:default}
.item .mauo.trong:hover{transform:none;box-shadow:none}
/* Cột giữa: ô gõ mã + tên màu + danh sách gợi ý. `min-width:0` là chốt chống
   tràn — thiếu nó là cả hàng đẩy ra ngoài khung phiếu. */
.item .maugiua{flex:1 1 130px;min-width:0;display:flex;flex-direction:column;gap:1px}
.item .mauin{
  width:100%;min-width:0;border:0;border-bottom:1px dashed var(--line);border-radius:0;
  background:transparent;font:inherit;font-size:12px;font-weight:700;letter-spacing:.02em;
  text-transform:uppercase;color:var(--ink);padding:2px 0;
}
.item .mauin::placeholder{color:var(--slate-2);font-weight:400;font-style:italic;text-transform:none}
.item .mauin:focus{border-bottom-color:var(--or);box-shadow:none;background:var(--or-50)}
/* b227 · Dòng dưới mã màu: [Base C] + tên màu. Base phải NỔI hơn tên, vì tên
   là để đối chiếu với khách còn base là để người bán đi lấy đúng thùng. */
.item .maudb{display:flex;align-items:center;gap:5px;min-width:0}
.item .maubase{
  flex:0 0 auto;font-size:10px;font-weight:800;letter-spacing:.02em;
  padding:1px 5px;border-radius:4px;white-space:nowrap;
  background:var(--sky-100);color:var(--sky-700);border:1px solid var(--sky-300);
}
.item .mauten{font-size:10.5px;color:var(--slate);line-height:1.25;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Ba gợi ý — chọn bằng mắt: ô màu thật đứng trước mã và tên. */
.item .maugoi{display:flex;flex-direction:column;gap:2px;margin-top:3px}
.item .maugoi button{
  display:flex;align-items:center;gap:6px;width:100%;min-width:0;padding:3px 5px;
  border:1px solid var(--line);border-radius:6px;background:var(--paper);text-align:left;
}
.item .maugoi button:hover{border-color:var(--sky-400);background:var(--sky-50)}
.item .maugoi b{font-size:11px;font-weight:700;font-family:var(--f-mono);color:var(--ink);white-space:nowrap}
/* b228 · Mỗi dòng gợi ý phải đủ để CHỌN BẰNG MẮT: ô màu + mã + BASE + tên.
   Anh Đạt 10/09: "bằng tên ghi chưa đủ" — nhiều mã hãng không đặt tên, chỉ
   thấy mỗi mã thì không biết dòng nào là dòng mình cần. */
.item .maugoi .maugb{
  flex:0 0 auto;font-style:normal;font-size:9.5px;font-weight:800;
  padding:0 4px;border-radius:3px;white-space:nowrap;
  background:var(--sky-100);color:var(--sky-700);
}
.item .maugoi span{font-size:10.5px;color:var(--slate);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.item .mauog{width:18px;height:18px;flex:0 0 18px;border-radius:4px;border:1px solid #AEBFCB;background:var(--mau,#fff)}
.item .mauog.trong{background:repeating-linear-gradient(45deg,#fff 0 4px,var(--line) 4px 5px)}
/* b225b · Hàng màu chỉ còn ĐÚNG MỘT con số. Anh Đạt 10/09, hai lần: "chỗ tiền
   chỉ hiện số, không ghi thêm gì" rồi "phần giá/lít bỏ". Ô "lít/lon" đã bỏ ở
   b225 (dung tích chọn trên dòng hàng), ô "số màu/lít" bỏ nốt ở đây.
   Con số này CHÍNH LÀ chỗ sửa — trông như chữ thường, rê vào mới hiện viền. */
.item .mautt{display:flex;align-items:center;gap:2px;flex:0 0 auto;margin-left:auto;
  font-size:12.5px;color:var(--ink);white-space:nowrap}
.item .mautti{
  width:84px;min-width:84px;padding:2px 4px;text-align:right;border:1px solid transparent;
  border-radius:5px;background:transparent;font-family:var(--f-num);font-size:12.5px;
  font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums;
}
.item:hover .mautti,.item:focus-within .mautti{border-color:var(--sky-300);background:var(--paper)}
.item .mautti:focus{border-color:var(--sky-400);background:#fff;box-shadow:none}
/* Sửa tay rồi thì nổi cam — để người bán biết con số này không còn là công thức. */
.item .mautt.sua .mautti{color:var(--or-7);border-color:#F3C9A2;background:var(--or-50)}
.item .mautra{display:grid;place-items:center;width:18px;height:18px;flex:0 0 18px;
  border-radius:4px;color:var(--or-7);font-size:11px;line-height:1}
.item .mautra:hover{background:var(--or-50)}
.item .mauwarn{flex:0 0 auto;margin-left:auto;font-size:11px;color:var(--or-safe);font-style:italic}
/* nút bỏ dòng CHỈ hiện (rõ, không mờ) khi rê vào dòng — anh Đạt 11/09 chọn. `.vuaxoa` =
   dòng vừa trồi lên dưới con trỏ sau một lần bỏ (pos.js delLine): hiện NGAY, không mờ dần,
   để nhịp bấm liên tục không gãy. Máy cảm ứng không có "rê" nên hiện thường trực: nút tàng
   hình mà vẫn bấm được là chạm nhầm mất dòng. */
.item .xoa{opacity:0;transition:opacity .12s}
.item:hover .xoa,.item:focus-within .xoa,.item.vuaxoa .xoa{opacity:1}
.item.vuaxoa .xoa{transition:none}
@media (hover:none){ .item .xoa{opacity:1} }
/* b186 · ô ảnh trong thẻ sản phẩm: ảnh hiện tại + nút chọn tệp / xóa */
.pimg-pick{display:flex;align-items:center;gap:var(--space-3)}
.pimg-cur{width:72px;height:72px;flex:0 0 72px;object-fit:contain;border:1px solid var(--line);border-radius:var(--r);background:#fff}
.pimg-cur.none{display:block;background:var(--sky-50);border-style:dashed}
.pimg-act{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-2)}
.pimg-act .hint{margin:0;flex-basis:100%}

/* b192 · đáy bảng Sản phẩm: đang xem bao nhiêu trong bao nhiêu + nút nạp thêm */
.p-more{display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding:14px 16px;border-top:1px solid var(--line)}
.p-more strong{color:var(--ink)}
/* b273: one bounded table scroller; paging remains visible outside it. */
.view.products-list{display:flex;flex-direction:column;min-height:0;overflow:hidden}
.products-list>*,.products-list #ptbl>*{flex-shrink:0}
.products-list #ptbl{display:flex;flex-direction:column;flex:1;min-height:0}
.products-list #p_fpanel{max-height:38vh;overflow:auto}
.products-list #ptbl .p-list-panel{display:flex;flex-direction:column;flex:1;min-height:0}
.products-list .p-table-scroll{flex:1;min-height:0;max-height:none;overscroll-behavior:contain}
.p-list-panel>.p-more{flex-shrink:0;background:var(--paper)}
.p-page-actions{display:flex;align-items:center;gap:8px;margin-left:auto}
.p-page-actions select{width:auto;min-width:84px}
.p-page-label{color:var(--slate);font-size:12px}


/* ============================================================
   b231 · BẢNG TICK NHÓM QUYỀN
   Bảng này dài (37 quyền) nên nó tự cuộn trong khung của mình, không kéo dài cả hộp thoại.
   Ô tick cao 24px cho ngón tay, và mỗi nhóm việc có đường viền riêng để mắt bám được hàng.
   ============================================================ */
.ap-bang { max-height: 46vh; overflow-y: auto; margin-top: 12px;
  border: 1px solid var(--line); border-radius: 8px; padding: 12px; background: var(--bg); }
.ap-nhom { border: 0; border-top: 1px solid var(--line); margin: 0; padding: 8px 0 4px; }
.ap-nhom:first-child { border-top: 0; padding-top: 0; }
.ap-nhom legend { padding: 0; font-size: 10.5px; font-weight: 800; letter-spacing: .09em;
  text-transform: uppercase; color: var(--slate); }
.ap-q { display: flex; align-items: center; gap: 8px; min-height: 24px;
  padding: 2px 0; font-size: 12.5px; cursor: pointer; }
.ap-q input { width: 16px; height: 16px; flex: 0 0 auto; margin: 0; }
@media (max-width: 880px) {
  .ap-bang { max-height: 40vh; }
  .ap-q { font-size: 14px; min-height: 32px; }
}

/* ═══ b248 · FORM SẢN PHẨM — KHUÔN A (anh Đạt chọn 17/09) ═══
   ĐO ở b247: 21 ô · 22 nhãn · 15 dòng chú thích trong một form. Cái nặng nhất
   là 15 dòng chú thích — ô thì mắt lướt qua được, chú thích thì buộc phải đọc
   rồi mới biết là không cần. Nên: chữ nghĩa GIỮ NGUYÊN, chỉ thôi nói cùng lúc.
   Tầng một (tên · đơn vị · giá bán · giá nhập · tồn · ảnh) nằm ngoài; phần còn
   lại trong <details> của trình duyệt — không tốn tay xử lý nội tuyến nào. */

/* Chú thích chỉ hiện ở ô ĐANG GÕ. Không dùng `display:none` cho phần đọc màn
   hình — `.hint` vẫn ở trong DOM và vẫn đọc được khi con trỏ vào ô. */
.fgrid .f .hint{display:none}
.fgrid .f:focus-within .hint{display:block}
/* Chú thích của khối KHÔNG có ô nhập (nút chi nhánh, nút xóa, dòng nhắc giữ
   hãng) thì luôn hiện — `:focus-within` không bao giờ đúng với chúng. */
.fgrid .f:not(:has(input)) .hint{display:block}

.fold{border:1px solid var(--line);border-radius:var(--r);background:var(--paper);
  grid-column:1/-1;overflow:hidden}
.fold+.fold{margin-top:calc(var(--space-2)*-1 + 2px)}
.fold>summary{list-style:none;cursor:pointer;display:flex;align-items:center;
  justify-content:space-between;gap:var(--space-3);min-height:var(--control-h);
  padding:0 var(--space-3);font-weight:700;color:var(--sky-700)}
.fold>summary::-webkit-details-marker{display:none}
.fold>summary::after{content:'⌄';color:var(--slate-2);font-weight:400;
  transition:transform var(--motion-fast)}
.fold[open]>summary::after{transform:rotate(180deg)}
.fold>summary:hover{background:var(--sky-50)}
.fold>summary:focus-visible{outline:2.5px solid var(--or);outline-offset:-2px}
.fold .fsum{font-weight:400;font-size:12.5px;color:var(--slate-2);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;text-align:right}
.fold>.fgrid{padding:var(--space-3);border-top:1px solid var(--line);background:var(--sky-50)}

/* Tiêu đề nhóm màu cảnh báo — thay cho style viết thẳng trong products.js */
.sect.dg{color:var(--red);border-bottom-color:#F0D2D0}

/* Ô giá: số tiền là thứ người ta nhìn, cho nó đậm hơn một nấc */
.fgrid .f.money input{font-weight:800;font-size:16px}

/* Chữ cái đầu khi món chưa có ảnh — học từ cách KiotViet làm (soi 17/09):
   mấy trăm khung xám giống hệt nhau thì mắt không bám vào đâu được. */
.pimg-cur.none{display:flex;align-items:center;justify-content:center;
  font-weight:800;font-size:21px;color:var(--slate-2);background:var(--sky-50)}

/* Nút CHỤP ẢNH chỉ có nghĩa ở máy có camera sau — tức điện thoại.
   Trên máy tính `capture` không làm gì, để nút đó chỉ tổ thừa một lựa chọn. */
.pimg-act .chup{display:none}
@media (max-width:880px){
  .pimg-act .chup{display:inline-flex}
  .fold>summary{min-height:48px}
}

/* ═══════════════════════════════════════════════════════════════════════════
   b257 · BA LOẠI ĐIỀU KHIỂN, BA BỘ ĐỒ KHÁC NHAU
   Anh Đạt 17/09 chụp màn Báo cáo: bộ lọc kỳ, tab chuyển màn và nút "Làm mới"
   đều là `.btn`, xếp hai hàng giống hệt nhau. Mắt không phân được bấm cái nào
   đổi SỐ, cái nào đổi MÀN, cái nào CHẠY LẠI.
     · chọn một trong mấy cái  → `.segbar/.seg`  (khối liền, ô đang chọn nổi lên)
     · chuyển màn              → `.tabline/.tabl` (chữ trên đường kẻ, vạch cam)
     · hành động               → `.text-action`   (nút chữ, tách hẳn sang phải)
   🔴 Cam chỉ TÔ, không VIẾT (tờ nhận diện §2): vạch dưới tab dùng `--or`, còn
   chữ thì dùng `--ink`. Không có chữ cam nào ở đây.
   ═══════════════════════════════════════════════════════════════════════════ */
.segbar{
  display:inline-flex;gap:var(--space-1);flex:0 0 auto;
  background:var(--sky-50);border:1px solid var(--line);
  border-radius:var(--r);padding:var(--space-1);
}
.seg{
  border:0;background:none;cursor:pointer;white-space:nowrap;
  height:calc(var(--control-h) - var(--space-2));
  padding:0 var(--space-3);border-radius:var(--r-sm);
  font-family:var(--f-ui);font-size:12.5px;font-weight:600;color:var(--slate);
  transition:background var(--motion-fast),color var(--motion-fast);
}
.seg:hover{color:var(--ink)}
.seg.on{background:var(--paper);color:var(--ink);font-weight:700;box-shadow:var(--shadow)}

.tabline{
  display:flex;align-items:center;gap:var(--space-5);
  border-bottom:1px solid var(--line);margin-bottom:var(--space-4);
  /* Khai CẢ HAI trục: một trục không phải `visible` thì trục kia tự thành `auto`
     (bẫy đã vấp ở Sổ lỗi #149). Ở đây không có gì nhô ra nên `hidden` là đúng. */
  overflow-x:auto;overflow-y:hidden;
}
.tabl{
  position:relative;flex:0 0 auto;border:0;background:none;cursor:pointer;
  white-space:nowrap;padding:var(--space-3) 0;
  font-family:var(--f-ui);font-size:14px;font-weight:700;color:var(--slate);
  transition:color var(--motion-fast);
}
.tabl:hover{color:var(--ink)}
.tabl.on{color:var(--ink)}
.tabl.on::after{
  content:"";position:absolute;left:0;right:0;bottom:-1px;height:3px;background:var(--or);
}
.tabline-act{margin-left:auto;flex:0 0 auto}

@media (max-width:880px){
  /* Điện thoại: khối kỳ trải hết bề ngang, mỗi ô chia đều — ngón tay bấm dễ.
     Ô cao lên đúng `--control-h` cho đủ 40px chạm. */
  .segbar{display:flex;width:100%}
  .seg{flex:1 1 0;min-width:0;height:var(--control-h);padding:0 var(--space-2)}
  .tabline{gap:var(--space-4)}
}

/* b259 · "Cần để ý" — mỗi dòng MỘT VIỆC, có đường sang đúng màn đã lọc sẵn.
   Đây là chỗ thay cho 14 cái bảng: báo cáo nói ra việc, không chép lại sổ. */
.dey{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
.dey li{
  display:flex;align-items:center;gap:var(--space-4);
  padding:var(--space-3) 0;border-bottom:1px solid var(--line-2);
  font-size:14px;color:var(--ink-2);line-height:1.5;
}
.dey li:last-child{border-bottom:0;padding-bottom:0}
.dey li:first-child{padding-top:0}
.dey li>span{flex:1 1 auto;min-width:0}
.dey li>button{flex:0 0 auto;white-space:nowrap}
@media (max-width:880px){
  .dey li{flex-direction:column;align-items:flex-start;gap:var(--space-2)}
}

/* b261 · Hàng trên cùng màn Báo cáo: bên trái là giờ lấy số, bên phải là ô chọn
   mục chi tiết — đúng chỗ nút "Làm mới" cũ đứng, ngay TRÊN hàng bốn ô số.
   Anh Đạt: *"Ý t ô chọn mục cần xem nằm trên phần khách còn nợ mà"*. */
.rep-top{
  display:flex;align-items:center;justify-content:space-between;gap:var(--space-4);
  flex-wrap:wrap;margin-bottom:var(--space-3);
}
/* Ô chọn phải trông như MỘT điều khiển, không phải chữ rời đứng cạnh hộp rời.
   Nhãn nằm trong cùng một khung, ngăn bằng một nét mảnh. */
.rep-chon{
  display:inline-flex;align-items:center;flex:0 0 auto;
  background:var(--paper);border:1px solid var(--line);border-radius:var(--r);
  overflow:hidden;transition:border-color var(--motion-fast),box-shadow var(--motion-fast);
}
.rep-chon:focus-within{border-color:var(--sky-500);box-shadow:0 0 0 3px var(--sky-100)}
.rep-chon>span{
  padding:0 var(--space-3);align-self:stretch;display:flex;align-items:center;
  background:var(--sky-50);border-right:1px solid var(--line);
  font-size:11.5px;font-weight:700;color:var(--slate);white-space:nowrap;
}
.rep-chon>select{
  width:auto;min-width:190px;border:0;border-radius:0;background:none;
  height:calc(var(--control-h) - var(--space-1));padding:0 var(--space-3);
  font-size:12.5px;font-weight:600;
}
.rep-chon>select:focus{box-shadow:none}
@media (max-width:880px){
  .rep-top{gap:var(--space-2)}
  .rep-chon{width:100%}
  .rep-chon>select{flex:1 1 auto;min-width:0;height:var(--control-h);font-size:16px}
}

/* b262 · Con số tổng mã nằm trong tab "Danh sách hàng" — chip bên dưới không có số này. */
.tabn{
  margin-left:var(--space-2);padding:1px var(--space-2);border-radius:var(--r-pill,999px);
  background:var(--sky-50);color:var(--slate);font-size:11.5px;font-weight:700;
}
.tabl.on .tabn{background:var(--or-50);color:var(--or-safe)}

/* 🔴 NÚT "SỬA" THÔI TÔ CAM CẢ CỘT (tờ nhận diện §2: cam để TÔ MỘT chỗ).
   Nút đứng im lặng, đậm lên khi con trỏ vào chính DÒNG đó — thứ người ta sắp
   bấm thì nổi, chín dòng còn lại thì thôi. Trên màn chạm không có `:hover` nên
   nút vẫn hiện đủ viền, chỉ là không cam. */
.prod-tbl tr:hover .actbtn{border-color:var(--sky-300);background:var(--sky-50);color:var(--ink)}

/* ═══ b264 · THANH CÔNG CỤ MÀN SẢN PHẨM: ô tìm là trọng điểm ═══
   Anh Đạt: *"Các ô chức năng phải là trọng điểm, phải là nội dung chính."*
   Đo bản cũ: ô tìm chiếm 19% bề ngang, nhỏ hơn cả nút "Chọn từng món". */
/* 🔴 Ô ĐỆM PHẢI TẮT, KHÔNG THÌ Ô TÌM KHÔNG NỞ RA ĐƯỢC. `.toolbar-sp{flex:1}` là
   chỗ trống co giãn dùng để đẩy nhóm bên phải ra mép — nó GIÀNH hết phần dư với
   ô tìm, nên ô tìm khai `flex:1` cũng đứng yên và giữa thanh hở một mảng trống.
   Thanh này không cần ô đệm: ô tìm nở ra là tự đẩy "Xếp theo" và phễu ra mép. */
.ptool .toolbar-sp{display:none}
.ptool .search-in{flex:1 1 auto;max-width:none}
/* 🔴 KHUNG RỘNG KHÔNG CÓ NGHĨA LÀ Ô NHẬP RỘNG. `.toolbar input{width:auto}` ở
   `components.css` đè lên `input{width:100%}` của nền, nên ô nhập co theo CHỮ:
   đo được khung 981px mà ô nhập chỉ 243px — ảnh chụp trông y như chưa sửa gì.
   Lại đúng họ lỗi "phần bị xén vẫn có toạ độ": đo nhầm cái vỏ, tưởng đã xong. */
.ptool .search-in input{
  width:100%;height:44px;font-size:15px;font-weight:600;padding-left:38px;
}
.ptool .search-in svg{width:19px;height:19px}
.ptool select{flex:0 0 auto;width:auto;min-width:max-content}

/* Nút lọc chỉ còn cái phễu. Có mục đang lọc thì nó tự mang màu cam + con số —
   cam ở ĐÚNG MỘT chỗ trên màn, và chỉ khi có chuyện (tờ nhận diện §2). */
.icoloc{
  display:inline-flex;align-items:center;gap:var(--space-1);
  width:auto;min-width:40px;height:40px;padding:0 var(--space-2);justify-content:center;
}
.icoloc svg{width:18px;height:18px;stroke-width:2}
.icoloc.on{background:var(--or-50);border-color:#F5C89A;color:var(--or-safe)}
.icoloc .fn{font-size:11.5px;font-weight:800}

/* Chân ngăn lọc: "Hiển thị" và nút xóa — KHÔNG phải bộ lọc nên tách hẳn,
   có nhãn riêng và một nét kẻ ngăn. */
.fpanel-ft{
  display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap;
  margin-top:var(--space-3);padding-top:var(--space-3);border-top:1px solid var(--line);
}

/* ═══ b265 · NGĂN LỌC CÓ BƯỚC: bốn dòng, mở đúng một tầng ═══
   Anh Đạt: *"Khi chọn từ tầng 1… sau khi chọn tự hiện tầng 2 (có khép tầng 1 lại
   và hiện mục đã chọn), tiếp tục đến kết quả cuối."* */
.lgdong{
  display:flex;align-items:center;gap:var(--space-3);width:100%;
  padding:var(--space-3) var(--space-1);
  border:0;border-bottom:1px solid var(--line-2);background:none;text-align:left;
  transition:color var(--motion-fast);
}
.lgdong + .chiprow:not([hidden]){padding-bottom:var(--space-3);border-bottom:1px solid var(--line-2)}
.lgdong:hover .lgten{color:var(--ink)}
.lgcaret{width:12px;font-size:11px;color:var(--slate)}
.lgten{font-size:13.5px;font-weight:700;color:var(--ink-2)}
.lgso{
  margin-left:auto;font-size:12px;color:var(--slate);
  max-width:52%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
/* Tầng đang có mục chọn: nói ra mục đó bằng màu cam an toàn — người dùng không
   phải mở lại mới biết mình đang lọc gì. Cam ở đây là CHỮ nên dùng --or-safe,
   không dùng --or (tờ nhận diện §2: cam sáng chỉ để tô nền). */
.lgdong.dachon .lgten{color:var(--ink)}
.lgdong.dachon .lgso{color:var(--or-safe);font-weight:700}
.lgdong.mo{border-bottom:0;padding-bottom:var(--space-1)}
.lgdong.mo .lgten{color:var(--ink)}

/* ===== SOURCE: styles/mobile.css ===== */
/* ============================================================
   BẢN CHO ĐIỆN THOẠI (b128) — chỉ bán 1 khách + tra giá
   ============================================================ */
.paybar{display:none}
@media (max-width:880px){
  /* thẻ hàng: xếp một cột thành dòng ngang, hết cảnh chữ bị cắt cụt */
  .grid-p{grid-template-columns:1fr;gap:7px}
  .pcard{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;
    gap:2px 10px;text-align:left;padding:11px 12px}
  .pcard .rank{position:static;grid-row:1/3;display:none}
  /* ══════ b242 · Ô ẢNH 24%, CHỪA SẴN CHO MỌI THẺ, TỒN Ở GÓC DƯỚI PHẢI ══════
     Anh Đạt 16/09, ba câu: *"khung ảnh nhỏ lắm"* · *"số lượng hàng tồn góc bên
     phải dưới cùng"* · *"khung ảnh vẫn là 24%, cùng tỉ lệ bản PC"*.

     Bản 15/09 để ảnh 64px CỐ ĐỊNH và chỉ thẻ CÓ ảnh mới được chừa cột — hai chỗ sai:
       · 64px nằm giữa thẻ cao 126px ⇒ thừa 62px chiều dọc, nhìn ra ô tem;
       · thẻ không ảnh chữ bắt đầu lệch 71px so với thẻ có ảnh ⇒ lưới so le,
         mà 4/5 mã trong sổ chưa có ảnh nên đó là cảnh thường gặp.

     Nay dùng ĐÚNG cách của bản máy tính: ảnh đặt tuyệt đối ở mép trái, cao bằng
     cả thẻ, rộng theo TỈ LỆ bề ngang thẻ, và thẻ chừa chỗ bằng `padding-left`
     nên mọi thẻ — có ảnh hay chưa — đều thẳng một cột. Máy tính 29%, điện thoại
     24% (anh Đạt chốt): thẻ điện thoại chỉ rộng 346px nên cùng một tỉ lệ ăn ít
     pixel hơn nhiều.

     Và đổi từ lưới NGANG (ảnh · chữ · giá) sang lưới DỌC — giá xuống hàng thứ ba.
     Đo tên hàng thật ở khổ 390px:
        cũ: ảnh 64px + cột giá 102px đứng suốt thẻ → chỗ cho tên 146px
        nay: ảnh 24% (≈83px), giá ăn một hàng ngang → chỗ cho tên ≈229px
     Ảnh to hơn mà tên còn rộng thêm hơn một nửa, thẻ vẫn cao chừng ấy.

     `object-fit:contain` chứ không `cover`: ảnh hàng chụp nền trắng, contain chỉ
     thêm lề trắng trên nền thẻ cũng trắng, mà món hàng còn nguyên đầu đuôi.
     Giữ `border-style` để thẻ hàng sắt mang data-ly vẫn tô được màu độ dày — b202. */
  /* 🔴 `.pcard.best` PHẢI viết ra: `pos.css` đặt `.pcard.best{padding:11px 12px}`
     với đặc tả 0,2,0 — cao hơn `.pcard` 0,1,0, nên không kể tên vào đây thì
     riêng thẻ khớp-nhất KHÔNG chừa ô ảnh, chữ nó bắt đầu lệch 82px so với các
     thẻ khác. Đúng cái bẫy đã sập một lần ở bản máy tính (b242, `.pcard.best
     .stk`): đặc tả bằng nhau thì ai sau thắng, đặc tả cao hơn thì đứng trước
     vẫn thắng. */
  .pcard,
  .pcard.best,
  .pcard.wide,
  .pcard:has(.pimg){position:relative;grid-template-columns:minmax(0,1fr);
    align-items:start;padding:11px 12px;padding-left:calc(24% + 12px)}
  .pcard .pimg,
  .pcard:has(.pimg) .pimg{display:block;position:absolute;inset:0 auto 0 0;
    width:24%;height:100%;object-fit:contain;padding:0;background:transparent;
    border:1px solid transparent;border-width:0;
    border-radius:var(--r-sm) 0 0 var(--r-sm)}
  .pcard .pn,
  .pcard:has(.pimg) .pn{grid-column:1;grid-row:1;font-size:14px;line-height:1.3;
    padding-right:0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
    overflow:hidden}
  /* Mã · hãng cắt ba chấm chứ đừng vỡ dòng: mã hàng đứng đầu nên phần bị cắt là
     tên hãng, thứ đọc được từ chính tên hàng. */
  .pcard .pmeta,
  .pcard:has(.pimg) .pmeta{grid-column:1;grid-row:2;font-size:11.5px;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .pcard .pwhole,
  .pcard:has(.pimg) .pwhole{grid-column:1;font-size:11.5px}
  /* Hàng giá: giá bám trái, NHÃN TỒN đẩy hẳn sang phải — anh Đạt chốt 16/09,
     giống hệt bố cục đã chốt cho máy tính. */
  .pcard .prow,
  .pcard:has(.pimg) .prow{grid-column:1;grid-row:3;display:flex;flex-direction:row;
    align-items:baseline;justify-content:space-between;gap:10px;
    white-space:nowrap;padding-right:0}
  .pcard .pp{font-size:15px}
  /* `.pcard.best .stk` phải viết ra: nó có `top:34px` đặc tả cao hơn, không kể
     tên vào đây thì thẻ khớp-nhất vẫn để nhãn tồn ở trên. */
  .pcard .stk,
  .pcard.best .stk{position:static;flex:0 0 auto;top:auto;right:auto;margin-left:auto}
  /* 15/09 · anh Đạt: "phần sản phẩm nhanh bị che". Đo lại bằng DOM thật thì
     thanh thanh toán KHÔNG che nó (cuộn hết còn dư 79px) — cái sai là VỊ TRÍ:
     kệ nằm SAU danh sách bán chạy, nên muốn bấm một nhóm phải cuộn hết danh
     sách, và trên đường cuộn nó cứ ló nửa người dưới mép thanh tiền.
     Đúng luật màn bán kiểu LAI anh chốt 02/09 — chưa gõ thì KỆ trước, bán chạy
     sau. .pos3-main là flex cột, nên chỉ cần đẩy .pane xuống sau; KHÔNG đụng
     thứ tự trong pos.js, nên máy tính giữ nguyên kệ ở đáy cột trái. */
  .pos3-main>.pane{order:1}
  .pos-quick{padding:0}
  .pos-qcats{gap:8px;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:thin}.pos-qcat{flex:0 0 150px;min-height:56px}
  .posq-manager{grid-template-columns:1fr;min-height:0}.posq-catlist{max-height:170px}
  .posq-products{grid-template-columns:1fr;max-height:290px}

  /* đầu trang gọn */
  .head h1{font-size:17px}
  .head .sub{font-size:11.5px}

  /* thanh thanh toán dính đáy, luôn nhìn thấy */
  .paybar{display:none}
  .paybar.on{display:flex;position:fixed;left:8px;right:8px;bottom:60px;z-index:55;
    align-items:center;gap:10px;background:var(--sky-900);color:#fff;
    border-radius:14px;padding:9px 10px 9px 15px;box-shadow:0 8px 26px rgba(24,27,32,.35)}
  .paybar .pb-l{display:flex;flex-direction:column;min-width:0;flex:1}
  .paybar .pb-n{font-size:11px;opacity:.72;letter-spacing:.3px}
  .paybar .pb-t{font-size:19px;font-weight:800;font-family:var(--f-mono);letter-spacing:-.5px}
  .paybar .pb-go{display:inline-flex;align-items:center;gap:6px;flex:0 0 auto;
    background:var(--or);color:#fff;border:0;border-radius:11px;
    padding:12px 16px;font:inherit;font-size:14.5px;font-weight:800;cursor:pointer}
  .paybar .pb-go svg{width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:2.4}
  .paybar .pb-go:active{background:var(--or-7)}
  /* chừa chỗ cho thanh đó khỏi che nút cuối phiếu */
  .tape{padding-bottom:76px}

  /* ---- màn Tra giá ---- */
  .ph-search{display:flex;align-items:center;gap:8px;background:var(--paper);
    border:1px solid var(--line);border-radius:12px;padding:0 10px;margin-bottom:10px}
  .ph-search svg{width:18px;height:18px;stroke:var(--slate-2);fill:none;stroke-width:2;flex:none}
  .ph-search input{flex:1;min-width:0;border:0;background:transparent;padding:13px 0;font-size:16px}
  .ph-search input:focus{box-shadow:none}
  /* 🔴 b243 · anh Đạt 16/09: "khung tìm tra giá bị lỗi UI".
     Ô nhập ở đây KHÔNG phải cái hộp người ta nhìn thấy — nó trong suốt, không
     viền, nằm lọt giữa hộp trắng `.ph-search`, bắt đầu SAU cái kính lúp và
     dừng TRƯỚC nút máy ảnh. Mà luật chung `:focus-visible{outline:2.5px solid
     var(--or)}` lại vẽ viền cam quanh CHÍNH Ô NHẬP ⇒ viền cam thò ra trên dưới
     (ô cao hơn hộp vì `padding:13px 0`) và thụt vào bên trái (bắt đầu sau kính
     lúp) — nhìn như hai khung lệch nhau.
     Vá: chuyển viền báo-đang-gõ sang HỘP NHÌN THẤY. KHÔNG bỏ viền đi —
     `:focus-within` vẫn là một dấu báo đầy đủ, chỉ là vẽ đúng chỗ. */
  .ph-search:focus-within{outline:2.5px solid var(--or);outline-offset:2px;border-color:var(--sky-500)}
  .ph-search input:focus-visible{outline:none}
  .ph-search .phcam{flex:none;border:0;background:var(--or-50);border-radius:9px;
    padding:8px;display:grid;place-items:center;cursor:pointer}
  .ph-search .phcam svg{width:20px;height:20px;stroke:var(--or-7)}
  .ph-hint{font-size:12px;color:var(--slate);margin:0 2px 8px}
  /* 🔴 SỔ LỖI #144 · `commerce.css` khai `.ph-list{max-height:38vh;overflow:auto}`
     cho màn rộng. Khối mobile vẽ lại `.ph-list` nhưng KHÔNG gỡ trần đó, nên trên
     điện thoại danh sách tra giá bị nhốt trong 38% chiều cao màn: cắt cụt giữa
     dòng rồi bỏ trống hơn nửa màn hình. Không ai báo vì nó không đổ vỡ — nó chỉ
     nhỏ đi. Vẽ lại một lớp thì phải gỡ CẢ những thuộc tính lớp cũ đặt, không chỉ
     đặt lại mấy cái mình quan tâm. */
  .ph-list{display:flex;flex-direction:column;gap:7px;max-height:none;overflow:visible}
  .ph-hint{font-size:12.5px}
  .ph-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;align-items:center;
    background:var(--paper);border:1px solid var(--line);border-radius:12px;padding:11px 13px}
  /* Tên dài thì xuống tối đa HAI dòng rồi cắt bằng dấu ba chấm — anh Đạt chốt
     16/09 cho thẻ hóa đơn, cùng lý do: *"ai muốn xem chi tiết cũng phải bấm vào"*.
     Không chặn thì một cái tên bốn dòng làm dòng đó cao gấp đôi mấy dòng kia. */
  .ph-nm{font-size:14px;font-weight:700;line-height:1.3;min-width:0;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  .ph-nm .ph-sub{-webkit-line-clamp:1}
  .ph-sub{font-size:11.5px;color:var(--slate-2);font-weight:400;margin-top:3px}
  .ph-pr{text-align:right;white-space:nowrap;display:flex;flex-direction:column;align-items:flex-end;gap:3px}
  .ph-p{font-size:16px;font-weight:800;font-family:var(--f-mono);letter-spacing:-.3px}
  .ph-p span{font-size:11.5px;font-weight:600;color:var(--slate-2);margin-left:2px;font-family:var(--f-ui)}
  .ph-w{font-size:11.5px;color:var(--slate)}
}

@media (max-width:880px){
  /* Ô đếm: 2 cột, nén lại — xếp dọc 4 ô là hết cả màn hình trước khi thấy nội dung */
  .kpis{grid-template-columns:1fr 1fr;gap:8px;margin-bottom:12px}
  .kpi{padding:10px 11px}
  .kpi .k{font-size:9.5px;letter-spacing:.3px}
  .kpi .v{font-size:17px}
  .kpi .n{font-size:10.5px;margin-top:2px;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  /* mấy dòng nhắc trên thanh công cụ không cần trên màn nhỏ */
  .toolbar .pill{display:none}
  .toolbar{gap:8px}
  .panel-hd h2{font-size:14.5px}
}

/* ---------- Thẻ thay bảng trên điện thoại (b130) ----------
   Bảng 7 cột không nhét vừa màn 390px, cuộn ngang thì mất nửa thông tin.
   Mỗi bản ghi thành một thẻ, đọc trọn trong một khung hình. */
.mcards{display:flex;flex-direction:column;gap:9px}
.mcard{background:var(--paper);border:1px solid var(--line);border-radius:13px;
  padding:12px 13px 11px;display:flex;flex-direction:column;gap:5px}
.mcard:active{background:var(--sky-50)}
.mc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
.mc-id{display:flex;flex-direction:column;min-width:0}
.mc-id strong{font-size:16px;letter-spacing:-.3px}
.mc-id span{font-size:11.5px;color:var(--slate)}
.mc-money{font-size:17px;font-weight:800;letter-spacing:-.4px;white-space:nowrap}
.mc-cust{font-size:14px;font-weight:700;line-height:1.3;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mc-cust span{font-weight:400;color:var(--slate);font-size:12.5px}
.mc-meta{font-size:12.5px;color:var(--slate);line-height:1.35;
  display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.mc-cod{font-size:12.5px;color:var(--red);background:var(--red-soft);
  border-radius:7px;padding:5px 9px}
.mc-cod.ok{color:var(--green);background:var(--green-soft)}
.mc-acts{display:flex;gap:6px;margin-top:4px;flex-wrap:wrap}
.mc-acts .actbtn{flex:1;justify-content:center;padding:11px 8px;font-size:13px;min-height:42px}
.mc-acts .actbtn.wide{flex:1 0 100%}
.mc-sum{display:flex;align-items:center;justify-content:space-between;
  padding:12px 14px;margin-top:10px;background:var(--sky-50);
  border:1px solid var(--sky-100);border-radius:12px;font-size:13px;color:var(--sky-600);font-weight:700}
.mc-sum strong{font-size:16px;color:var(--ink)}
@media (max-width:880px){
  .pgbar{flex-direction:column;align-items:stretch;gap:9px;border-top:0;padding:12px 2px 0}
  .pgn-wrap{justify-content:center}
  .pgi{text-align:center}
}

/* thẻ hóa đơn bản nén — mỗi màn thấy 6 hóa đơn thay vì 3 (b130) */
.mcard.tight{gap:3px;padding:11px 13px 9px}
.mc-line{display:flex;align-items:center;justify-content:space-between;gap:8px;min-width:0}
.mc-line .mc-cust{flex:1;min-width:0;font-size:13.5px}
.mc-foot{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:2px}
.mc-btns{display:flex;gap:6px;flex:0 0 auto}
.icobtn.lg{width:40px;height:40px;border:1px solid var(--line);border-radius:10px;
  display:grid;place-items:center;background:#fff}
.icobtn.lg svg{width:19px;height:19px}
.icobtn.lg.done{background:var(--green-soft);border-color:#A9D8C6;color:var(--green)}
.mcard.tight .mc-meta{font-size:12.5px}

@media (max-width:880px){
  /* Thẻ đã có khung riêng rồi — bỏ khung panel bọc ngoài cho đỡ hai lớp viền */
  .panel:has(.mcards){background:transparent;border:0;box-shadow:none;padding:0;margin-bottom:14px}
  .panel:has(.mcards) .panel-hd{padding:0 2px 9px;border:0;background:transparent;
    display:flex;align-items:center;gap:8px;flex-wrap:nowrap}
  .panel:has(.mcards) .panel-hd h2{font-size:14px;white-space:nowrap;
    overflow:hidden;text-overflow:ellipsis}
  .panel:has(.mcards) .panel-hd .tag{flex:0 0 auto}
  .panel:has(.mcards) .head-sp{flex:1}
  /* chip lọc phiếu giao: cho cuộn ngang thay vì xuống 2 hàng */
  .fchips{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;padding-bottom:2px}
  .fchips::-webkit-scrollbar{display:none}
  .fchip{flex:0 0 auto}
}

/* ---------- b133: thẻ "Sao lưu & phục hồi" — MỘT tấm 4 dòng ----------
   Anh Đạt duyệt qua mockup 10/08: mỗi dòng = icon + tên + 1 dòng tình
   trạng + huy hiệu màu + 1 nút. Chi tiết (bảng bản lưu) giấu sau nút. */
.bkrow{display:flex;align-items:center;gap:14px;padding:15px 16px;border-bottom:1px solid var(--line-2)}
.bkrow:last-child{border-bottom:0}
.bkic{width:38px;height:38px;flex:0 0 38px;border-radius:10px;background:var(--sky-50);
  display:grid;place-items:center;color:var(--slate)}
.bkic svg{width:19px;height:19px;stroke-width:1.9;fill:none;stroke:currentColor;
  stroke-linecap:round;stroke-linejoin:round}
.bktx{flex:1;min-width:0}
.bkt{font-size:14px;font-weight:700;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.bkt .tag{border-radius:99px;padding:2px 9px}
.bks{font-size:12.5px;color:var(--slate);margin-top:3px;overflow-wrap:anywhere}
.bkrow .btn{flex:0 0 auto}
#snaplist{border-bottom:1px solid var(--line-2)}
#snaplist .tbl-wrap{max-height:300px}
@media (max-width:880px){
  .bkrow{flex-wrap:wrap;padding:13px 12px;gap:10px}
  .bkrow .btn{flex:1;min-width:110px}
  .bkic{display:none}
}

/* b248 · NÚT CHỤP ẢNH NGAY TRÊN DÒNG TRA GIÁ (điện thoại, chỉ Chủ).
   Trên điện thoại màn Sản phẩm đổi thành Tra giá nên không có form để vào —
   đây là cửa duy nhất để chụp ảnh hàng khi đang đứng ở kho.

   🔴 SỔ LỖI #143 · THÊM PHẦN TỬ THỨ BA VÀO MỘT HÀNG CHỈ TÍNH CHO HAI.
   `.ph-row` là lưới `minmax(0,1fr) auto` — ĐÚNG HAI cột. Bản đầu của b248 nhét
   ô ảnh vào làm con thứ ba mà không sửa luật xếp ⇒ nó rơi xuống hàng ngầm phía
   dưới, cả dòng vỡ thành hình zigzag: tên một nơi, giá một nẻo, chip tồn trôi
   giữa. Và `flex:0 0 44px` viết trên con của LƯỚI thì không có tác dụng gì.
   Bài đo của tôi chỉ hỏi "có nút chụp ảnh không → CÓ" nên báo ĐẠT trong lúc
   dòng đang vỡ — đúng #40 · #50: đo được con số, không đo được cái xấu.
   → Nay khai đủ BA cột, và chỉ khi dòng thật sự có ô ảnh. */
.ph-row:has(.ph-cam){grid-template-columns:44px minmax(0,1fr) auto}
.ph-row .ph-cam{width:44px;height:44px;border-radius:var(--r-sm);
  border:1px dashed var(--line);background:var(--sky-50);color:var(--slate-2);
  display:flex;align-items:center;justify-content:center;cursor:pointer;overflow:hidden}
.ph-row .ph-cam.co{border-style:solid;border-color:var(--line);background:var(--paper)}
.ph-row .ph-cam{position:relative}
.ph-row .ph-cam img{width:100%;height:100%;object-fit:contain}
/* Chữ cái đầu thay cho sáu ô máy ảnh giống hệt nhau đè cạnh trái — học từ cách
   KiotViet làm. Huy hiệu máy ảnh nhỏ ở góc vẫn nói cho biết ô này BẤM ĐƯỢC. */
.ph-row .ph-cam b{font-weight:800;font-size:18px;color:var(--slate-2)}
.ph-row .ph-cam-hh{position:absolute;right:-3px;bottom:-3px;width:18px;height:18px;
  border-radius:999px;background:var(--sky-700);display:flex;align-items:center;justify-content:center}
.ph-row .ph-cam-hh svg{width:11px;height:11px;stroke:#fff;fill:none;stroke-width:2.2}
.ph-row .ph-cam.co .ph-cam-hh{background:var(--slate-2)}
.ph-row .ph-cam:active{background:var(--or-50);border-color:var(--or)}

/* ═══ b251 · THANH DƯỚI ĐIỆN THOẠI — DỰNG LẠI CHO CÂN ═══
   Anh Đạt 17/09 nhìn máy thật: *"Bán hàng nhìn rõ ràng k cân. B xem lại cách sắp
   xếp, thao tác nhấn cũng hài hoà."* Ông đúng. Ba chỗ sai của bản b250:

   ① 🔴 NĂM NÚT KHÔNG BẰNG NHAU. `.navbtn{flex:1 0 auto;min-width:68px}` cho mỗi
      nút rộng theo ĐỘ DÀI CHỮ ("Cho thuê" ngắn hơn "Bán hàng"), nên nút thứ ba
      không nằm ở TÂM thanh. Và bài đo của tôi báo "✅ chính giữa" vì nó đếm THỨ
      TỰ (3/5), không đo TÂM HÌNH HỌC — đo nhầm thứ, lại một lần nữa (#30 · #49).
      → `flex:1 1 0` + `min-width:0`: năm cột bằng nhau tuyệt đối, cột giữa nằm
      đúng tâm dù chữ dài ngắn thế nào.

   ② 🔴 NHÃN KHÔNG CÙNG MỘT ĐƯỜNG. b250 nhấc cả CÁI NÚT lên, nên chữ "Bán hàng"
      cao hơn bốn chữ kia — mắt đọc ra một hàng gãy. → Chỉ nhấc BIỂU TƯỢNG lên
      (huy hiệu cam), còn NHÃN đứng nguyên hàng với bốn nhãn kia. `transform`
      không chiếm chỗ nên nhãn không xê dịch một pixel nào.

   ③ 🔴 HAI THỨ CÙNG ĐÒI CHÚ Ý. Nút đang mở có nền sáng + vạch cam, đứng cạnh ô
      cam thì thành hai điểm nhấn cạnh nhau. → Nút thường: bỏ nền, chỉ đổi màu
      chữ/biểu tượng và một vạch cam mảnh trên đầu. Ô giữa: cam. Mỗi thứ một vai.

   Chạm: mỗi cột cao 56px (≥44px theo chuẩn), `:active` cùng một kiểu cho cả năm
   — "thao tác nhấn hài hoà" như anh nói. */
@media (max-width:880px){
  /* 🔴 PHẢI MỞ CẢ HAI TRỤC. `foundation.css` đặt `overflow-y` cho thanh DỌC ở máy
     quầy; ở đây chỉ mở `overflow-x:visible` thì CSS **bắt buộc** biến nó thành
     `auto` — luật: một trục không phải `visible` thì trục `visible` kia tự thành
     `auto`. Kết quả: thanh vẫn xén, huy hiệu cam bị cắt mất nửa trên, mà mọi phép
     đo toạ độ vẫn báo đúng vì phần bị cắt VẪN CÓ TOẠ ĐỘ — nó chỉ không được vẽ.
     Đo bằng `getComputedStyle(.rail).overflow` mới thấy: `auto / x:auto / y:auto`. */
  .rail{
    overflow:visible;align-items:stretch;gap:0;
    padding:6px 4px calc(6px + env(safe-area-inset-bottom));
  }
  .navbtn{
    flex:1 1 0;min-width:0;gap:4px;padding:6px 2px;border-radius:var(--r);
    min-height:56px;justify-content:center;
  }
  .navbtn span{
    max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  }
  /* Nút thường đang mở: KHÔNG nền, chỉ sáng chữ + vạch cam mảnh trên đầu. */
  .navbtn.on,.navbtn:hover{background:none}
  .navbtn.on{color:#fff}
  /* Vạch báo màn đang mở: ngắn lại và bo tròn cho cân với huy hiệu tròn ở giữa. */
  .navbtn.on::before{
    left:50%;right:auto;transform:translateX(-50%);
    top:0;bottom:auto;width:26px;height:3px;border-radius:0 0 3px 3px;
  }
  .navbtn:active{background:rgba(255,255,255,.10)}

  /* Ô giữa: biểu tượng nhấc lên thành huy hiệu cam KHI ĐANG Ở MÀN KHÁC, và nằm
     phẳng như bốn nút kia KHI ĐANG Ở CHÍNH MÀN BÁN HÀNG.
     Anh Đạt 17/09: *"Ô bán hàng sẽ bình thường khi ở phần bán hàng. Nhưng hiện
     nổi như ảnh khi đang ở tab khác. Để tạo thói quen nhanh biết ngay cần bán
     hàng ở đâu."* — huy hiệu là CÁI CHỈ ĐƯỜNG: tới nơi rồi thì thôi chỉ.
     Kèm một cái lợi: ở màn Bán hàng huy hiệu không nhấc lên nữa nên không thể
     chạm vào phiếu bán hàng ngay phía trên — hết hẳn chuyện "có vướng phiếu không".
     Nền `--or` + nét `--ink` đo được 5,96:1 — chữ trắng trên cam chỉ 2,80:1
     nên không bao giờ dùng (tờ nhận diện §2). */
  .navbtn.navgiua{background:none}
  .navbtn.navgiua svg{transition:transform .16s ease,background-color .16s ease}
  /* 🔴 BA CON SỐ NÀY ĂN KHỚP NHAU, ĐỔI MỘT THÌ PHẢI TÍNH LẠI CẢ BA.
       cao huy hiệu = 26 (nét) + 26 (đệm) + 6 (viền) = 58px
       margin-bottom = -(58 - 20) = -38px   → trả lại chỗ, nhãn về đúng hàng
       translateY   = -38px                 → nhấc lên
     Đáy huy hiệu sau khi nhấc = 58 - 38 = 20px, trong khi nhãn bắt đầu ở 24px
     ⇒ chừa 4px, KHÔNG đè lên chữ.
     b251 bản đầu để 45px — anh Đạt xem máy thật: *"nên to hơn chút"*. Và đổi
     sang HÌNH TRÒN: khối bo 15px trên nền thanh tối đọc ra như một cái bia mộ,
     cạnh dưới trông như bị cắt. Tròn thì không có cạnh nào để nhìn ra lệch.
     Bản trước lấy huy hiệu 52px mà chỉ nhấc 15px: đáy nó rơi xuống 37px, tức
     ĐÈ LÊN CHỮ 13px — mất hẳn chữ "Bán hàng". Bài đo lúc đó chỉ hỏi "nhãn có
     cùng đường không" (có), không hỏi "nhãn có bị che không". Nay hỏi cả hai. */
  .navbtn.navgiua:not(.on) svg{
    width:26px;height:26px;box-sizing:content-box;padding:13px;
    border-radius:999px;background:var(--or);stroke:var(--ink);stroke-width:2.1;opacity:1;
    transform:translateY(-38px);
    box-shadow:0 8px 20px rgba(249,115,22,.38), 0 2px 6px rgba(8,51,79,.22);
    border:3px solid var(--bg);
    margin-bottom:-38px;
  }
  .navbtn.navgiua:not(.on) span{color:var(--or);font-weight:800}
  .navbtn.navgiua:not(.on)::before{display:none}
  .navbtn.navgiua:not(.on):active svg{background:var(--or-6,#EA6A0B);transform:translateY(-34px) scale(.96)}
  /* Đang ở màn Bán hàng: rơi hẳn về kiểu nút thường — chữ trắng + vạch cam trên
     đầu, giống hệt bốn nút kia. Không khai lại gì ở đây là CỐ Ý. */
  .navbtn.navgiua:active{background:none}
}

/* b273: product pages on narrow screens. */
@media(max-width:880px){
  #phlist .p-more{padding:12px 0}
  #phlist .p-page-actions{width:100%;justify-content:space-between;margin-left:0}
  #phlist .p-page-actions .btn,#phlist .p-page-actions select{min-height:44px}
}

/* ===== SOURCE: styles/workflows.css ===== */
/* ============================================================
   BẢO HÀNH (b136) — sổ hàng đang giữ của khách
   Anh Đạt 14/08/2026: bỏ hẳn màn tra + huy hiệu đếm ngược.
   Còn lại đúng một bảng: món của ai, lỗi gì, cầm bao lâu rồi.
   ============================================================ */
.bh-tbl{width:100%;border-collapse:collapse;font-size:13.5px}
.bh-tbl td{padding:13px 15px;border-bottom:1px solid var(--line-2);vertical-align:middle}
.bh-tbl tbody tr:last-child td{border-bottom:0}
.bh-tbl .nm{font-weight:700;font-size:14px;line-height:1.35}
.bh-tbl .sub2{font-size:12px;color:var(--slate);margin-top:3px;font-family:var(--f-mono)}
.bh-tbl .bh-fault{font-size:12.5px;color:var(--ink-2);margin-top:4px;font-style:italic}
.bh-tbl td.c-who{width:210px}
.bh-tbl td.c-age{width:150px}
.bh-tbl td.a{width:190px;text-align:right}

/* Cầm hàng của khách bao lâu rồi. Quá 10 ngày tô cam — không phải cảnh báo
   hệ thống, mà là nhắc gọi cho khách trước khi khách gọi cho mình. */
.wbadge{display:inline-flex;align-items:center;border-radius:9px;padding:7px 12px;
  font-size:13px;font-weight:800;line-height:1.2;white-space:nowrap}
.wb-soon{background:#FFF3E0;color:#8A4B00}
.wb-non{background:#EEF0F3;color:var(--slate)}

/* bốn bước — bấm để lọc, con số là số món đang đứng ở bước đó */
.stepbar{display:flex;margin:0 0 14px}
.step{flex:1;padding:9px 6px;text-align:center;font-size:12.5px;font-weight:700;
  border:1px solid var(--line);background:var(--paper);color:var(--slate);
  font-family:inherit;cursor:pointer;min-height:44px}
.step:first-child{border-radius:9px 0 0 9px}
.step:last-child{border-radius:0 9px 9px 0}
.step+.step{border-left:0}
.step:hover:not(.on){background:var(--sky-50);color:var(--ink)}
.step.on{background:var(--sky-900);border-color:var(--sky-900);color:#fff}
.step b{display:block;font-family:var(--f-mono);font-size:15px;margin-top:2px}

/* thẻ trên điện thoại — tên khách đứng trước, vì câu hỏi luôn là "của ai" */
.bcard{background:var(--paper);border:1px solid var(--line);border-radius:13px;padding:12px 13px;margin-bottom:9px}
.bcard .l1{display:flex;justify-content:space-between;gap:8px;align-items:baseline}
.bcard .l1 b{font-size:15px;line-height:1.3;min-width:0}
.bcard .l1 span{font-family:var(--f-mono);font-size:12px;color:var(--slate);flex:0 0 auto}
.bcard .l2{font-size:12.5px;color:var(--slate);font-family:var(--f-mono);margin:2px 0 7px}
.bcard .bh-item{font-size:13.5px;font-weight:700;line-height:1.35}
.bcard .bh-fault{font-size:12.5px;color:var(--ink-2);font-style:italic;margin:3px 0 8px}
.pill2{display:inline-flex;align-items:center;border-radius:100px;padding:5px 11px;font-size:12px;font-weight:700}

@media (max-width:880px){
  .stepbar{overflow-x:auto}
  .step{flex:0 0 auto;min-width:126px}
}

/* thanh tiến độ đẩy máy chủ (b137) */
.pgline{height:8px;border-radius:100px;background:var(--line-2);overflow:hidden;margin:0 0 13px}
.pgfill{height:100%;background:var(--or);border-radius:100px;transition:width .25s ease-out}

/* thanh gập trong Danh mục & hệ thống (b141) */
.acchd{cursor:pointer;user-select:none}
.acchd:hover h2{color:var(--sky-700)}
.acar{font-size:13px;color:var(--slate-2);width:18px;text-align:center}

/* ---- b144: mã đánh giá Google trên bill nhiệt ---- */
.p-80 .rvq{text-align:center;margin:1.5mm 0 .5mm}
.p-80 .rvq svg{width:24mm;height:24mm}
.p-80 .rvq .t{font-size:8pt;line-height:1.4}

/* ---- b145 → b147: Sổ màu sơn ----
   Bỏ bảng, đổi sang thẻ từng khách: câu hỏi ở quầy luôn là "màu của AI",
   nên tên khách phải là thứ to nhất, mã màu nằm bên trong.
   Đệm theo thang 4/8/12 của sổ tay mục 4; CAM vẫn chỉ dành cho hành động
   chính (nút Thêm màu), thẻ mã màu dùng cam NHẠT vì nó là thứ cần chú ý
   nhất trong khối, không phải nút hành động thứ hai. */
.smwrap{max-height:calc(100vh - 268px);overflow:auto}
.smlist{display:grid;gap:8px}
.smk{border:1px solid var(--line);border-radius:var(--r-lg);background:var(--paper);overflow:hidden}
.smk.on{border-color:var(--sky-300);box-shadow:var(--shadow)}
.smhd{display:flex;align-items:center;gap:12px;width:100%;text-align:left;padding:8px 12px;background:none}
.smhd:hover{background:var(--sky-50)}
.smav{
  flex:0 0 auto;width:34px;height:34px;border-radius:50%;display:grid;place-items:center;
  background:var(--sky-100);color:var(--sky-700);font-weight:700;font-size:14px;
}
.smnm{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.smnm b{font-size:14px;font-weight:700;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.smnm i{font-style:normal;font-size:12px;color:var(--slate-2)}
.smdt{flex:0 0 auto;font-size:12px;color:var(--slate-2)}
.smar{flex:0 0 auto;width:16px;text-align:center;color:var(--slate-2);font-size:12px}
.smbd{padding:0 12px 12px 58px;display:grid;gap:8px}
.smm{
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  background:var(--sky-50);border:1px solid var(--line-2);border-radius:var(--r);padding:6px 8px 6px 10px;
}
.smmi{flex:1;min-width:140px;font-size:12px;color:var(--slate);line-height:1.5}
.smmi i{font-style:italic;color:var(--ink-2)}
.smact{flex:0 0 auto;display:flex;gap:2px;margin-left:auto}
.smadd{justify-self:start;margin-top:2px}
.smchips{display:flex;flex-wrap:wrap;gap:7px}
.smchip{display:inline-flex;align-items:center;gap:6px;cursor:pointer;
  font-family:inherit;font-size:12.5px;font-weight:700;color:var(--or-7);
  background:#FFF4EC;border:1px solid #F3C9A6;border-radius:999px;padding:5px 11px;
  line-height:1.3;white-space:nowrap}
.smchip:hover{background:#FFE8D6;border-color:#E9A96F}
.smchip b{font-weight:800;color:var(--slate);font-size:11.5px}

/* Điện thoại: bỏ thụt lề theo vòng tròn tên khách cho rộng chỗ, và để màn
   tự cao — cuộn của cả trang lo, không cần khung cuộn riêng. */
@media (max-width:880px){
  .smwrap{max-height:none;overflow:visible}
  .smbd{padding-left:12px}
  .smm{gap:8px}
  .smmi{min-width:100%;order:3}
  .smact{order:2}
}

/* ================= b146 — CHỐNG IPHONE PHÓNG TO KHI CHẠM / LƯỚT =================
   Anh Đạt báo 19/08: "vào app bằng điện thoại, vẫn bị zoom khi lướt."
   Web đã trị hồi bản 34, app thì quên — hai bên hai bộ CSS khác nhau.
   Có BA nguyên nhân, phải trị đủ cả ba mới hết:

   1. Chạm đôi phóng trang. Trước đây chỉ đặt cho nút và thẻ, nên chạm trúng
      khoảng trống giữa chúng là lỗi quay lại. PHẢI đặt cho `*`.
      `manipulation` vẫn cho véo hai ngón phóng to — người lớn tuổi cần cái đó,
      chỉ tắt riêng phóng-bằng-chạm-đôi.
   2. Safari tự phóng khi con trỏ vào ô nhập có cỡ chữ dưới 16px, và KHÔNG tự
      thu lại. App đang có mấy ô 11,5–13px.
   3. Chữ tự phồng khi xoay ngang máy.
   Bài kiểm bắt buộc trước mỗi bản: xem `so-tay-web.md` mục A. */
*{touch-action:manipulation}
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}
@media (max-width:880px){
  input,select,textarea{font-size:16px}
  .cust-row input,.eqrow input,.eqrow select,input[type=file]{font-size:16px}
  /* mấy ô hẹp phải nới ra cho vừa cỡ chữ 16px, không thì chữ bị cắt */
  .trow input{width:104px;font-size:16px;padding:4px 7px}
  .trow select{font-size:16px;padding:4px 6px}
  .qty input{font-size:16px}
  .pin input{font-size:16px}
  /* ô Thuế GTGT và ô Giảm giá ở chân giỏ hàng — hai ô này thừa hưởng cỡ
     12,5px của khối .fcell, phải nói rõ mới thắng được */
  .fcell input,.fcell select{font-size:16px;width:124px;padding:5px 8px}
}

/* Tương phản WCAG 2.2 AA cho các nút dùng chữ/biểu tượng trắng.
   Không thay font, cỡ chữ hay kích thước vùng bấm. */
.btn.acc,.scan-mic,.scan-mic.on,.best-tick,.pin button,.tab .tn,
.ck-step button.on,.ph-hit.mid .ph-i,.ph-badge.pick,.bigbtn.on,
.navbtn.lockbtn.on,.paybar .pb-go{background:var(--or-safe);border-color:var(--or-safe)}
.btn.acc:hover,.scan-mic:hover,.pin button:hover,.bigbtn.on:hover,.navbtn.lockbtn.on:hover,
.paybar .pb-go:active{background:var(--or-safe-hover);border-color:var(--or-safe-hover)}
.scan-cam:hover,.ph-tools button:hover{background:var(--or-safe);border-color:var(--or-safe)}
.btn-next{background:linear-gradient(180deg,var(--or-safe),var(--or-safe-hover))}

/* ═══════════════════════════════════════════════════════════════════════════
   BẢN 149 — SỬA HÓA ĐƠN: THÊM / BỚT HÀNG
   ═══════════════════════════════════════════════════════════════════════════
   Băng nhắc "đang sửa hóa đơn" phải ĐẬP VÀO MẮT. Người bán quen bấm F2 rồi
   quét hàng liên tục; lỡ quét nhầm vào thẻ đang sửa thì hóa đơn cũ bị ghi đè
   mà không ai hay. Nên dùng nền đỏ nhạt + viền trái đỏ đậm, đứng ngay trên ô
   quét — chỗ mắt nhìn tới đầu tiên. */
.edbar{display:flex;align-items:center;gap:12px;margin:0 0 10px;
  padding:10px 12px;border-radius:8px;background:#FEF2F2;
  border:1px solid #FCA5A5;border-left:4px solid #DC2626}
.edbar .ed-ic{flex:0 0 auto;display:flex;color:#B91C1C}
.edbar .ed-tx{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;line-height:1.35}
.edbar .ed-tx strong{font-size:14px;color:#991B1B}
.edbar .ed-tx span{font-size:12.5px;color:var(--slate-2)}
.edbar .btn{flex:0 0 auto}
/* Nút thanh toán lúc đang sửa: đổi hẳn màu để không bấm theo quán tính. */
.pb-go.ed{background:#B91C1C;border-color:#B91C1C;color:#fff}
.pb-go.ed:hover{background:#991B1B;border-color:#991B1B}

/* Ô tìm hàng trong hộp Sửa hóa đơn. Cố ý chỉ 8 dòng và cao tối đa 210px —
   đây là hộp sửa chữa, cần danh sách dài thì mở ra màn Bán hàng. */
.ei-add{margin-top:12px}
.ei-add>label{display:block;font-size:12px;font-weight:600;color:var(--slate-2);margin-bottom:5px}
.ei-add>input{width:100%}
.ei-res{margin-top:6px;max-height:210px;overflow-y:auto;overscroll-behavior:contain}
.ei-res:empty{display:none}
.ei-r{display:flex;align-items:center;gap:9px;padding:7px 8px;border-radius:6px}
.ei-r+.ei-r{border-top:1px solid var(--line)}
.ei-r:hover{background:var(--sky-50)}   /* b248 · SỔ NHẬN DIỆN §1: `--sky-1` là biến của WEB, app không khai và ở đây KHÔNG có màu dự phòng ⇒ rê chuột vào dòng trong hộp Sửa hóa đơn không sáng lên, im lặng suốt nhiều bản. Đổi sang `--sky-50` là nền rê chuột app đang dùng. */
.ei-n{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.ei-n strong{font-size:13.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ei-n i{font-style:normal;font-size:11.5px;color:var(--slate-2)}
.ei-r .btn{flex:0 0 auto}
.ei-non{padding:12px 8px;font-size:13px;color:var(--slate-2);text-align:center}

/* Dòng "BẢN SỬA LẦN N" trên phiếu in. In ra giấy nhiệt và giấy A4 đều phải
   thấy — đây là thứ để biết tờ nào mới khi hai tờ cùng một số hóa đơn. */
.ed-mark{font-weight:700}
@media print{ .ed-mark{display:block} }

@media (max-width:880px){
  .edbar{flex-wrap:wrap;gap:8px}
  .edbar .ed-tx{flex:1 1 100%;order:2}
  .edbar .btn{order:3;margin-left:auto;font-size:16px}
  .ei-res{max-height:240px}
  .ei-add>input{font-size:16px}     /* dưới 16px là iPhone tự phóng to cả trang */
}

/* Khung xem trước lúc đang sửa: đổi màu thanh tiêu đề để không nhìn nhầm
   thành phiếu bán mới. Nút chính cũng đổi sang đỏ — bấm theo quán tính vào
   nút cam quen thuộc là ghi đè hóa đơn cũ mà không kịp nghĩ. */
.tape-bar.ed{background:#7F1D1D}
.tape-hd .meta .ed-t{color:#B91C1C;font-weight:700}
.btn.acc.big.ed{background:#B91C1C;border-color:#B91C1C;color:#fff}
.btn.acc.big.ed:hover{background:#991B1B;border-color:#991B1B}

/* ── b149, vá kèm: hai chỗ nhỏ trên iPhone ──────────────────────────────────
   Cả hai đều CÓ SẴN từ trước, không phải do bản sửa hóa đơn đẻ ra. Nhưng bản
   sửa làm chúng lộ ra thường xuyên nên vá luôn — đúng Sổ lỗi #10: "vá một chỗ
   thì hỏi ngay, chỗ kia có dính không".

   1. Ô ghi chú từng món (.ntin) đang 11,5px. Safari tự phóng to CẢ TRANG khi
      con trỏ vào ô dưới 16px và KHÔNG tự thu lại — đúng con bệnh anh Đạt báo
      ở b146. Lần đó vá Thuế GTGT với Giảm giá mà sót ô này vì nó chỉ hiện khi
      rê chuột, trên máy tính không ai thấy.
   2. Nút ↺ "trả về giá gốc" đang 19×19px, dưới mức 24px sờ được. Lúc bán
      thường nó chỉ hiện khi tự gõ đè giá nên ít gặp; lúc SỬA hóa đơn thì mọi
      dòng đều mang giá đã bán, tức là dòng nào cũng hiện nút này. */
@media (max-width:880px){
  .item .ntin{font-size:16px}
  .item .ntrow{max-height:none}
  .item .ntrow svg{width:14px;height:14px}
  .pin button{min-width:24px;min-height:24px;display:inline-flex;
    align-items:center;justify-content:center;font-size:15px;line-height:1}
}


/* ═══════════════════════════════════════════════════════════════════════════
   BẢN 150 — HỘP SỬA HÓA ĐƠN GỌN LẠI
   ═══════════════════════════════════════════════════════════════════════════
   Anh Đạt xem mẫu 20/08 rồi chốt: bỏ ô Giảm giá, Thuế GTGT, Thanh toán; hai
   khối chữ dài gom thành hai nút.

   NGUYÊN TẮC CỦA HỘP NÀY SAU BẢN 150: hộp Sửa chỉ lo HÀNG và KHÁCH. Giảm giá,
   thuế, hình thức trả tiền đều làm ở màn Bán hàng. Đừng nhét mấy ô đó về lại —
   nhét về là hộp dài ra, mà việc thì đã có chỗ làm tử tế hơn.

   BA CON SỐ BỊ BỎ Ô NHẬP VẪN PHẢI HIỆN RA BẰNG CHỮ ở dòng tổng (.eis-2).
   Giấu một con số tiền đi là kiểu lỗi tệ nhất: người bán tưởng hóa đơn không
   giảm giá, thực ra đang giảm 200 nghìn nằm im. Xóa dòng đó là phạm luật này. */
/* ── LUẬT MÀU CỦA HỘP NÀY ───────────────────────────────────────────────
   Mỗi màu mang MỘT nghĩa, dùng đúng nghĩa đó, không tô cho đẹp:
     XANH LÁ  dòng MỚI thêm vào · hàng còn tồn
     CAM      dòng ĐÃ SỬA số · số tiền khách trả · hàng sắp hết
     ĐỎ       dòng ĐÃ BỎ · nút bỏ dòng · hàng hết
     XÁM THAN khung sườn, số thứ tự các phần
   Dòng KHÔNG đụng gì thì để trắng — mắt chỉ phải nhìn chỗ đã đổi.
   Đừng thêm màu thứ năm. Thêm là hết phân biệt được. */

/* nhãn đánh số từng phần — thứ giúp mắt bám nhanh nhất, rẻ nhất */
/* Lề TRÊN 20px là bắt buộc, không phải cho đẹp: nhãn phần 3 nằm ngay dưới ô
   tìm hàng, không có lề thì hai thứ dán vào nhau và vòng cam lúc gõ đè lên
   chữ. Lề trên của phần 1 và 2 sẽ tự gộp với lề dưới của khối phía trước
   (margin collapsing), nên không đẻ thêm khoảng trống thừa ở hai chỗ đó. */
.ei-sec{display:flex;align-items:center;gap:8px;margin:20px 0 8px;
  font-size:11.5px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--sky-600)}
.ei-sec i{font-style:normal;font-size:10.5px;font-weight:600;letter-spacing:.04em;
  text-transform:none;color:var(--red);background:var(--red-soft);padding:2px 7px;border-radius:99px}
.ei-no{flex:0 0 auto;width:19px;height:19px;border-radius:50%;background:var(--sky-800);color:#fff;
  display:grid;place-items:center;font-size:11px;font-weight:700;letter-spacing:0}

/* hai nút lối tắt — chip màu bên trong nói nghĩa của nút */
.ei-jump{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:6px}
.ei-jump .btn{justify-content:flex-start;gap:9px;padding-left:8px}
.ei-jc{flex:0 0 auto;width:28px;height:28px;border-radius:var(--r-sm);display:grid;place-items:center}
.ei-jc svg{width:15px;height:15px}
.ei-j1 .ei-jc{background:var(--red-soft);color:var(--red)}      /* hàng đi ngược về kho */
.ei-j2 .ei-jc{background:var(--or-50);color:var(--or-7)}        /* đi bán tiếp */
.ei-j1:hover{border-color:var(--red)} .ei-j2:hover{border-color:var(--or-6)}
/* b152: đã bỏ dòng nhắc .ei-jh. Nghĩa của hai nút nay nằm trong thuộc tính
   title — rê chuột vào là hiện. Cần nói lại thì để trong title, đừng đắp thêm
   một dòng chữ xám nữa: chữ xám mà lần nào cũng hiện thì không ai đọc. */
.ei-jump{margin-bottom:16px}

/* bảng dòng hàng */
#ei_rows .eir>td{padding:9px 8px;border-bottom:1px solid var(--line-2);vertical-align:middle}
#ei_rows .eir:hover>td{background:var(--sky-50)}
/* KHÔNG BAO GIỜ đặt display:flex thẳng lên thẻ <td>. Trình duyệt lôi nó ra
   khỏi bảng rồi bọc vào một ô vô danh — nền và đường kẻ đứt một khoảng ngay
   cạnh cột đó, nhìn như bảng bị vỡ. Flex phải nằm trong một <span> bên trong. */
.ei-tnc{max-width:0;width:38%}
.ei-tn{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.ei-tn .nm{font-weight:600}
.ei-dv{color:var(--slate-2);font-size:13px}
.ei-tt{font-weight:700;font-family:var(--f-mono);font-size:13.5px}
/* ô nhập được thì có nền — ô chỉ để đọc thì không. Nhìn là biết chỗ nào gõ được. */
.ei-in{width:76px;text-align:right;padding:5px 8px;background:var(--sky-50);
  border:1px solid var(--line);border-radius:var(--r-sm);font-family:var(--f-mono);font-size:13px}
.ei-in.wide{width:98px}
.ei-in:focus{background:#fff;border-color:var(--sky-500)}

/* ba trạng thái, ba màu — vạch dọc bên trái là thứ mắt bắt trước cả chữ */
.ei-tag{font-size:10.5px;font-weight:700;letter-spacing:.02em;padding:2px 7px;border-radius:99px;white-space:nowrap}
.ei-cu{font-size:11px;color:var(--slate-2);text-decoration:line-through;font-variant-numeric:tabular-nums}
#ei_rows .eir.moi>td:first-child{box-shadow:inset 3px 0 0 var(--green)}
#ei_rows .eir.moi>td{background:var(--green-soft)}
.ei-tag.moi{background:var(--green);color:#fff}
#ei_rows .eir.sua>td:first-child{box-shadow:inset 3px 0 0 var(--or-6)}
#ei_rows .eir.sua>td{background:var(--or-50)}
.ei-tag.sua{background:var(--or-safe);color:#fff}
#ei_rows .eir.bo>td:first-child{box-shadow:inset 3px 0 0 var(--red)}
#ei_rows .eir.bo>td{background:var(--red-soft)}
#ei_rows .eir.bo .nm,#ei_rows .eir.bo .ei-tt{text-decoration:line-through;color:var(--slate-2)}
.ei-tag.bo{background:var(--red);color:#fff}
.ei-del:hover{background:var(--red-soft);color:var(--red)}
.ei-undo{background:var(--red-soft);color:var(--red)}
.ei-undo:hover{background:var(--red);color:#fff}

/* ô tìm hàng */
.ei-add{margin-top:16px}
.ei-add>label{display:flex;align-items:center;gap:6px;font-size:12px;font-weight:650;
  color:var(--sky-600);margin-bottom:6px}
.ei-add>label svg{width:14px;height:14px}
.ei-ton{font-weight:650;padding:1px 6px;border-radius:99px}
.ei-ton.con{background:var(--green-soft);color:var(--green)}
.ei-ton.sap{background:var(--or-50);color:var(--or-safe)}
.ei-ton.het{background:var(--red-soft);color:var(--red)}

/* thẻ tổng tiền — nền xám than, số cam. Giống hệt thanh KHÁCH TRẢ ở màn Bán
   hàng nên mắt quen sẵn; và cam trên xám than đo được 5,61:1, đạt chuẩn AA. */
.ei-sum{margin-top:14px;background:var(--sky-800);border-radius:var(--r);padding:12px 14px;color:#fff}
.eis-hd{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.eis-l{flex:1;min-width:0;font-size:11.5px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--sky-300)}
.eis-l b{color:#fff}
.eis-v{font-size:21px;font-weight:800;color:var(--or);font-family:var(--f-mono);letter-spacing:-.02em}
.eis-d{font-weight:700;font-size:12px;padding:2px 8px;border-radius:99px}
.eis-d.up{background:var(--or-50);color:var(--or-safe)}
.eis-d.dn{background:var(--green-soft);color:var(--green)}
/* KHÔNG dùng font mono cho dòng có CHỮ TIẾNG VIỆT. JetBrains Mono không dựng
   được dấu, "Tiền" ra "Tiêǹ", "sửa" ra "sưả" — nhìn như trang bị lỗi phông.
   Mono chỉ dành cho ô toàn số: .ei-in, .ei-tt, .eis-v. */
.eis-2{margin-top:7px;padding-top:7px;border-top:1px solid rgba(255,255,255,.14);
  font-size:12px;color:var(--sky-300);font-variant-numeric:tabular-nums}
.eis-3{margin-top:3px;font-size:11.5px;color:var(--sky-400);line-height:1.5}
.eis-3 i{font-style:normal;opacity:.9}

@media (max-width:880px){
  .ei-jump{grid-template-columns:1fr}
  .ei-in{width:70px;font-size:16px} .ei-in.wide{width:92px;font-size:16px}
  .eis-v{font-size:19px}
}


/* ═══════════════════════════════════════════════════════════════════════════
   BẢN 150 — DANH SÁCH HÓA ĐƠN: MỌI DÒNG CAO BẰNG NHAU
   ═══════════════════════════════════════════════════════════════════════════
   Luật của khối này, đừng phá:

   1. MỖI DÒNG ĐÚNG HAI HÀNG CHỮ. Chiều cao ghim cứng 62px. Muốn thêm thông
      tin thì thay chữ trong hai hàng đó, TUYỆT ĐỐI không đẻ hàng thứ ba —
      một dòng cao lên là gãy nhịp cả danh sách, mắt phải rà lại từ đầu.
   2. BÁO CHUYỆN KHÁC THƯỜNG BẰNG MÀU CHỮ SẴN CÓ, không bằng thẻ mới.
      Còn nợ  -> chấm cam đầu dòng + dòng dưới cột tiền đổi sang đỏ.
      Đã sửa  -> dấu bút chì mờ cạnh số hóa đơn.
      Cả hai đều nằm lọt trong hai hàng, nên chiều cao không đổi.
   3. DÙNG LƯỚI, KHÔNG DÙNG <table>. Ô bảng cao theo nội dung dài nhất nên
      không ghim được; lưới thì ghim được. Tiện thể hết luôn cái bẫy
      display:flex trên thẻ <td>.
   4. HÀNG BÌNH THƯỜNG KHÔNG ĐEO GÌ CẢ. Chín trên mười hóa đơn là bình
      thường — tô hết thì màu mất nghĩa, mà đó mới đúng là lúc cần màu. */

.ipanel{padding:0;overflow:hidden}
.ilist{display:flex;flex-direction:column}
/* Một chỗ khai bề ngang cột cho CẢ đầu bảng lẫn mọi dòng — hai chỗ khai riêng
   là có ngày lệch nhau mà không ai để ý. */
.ilist .ihead,.ilist .irow{
  display:grid;align-items:center;
  grid-template-columns:22px 132px minmax(0,1fr) 156px 78px;
  gap:0 14px;padding:0 16px 0 4px}
.ilist.loi .ihead,.ilist.loi .irow{grid-template-columns:22px 132px minmax(0,1fr) 116px 156px 78px}
.ilist .ihead{height:38px;border-bottom:1px solid var(--line);
  font-size:10.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--slate-2)}
.ilist .ihead .r{text-align:right}

.ilist .irow{height:62px;border-bottom:1px solid var(--line-2);cursor:pointer;
  background:none;border-left:0;border-right:0;border-top:0;width:100%;text-align:left;
  font:inherit;color:inherit;transition:background .12s}
.ilist .irow:hover{background:var(--sky-50)}
.ilist .irow:focus-visible{outline:2.5px solid var(--or-safe);outline-offset:-3px}
.ilist .irow:last-of-type{border-bottom:0}

/* hai hàng chữ — cùng một khuôn cho cả ba cột, nên chúng thẳng hàng nhau */
.ic1,.ic2,.ic3,.ic4{min-width:0;display:block;line-height:1.3}
.ic1 b,.ic2 b,.ic3 b,.ic4 b{display:block;font-size:14px;font-weight:650;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* b262 · Dòng hóa đơn đổi vai: TÊN HÀNG lên dòng chính (thứ duy nhất phân biệt
   các dòng), tên khách xuống dòng phụ. "Khách lẻ" lặp ở mọi dòng nên để nhạt;
   khách CÓ TÊN thì đậm hơn một nấc — đó mới là thông tin. */
.ic2 i.kh{color:var(--ink-2);font-weight:600}
.ic1 i,.ic2 i,.ic3 i,.ic4 i{display:block;font-style:normal;font-size:11.5px;color:var(--slate-2);
  margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-height:15px}
.ic3,.ic4{text-align:right}
.ic3 b{font-size:14.5px;font-weight:700}

/* chấm báo còn nợ — 7px, nằm gọn trong hàng, không đẩy gì đi đâu */
.idot{width:7px;height:7px;border-radius:50%;background:transparent;margin-left:9px}
.irow.no .idot{background:var(--or)}
.ic3 i.no{color:var(--red);font-weight:650}

/* Dấu bút chì "đã sửa" — nhỏ, mờ, nằm NGAY TRONG dòng số hóa đơn.
   Đừng dùng position:absolute cho nó: bỏ absolute ra thì nó tự tìm chỗ, còn
   để absolute mà quên khai left/right là nó rơi xuống dòng dưới, mất tăm. */
.ic1 b{display:flex;align-items:center;gap:5px}
.ic1 b>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ic1 .ised{display:inline-flex;flex:0 0 auto;color:var(--slate-2);opacity:.8}
.ic1 .ised svg{width:11px;height:11px}

/* hai nút im lặng, chỉ đậm lên khi rê chuột. Cố ý KHÔNG ẩn hẳn: màn cảm ứng
   không có rê chuột, ẩn là nhân viên không tìm ra nút. */
.iact{display:flex;gap:2px;justify-content:flex-end}
/* Màu nghỉ phải là --sky-400 (3,2:1), KHÔNG được dùng --sky-300 (2,0:1) —
   dưới mốc 3:1 cho thành phần bấm được. Mờ là để nó im lặng, không phải để
   nó biến mất. */
.iact .icobtn{width:30px;height:30px;color:var(--sky-400)}
.irow:hover .iact .icobtn{color:var(--slate)}
.iact .icobtn:hover{background:var(--sky-100);color:var(--ink)}

.ifoot{display:flex;align-items:center;justify-content:space-between;gap:16px;
  height:48px;padding:0 16px 0 26px;border-top:1px solid var(--line);background:var(--sky-50);
  font-size:11.5px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--slate-2)}
.ifoot strong{font-size:16px;letter-spacing:0;text-transform:none;color:var(--ink)}

/* thanh chọn ngày thay cho dãy 5 chip cũ */
.itool{gap:10px}
.idate{display:flex;align-items:center;gap:6px;margin-left:auto}
.ilb{font-size:11.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--slate-2)}
.idate input[type=date]{width:auto;padding:7px 9px;font-size:13px}
/* b242 · mỗi ô ngày nay bọc trong <label class=idf> để ĐIỆN THOẠI có nhãn chữ.
   Máy tính giữ y nguyên: `display:contents` cho ô date vẫn là con trực tiếp của
   thanh flex, nhãn phụ ẩn đi. Không lệch một pixel nào so với b241. */
.idf{display:contents}
.idf>span{display:none}
.idash{color:var(--slate-2)}
.ixoa{width:32px;height:32px;flex:0 0 auto;border:1px solid var(--line);background:var(--paper);
  border-radius:var(--r-sm);color:var(--slate-2);cursor:pointer;display:grid;place-items:center}
.ixoa:hover{border-color:var(--red);color:var(--red)}
.ixoa svg{width:13px;height:13px}

@media (max-width:880px){
  /* Điện thoại: thẻ ba cột không nhét vừa 390px — xếp thành thẻ, nhưng vẫn
     giữ đúng luật: mọi thẻ cao bằng nhau. */
  .ilist.ph{gap:var(--space-2);background:none}

  /* ══════ b242 · THẺ HÓA ĐƠN ĐIỆN THOẠI — DỰNG LẠI THEO ĐƯỜNG CHÂN CHỮ ══════
     Anh Đạt 16/09: "chữ cao chữ thấp nhìn k dễ chịu".
     Đo chân chữ bằng `<span>` RỖNG `inline-block;width:0;height:0;overflow:
     hidden` — ô như vậy lấy mép dưới làm chân chữ nên trình duyệt đặt nó đúng
     trên chân chữ của dòng. (Nhét chữ 'X' vào đo là SAI: ra mép hộp dòng.)
     b241 chưa vá — chỗ đáng lẽ MỘT hàng có tới BỐN chân chữ, trải 18,1px:
       HD-000003 14,5px/650/Mono y=229,3 · ngày 11,5/400/BVP y=228,3 ·
       62.000 15,5px/700/Mono y=220,8 · Tiền mặt 11,5/400 y=238,9.
     SAU KHI VÁ: cùng y=250,7 / y=274,5 — lệch 0,0px. Thẻ thấp lại 84→69px.
     Gốc: `.ic1 b` và `.ic1 i` canh `vertical-align:middle` — canh TÂM HỘP, hai
     hộp khác cỡ chữ thì tâm trùng mà chân chữ lệch; `.ic3` là khối riêng.
     VÁ: (1) `.ic3{display:contents}` để tiền lên đúng hàng số hóa đơn, hình
     thức trả xuống hàng tên khách; (2) `align-items:baseline`; (3) cỡ chữ về
     thang 11,5 · 12,5 · 14 · 16 — bỏ 13,5 · 14,5 · 15,5px và độ đậm 650. */
  .ilist.ph .irow{height:auto;min-height:0;display:grid;
    grid-template-columns:10px minmax(0,1fr) auto;
    align-items:baseline;gap:var(--space-1) var(--space-2);
    padding:var(--space-3);background:var(--paper);
    border:1px solid var(--line);border-radius:var(--r)}
  .ilist.ph .irow .idot{grid-column:1;grid-row:1/3;align-self:center;margin-left:0}

  .ilist.ph .ic1{grid-column:2;grid-row:1;
    display:flex;align-items:baseline;gap:var(--space-2);min-width:0}
  .ilist.ph .ic1 b{display:block;font-size:14px;font-weight:700;flex:0 0 auto}
  .ilist.ph .ic1 i{display:block;font-size:12.5px;font-weight:400;margin:0;
    min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  /* `display:contents`: hai con của `.ic3` thành ô lưới; chữ vẫn nằm trong nó
     nên trình đọc màn hình đọc y cũ. */
  .ilist.ph .ic3{display:contents}
  .ilist.ph .ic3 b{grid-column:3;grid-row:1;font-size:16px;font-weight:800;
    text-align:right;white-space:nowrap}

  /* 🔴 b242 · "chữ trong ô sản phẩm vẫn dư chạy ra ngoài". Hóa đơn 6 món tên
     dài: thẻ rộng 364px mà RUỘT 599px (thẻ `<i>` tên hàng 493px chạy tới x=613,
     mép phải thẻ ở 377) ⇒ cuộn ngang, kéo một cái là số hóa đơn và ngày biến
     mất. Anh Đạt chốt: "gần hết chỗ thì để dấu ...". `min-width:0` bắt buộc —
     ô lưới mặc định `min-width:auto`, thiếu nó `overflow:hidden` vô nghĩa. */
  .ilist.ph .ic2{grid-column:2;grid-row:2;text-align:left;
    display:flex;align-items:baseline;gap:var(--space-2);
    min-width:0;white-space:nowrap;overflow:hidden}
  .ilist.ph .ic2 b{display:block;font-size:14px;font-weight:700;flex:0 0 auto}
  .ilist.ph .ic2 i{display:block;font-size:12.5px;font-weight:400;margin:0;
    min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .ilist.ph .ic3 i{grid-column:3;grid-row:2;font-size:11.5px;font-weight:600;
    text-align:right;white-space:nowrap}
  .ilist.ph .irow:last-of-type{border-bottom:1px solid var(--line)}
  .ifoot{border-radius:var(--r);border:1px solid var(--line);margin-top:10px;padding:0 14px}
  .itool{flex-wrap:wrap}
  /* b231+ · 15/09: hàng NGÀY TRÀN 43px trên máy 390px. Ô date có bề rộng nội tại
     150px, mà flex item mặc định là min-width:auto nên `flex:1` KHÔNG co được —
     đo trên Chromium 390x844: ruột 415px nhét trong khung 366px, nút xóa văng
     hẳn ra ngoài và kéo lệch cả trang, nên thẻ hóa đơn bên dưới bị cắt mất chữ
     đầu. Hai triệu chứng, một lỗi.
     Vá: xuống hai hàng — nhãn một hàng, hai ô chia đôi hàng dưới, bỏ dấu gạch
     ngang (hai ô cạnh nhau đã tự nói lên là một khoảng). Ô rộng 155px.
     Chỉ thêm min-width:0 mà giữ một hàng thì ô còn 128,6px — vẫn hết tràn,
     nhưng chữ dd/mm/yyyy ở cỡ 16px bắt buộc sẽ rất sát. */
  .idate{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
    column-gap:var(--space-2);row-gap:var(--space-1);
    width:100%;margin-left:0}
  /* Hàng 1: nhãn NGÀY bên trái, nút bỏ chọn bên phải — nút không còn là cột thứ
     ba của hàng ô, nên không cách nào đẩy ô ngày tràn ra ngoài được nữa.
     Hàng 2: hai ô chia đôi, mỗi ô có nhãn chữ riêng. */
  .ilb{grid-column:1;grid-row:1;align-self:center}
  .ixoa{grid-column:2;grid-row:1;justify-self:end}
  .idash{display:none}
  /* 🔴 b242 · anh Đạt 16/09: "ô ngày quá xấu, k hề có tính chất UI, chữ bị đẩy
     ra ngoài". Lỗi gốc: iPhone vẽ input[type=date] RỖNG là một hộp TRẮNG TRƠN —
     không chữ gợi ý, không dd/mm/yyyy, không gì cả. Hai hộp trắng cạnh nhau
     dưới chữ NGÀY thì không ai đoán được hộp nào là "từ", hộp nào là "đến".
     Vá: mỗi ô thành một trường có nhãn chữ riêng, nhãn nằm TRONG khung cùng ô,
     nên hộp rỗng vẫn tự nói ra nó là gì. */
  .idf{display:grid;grid-row:2;gap:3px;min-width:0;
    border:1px solid var(--line);border-radius:var(--r-sm);
    background:var(--paper);padding:7px 10px 8px}
  .idf:nth-of-type(1){grid-column:1}
  .idf:nth-of-type(2){grid-column:2}
  .idf>span{display:block;font-size:10.5px;font-weight:700;letter-spacing:.06em;
    text-transform:uppercase;color:var(--slate-2);line-height:1}
  .idate input[type=date]{min-width:0;width:100%;font-size:16px;
    border:0;background:none;padding:0;height:22px;line-height:22px}
  /* 🔴 b242 · anh Đạt 16/09: "ô của t thì trống trơn". iPhone vẽ ô ngày RỖNG là
     một hộp trắng không chữ nào (Chromium vẽ sẵn "dd/mm/yyyy", nên ảnh em chụp
     có chữ mà máy anh không). Bấm vào vẫn ra lịch — chỉ là nhìn không biết ô đó
     làm gì. Lớp `trong` do `iNgayGoi()` gắn; `pointer-events:none` để chữ gợi ý
     không nuốt cú chạm, bấm vào đâu trong khung cũng mở lịch như cũ. */
  .idf.trong{position:relative}
  /* Chromium thì NGƯỢC LẠI: nó tự vẽ "mm/dd/yyyy" sẵn, nên nếu chỉ chồng chữ
     của mình lên là hai dòng đè nhau. Giấu phần chữ native lúc ô còn rỗng rồi
     tự vẽ một dòng duy nhất — cách này đúng cho CẢ HAI trình duyệt, không cần
     đoán xem đang chạy trên máy nào. Chỉ giấu khi `.trong`, nên ô đã có ngày
     vẫn hiện ngày như thường. */
  .idf.trong input[type=date]::-webkit-datetime-edit{opacity:0}
  .idf.trong::after{content:'dd/mm/yyyy';position:absolute;left:10px;bottom:8px;
    font-family:var(--f-mono);font-size:16px;line-height:22px;color:var(--slate-2);
    opacity:.7;pointer-events:none}
  .idate input[type=date]:focus{outline:none}
  .idf:focus-within{border-color:var(--sky-600)}
}


/* ── b152: danh sách hóa đơn giãn ra lấp đầy trang ──────────────────────────
   Anh Đạt: "phóng to phần hóa đơn cho fix với trang, giữ 8 hóa đơn là được."

   Trước: mỗi dòng cao cứng 62px, 8 dòng hết ~700px, màn 1080 còn dư một mảng
   trắng to ở dưới. Chữ thì nhỏ mà chỗ thì thừa.

   Nay: DÙNG FLEX CHO NÓ TỰ CHIA, không đoán số pixel. Chuỗi co giãn chạy từ
   .view xuống tận từng dòng, mỗi khâu đều phải có min-height:0 — thiếu một
   chỗ là cả chuỗi đứt, flex item không co nhỏ hơn nội dung được.
     .view  ->  #itbl  ->  .ipanel  ->  .ilist  ->  .irow

   Chặn hai đầu: KHÔNG dưới 62px (màn thấp thì cho cuộn, đừng bóp chữ dính
   nhau) và KHÔNG quá 104px (màn 2K mà mỗi dòng cao bằng bàn tay thì trống
   huếch, đọc còn mệt hơn).

   Vẫn ĐÚNG 8 hóa đơn mỗi trang — IPP không đổi. */
.view:has(.ilist){display:flex;flex-direction:column}
.view:has(.ilist) .itool{flex:0 0 auto}
.view:has(.ilist) #itbl{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}
#itbl .ipanel{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}
#itbl .ipanel .ilist{flex:1 1 auto;min-height:0;overflow:auto}
#itbl .ipanel .ihead,#itbl .ipanel .ifoot{flex:0 0 auto}
#itbl .ipanel .irow{flex:1 1 0;min-height:62px;max-height:104px}
#itbl .pgbar{flex:0 0 auto;margin-top:12px}
/* Dòng cao lên thì chữ cũng nở theo một chút cho cân — nhưng KHÔNG đụng tới
   cỡ chữ chung của app (luật b147/b148: không đổi font, cỡ chữ, kích thước). */
#itbl .ipanel .ic1 b,#itbl .ipanel .ic2 b{font-size:14.5px}
#itbl .ipanel .ic3 b{font-size:15.5px}

@media (max-width:880px){
  /* Điện thoại: thẻ xếp dọc và cuộn bình thường, đừng ép giãn. */
  .view:has(.ilist){display:block}
  #itbl .ilist.ph .irow{flex:0 0 auto;min-height:0;max-height:none}
  /* 🔴 Hai dòng `#itbl .ipanel .icN b` ở trên nới cỡ chữ cho dòng giãn theo
     chiều cao màn — CHỈ đúng trên máy tính. Chúng mang ID nên đặc tả 1,2,1,
     đè cả `.ilist.ph .ic1 b` (0,3,1) của khối điện thoại, nên đo ra 14,5px và
     15,5px trong khi khối kia viết 14px và 16px. Điện thoại không có chuyện
     dòng giãn theo màn, nên trả cỡ chữ về đúng thang nhận diện.
     Bài học lặp lại lần thứ ba trong b242: đặc tả cao hơn thì đứng trước vẫn
     thắng — phải đi tìm kẻ đang thắng, đừng viết thêm một dòng nữa rồi mong. */
  #itbl .ipanel .ic1 b,#itbl .ipanel .ic2 b{font-size:14px}
  #itbl .ipanel .ic3 b{font-size:16px}
}
/* Trạng thái nguồn dữ liệu máy chủ; không thay đổi font hoặc thang chữ của app. */
.rail-ft{display:flex;align-items:center;justify-content:space-between;gap:7px}
.server-mode{display:inline-flex;align-items:center;gap:4px;font-size:8px;font-weight:800;letter-spacing:.06em;border-radius:999px;padding:3px 5px;background:#E8EDF2;color:#52606D}
.server-mode.online{background:#DDF4E7;color:#167348}
.server-mode.offline{background:#FCE4DE;color:#A52C24}
.server-mode.local{background:#EEF0F3;color:#626A75}
/* b240 · CHẤM ĐƯỜNG TRUYỀN — anh Đạt 14/09: "chỉ cần xanh lá, cam, đỏ là được".
   Chấm nói CHẤT LƯỢNG ĐƯỜNG, nền huy hiệu vẫn nói TRẠNG THÁI MÁY CHỦ như cũ —
   hai thứ khác nhau, đừng gộp: máy chủ online mà đường chậm là có thật.
   Màu lấy đúng thang nhận diện: xanh #167348 · cam #B4690E · đỏ #A52C24.
   Không dùng MÌNH màu để báo (người mù màu đỏ–lục không phân biệt được):
   kèm aria-label và title bằng chữ, và chấm đỏ có viền trong cho khác hình. */
.sm-cham{width:6px;height:6px;border-radius:50%;flex:0 0 auto;background:currentColor}
.server-mode.dt-tot .sm-cham{background:#167348}
.server-mode.dt-cham .sm-cham{background:#B4690E}
.server-mode.dt-mat .sm-cham{background:#A52C24;box-shadow:inset 0 0 0 1.5px #FCE4DE}
.server-mode.dt-local .sm-cham{background:#8A94A0}
.sm-ms{font-style:normal;font-weight:600;opacity:.72;letter-spacing:0;font-variant-numeric:tabular-nums}
@media (prefers-reduced-motion:no-preference){.sm-cham{transition:background .2s ease}}

/* Tôn trọng thiết lập giảm chuyển động của hệ điều hành trên toàn app. */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{scroll-behavior:auto!important;animation-duration:.01ms!important;
    animation-iteration-count:1!important;transition-duration:.01ms!important}
}

/* ===== SOURCE: styles/khach-hang.css ===== */
/* ═══════════════════════════════════════════════════════════════════════════
   DẢI KHÁCH HÀNG Ở MÀN BÁN — tách khỏi workflows.css ngày 16/09/2026 (b244)
   ═══════════════════════════════════════════════════════════════════════════
   Tách ra vì hai lẽ, không phải để lách trần dòng:
     · `workflows.css` đã thành cái rổ đựng chung (hóa đơn, công nợ, ngày tháng,
       khách hàng…) — sửa một chỗ phải đọc cả tệp;
     · phần khách hàng vừa đổi luật gốc (b243–b244: SỐ ĐIỆN THOẠI là chìa, TÊN
       chỉ để tìm), sẽ còn được đụng tới, nên cho nó chỗ riêng có tên.
   Nạp NGAY SAU `workflows.css` trong `styles/manifest.json` để giữ nguyên thứ
   tự đè như trước khi tách.

   LUẬT của dải này (b247, anh Đạt chốt 17/09: *"CÓ số thì k trùng"* — đúng luật
   KiotViet):
     · SỐ ĐIỆN THOẠI là chìa nhận diện khách — KHÔNG bắt buộc, nhưng đã điền thì
       không được trùng ai;
     · TÊN chỉ để TÌM, KHÔNG để GÁN. App không bao giờ tự gán khách theo tên;
       gõ tên ra gợi ý, người bán bấm mới gán.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── b151: tự lưu khách khi bán ─────────────────────────────────────────
   Ô tích CHỈ hiện khi nó thật sự sắp làm gì đó — có đủ tên và số mà chưa gán
   khách. Hiện lúc nào cũng thấy thì thành thứ trang trí, người bán nhìn quen
   rồi thôi không đọc nữa. */
.kh-luu{display:flex;align-items:center;gap:8px;margin-top:7px;padding:6px 8px;
  border-radius:var(--r-sm);background:var(--sky-50);cursor:pointer;
  font-size:12px;color:var(--slate);line-height:1.4}
.kh-luu input{width:16px;height:16px;flex:0 0 auto;accent-color:var(--or-6);margin:0}
.kh-luu b{color:var(--ink);font-weight:650}
.kh-luu:hover{background:var(--sky-100)}

.custline .kh-sua{margin-left:auto;width:24px;height:24px;flex:0 0 auto;border:0;background:none;
  border-radius:var(--r-sm);color:var(--slate-2);cursor:pointer;display:grid;place-items:center}
.custline .kh-sua svg{width:13px;height:13px}
.custline .kh-sua:hover{background:var(--sky-100);color:var(--ink)}

/* Tên vừa gõ khác tên trong sổ — mời đổi bằng một cú bấm, KHÔNG tự đổi.
   Gõ tắt "Ba" một lần là ghi đè mất "Anh Ba Thợ Hồ" đã lưu công phu. */
/* b243 · HAI ĐƯỜNG cho cảnh "tên gõ khác tên trong sổ" — trước chỉ có đường đổi
   tên khách cũ, nên gặp khách mới trùng một phần tên là kẹt. Hai nút này ĐỔI DỮ
   LIỆU KHÁCH nên phải bấm có chủ ý: nút thật, đủ `--control-h` trên điện thoại
   và mỗi nút một hàng — hai chữ gạch chân 11,5px dính nhau ở 390px là đúng cảnh
   bấm nhầm, mà bấm nhầm ở đây là đổi tên nhầm một khách. Màu bỏ
   `var(--blue-2,#1C5A8F)`: `--blue-2` là biến CỦA WEB, app không khai, chỉ chạy
   nhờ màu dự phòng (tờ nhận diện mục 1) — dùng `--sky-700`, 12,67:1 trên trắng.
   Nút "người khác" là đường an toàn (không đụng khách cũ) nên cho nổi hơn. */
.kh-doi{margin-top:var(--space-2);font-size:12.5px;color:var(--slate-2);line-height:1.45;
  display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-2)}
.kh-doi b{color:var(--ink);font-weight:700}
.kh-doi button{flex:0 0 auto;min-height:32px;padding:6px 12px;cursor:pointer;
  font:inherit;font-weight:700;border-radius:var(--r-sm);
  border:1px solid var(--line);background:var(--paper);color:var(--sky-700)}
.kh-doi button:hover{border-color:var(--sky-500);background:var(--sky-50)}
/* b244 · DÒNG GỢI Ý khách quen. Tên chỉ để TÌM, không để GÁN (luật KiotViet)
   nên đây là LỜI MỜI, bấm mới gán. Cùng kiểu nút với `.kh-doi`. */
.kh-goi{margin-top:var(--space-2);font-size:12.5px;color:var(--slate-2);
  display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-1) var(--space-2)}
.kh-goi button{flex:0 0 auto;min-height:32px;padding:6px 12px;cursor:pointer;
  font:inherit;font-weight:700;border-radius:var(--r-sm);
  border:1px solid var(--line);background:var(--paper);color:var(--sky-700)}
.kh-goi button:hover{border-color:var(--sky-500);background:var(--sky-50)}
@media (max-width:880px){ .kh-goi button{min-height:var(--control-h)} }
@media (max-width:880px){
  .kh-doi{flex-direction:column;align-items:stretch}
  .kh-doi button{min-height:var(--control-h);width:100%}
}

@media (max-width:880px){ .kh-luu{font-size:13px} .kh-luu input{width:20px;height:20px} }

/* ===== SOURCE: styles/mobile-runtime.css ===== */
/* ═══════════════ b164 — ĐIỆN THOẠI: LỀ AN TOÀN + BÀN PHÍM ═══════════════
   Anh Đạt báo 25/08: "bàn phím của điện thoại ảnh hưởng tầm nhìn app, khi tắt
   bàn phím xuống thì tạm ổn." Anh dùng kiểu ĐÃ THÊM VÀO MÀN HÌNH CHÍNH — không
   còn thanh địa chỉ che, nên cả hai lỗi dưới đây lộ rõ nhất ở kiểu đó.

   HAI nguyên nhân, phải trị đủ cả hai:

   1. LỀ AN TOÀN. index.html bật `viewport-fit=cover` và status bar
      `black-translucent` — tức đã bảo iOS cho nội dung tràn ra tận mép máy.
      Nhưng CSS chưa dùng env(safe-area-inset-*) một lần nào (đếm được 0 trong
      cả cây 81 file), nên thanh 5 nút nằm đè lên vạch home — dải iOS giữ riêng
      cho cử chỉ vuốt, bấm hay không ăn — và đầu trang chui lên dưới đồng hồ.

   2. BÀN PHÍM. Bàn phím iOS làm màn hình NHÌN THẤY co lại, nhưng khung layout
      thì KHÔNG. Nên `height:100vh` và `position:fixed;bottom:0` vẫn tính theo
      cả màn hình: thanh 5 nút, thanh đơn-đang-theo-dõi và dòng thông báo rơi
      ra sau lưng bàn phím, còn vùng cuộn `.view` thì kéo dài xuống dưới bàn
      phím nên ô đang gõ trôi khỏi tầm nhìn.
      ⚠️ `100dvh` KHÔNG chữa được — iOS cố ý loại bàn phím khỏi mọi đơn vị
      viewport. Chỉ `visualViewport` đo được, app.js đặt --vvh và --kb.
      Máy nào không có visualViewport thì hai biến đó vắng mặt và mọi dòng
      dưới đây rơi về đúng giá trị cũ — không hỏng gì.

   ĐỪNG hạ cỡ chữ ô nhập xuống dưới 16px: chuyện iPhone tự phóng to đã trị từ
   b146, khối ở trên. Hai chuyện khác nhau, đừng gộp.
   Bài kiểm bắt buộc trên MÁY THẬT (Sổ lỗi #27): trang "Thước đo iPhone". */

@media (max-width:880px){
  /* ---- 1 · lề an toàn ---- */
  .app{padding-top:env(safe-area-inset-top)}
  .rail{padding-bottom:calc(4px + env(safe-area-inset-bottom))}
  .view{padding-bottom:calc(78px + env(safe-area-inset-bottom))}
  .pos3{padding-bottom:calc(78px + env(safe-area-inset-bottom))}

  /* ---- 2 · bàn phím ---- */
  .app{height:var(--vvh,100dvh)}
  .rail{bottom:var(--kb,0px)}
  .sale-follow{bottom:calc(66px + var(--kb,0px) + env(safe-area-inset-bottom))}
  .toasts{bottom:calc(18px + var(--kb,0px) + env(safe-area-inset-bottom))}
  .sale-follow:not([hidden]) + .toasts{bottom:calc(138px + var(--kb,0px) + env(safe-area-inset-bottom))}

  /* ⚠️ TÊN LỚP: phải là `banphim`, KHÔNG được đặt `kbd`.
     App đã có sẵn `.kbd` từ trước — đó là cái phím giả in chữ F2/F9, và nó
     khai `font-family:var(--f-mono)` cùng viền, nền, padding. Đặt `body.kbd`
     là biến CẢ CÁI APP thành một phím bấm: toàn bộ chữ nhảy sang phông máy
     chữ. Ba bộ kiểm (17/17 · 271/271 · 63/63) và 23 phép đo trong trình duyệt
     đều XANH HẾT khi đang dính lỗi này — chỉ chụp màn hình ra nhìn mới thấy.
     Sổ lỗi #40. Đặt tên lớp mới thì grep xem tên đó có ai dùng chưa.

     Bàn phím lên thì giấu thanh điều hướng: lúc đang gõ không ai bấm nó, mà
     giấu đi thì phần màn hình còn lại dành hết cho kết quả tìm hàng. Bỏ luôn
     78px chừa cho nó, không thì đáy vùng cuộn thừa một mảng trống. */
  body.banphim .rail{display:none}
  body.banphim .view{padding-bottom:12px}
  body.banphim .pos3{padding-bottom:10px}
  body.banphim .sale-follow{bottom:calc(10px + var(--kb,0px))}
  body.banphim .toasts{bottom:calc(10px + var(--kb,0px))}
  body.banphim .sale-follow:not([hidden]) + .toasts{bottom:calc(80px + var(--kb,0px))}
}

/* ═══════════════ b165 — ĐIỆN THOẠI: PHIẾU BÁN HÀNG THÀNH NGĂN KÉO ═══════════════
   Anh Đạt 26/08, sau khi thử b164 trên iPhone thật:
   *"Phần chính là phiếu bán hàng nằm tận dưới đáy, việc theo dõi k tiện vì thêm
   sản phẩm kéo xuống càng dài. Bạn có thể làm 1 nút gọn (như kiểu xem giỏ hàng),
   khi mình chọn sản phẩm thì Số lượng sẽ hiển thị nhỏ bên trên, nhấn vào thì là
   phiếu bán hàng."*

   ⚠️ ĐỌC TRƯỚC KHI SỬA: một nửa việc này ĐÃ CÓ SẴN từ trước — khối
   `@media(max-width:880px){.paybar.on{...}}` ở trên đã là thanh dính đáy có số
   mặt hàng và tổng tiền. Anh Đạt không thấy nó vì `renderPaybar()` giấu thanh
   khi giỏ TRỐNG, mà lúc anh thử thì sổ chưa có mặt hàng nào.
   → b165 KHÔNG dựng lại thanh đó. Chỉ làm hai việc: cho nó luôn hiện trên điện
   thoại, và cho nửa trái bấm được để kéo phiếu lên.

   🔴 VÀ VÁ NỐT MỘT CHỖ b164 BỎ SÓT: b164 kéo `.rail`, `.sale-follow`, `.toasts`
   lên theo bàn phím nhưng QUÊN `.paybar` — nó vẫn đóng đinh `bottom:60px`, nên
   bàn phím lên là thanh tổng tiền nằm sau lưng bàn phím, đúng cái lỗi b164 sinh
   ra để chữa. Đếm sót vì lúc đó giỏ trống nên thanh không hiện, không ai thấy.
   → Bài học: liệt kê MỌI thứ `position:fixed` rồi mới vá, đừng vá thứ đang nhìn thấy. */

@media (max-width:880px){

  /* ---- 1 · vá chỗ b164 bỏ sót ---- */
  .paybar.on{
    bottom:calc(60px + var(--kb,0px) + env(safe-area-inset-bottom));
  }
  body.banphim .paybar.on{ bottom:calc(8px + var(--kb,0px)); }
  /* bàn phím lên thì thanh nút đã giấu, nhưng thanh tổng tiền vẫn còn —
     chừa chỗ cho nó, không thì dòng cuối chui xuống dưới nó */
  body.banphim .pos3{ padding-bottom:70px; }

  /* ---- 2 · nửa trái thanh = nút mở phiếu ---- */
  .paybar .pb-l{
    text-align:left; padding:0; background:none; border:0; color:inherit;
    align-items:flex-start;
  }
  .paybar .pb-n{ display:flex; align-items:center; gap:5px; }
  .paybar .pb-n svg{
    width:13px; height:13px; stroke:currentColor; fill:none; stroke-width:2.2; opacity:.85;
  }
  .paybar.trong .pb-t{ font-size:15px; font-weight:700; opacity:.82; font-family:var(--f-ui); letter-spacing:0; }
  .paybar .pb-nhe{
    background:rgba(255,255,255,.16); border:1px solid rgba(255,255,255,.3);
  }
  .paybar .pb-nhe:active{ background:rgba(255,255,255,.26); }

  /* ---- 3 · phiếu bán hàng thành ngăn kéo ---- */
  .gio-nen{
    position:fixed; inset:0; z-index:75; background:rgba(8,32,52,.44);
    opacity:0; pointer-events:none; transition:opacity .2s ease-out;
  }
  body.gio .gio-nen{ opacity:1; pointer-events:auto; }

  .tape-col{
    position:fixed; left:0; right:0; bottom:0; z-index:80;
    grid-template-rows:auto 1fr;
    /* ⚠️ CHIỀU CAO PHẢI XÁC ĐỊNH. Thử `height:auto; max-height:...` thì hỏng:
       chiều cao không xác định nên `1fr` của lưới bên trong chia theo NỘI DUNG
       chứ không theo khung, rồi khung mới bị kéo tới trần — dư ra 85px trắng
       nằm dưới nút Thanh toán (đo được 26/08: .tape cao 719 mà tổng hàng 639).
       Đặt chiều cao xác định rồi cho cả chuỗi co giãn bằng flex. */
    height:min(92vh, calc(var(--vvh,100dvh) - 44px));
    background:var(--bg);
    border-top:1px solid var(--line);
    border-radius:18px 18px 0 0;
    box-shadow:0 -12px 40px rgba(8,51,79,.30);
    /* Bề ngang phải bằng đúng lúc phiếu nằm trong dòng, không thì ruột phiếu
       (ô Giảm giá, hàng tiền gợi ý, dòng KHÁCH TRẢ) bị cắt mất mép phải.
       Trước: .tape-col padding 0 → tape 390 − viền 4 − .tape-in 32 = 354.
       Nay:   padding 0 4px      → tape 382 − viền 4 − .tape-in 24 = 354. Bằng nhau. */
    padding:0 4px calc(6px + env(safe-area-inset-bottom));
    overflow:hidden; min-height:0;
    transform:translateY(102%);
    transition:transform .22s ease-out;
  }
  body.gio .tape-col{ transform:translateY(0); }
  /* Chuỗi co giãn từ ngăn kéo xuống tới danh sách hàng: mỗi mắt phải min-height:0
     thì con mới co được, không thì phần thừa dồn xuống đáy thành mảng trắng. */
  .tape-col{ display:flex; flex-direction:column; }
  .tape-col .tape{ flex:1 1 0%; min-height:0; display:flex; flex-direction:column; }
  /* Cơ sở phải là 0%, KHÔNG phải auto. Với `flex-basis:auto` trình duyệt lấy
     chiều cao nội dung làm mốc rồi mới chia phần dư — đo 26/08 thì nó không
     chia, để lại đúng 85px trắng dưới nút Thanh toán. `0%` buộc chia theo khung. */
  .tape-col .tape-in{ flex:1 1 0%; min-height:0; display:flex; flex-direction:column; }
  .tape-col .tape-in > .items{ flex:1 1 0%; min-height:0; overflow-y:auto; }
  .tape-col .tape-in > .tape-hd,
  .tape-col .tape-in > .tape-ft{ flex:0 0 auto; }
  /* Hai dải răng cưa trang trí: trong ngăn kéo chúng chỉ làm rối phép chia
     chiều cao. Giấu đi, rồi cho ruột phiếu chiếm trọn khung. */
  .tape-col .zig{ display:none; }
  .tape-col .tape-in{ height:100%; }
  /* 🔴 CHỖ THẬT SỰ GÂY RA 85px TRẮNG: `.tape` có padding-bottom 76px, chừa sẵn
     cho thanh thanh toán hồi nó còn nằm TRONG dòng. Nay phiếu là ngăn kéo và
     thanh thanh toán nằm ngoài, khoảng chừa đó thành mảng trắng dưới nút.
     Mất gần một tiếng đi tìm trong flex/grid, hoá ra chỉ là một dòng padding —
     Sổ lỗi #43: đọc padding và margin TRƯỚC khi nghi ngờ cách chia khung. */
  .tape-col .tape{ padding-bottom:0; }
  .tape-col .tape-in{ padding:0 12px; }

  .gio-top{
    display:flex; align-items:center; gap:10px;
    padding:11px 8px 5px; position:relative; flex:0 0 auto;
  }
  .gio-top strong{ font-size:15.5px; font-weight:800; letter-spacing:-.01em; }
  .gio-keo{
    position:absolute; top:6px; left:50%; transform:translateX(-50%);
    width:42px; height:4px; border-radius:99px; background:var(--line);
  }
  .gio-x{
    margin-left:auto; width:34px; height:34px; border-radius:9px;
    display:grid; place-items:center;
    background:var(--sky-50); border:1px solid var(--line); color:var(--slate);
  }
  .gio-x svg{ width:18px; height:18px; stroke:currentColor; fill:none; stroke-width:2.2; }

  /* ---- 4 · dòng thông báo phải tránh thanh giỏ ----
     .toasts nằm NGOÀI .view nên không có quan hệ anh em với .paybar — chọn
     bằng lớp trên body (app.js đặt trong renderPaybar). Không có khối này thì
     toast "Đã thêm ..." đè thẳng lên tổng tiền. */
  body.cogio .toasts{
    bottom:calc(126px + var(--kb,0px) + env(safe-area-inset-bottom));
  }
  /* Ngăn kéo mở thì đáy màn hình là dòng KHÁCH TRẢ và nút Thanh toán — hai thứ
     KHÔNG được để bất cứ gì đè lên. Đẩy dòng thông báo lên đầu màn hình.
     Ảnh chụp 26/08 cho thấy toast "Đã thêm ..." nằm chồng đúng lên tổng tiền. */
  body.gio .toasts{
    top:calc(env(safe-area-inset-top) + 12px);
    bottom:auto;
  }
  body.cogio.banphim .toasts{ bottom:calc(74px + var(--kb,0px)); }
  body.cogio .sale-follow{
    bottom:calc(126px + var(--kb,0px) + env(safe-area-inset-bottom));
  }
  body.cogio .sale-follow:not([hidden]) + .toasts{
    bottom:calc(200px + var(--kb,0px) + env(safe-area-inset-bottom));
  }
  .toasts .toast{ max-width:min(300px, calc(100vw - 40px)); }

  /* ---- 5 · góc phải thanh nút: huy hiệu + số bản, xếp như một nút ----
     Anh Đạt 26/08: "Phiên bản có thể ghi nhìn chuyên nghiệp hơn k".
     Xếp dọc cho khớp nhịp mấy nút bên cạnh (biểu tượng trên, chữ dưới),
     và nowrap để "Online 1" không bị bẻ làm hai dòng. */
  /* ⚠️ ĐO TRƯỚC KHI SỬA CHỖ NÀY. Thanh dưới là một hàng flex: 5 nút đích +
     ô này. Máy hẹp nhất hay gặp là iPhone SE 375px. Ô này rộng thêm một chút
     là 5 nút đẩy nó tràn khỏi mép phải và huy hiệu bị CẮT — đã xảy ra thật khi
     đặt min-width:64px, và không phép đo nào bắt được, chỉ chụp ảnh mới thấy.
     Tính: 5 × 56 + 70 + 4 = 354 < 375. Còn dư chỗ.
     Nới min-width của .navbtn xuống 56px (vẫn hơn ngưỡng chạm 44px) để nhường. */
  .navbtn{ min-width:56px; }
  .rail-ft{
    flex:0 0 auto; flex-direction:column; align-items:center; justify-content:center;
    gap:2px; padding:5px 6px 4px; min-width:68px; max-width:80px; text-align:center;
    font-size:8.5px; color:rgba(255,255,255,.40); letter-spacing:.06em;
    font-family:var(--f-mono);
  }
  .rail-ft .server-mode{
    font-size:9px; font-weight:800; letter-spacing:.02em; padding:3px 7px;
    white-space:nowrap; max-width:100%;
  }
}

/* ═══ b165 · NGĂN KÉO PHIẾU: ƯU TIÊN DANH SÁCH HÀNG ═══
   Anh Đạt 26/08: *"màn hình phải nhìn được ít nhất 4 sản phẩm"*.
   **(ĐÃ ĐO 26/08, iPhone 390×844)** ngăn kéo cao 709px, chia ra:
   `.gio-top` 58 · `.tape-hd` 116 · **`.items` 124** · **`.tape-ft` 274**.
   Một dòng hàng cao **117px** → chỉ thấy **1 sản phẩm**. Khối thanh toán ăn
   gần hết chỗ, mà lúc đang thêm hàng thì chưa ai cần tới nó.
   → Gấp `.ftgrid` + `.quickcash` lại sau nút "Thuế · giảm giá".
   → Dòng KHÁCH TRẢ và nút Thanh toán KHÔNG bao giờ giấu.
   Ngưỡng nghiệm thu: `thu/kiem-gio.js` đếm số dòng hàng NHÌN THẤY TRỌN VẸN,
   phải **>= 4**. Đừng sửa chỗ này mà không chạy lại phép đếm đó. */
@media (max-width:880px){
  /* ⚠️ Lớp của hàng tiền gợi ý là `.cashsug`, KHÔNG phải `.quickcash`.
     Lần đầu nhắm nhầm `.quickcash` nên nó vẫn chiếm 31px mà không ai thấy —
     chỉ lộ ra khi đo chiều cao từng khối con. Đo, đừng nhắm. */
  body.gio .tape-ft .ftgrid,
  body.gio .tape-ft .cashsug{ display:none; }
  body.gio.chitiet .tape-ft .ftgrid{ display:grid; }
  body.gio.chitiet .tape-ft .cashsug{ display:flex; }

  /* Tiêu đề chồng tiêu đề: `.gio-top` đã ghi "Phiếu bán hàng" rồi thì thanh
     `.tape-bar` bên trong lặp lại y hệt — 36px không nói thêm điều gì. */
  body.gio .tape .tape-bar{ display:none; }
  /* Dòng ngày giờ + đếm mặt hàng: số mặt hàng đã có trên thanh giỏ, ngày giờ
     có trên phiếu in. Trong ngăn kéo thì 16px này chỉ để chiếm chỗ. */
  body.gio .tape-hd .meta{ display:none; }

  /* Ô ghi chú từng dòng hàng cao 28px × mỗi dòng — nhân với 5 dòng là 140px,
     tức mất hơn một sản phẩm rưỡi. Gấp lại, nhưng dòng nào ĐÃ GÕ ghi chú thì
     vẫn hiện (`:has`), để không có chữ nào của anh Đạt bị giấu đi. */
  body.gio .item .ntrow{ display:none; }
  body.gio.chitiet .item .ntrow{ display:flex; }
  body.gio .item:has(.ntrow input:not(:placeholder-shown)) .ntrow{ display:flex; }

  .gio-ct{
    margin-left:auto; display:inline-flex; align-items:center; gap:4px;
    font-size:11.5px; font-weight:700; color:var(--sky-700);
    background:var(--sky-50); border:1px solid var(--line);
    border-radius:99px; padding:5px 10px; white-space:nowrap;
  }
  .gio-ct svg{ width:13px; height:13px; stroke:currentColor; fill:none; stroke-width:2.4;
    transition:transform .18s ease-out; }
  body.chitiet .gio-ct{ background:var(--sky-100); color:var(--sky-800); }
  body.chitiet .gio-ct svg{ transform:rotate(180deg); }
  .gio-top .gio-x{ margin-left:6px; }

  /* Ô Giảm giá và Khách đưa đóng đinh width:124px từ khối b146, cộng nhãn là
     tràn khỏi mép phải phiếu — đo được 26/08: mép phải 392 và 403 trên khung
     rộng 390. Cho chúng co lại theo ô chứa. */
  body.gio .tape-ft .fcell{ min-width:0; }
  /* b275 · width:100% KHÔNG co: ô là flex item `flex:none` nên 100% = trọn ô lưới
     (170px), cộng nhãn "Giảm giá" 57px nữa là thò ra ngoài màn — ĐÃ ĐO 20/09
     ở 390px: ô Giảm giá nằm 267→437, khung 390. Cho ô LẤP PHẦN CÒN LẠI sau nhãn
     thay vì đóng đinh bề rộng. */
  body.gio .tape-ft .fcell input,
  body.gio .tape-ft .fcell select{ width:auto; flex:1 1 40px; min-width:0; }
}

/* ═══════ b166 · 🔴 MÀN BÁN HÀNG TRÊN ĐIỆN THOẠI KHÔNG CUỘN ĐƯỢC ═══════
   Anh Đạt 26/08: *"Gợi ý 12 sản phẩm nhưng lướt xem k được. Giữ lướt thì app
   nhận diện chọn sản phẩm luôn. Cái này quan trọng vì nó sẽ làm việc chọn nhầm
   hàng xảy ra thường xuyên."*

   NGUYÊN NHÂN — có sẵn từ b163, không phải do b164/b165 (đã so ba bản):

     app.css:190  .view.pos{ overflow:hidden }        ← màn Bán hàng khoá cuộn
     app.css:268  .results{ overflow:auto }           ← máy tính: DANH SÁCH tự cuộn
     app.css:849  @media(<=880px){ .results{overflow:visible} }
                                                      ← điện thoại: bỏ luôn cuộn đó

   Máy tính: `.view` khoá nhưng `.results` cuộn → đúng.
   Điện thoại: `.view` khoá, `.results` cũng bỏ cuộn → **KHÔNG CÒN AI CUỘN.**

   Trước đây không ai thấy vì danh mục rỗng, chẳng có gì để cuộn. Nạp 20 mặt
   hàng vào sổ thử là lộ ngay.

   ⚠️ VÌ SAO PHÉP ĐO CỦA CLAUDE BÁO "CUỘN ĐƯỢC": nó kiểm
   `scrollHeight > clientHeight` — **đúng cả khi overflow:hidden**, và
   `element.scrollTop = 120` bằng mã **cũng chạy** trên khung overflow:hidden.
   Hai phép đo đều trả về giá trị hợp lệ mà sai — Sổ lỗi #35, #44.
   Muốn biết có cuộn được bằng NGÓN TAY thì phải đọc `getComputedStyle().overflowY`,
   hoặc vuốt thật rồi đo. */
@media (max-width:880px){
  .view.pos{ overflow-y:auto; -webkit-overflow-scrolling:touch; }
}

/* ═══════════════════════════════════════════════════════════════════════
   b169 · THANH TÌM HÀNG DÍNH LẠI · HUY HIỆU MÁY CHỦ LÊN THANH TIÊU ĐỀ
   Anh Đạt 26/08: "khi cuộn xuống xem hàng là thanh tìm hàng bị trôi luôn.
   Và ô Online + phiên bản để trên cùng bên phải, sát tài khoản đang dùng."
   ═══════════════════════════════════════════════════════════════════════ */
@media (max-width:880px){

  /* ---- 1 · thanh tìm hàng dính lại ----------------------------------
     b166 mở cuộn cho .view.pos để vuốt xem 12 gợi ý (Sổ lỗi #44). Hệ quả
     KHÔNG AI LƯỜNG: cả .pos3 cuộn theo, nên THANH TÌM trôi khỏi màn hình.
     Một bản vá đẻ ra một lỗi mới, và ba tuần sau không ai nối được hai
     chuyện với nhau nếu không ghi ở đây.

     ⚠️ Vì sao phải mở .pos3-main ra trước: nó đang overflow:hidden, mà một
     phần tử overflow khác visible thì TỰ NÓ thành khung cuộn. position:sticky
     dính vào khung cuộn GẦN NHẤT — tức dính vào .pos3-main chứ không phải
     .view.pos. Mà .pos3-main không cuộn, nên sticky nằm im không làm gì cả,
     KHÔNG báo lỗi, KHÔNG hiện ra trong bộ kiểm. Đúng họ Sổ lỗi #44:
     thứ trông như đã bật mà thật ra chưa bao giờ chạy. */
  .pos3-main{ overflow:visible; }

  .scanner{
    position:sticky; top:0;
    z-index:3;                 /* trên .res-head (2), dưới .paybar (55),
                                  thanh dưới (60), ngăn kéo phiếu (80).
                                  Đo thật trong app.css, không đoán. */
    /* .scanner đã có background:var(--paper) từ đầu — sticky mà nền trong
       suốt thì hàng cuộn lên sẽ hiện xuyên qua chữ. Ghi lại đây để ai gỡ
       nền ở trên biết là nó đang gánh thêm việc này. */

    /* DẢI NỀN NỐI THÊM DƯỚI ĐÁY — đo được rồi mới thêm, không phải cho đẹp:
       chụp màn hình lúc cuộn 400px thấy một thẻ hàng trắng thò ra ngay sát
       dưới viền đáy thanh tìm, lộ cả góc bo và viền, trông như thanh tìm bị
       dán thêm một thẻ ma. Bộ kiểm không thấy — nó chỉ đếm toạ độ, mà toạ độ
       thì đúng (Sổ lỗi #40: bộ kiểm đo số, không đo xấu — mở ra nhìn).
       Nguyên do: dính rồi thì hàng cuộn lên chạm ĐÚNG mép đáy thanh tìm,
       không còn khoảng thở như lúc nằm yên.
       Cách chữa: bóng thứ hai, không nhoè, nở 10px và dời xuống 10px — thành
       một dải var(--bg) đặc dài đúng 20px dưới đáy, hàng cuộn chui sau nó.
       Vì sao đúng 20px: đo trong trình duyệt — .pos3-main gap 10px và có một
       div rỗng chen giữa ăn thêm một gap nữa, nên lúc nằm yên đáy thanh tìm
       ở y=151 mà khối hàng bắt đầu ở y=171. Lấy đúng 20 thì lúc nằm yên dải
       này phủ vừa khít khoảng trống sẵn có, KHÔNG che mất mép thẻ đầu tiên.
       Đổi gap thì phải đổi số này — không thì nó ăn vào thẻ.

       ⚠️ LẦN ĐẦU LÀM BẰNG box-shadow LỚP HAI — KHÔNG ĂN, và không báo gì.
       Vì `.scanner:focus-within` (dòng 300) cũng đặt box-shadow, mà nó nặng
       ký hơn (0,2,0 so với 0,1,0) nên đè mất. Ô tìm hàng thì gần như LÚC NÀO
       CŨNG đang được chọn — focusScan() gọi sau mỗi lần thêm/bớt hàng — nên
       lớp bóng mới không bao giờ được vẽ. Đo pixel ra vẫn trắng y như cũ.
       Dùng ::after thì không ai đè được, và cũng không đụng vào bóng sẵn có. */
  }
  .scanner::after{
    /* Nới ra -10px cho bằng ĐÚNG padding hai bên của .pos3 trên màn nhỏ
       (10px), để dải chạm mép màn hình. Để -2px thì cái đuôi bóng mờ của
       thanh tìm còn thò ra hai bên rồi bị cắt ngang, thành hai vệt xám nhỏ.
       Đổi padding .pos3 thì đổi luôn số này. Không nới quá 10 — quá thì
       .view.pos sinh thanh cuộn ngang. */
    content:''; position:absolute; left:-10px; right:-10px;
    top:calc(100% + 1.5px);      /* 100% là đáy hộp ĐỆM, cộng 1.5px cho hết viền */
    height:20px; background:var(--bg); pointer-events:none;
  }

  /* .res-head ("HÀNG BÁN CHẠY 12") cũng sticky top:0. Hai thứ cùng dính ở
     một mốc thì chồng lên nhau — cái z-index thấp hơn chui xuống dưới rồi
     biến mất, trông như lỗi vẽ. Chỉ để ĐÚNG MỘT thứ dính: thanh tìm. */
  .results .res-head{ position:static; }

  /* ---- 2 · huy hiệu máy chủ + số bản lên thanh tiêu đề ---------------
     Rời khỏi chân thanh bên. Thanh dưới nay chỉ còn 5 nút đích. */
  .rail-ft{ display:none; }

  /* Trả .navbtn về bề rộng cũ. Con số 56px đặt ra hồi huy hiệu còn chen
     chỗ ở thanh dưới; nay nó đi rồi thì không phải bóp nữa.
     ĐO LẠI cho máy hẹp nhất hay gặp — iPhone SE 375px:
        5 nút × 68 = 340 < 375.  Còn dư 35px. */
  .navbtn{ min-width:68px; }

  .head-may{
    margin-left:auto;           /* việc đẩy sang phải nay là của khối này */
    display:inline-flex; flex-direction:column; align-items:flex-end;
    gap:2px; line-height:1; flex:0 0 auto;
  }
  .head-ban{
    font-family:var(--f-mono); font-size:10.5px; font-weight:700;
    letter-spacing:.04em; color:var(--slate-2);
  }
  .head-may .server-mode{
    white-space:nowrap;
    /* .server-mode sinh ra cho CHÂN THANH BÊN, cỡ 8px. Trên thanh tiêu đề
       điện thoại thì 8px quá nhỏ — mà 8px cũng KHÔNG nằm trên thang chữ:
       nấc nhỏ nhất của tờ nhận diện là --t0 10.5px. Kéo lên đúng nấc, cho
       bằng .head-ban ngay dưới nó.
       Viết thẳng 10.5px chứ không var(--t0): app.css KHÔNG khai --t0 (đã
       grep 26/08). Dùng biến không khai thì nó im lặng không ăn — đúng cái
       bẫy .ei-r:hover/--sky-1 mà tờ nhận diện ghi. */
    font-size:10.5px; padding:2px 6px;
  }

  /* .mobile-account đang giữ margin-left:auto từ khối trước. Nay .head-may
     làm việc đó, nên nút tài khoản chỉ cần nằm SÁT bên phải huy hiệu —
     đúng chỗ anh Đạt yêu cầu. */
  .mobile-account{ margin-left:6px; }

  /* ---- 2b · giữ huy hiệu + nút tài khoản KHÔNG bị đẩy khỏi màn ----------
     ĐO ĐƯỢC 26/08 trên iPhone SE 375px, màn Hóa đơn:
        #head nội dung 439px / khung 375  →  nút tài khoản hết ở x=439.
     Tức là nó đã NẰM NGOÀI MÀN TỪ TRƯỚC b169, không phải lỗi mới —
     đo lại sau khi bỏ .head-may đi vẫn 439. b169 chỉ làm nó tệ thêm
     (507) và làm nó lộ ra. Ghi rõ để đừng ai đi tìm nhầm ở b169.

     Vì sao: .head là một hàng flex nowrap. Màn Hóa đơn nhét thêm hai nút
     chữ dài — "Xem lợi nhuận" 148px và "Xuất Excel" 127px. Cộng tiêu đề
     70 + huy hiệu 58 + nút tài khoản 40 + 5 khoảng cách là quá 375.
     Nút cuối hàng bị đẩy ra ngoài, mà .head không cuộn ngang nên nó mất hẳn.

     ĐÃ THỬ VÀ BỎ — cho nút co lại bằng `flex:0 1 auto; overflow:hidden;
     text-overflow:ellipsis`. Số đo đẹp (375/375, không nút nào ra ngoài)
     nhưng MỞ RA NHÌN thì chữ bị cắt cụt KHÔNG có dấu ba chấm — hiện ra
     "Xem lợi nh" và "Xuất Exc". Lý do: text-overflow chỉ ăn trên hộp khối,
     .btn là hộp flex nên nó lờ đi. Đúng Sổ lỗi #40: bộ kiểm đo số, không
     đo xấu — chụp ảnh ra nhìn mới thấy.
     Nay chữa ở MÃ chứ không ở CSS: màn hẹp thì rút gọn nhãn (xem
     VIEWS.invoices.head trong app.js). Ở đây chỉ chốt một luật: huy hiệu
     và nút tài khoản KHÔNG BAO GIỜ bị bóp — hai thứ này anh Đạt yêu cầu
     phải nằm trên cùng bên phải. */
  .head{ min-width:0; }
  .head-may, .head .mobile-account{ flex:0 0 auto; }
  /* b275 · số ms trong huy hiệu làm bề rộng thanh tiêu đề ĐỔI THEO ĐƯỜNG TRUYỀN:
     "6ms" 68px, "128ms" ~93px — ĐÃ ĐO 20/09 ở 360px màn Cho thuê: nút tài
     khoản 308→348 khi 6ms, 333→373 khi ms dài (văng ra 13px). Trên điện thoại
     giấu số ms (vẫn còn trong title/aria-label và ở chân thanh bên máy tính). */
  .head-may .sm-ms{ display:none; }
}
