/* ============================================================
   SYS ĐƠN HÀNG — Design System
   Mục tiêu: laptop 1366–1600 là chính, tablet & điện thoại đầy đủ.
   Không phụ thuộc framework CSS nào. Không cần build step.
   ============================================================ */

/* ---------- 1. TOKENS ---------- */
:root {
  /* Nền & mực — neutral lệch xanh lam nhẹ, không phải xám thuần */
  --c-ground:      #F2F5F7;
  /* Khung ứng dụng — menu trái và thanh trên dùng chung một nền, tách hẳn khỏi vùng
     nội dung. Trước đây cả hai đều lấy --c-surface nên khung và thẻ nội dung cùng một
     màu, nhìn vào không biết đâu là khung đâu là nội dung. */
  --c-chrome:      #E8EFF3;
  --c-surface:     #FFFFFF;
  --c-surface-2:   #E9EEF1;
  --c-surface-3:   #DFE6EA;
  --c-ink:         #131A1F;
  --c-ink-2:       #47555F;
  --c-ink-3:       #74848E;
  --c-rule:        #CFD9DE;
  --c-rule-soft:   #E4EAEE;

  /* Nhấn — xanh petrol, đọc tốt trên cả nền sáng và tối */
  --c-accent:      #0B5A69;
  --c-accent-hi:   #0E7185;
  --c-accent-wash: #DEEDF0;
  --c-accent-ink:  #FFFFFF;

  /* Ngữ nghĩa — tách khỏi màu nhấn.

     THANG MÀU TRẠNG THÁI ĐƠN, 9 bậc. Đọc từ trên xuống là đọc đúng đường đi của một đơn:
     ba bậc đầu là đường thuận, năm bậc sau là đường hỏng xếp theo mức mất mát tăng dần.

         info       xanh dương  đang trên đường
         giao       tím         shipper đang mang tới khách — nhịp cuối còn can thiệp được
         ok         xanh lá     đã xong, tiền về
         warn       hổ phách    vướng một nhịp, hàng còn ở ngoài, còn cứu được
         hoan       cam đất     hàng đang quay về
         hoan-xong  xanh petrol hàng hoàn đã về tới kho
         hoan-loi   mận sẫm     hoàn không thành công — mất đơn mà hàng cũng không về
         crit       đỏ          hủy — mất đơn, hàng còn trong kho
         idle       xám         không đọc được nghĩa

     [SỬA 18/08/2026] Ba bậc giao · hoan-xong · hoan-loi thêm theo bảng mã màu chủ dự án gửi.
     Mã màu KHÔNG chép nguyên bảng ấy: bảng đó là một bộ hex duy nhất, mà ở đây màu dùng làm
     MÀU CHỮ trên hai nền — đo lại thì cả 32 ô của bảng trượt tương phản 4,5:1 ở ít nhất một
     nền (ví dụ #EAB308 chỉ đạt 1,92:1 trên nền trắng, #991B1B đạt 2,05:1 trên nền tối). Nên
     mỗi bậc giữ hai mã màu — sáng và tối — cùng nghĩa, khác sắc độ.

     Luật gán màu nằm ở Data/NhanTrangThai.cs và CHỈ ở đó. Xem chú thích của lớp đó về ba
     luật màu chép tay đã bị gỡ ngày 17/08/2026. */
  --c-ok:          #1B6B4E;   --c-ok-wash:   #DFEFE8;
  --c-warn:        #8A5600;   --c-warn-wash: #FAEFD8;
  --c-crit:        #A32029;   --c-crit-wash: #F9E7E8;
  --c-info:        #1F5595;   --c-info-wash: #E3ECF7;
  --c-idle:        #5B6970;   --c-idle-wash: #E8ECEE;

  /* giao — "đang giao tới tay khách". Tím, đúng như bảng chủ dự án gửi (#7C3AED), hạ độ sáng
     cho đủ tương phản trên nền trắng. Đứng riêng chứ không mượn --c-hen dù cùng họ tím: hen
     nghĩa là "khách hẹn dịp khác" ở kết quả gọi, hai trục khác nhau. */
  --c-giao:        #6D28D9;   --c-giao-wash: #EDE6FB;

  /* hoan — bậc "hàng quay về". Đứng riêng chứ không mượn --c-lac dù cùng một mã màu: lac
     nghĩa là "số điện thoại không dùng được" ở kết quả gọi, hai domain không bao giờ xuất
     hiện cùng một widget, và ngày nào cần chỉnh một bên thì bên kia phải đứng yên. */
  --c-hoan:        #A8410A;   --c-hoan-wash: #FAE7DC;

  /* Hai bậc còn lại của họ "hàng quay về".

     hoan-xong — hàng đã về TỚI KHO. Chủ dự án đề nghị petrol #0F766E; giữ đúng sắc nhưng
     kéo về phía lam (#0E6C8C) vì #0F766E cách --c-ok chỉ dE 13,8 ở nền sáng và 11,4 ở nền
     tối, mà hai bậc ấy mang nghĩa NGƯỢC nhau — "giao xong" với "hoàn xong". Ở mức chữ 11px
     trên dòng 39px thì 13 điểm dE là chưa đủ để mắt tách ra.

     hoan-loi — hoàn không thành công, bậc mất mát nặng nhất. Mận sẫm, cố ý tối hơn hẳn
     --c-crit (dE 28,2 ở nền sáng · 25,9 ở nền tối) để không bị đọc nhầm thành "hủy". */
  --c-hoan-xong:   #0E6C8C;   --c-hoan-xong-wash: #DCEDF5;
  --c-hoan-loi:    #6E1230;   --c-hoan-loi-wash:  #F6E1E6;

  /* Hai sắc riêng cho kết quả gọi — xem Data/KetQuaGoi.cs. Đứng ở đây chứ không mượn màu
     hãng vận chuyển: --c-vtp cũng là cam và --c-shop cũng là tím, nhưng chúng mang nghĩa
     "Viettel Post" và "mua tại shop", dùng lẫn thì một ngày nào đó đổi màu hãng là đổi luôn
     màu của "không liên lạc được".
       lac — cam đất: số không dùng được, gọi lại vô ích.
       hen — tím: khách hẹn dịp khác, tức đã nói được chuyện. */
  --c-lac:         #A8410A;   --c-lac-wash:  #FAE7DC;
  --c-hen:         #6A4BA8;   --c-hen-wash:  #EBE7F7;

  /* Hãng vận chuyển — nhận diện bằng màu, quét mắt nhanh */
  --c-jt:          #C8102E;   --c-jt-wash:   #FBE6E9;
  --c-ss:          #12897A;   --c-ss-wash:   #DDF2EF;
  --c-ghtk:        #1F7A3D;   --c-ghtk-wash: #E2F1E7;
  --c-vtp:         #B54708;   --c-vtp-wash:  #FBECE0;
  --c-shop:        #5B4B9E;   --c-shop-wash: #EAE7F6;

  /* Tiền ship — MỘT màu riêng, không mượn --c-warn.
     Chủ dự án chốt 18/08/2026: phí ship phải nhận ra được bằng màu ở mọi màn hình. Mượn
     --c-warn thì con số ship trông như một cảnh báo, mà nó chỉ là một khoản chi bình thường;
     mượn --c-vtp thì nó mang màu của ViettelPost. Vàng cam riêng, nghĩa riêng. */
  --c-ship:        #A8560A;   --c-ship-wash: #FAEEDD;

  /* Nhà mạng di động. Màu THƯƠNG HIỆU nằm ở chấm tròn (xem .nm__cham) — đó là chỗ duy nhất
     dùng được đúng mã màu của hãng, vì chấm là một khối đặc, không phải chữ.

     Hai biến dưới đây là màu CHỮ và màu NỀN của nhãn: cùng tông với thương hiệu nhưng đã
     chỉnh độ đậm cho đọc được. Lấy thẳng mã logo làm màu chữ thì hỏng ngay — đỏ Viettel
     #EE0033 trên nền trắng chỉ đạt 4,0:1, còn trên nền phấn hồng của chính nhãn thì tụt
     xuống khoảng 3:1, mà đây là chữ 10px. */
  --c-nm-viettel:  #B3001B;   --c-nm-viettel-wash: #FBE7E9;
  --c-nm-mobi:     #0A5CA8;   --c-nm-mobi-wash:    #E4EDF8;
  --c-nm-vina:     #06718F;   --c-nm-vina-wash:    #E0F1F6;
  --c-nm-vnm:      #A65214;   --c-nm-vnm-wash:     #FAEBE0;
  --c-nm-itel:     #B23C10;   --c-nm-itel-wash:    #FBEAE2;
  --c-nm-wintel:   #A81028;   --c-nm-wintel-wash:  #FBE7EA;
  --c-nm-gmobile:  #4A7A0F;   --c-nm-gmobile-wash: #EEF5E2;

  /* Chữ */
  --f-sans: system-ui, "Segoe UI", "Segoe UI Variable Text", Roboto, "Helvetica Neue", Arial, sans-serif;
  --f-mono: ui-monospace, "Cascadia Mono", Consolas, "SF Mono", "Liberation Mono", monospace;

  /* Nhịp — thay đổi theo mật độ, xem §2 */
  --row-h:      38px;
  --row-py:     6px;
  --fs-table:   13px;
  --fs-base:    14px;
  --cell-px:    10px;
  --thumb:      34px;

  --radius:     4px;
  --radius-sm:  3px;

  --shadow-1: 0 1px 2px rgba(19,26,31,.07), 0 1px 1px rgba(19,26,31,.04);
  --shadow-2: 0 4px 12px rgba(19,26,31,.10), 0 1px 3px rgba(19,26,31,.06);
  --shadow-3: 0 12px 32px rgba(19,26,31,.16), 0 2px 8px rgba(19,26,31,.08);

  /* 178px — hẹp lại 46px so với 224px trước đây (16/08/2026). 224px vốn nới ra chỉ để chứa
     cho hết cái tên dài "QUẢN LÝ ĐƠN HÀNG"; tên rút thành "QUẢN LÝ ĐƠN" thì trả lại được.

     Đo thẳng trên trình duyệt bằng Range, không ước lượng. Thứ quyết định con số này là
     DÒNG TÊN: "QUẢN LÝ ĐƠN" cần 84,9px. Chữ bắt đầu bị cắt ở dưới 170px, tức 178px còn
     thừa 8px cho khác biệt dựng chữ giữa các máy.

     Ngưỡng 170px ấy có được là nhờ siết khoảng cách giữa khối logo và nút thu gọn xuống 4px
     (xem .rail__brand). Không siết thì chữ cắt ngay từ dưới 176px, và 178px chẳng còn một
     pixel dư nào — vừa khít trên máy này, so le trên máy khác.

     Dòng phụ KHÔNG phải chỗ chật: nó viết hoa cỡ 7px và được căn đều cho rộng đúng bằng
     dòng tên (xem .rail__name small), nên tự khớp chứ không đòi thêm chỗ. Trước đây nó là
     dòng rộng nhất và chính nó giữ cột menu ở 224px.

     Muốn hẹp thêm nữa thì phải rút DÒNG TÊN, đừng hạ số này xuống dưới 170.

     Mục menu không phải chỗ chật: nhãn dài nhất ("Hủy & trả hàng") vẫn nằm gọn một dòng
     tới tận 164px. */
  --rail-w: 178px;
  --topbar-h: 52px;

  color-scheme: light;
}

/* Chế độ tối — theo hệ điều hành, trừ khi người dùng chọn Sáng */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --c-ground:      #0D1317;
    --c-chrome:      #121B21;
    --c-surface:     #141D23;
    --c-surface-2:   #1B262D;
    --c-surface-3:   #243139;
    --c-ink:         #E4EBEF;
    --c-ink-2:       #AEBDC6;
    --c-ink-3:       #7A8B95;
    --c-rule:        #2A3841;
    --c-rule-soft:   #202C34;

    --c-accent:      #4FB0C4;
    --c-accent-hi:   #6AC5D8;
    --c-accent-wash: #143038;
    --c-accent-ink:  #06222A;

    --c-ok:          #63C09A;   --c-ok-wash:   #122E24;
    --c-warn:        #DCAE5C;   --c-warn-wash: #2F2510;
    --c-crit:        #EE8790;   --c-crit-wash: #351C20;
    --c-info:        #7FB0E8;   --c-info-wash: #16263A;
    --c-idle:        #8B99A1;   --c-idle-wash: #1E282E;
    --c-hoan:        #E2793F;   --c-hoan-wash: #331D0E;
    --c-giao:        #B57AF0;   --c-giao-wash: #241A38;
    --c-hoan-xong:   #4FB6CE;   --c-hoan-xong-wash: #0E2833;
    --c-hoan-loi:    #B9799E;   --c-hoan-loi-wash:  #331A24;

    --c-lac:         #E2793F;   --c-lac-wash:  #331D0E;
    --c-hen:         #B49BE8;   --c-hen-wash:  #241C36;

    --c-jt:          #F0808F;   --c-jt-wash:   #331A1E;
    --c-ss:          #58C3B4;   --c-ss-wash:   #10302C;
    --c-ghtk:        #6DBE85;   --c-ghtk-wash: #162E1D;
    --c-vtp:         #E39A62;   --c-vtp-wash:  #33220F;
    --c-shop:        #A395DE;   --c-shop-wash: #221E38;
    --c-ship:        #E5A85F;   --c-ship-wash: #33260F;

    --c-nm-viettel:  #F08A93;   --c-nm-viettel-wash: #331A1E;
    --c-nm-mobi:     #7FB4EA;   --c-nm-mobi-wash:    #13233A;
    --c-nm-vina:     #62C3DE;   --c-nm-vina-wash:    #102A33;
    --c-nm-vnm:      #E5A472;   --c-nm-vnm-wash:     #33230F;
    --c-nm-itel:     #EE9A72;   --c-nm-itel-wash:    #33200F;
    --c-nm-wintel:   #EE8896;   --c-nm-wintel-wash:  #331A1F;
    --c-nm-gmobile:  #A8CE6A;   --c-nm-gmobile-wash: #202C10;

    --shadow-1: 0 1px 2px rgba(0,0,0,.4);
    --shadow-2: 0 4px 12px rgba(0,0,0,.45);
    --shadow-3: 0 12px 32px rgba(0,0,0,.55);

    color-scheme: dark;
  }
}
/* Người dùng chọn Tối — thắng cả khi hệ điều hành đang Sáng */
:root[data-theme="dark"] {
  --c-ground:      #0D1317;
  --c-chrome:      #121B21;
  --c-surface:     #141D23;
  --c-surface-2:   #1B262D;
  --c-surface-3:   #243139;
  --c-ink:         #E4EBEF;
  --c-ink-2:       #AEBDC6;
  --c-ink-3:       #7A8B95;
  --c-rule:        #2A3841;
  --c-rule-soft:   #202C34;

  --c-accent:      #4FB0C4;
  --c-accent-hi:   #6AC5D8;
  --c-accent-wash: #143038;
  --c-accent-ink:  #06222A;

  --c-ok:          #63C09A;   --c-ok-wash:   #122E24;
  --c-warn:        #DCAE5C;   --c-warn-wash: #2F2510;
  --c-crit:        #EE8790;   --c-crit-wash: #351C20;
  --c-info:        #7FB0E8;   --c-info-wash: #16263A;
  --c-idle:        #8B99A1;   --c-idle-wash: #1E282E;
  --c-hoan:        #E2793F;   --c-hoan-wash: #331D0E;
  --c-giao:        #B57AF0;   --c-giao-wash: #241A38;
  --c-hoan-xong:   #4FB6CE;   --c-hoan-xong-wash: #0E2833;
  --c-hoan-loi:    #B9799E;   --c-hoan-loi-wash:  #331A24;

  --c-lac:         #E2793F;   --c-lac-wash:  #331D0E;
  --c-hen:         #B49BE8;   --c-hen-wash:  #241C36;

  --c-jt:          #F0808F;   --c-jt-wash:   #331A1E;
  --c-ss:          #58C3B4;   --c-ss-wash:   #10302C;
  --c-ghtk:        #6DBE85;   --c-ghtk-wash: #162E1D;
  --c-vtp:         #E39A62;   --c-vtp-wash:  #33220F;
  --c-shop:        #A395DE;   --c-shop-wash: #221E38;
  --c-ship:        #E5A85F;   --c-ship-wash: #33260F;

    --c-nm-viettel:  #F08A93;   --c-nm-viettel-wash: #331A1E;
    --c-nm-mobi:     #7FB4EA;   --c-nm-mobi-wash:    #13233A;
    --c-nm-vina:     #62C3DE;   --c-nm-vina-wash:    #102A33;
    --c-nm-vnm:      #E5A472;   --c-nm-vnm-wash:     #33230F;
    --c-nm-itel:     #EE9A72;   --c-nm-itel-wash:    #33200F;
    --c-nm-wintel:   #EE8896;   --c-nm-wintel-wash:  #331A1F;
    --c-nm-gmobile:  #A8CE6A;   --c-nm-gmobile-wash: #202C10;

  --shadow-1: 0 1px 2px rgba(0,0,0,.4);
  --shadow-2: 0 4px 12px rgba(0,0,0,.45);
  --shadow-3: 0 12px 32px rgba(0,0,0,.55);

  color-scheme: dark;
}

/* ---------- 2. MẬT ĐỘ (người dùng tự đổi, lưu theo tài khoản) ---------- */
:root[data-density="thoang"] {
  --row-h:    54px;
  --row-py:   11px;
  --fs-table: 14px;
  --fs-base:  15px;
  --cell-px:  14px;
  --thumb:    44px;
}

/* Trên tablet/điện thoại luôn nới ra cho đủ vùng chạm, bất kể cài đặt */
@media (pointer: coarse) {
  :root, :root[data-density="day"] {
    --row-h:  48px;
    --row-py: 10px;
    --cell-px: 12px;
  }
}

/* ---------- 3. RESET ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

/* Thuộc tính `hidden` phải thắng mọi `display` của thư viện lớp ở dưới.
   Trình duyệt cài `[hidden] { display: none }` ở mức UA — mức đó thua BẤT KỲ luật nào của
   mình, nên `.field { display: flex }` là đủ để một phần tử `hidden` vẫn hiện ra. Đã dính
   thật ở ô "khu vực hủy vì phí ship" của /telesale: JS đặt hidden, thuộc tính có trong DOM,
   mà ô vẫn nằm chình ình trên màn hình. Đặt ở đây một lần cho mọi chỗ. */
[hidden] { display: none !important; }
body {
  margin: 0;
  background: var(--c-ground);
  color: var(--c-ink);
  font-family: var(--f-sans);
  font-size: var(--fs-base);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4 { margin: 0; font-weight: 620; line-height: 1.25; letter-spacing: -.01em; text-wrap: balance; }
p { margin: 0 0 .7em; }
a { color: var(--c-accent); text-decoration: none; }
a:hover { text-decoration: underline; }
img { max-width: 100%; display: block; }
:focus-visible { outline: 2px solid var(--c-accent-hi); outline-offset: 1px; border-radius: 2px; }
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; } }

/* ---------- 4. KHUNG ỨNG DỤNG ---------- */
/* grid-template-rows PHẢI khai báo: menu trái dùng "grid-row: 1 / -1" để trải hết
   chiều cao, mà -1 chỉ trỏ đúng khi lưới hàng được định nghĩa tường minh.
   Thiếu dòng này thì -1 quy về hàng 1, menu cao 100vh chiếm trọn hàng đầu
   và đẩy toàn bộ nội dung xuống dưới một màn hình. */
.app {
  display: grid; min-height: 100vh;
  grid-template-columns: var(--rail-w) minmax(0, 1fr);
  grid-template-rows: auto 1fr;
}

/* Lớp phủ chỉ dùng khi menu trượt ra trên màn hình hẹp.
   Phải ẩn hẳn ở màn hình rộng, nếu không nó chiếm một ô lưới và đẩy nội dung xuống. */
.rail-scrim { display: none; }

/* --- thanh điều hướng trái --- */
.rail {
  grid-row: 1 / -1;
  background: var(--c-chrome);
  border-right: 1px solid var(--c-rule);
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
  z-index: 40;
}
/* Lề trái 14px để chữ SĐ đứng gần thẳng hàng với dãy biểu tượng của menu bên dưới
   (chúng bắt đầu ở 17px: .rail__nav 8px + .nav-item 9px).

   gap 4px — khoảng cách TỐI THIỂU giữa khối logo và nút thu gọn, không phải khoảng cách
   nhìn thấy: .rail__thu có margin-left:auto nên mọi chỗ thừa của hàng đều dồn vào đây, ở
   178px mắt thấy 7px. Con số 4 chỉ có tác dụng lúc hàng chật — và chính nó hạ ngưỡng cắt
   chữ từ 176px xuống 170px, tức đổi được 6px bề rộng cho cả ứng dụng mà không ai thấy
   khác gì. Xem phần đo ở --rail-w. */
.rail__brand {
  display: flex; align-items: center; gap: 4px;
  padding: 0 6px 0 14px; height: var(--topbar-h); flex: none;
  border-bottom: 1px solid var(--c-rule-soft);
}
.rail__thu { margin-left: auto; flex: none; }

/* --- thu gọn menu trái (nhớ theo tài khoản) ---
   Chỉ thu cột đầu về 0 và trượt menu ra ngoài. KHÔNG đổi grid-column của thanh trên
   và vùng nội dung: menu vẫn chiếm ô hàng-1-cột-1, nên nếu cho chúng trải "1 / -1"
   thì thuật toán xếp lưới không đặt được vào hàng 1 và đẩy tuột xuống hàng 3
   — cả trang trông như trắng trơn. */
@media (min-width: 1101px) {
  :root[data-menu="an"] .app { grid-template-columns: 0 minmax(0, 1fr); }
  :root[data-menu="an"] .rail {
    width: var(--rail-w); transform: translateX(-100%);
    visibility: hidden;
  }
  .rail { transition: transform .18s ease; }
  .rail-toggle { display: grid; }      /* luôn hiện để bật lại được */
}
.rail__mark {
  width: 26px; height: 26px; flex: none; border-radius: var(--radius-sm);
  background: var(--c-accent); color: var(--c-accent-ink);
  display: grid; place-items: center;
  font-family: var(--f-mono); font-size: 12px; font-weight: 700; letter-spacing: -.04em;
}
/* Khối tên: KHÔNG được xuống dòng, và hai dòng cách nhau thoáng.
   Cỡ chữ hạ xuống 12.5px (dòng đầu) và 10px (dòng phụ) để khối tên vừa chỗ trống của cột
   menu — xem phần đo ở --rail-w. nowrap + ellipsis giữ cho mọi tên sau này cũng không vỡ
   dòng: đổi tên dài hơn thì nó bị cắt bằng dấu ba chấm, chứ không đẩy cao thanh trên.
   Khoảng cách hai dòng nới bằng margin-top thay vì line-height — line-height nới thì chữ hoa
   của dòng phụ trông như rơi khỏi khối. */
.rail__name { font-size: 12.5px; font-weight: 650; letter-spacing: -.01em; line-height: 1.15; min-width: 0; }
.rail__name, .rail__name small { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Dòng phụ VIẾT HOA, cỡ nhỏ, và <b>rộng đúng bằng dòng tên</b> — hai dòng khép thành một
   khối chữ nhật, mép phải thẳng hàng với chữ "ĐƠN" ở trên.

   Bằng nhau bằng `text-align-last: justify` chứ không phải bằng cách dò cỡ chữ cho vừa.
   Lý do: dò cỡ chữ thì chỉ đúng trên đúng một máy — phông chữ dựng lệch vài phần trăm ở
   máy khác là hai mép lại so le, mà không ai nhận ra. Căn đều thì kéo giãn khoảng cách chữ
   cho vừa ĐÚNG bề rộng khối, nên bằng nhau ở mọi máy, mọi cỡ phông.

   Cách này chỉ chạy khi bề rộng tự nhiên của dòng phụ NHỎ HƠN dòng tên — có chỗ trống thì
   mới giãn ra được. 7px viết hoa cần 79,6px so với 84,9px của dòng tên, tức thừa 6,6% cho
   khác biệt dựng chữ giữa các máy. Vì thế đừng nâng cỡ chữ này lên 7,5px: ở đó dòng phụ
   cần 85,3px, vượt dòng tên, căn đều mất tác dụng và chính nó quay lại quyết định bề rộng
   cả cột menu (xem --rail-w).

   `white-space: nowrap` thừa hưởng từ .rail__name không cản: căn đều dòng cuối vẫn giãn
   được các khoảng trắng, đã đo trên Chrome. */
.rail__name small {
  display: block; margin-top: 4px;
  font-size: 7px; font-weight: 500; color: var(--c-ink-3);
  text-transform: uppercase; letter-spacing: 0;
  text-align: justify; text-align-last: justify;
}

.rail__nav { padding: 10px 8px; flex: 1; display: flex; flex-direction: column; gap: 1px; }
.rail__group {
  font-family: var(--f-mono); font-size: 9.5px; letter-spacing: .13em; text-transform: uppercase;
  color: var(--c-ink-3); padding: 14px 8px 5px;
}
.rail__group:first-child { padding-top: 2px; }
.nav-item {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 9px; border-radius: var(--radius);
  color: var(--c-ink-2); font-size: 13px; font-weight: 500;
  transition: background .12s, color .12s;
  min-height: 34px;
}
.nav-item:hover { background: var(--c-surface-2); color: var(--c-ink); text-decoration: none; }
.nav-item[aria-current="page"] { background: var(--c-accent-wash); color: var(--c-accent); font-weight: 620; }
.nav-item svg { width: 16px; height: 16px; flex: none; stroke-width: 1.7; }
.nav-item .badge { margin-left: auto; }

.rail__foot { padding: 8px 8px 10px; border-top: 1px solid var(--c-rule-soft); flex: none; }

/* Tuỳ chọn hiển thị (mật độ, sáng/tối) đứng ở HAI chỗ, và mỗi khổ màn hình chỉ hiện một:
   thanh trên khi rộng, menu trái khi hẹp. Ở khổ điện thoại thanh trên phải để dành cho việc
   của trang — thêm hai biểu tượng tuỳ chọn vào đó là đủ để mọi thứ chèn lên nhau. */
.rail__tuychon { display: none; }
@media (max-width: 620px) {
  /* `.topbar .topbar__tuychon` chứ không phải `.topbar__tuychon`: một lớp đơn có cùng độ ưu
     tiên với `.btn`, mà `.btn { display: inline-flex }` nằm SAU trong file nên nó thắng —
     câu lệnh ẩn thành vô hiệu, hai nút vẫn hiện nguyên trên thanh trên ở khổ điện thoại.
     Media query không cộng thêm độ ưu tiên, nên phải tự nâng bằng bộ chọn. */
  .topbar .topbar__tuychon { display: none; }
  .rail__tuychon { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-top: 10px; }
}

/* Liên kết "Đổi mật khẩu" dưới tên tài khoản. Cố ý là CHỮ chứ không phải biểu tượng:
   đây là đường vào duy nhất tới /doi-mat-khau, và một biểu tượng nữa cạnh nút đăng
   xuất thì người dùng vẫn phải đoán. */
.rail__doimk { display: inline-block; margin-top: 2px; color: var(--c-ink-3); }
.rail__doimk:hover, .rail__doimk.is-on { color: var(--c-accent); }

/* --- thanh trên --- */
.topbar {
  grid-column: 2; position: sticky; top: 0; z-index: 30;
  height: var(--topbar-h); flex: none;
  /* Cùng nền với menu trái: hai thứ này là KHUNG của ứng dụng, phải đọc như một mảnh
     liền chứ không phải hai tấm thẻ rời. */
  background: color-mix(in srgb, var(--c-chrome) 92%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--c-rule);
  display: flex; align-items: center; gap: 10px; padding: 0 14px;
}
/* Thanh trên PHẢI co lại được. Để mặc định min-width:auto thì bề rộng tối thiểu của nó
   bằng tổng các nút + tiêu đề + tab; ở điện thoại con số đó lớn hơn màn hình nên nó kéo
   rộng cả CỘT LƯỚI, kéo luôn vùng nội dung — cả trang cuộn ngang dù bảng bên trong đã
   có khung cuộn riêng. Chỉ nới cho các khối <div> co, giữ nguyên các nút. */
.topbar { min-width: 0; }
.topbar > div { min-width: 0; }

/* Khổ hẹp thì thu lề và khoảng cách: các nút đã ghim flex:none nên chúng không co, thừa ra
   bao nhiêu là lấn vào lề bấy nhiêu.

   Khối này phải đứng SAU luật .topbar cơ sở ở trên. Đặt nó cạnh .rail__tuychon (trước đó
   khoảng 20 dòng) thì nó thua, vì cùng độ ưu tiên mà luật cơ sở đứng sau — media query
   KHÔNG cộng thêm độ ưu tiên. Đúng cái bẫy đã làm câu lệnh ẩn .topbar__tuychon thành vô
   hiệu; ở đây nó lặp lại lần thứ hai trong cùng một khối. */
@media (max-width: 620px) {
  .topbar { padding: 0 8px; gap: 8px; }
}

/* Nút trên thanh KHÔNG được co. Mặc định flex-shrink là 1, mà nội dung bên trong đã
   white-space:nowrap — nên khi hết chỗ, hộp nút teo lại còn chữ và biểu tượng thì không,
   và chúng tràn ra đè lên nút bên cạnh. Đúng lỗi "các icon chồng chéo nhau" ở khổ điện
   thoại: không phải thiếu chỗ một cách vô hại, mà là các nút chèn lên nhau. */
.topbar > *, .topbar .btn, .topbar .select, .topbar .row > * { flex: none; }
/* Chỉ khối tiêu đề được co, và nó co tới 0 cũng không sao vì đã cắt bằng dấu … */
.topbar > div:not(.topbar__spacer):not(.row) { flex: 0 1 auto; }
.topbar__title { font-size: 15px; font-weight: 650; letter-spacing: -.015em; }
.topbar__sub { font-size: 11.5px; color: var(--c-ink-3); font-family: var(--f-mono); }
.topbar__title, .topbar__sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar .tabs { overflow-x: auto; scrollbar-width: none; }
.topbar .tabs::-webkit-scrollbar { display: none; }
.topbar__spacer { flex: 1; }
.rail-toggle { display: none; }

/* --- vùng nội dung --- */
.content { grid-column: 2; padding: 14px; min-width: 0; }
@media (min-width: 1400px) { .content { padding: 18px 20px; } }

/* --- responsive: tablet & điện thoại --- */
@media (max-width: 1100px) {
  .app { grid-template-columns: 1fr; }
  .rail {
    position: fixed; inset: 0 auto 0 0; width: 262px;
    transform: translateX(-100%); transition: transform .2s ease;
    box-shadow: var(--shadow-3);
  }
  .app[data-rail="open"] .rail { transform: none; }
  .topbar, .content { grid-column: 1; }
  .rail-toggle { display: grid; }
  .rail-scrim {
    display: block;
    position: fixed; inset: 0; background: rgba(9,14,17,.42);
    opacity: 0; pointer-events: none; transition: opacity .2s;
  }
  /* Thứ tự lớp trên điện thoại: MENU TRÁI trên cùng, rồi lớp phủ, dưới nữa mới là
     tấm chi tiết (z-index 60). Người dùng mở menu là đang muốn rời khỏi đơn đang xem,
     nên tấm chi tiết không được đè lên menu. */
  .rail { z-index: 80; }
  .rail-scrim { z-index: 70; }
  .app[data-rail="open"] .rail-scrim { opacity: 1; pointer-events: auto; }
}
@media (max-width: 620px) { .content { padding: 10px; } }

/* ---------- 5. NÚT ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 32px; padding: 0 12px;
  border: 1px solid var(--c-rule); border-radius: var(--radius);
  background: var(--c-surface); color: var(--c-ink);
  font: inherit; font-size: 13px; font-weight: 550; line-height: 1;
  cursor: pointer; white-space: nowrap;
  transition: background .12s, border-color .12s, color .12s;
}
.btn:hover { background: var(--c-surface-2); border-color: var(--c-ink-3); text-decoration: none; }
.btn:active { transform: translateY(.5px); }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .45; cursor: not-allowed; pointer-events: none; }
.btn svg { width: 15px; height: 15px; stroke-width: 1.8; flex: none; }

.btn--primary { background: var(--c-accent); border-color: var(--c-accent); color: var(--c-accent-ink); }
.btn--primary:hover { background: var(--c-accent-hi); border-color: var(--c-accent-hi); }
.btn--danger { color: var(--c-crit); border-color: color-mix(in srgb, var(--c-crit) 35%, var(--c-rule)); }
.btn--danger:hover { background: var(--c-crit-wash); border-color: var(--c-crit); }
.btn--ghost { border-color: transparent; background: transparent; color: var(--c-ink-2); }
.btn--ghost:hover { background: var(--c-surface-2); color: var(--c-ink); }
.btn--sm { min-height: 26px; padding: 0 8px; font-size: 12px; }
/* Nút của một việc CHÍNH: cao hơn và đậm hơn nút thường. Bề rộng do khung ngoài quyết định
   (xem .row--2), vì hai nút đứng ngang hàng phải bằng nhau bất kể chữ dài ngắn. */
.btn--manh { min-height: 40px; padding: 0 14px; font-size: 14px; font-weight: 650; }
/* Nút đặc màu cảnh báo. Khác .btn--danger (viền đỏ, nền trong) — cái này để dành cho việc
   cần đập vào mắt chứ không phải việc nguy hiểm. */
/* Nút đặc màu xanh ngọc. Nền là màu CỐ ĐỊNH nên chữ cũng phải cố định — để var(--c-ink)
   thì ở chế độ nền tối chữ thành gần trắng nằm trên nền xanh nhạt, không đọc nổi. */
.btn--ngoc { background: #6AC5D8; border-color: #6AC5D8; color: #06222A; }
.btn--ngoc:hover { background: #55B6CB; border-color: #55B6CB; color: #06222A; }
.btn--icon { padding: 0; width: 32px; min-height: 32px; }
.btn--icon.btn--sm { width: 26px; min-height: 26px; }
@media (pointer: coarse) {
  .btn { min-height: 40px; padding: 0 14px; }
  .btn--icon { width: 40px; }
  .btn--sm { min-height: 34px; }
  .btn--icon.btn--sm { width: 34px; }
}

/* ---------- 6. Ô NHẬP ---------- */
.field { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.field__label {
  font-size: 10.5px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--c-ink-3);
}
.input, .select, .textarea {
  width: 100%; min-height: 32px; padding: 5px 9px;
  border: 1px solid var(--c-rule); border-radius: var(--radius);
  background: var(--c-surface); color: var(--c-ink);
  font: inherit; font-size: 13px;
  transition: border-color .12s, box-shadow .12s;
}
.input:hover, .select:hover, .textarea:hover { border-color: var(--c-ink-3); }
.input:focus, .select:focus, .textarea:focus {
  outline: none; border-color: var(--c-accent);
  box-shadow: 0 0 0 3px var(--c-accent-wash);
}
.input::placeholder, .textarea::placeholder { color: var(--c-ink-3); opacity: .8; }

/* Ô tìm có nút kính lúp nằm trong. Nút phải là <button type=submit> thật, không phải một cái
   icon gắn sự kiện: bàn phím ảo trên điện thoại thường không có Enter, mà form vẫn phải gửi
   được kể cả khi JavaScript hỏng.

   Vùng bấm 34px — ngón cái cần chừng đó; icon bên trong nhỏ hơn nhiều nhưng vùng bấm mới là
   thứ người ta chạm. Ô nhập chừa chỗ bằng padding-right nên chữ không chui xuống dưới nút. */
.o-tim { position: relative; display: block; }
.o-tim .input { padding-right: 36px; }
/* Nút xoá sẵn có của type=search bị ẩn: nó đứng đúng chỗ nút tìm và hai cái chồng lên nhau. */
.o-tim .input::-webkit-search-cancel-button { display: none; }
.o-tim__nut {
  position: absolute; top: 0; right: 0; width: 34px; height: 100%;
  display: grid; place-items: center;
  border: 0; background: none; padding: 0; cursor: pointer;
  color: var(--c-ink-3); border-radius: 0 var(--radius) var(--radius) 0;
}
.o-tim__nut svg { width: 16px; height: 16px; }
.o-tim__nut:hover { color: var(--c-accent); }
.o-tim__nut:focus-visible { outline: 2px solid var(--c-accent-hi); outline-offset: -2px; }
.textarea { min-height: 54px; resize: vertical; line-height: 1.45; }
.select {
  appearance: none; padding-right: 26px; cursor: pointer;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2374848E' stroke-width='2' stroke-linecap='round'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat: no-repeat; background-position: right 6px center;
}
.input--mono { font-family: var(--f-mono); font-variant-numeric: tabular-nums; }

/* --- ô chọn có tìm kiếm (bọc quanh <select data-timkiem>, dựng bởi app.js) ---
   Thẻ <select> thật nằm chồng ngay dưới ô nhập, trong suốt và không nhận chuột:
   giữ nguyên tên trường khi gửi form và để trình duyệt còn chỗ hiện thông báo
   "vui lòng chọn" của required — dùng display:none thì trình duyệt báo lỗi
   không focus được và chặn luôn việc gửi form. */
.chon { position: relative; }
.chon__that {
  position: absolute; left: 0; top: 0; width: 100%; height: 100%;
  opacity: 0; pointer-events: none; margin: 0; padding: 0; border: 0;
}
.chon__o { padding-right: 30px; text-overflow: ellipsis; }
.chon::after {
  content: ""; position: absolute; right: 12px; top: 50%; width: 7px; height: 7px;
  margin-top: -6px; pointer-events: none;
  border-right: 1.6px solid var(--c-ink-3); border-bottom: 1.6px solid var(--c-ink-3);
  transform: rotate(45deg);
}
.chon__dd {
  position: fixed; z-index: 95; overflow-y: auto; padding: 4px;
  background: var(--c-surface); border: 1px solid var(--c-rule);
  border-radius: var(--radius); box-shadow: var(--shadow-3);
  overscroll-behavior: contain;
}
.chon__m {
  padding: 7px 9px; border-radius: 3px; cursor: pointer;
  font-size: 13.5px; line-height: 1.35;
}
.chon__m:hover, .chon__m.is-tren { background: var(--c-accent-wash); }
.chon__m[aria-selected="true"] { font-weight: 650; color: var(--c-accent); }
.chon__m b { font-weight: inherit; border-radius: 2px; background: var(--c-warn-wash); color: var(--c-ink); }
.chon__trong { padding: 9px; font-size: 12.5px; color: var(--c-ink-3); }
@media (pointer: coarse) { .chon__m { padding: 11px 10px; font-size: 14px; } }

/* --- Dòng phụ trong ô chọn: tồn kho và trạng thái bán ---
   Chỉ xuất hiện khi <option> mang data-t / data-dung, tức thực tế là hai ô chọn sản phẩm
   (/don-hang/moi và /nhap-hang). Ô chọn nhân viên, tỉnh thành, nhóm hàng không đổi gì.

   Đặt thành dòng riêng bên dưới tên chứ không nối vào tên: chữ của <option> là KHOÁ TÌM
   KIẾM và cũng là chữ đổ vào ô nhập sau khi chọn — nối "· tồn 24" vào đó thì gõ "24" khớp
   mọi hàng tồn 24, và ô nhập hiện một câu thay vì tên sản phẩm. */
.chon__ten { display: block; }
.chon__phu {
  display: flex; gap: 8px; margin-top: 2px;
  font-family: var(--f-mono); font-size: 11px; letter-spacing: -.01em;
}
.chon__ton  { font-style: normal; color: var(--c-ok); }
.chon__ton.la-it  { color: var(--c-warn); }
.chon__ton.la-het { color: var(--c-ink-3); }
.chon__dung { font-style: normal; color: var(--c-warn); }
.chon__dung.la-ngung { color: var(--c-crit); }
/* Mục đang chọn tô đậm cả dòng; dòng phụ giữ nguyên màu riêng để vẫn đọc được trạng thái. */
.chon__m[aria-selected="true"] .chon__phu { font-weight: 400; }
@media (pointer: coarse) { .input, .select, .textarea { min-height: 40px; font-size: 16px; } }

/* ---------- 7. THẺ & KHUNG ---------- */
.card {
  background: var(--c-surface); border: 1px solid var(--c-rule-soft);
  border-radius: var(--radius); box-shadow: var(--shadow-1);
}
.card__head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 12px; border-bottom: 1px solid var(--c-rule-soft);
}
.card__title { font-size: 13px; font-weight: 640; }
.card__body { padding: 12px; }

/* Khung báo động ("Bất thường — cần nhìn ngay").

   Trước đây khung này có border-left: 3px đỏ. Nhưng mỗi dòng bên trong ĐÃ có vạch màu bên
   trái riêng theo mức độ (.row-item[data-flag]) — hai vạch dựng sát nhau, mắt không biết
   vạch nào nói gì, và vạch đỏ của khung còn nói sai về những dòng chỉ ở mức cảnh báo.

   Điểm nhấn dời lên phần đầu khung: nền đỏ nhạt + tiêu đề đỏ. Đọc ra ngay "khung này là
   khung báo động" mà không tranh chỗ với vạch của từng dòng. Con số đếm phải đổi sang nền
   đỏ đặc, vì badge--crit vốn cũng dùng nền wash — để nguyên là nó tan vào nền đầu khung. */
.card--bao > .card__head {
  background: var(--c-crit-wash);
  border-bottom-color: color-mix(in srgb, var(--c-crit) 30%, transparent);
  border-radius: var(--radius) var(--radius) 0 0;
}
.card--bao > .card__head .card__title { color: var(--c-crit); }
.card--bao > .card__head .badge--crit { background: var(--c-crit); color: var(--c-surface); }

/* thanh lọc */
.filterbar {
  display: flex; align-items: flex-end; gap: 8px; flex-wrap: wrap;
  padding: 10px 12px;
  background: var(--c-surface); border: 1px solid var(--c-rule-soft);
  border-radius: var(--radius); box-shadow: var(--shadow-1);
  margin-bottom: 12px;
}
.filterbar .field { flex: 0 1 auto; }
.filterbar__spacer { flex: 1 1 auto; }
@media (max-width: 820px) {
  .filterbar { padding: 0; border: 0; background: none; box-shadow: none; margin-bottom: 8px; }
  .filterbar__panel {
    display: flex; width: 100%; gap: 8px; flex-direction: column;
    padding: 12px; background: var(--c-surface);
    border: 1px solid var(--c-rule-soft); border-radius: var(--radius);
  }
  /* !important vì các trang gắn thẳng `style="flex:1 1 220px;max-width:280px"` lên từng ô —
     những con số đó dành cho bố cục NGANG. Xếp dọc mà giữ nguyên thì flex-grow kéo ô cao
     lên thành một mảng trống, còn max-width giữ ô hẹp một nửa màn hình. Kiểu inline chỉ
     thua được !important. */
  .filterbar__panel .field { width: 100%; flex: none !important; max-width: none !important; }
  /* Khoảng đệm giữa hai nhóm chỉ có nghĩa khi xếp ngang; xếp dọc thì nó thành một mảng
     trống kéo dài giữa thanh. */
  .filterbar__panel .filterbar__spacer { display: none; }

  /* CHỈ gập thanh nào thật sự CÓ nút mở.
     Trước đây gập mọi thanh lọc, trong khi 11 trong 15 thanh của dự án không có nút
     [data-filter-toggle] — nghĩa là ở khổ điện thoại chúng biến mất hẳn và không có cách nào
     mở ra. Ở /telesale đó là ô tra cứu số điện thoại và nút "Trả lead": đúng hai thứ người
     trực cần nhất khi đang cầm máy mà không ngồi trước laptop. */
  .filterbar:has(.filterbar__toggle) .filterbar__panel { display: none; }
  .filterbar:has(.filterbar__toggle)[data-open="1"] .filterbar__panel { display: flex; }
}
@media (min-width: 821px) {
  .filterbar__panel { display: contents; }
  .filterbar__toggle { display: none; }
}

/* ---------- 8. BẢNG DỮ LIỆU ---------- */
.tablewrap {
  background: var(--c-surface);
  border: 1px solid var(--c-rule-soft); border-radius: var(--radius);
  box-shadow: var(--shadow-1); overflow: hidden;
}
/* overflow-x: auto biến vùng này thành khung cuộn riêng, nên header dính (sticky)
   sẽ bám theo khung này chứ không theo cửa sổ. Vì vậy trên màn hình đủ rộng ta
   cho khung cuộn cả chiều dọc — header dính hoạt động, còn thanh phân trang
   nằm ngoài nên luôn nhìn thấy. */
.tablescroll { overflow-x: auto; }
@media (min-width: 1100px) {
  .tablescroll { max-height: calc(100vh - var(--topbar-h) - 176px); overflow-y: auto; }
}
/* Bề rộng tối thiểu đặt qua biến --dt-min để màn hình hẹp còn hạ xuống được;
   viết thẳng "min-width" trong thuộc tính style của thẻ table thì media query
   không đè lại được (trừ khi dùng !important). */
.dt {
  width: 100%; border-collapse: separate; border-spacing: 0;
  font-size: var(--fs-table); min-width: var(--dt-min, 900px);
}
.dt thead th {
  position: sticky; top: 0; z-index: 5;
  background: var(--c-surface-2); color: var(--c-ink-2);
  font-family: var(--f-mono); font-size: 10px; font-weight: 650;
  letter-spacing: .09em; text-transform: uppercase;
  text-align: left; white-space: nowrap;
  padding: 7px var(--cell-px);
  border-bottom: 1px solid var(--c-rule);
}
.dt thead th a { color: inherit; display: inline-flex; align-items: center; gap: 3px; }
.dt thead th a:hover { color: var(--c-accent); text-decoration: none; }
.dt tbody td {
  padding: var(--row-py) var(--cell-px);
  border-bottom: 1px solid var(--c-rule-soft);
  vertical-align: top;
}
.dt tbody tr { transition: background .1s; }
.dt tbody tr:hover { background: var(--c-surface-2); }

/* Dòng đang TẮT — dùng ở /data-feed.

   Trạng thái đã có nhãn riêng ở cột cuối, nhưng nhãn thì phải đọc từng dòng mới thấy. Làm mờ
   cả dòng để "tệp nào đang chạy" đọc được bằng một cái liếc qua cả bảng. Cố ý chỉ hạ độ đậm
   chứ không đổi màu chữ: dòng tắt vẫn phải đọc được rõ, vì người ta mở màn hình này chính là
   để đọc rồi bật nó lên. Ô tick và nút bấm giữ nguyên — dòng tắt vẫn thao tác được bình thường. */
.dt tbody tr.is-off > td { opacity: .55; }
.dt tbody tr.is-off > td:first-child,
.dt tbody tr.is-off > td:last-child { opacity: 1; }
.dt tbody tr.is-off:hover > td { opacity: 1; }
.dt tbody tr:last-child td { border-bottom: 0; }
.dt .num { font-family: var(--f-mono); font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.dt .nowrap { white-space: nowrap; }
.dt .center { text-align: center; }
.dt col.w-tick { width: 34px; }

/* ô đặc thù nghiệp vụ */
.cell-code { font-family: var(--f-mono); font-size: 12px; font-weight: 600; letter-spacing: -.02em; }
.cell-code small { display: block; font-weight: 400; color: var(--c-ink-3); font-size: 10.5px; letter-spacing: .02em; }
.cell-name { font-weight: 600; color: var(--c-ink); }
.cell-phone { font-family: var(--f-mono); font-size: 12.5px; color: var(--c-ink-2); }
/* .cell-addr và .cell-sub là HAI SẮC ĐỘ CỦA CÙNG MỘT VAI: dòng phụ nằm dưới .cell-name.
   Cả sáu chỗ dùng .cell-addr (panel bảng kê, bốn màn hình báo cáo) đều đặt nó ngay cạnh một
   .cell-sub, nên chúng phải cùng CỠ CHỮ — thiếu font-size thì .cell-addr rơi về --fs-table và
   dòng địa chỉ to hơn hẳn dòng phụ ngay dưới nó, đọc như hai cấp thông tin khác nhau trong khi
   chúng cùng một cấp.

   Chỉ gộp cỡ chữ, KHÔNG gộp màu: địa chỉ giữ --c-ink-2 đậm hơn --c-ink-3 vì nó là dữ liệu
   người dùng cần đọc, còn .cell-sub thường là chú thích liếc qua. */
.cell-addr,
.cell-sub { font-size: 11.5px; }
.cell-addr { color: var(--c-ink-2); line-height: 1.42; max-width: 34ch; }
.cell-sub { color: var(--c-ink-3); }
.cell-money { font-family: var(--f-mono); font-variant-numeric: tabular-nums; font-weight: 600; text-align: right; white-space: nowrap; }
.cell-money small { display: block; font-weight: 400; font-size: 10.5px; color: var(--c-ink-3); }
.thumb {
  width: var(--thumb); height: var(--thumb); flex: none;
  border-radius: var(--radius-sm); border: 1px solid var(--c-rule-soft);
  object-fit: cover; background: var(--c-surface-2);
}

/* Lịch sử đơn cũ / lịch sử liên hệ — mỗi mục cách nhau 5px cho dễ phân biệt.
   Đặt khoảng cách trên chính dòng chứ không dùng gap của khung bao, để chỗ nào
   in ra dòng mà không có khung bao vẫn giãn đúng. */
.hist { margin-top: 4px; }
.hist__row {
  font-size: 11.5px; line-height: 1.55; color: var(--c-ink-3);
  padding: 6px 9px; border-left: 3px solid var(--c-rule);
  background: var(--c-surface-2); border-radius: 0 var(--radius) var(--radius) 0;
}
.hist__row + .hist__row { margin-top: 5px; }
.hist__row .cell-sub { margin-top: 2px; }

/* HTML sẵn có trong DB (ảnh sản phẩm, bảng giá do website sinh ra) */
.sp-anh { display: inline-block; vertical-align: middle; margin-right: 6px; }
.sp-anh img {
  display: inline-block; height: 26px; width: auto; max-width: 44px;
  object-fit: cover; border-radius: var(--radius-sm); border: 1px solid var(--c-rule-soft);
  vertical-align: middle;
}
/* [BỎ 19/08/2026] .sp-anh--to — khối ảnh to ở đầu panel chi tiết đơn hàng và chăm sóc đơn.
   Chủ dự án chốt bỏ: nó không nói thêm gì so với ảnh nhỏ đã có ở từng dòng sản phẩm, mà đẩy
   cả danh sách xuống dưới tầm mắt. Luật CSS xoá theo, không để lại lớp không ai gắn. */

/* Ô sản phẩm trong danh sách: ảnh là khối cố định bên trái, chữ chiếm phần còn lại.
   Nhờ flex, ảnh cao gần bằng dòng mà KHÔNG làm hộp dòng của chữ phình ra,
   nên chiều cao các dòng vẫn bằng nhau. */
.rc--sp { display: flex; align-items: center; gap: 8px; }
.rc--sp .sp-anh { flex: none; line-height: 0; margin: 0; }
.rc--sp .sp-anh img {
  height: var(--sp-anh, 32px); width: var(--sp-anh, 32px);
  object-fit: cover; border-radius: var(--radius-sm);
  border: 1px solid var(--c-rule-soft); background: var(--c-surface-2);
}
.rc--sp .sp-anh img ~ img { display: none; }   /* vài đơn có 2 ảnh, chỉ lấy ảnh đầu */
.rc__txt { min-width: 0; flex: 1; }
.rc__d1 { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
:root[data-density="thoang"] .rc--sp { --sp-anh: 46px; }

.html-db {
  font-size: 13px; line-height: 1.55; color: var(--c-ink-2);
  padding: 9px 11px; background: var(--c-surface-2);
  border: 1px solid var(--c-rule-soft); border-radius: var(--radius);
  overflow-wrap: anywhere;
}
.html-db img { max-width: 100%; height: auto; border-radius: var(--radius-sm); margin-top: 5px; }
.html-db a { font-weight: 550; }
.html-db div { max-width: 100%; }
.html-db--sp { background: var(--c-surface); }
.hist__row b { font-weight: 600; }

/* Viền trái + tên kết quả cùng một màu.

   [SỬA 17/08/2026 — thống nhất thang màu] Lịch sử ĐƠN nay trả về đúng bộ lớp của thang màu
   trạng thái (ok · info · warn · hoan · crit — xem Data/DonHangRepo.cs · LichSuRow.KetQua),
   không còn bộ tên riêng `ship`/`huy` vốn tô "Chưa đóng gói" thành ĐỎ ở đây trong khi bảng
   đơn tô hổ phách, và tô "Đang giao" thành hổ phách trong khi bảng đơn tô xanh dương.
   Luật `huy` giữ lại vì /telesale còn dùng nó cho khối "lượt đặt bị chặn"; luật `ship` đã gỡ
   vì không còn chỗ nào sinh ra lớp đó.

   Các lớp lac · hen là của KẾT QUẢ GỌI — xem Data/KetQuaGoi.cs.

   [SỬA 17/08/2026] Trước đó nữa chỉ có ba luật ok/ship/huy, trong khi `LienHeRow.LopKetQua`
   sinh ra crit · warn · info · idle. Không luật nào khớp thì dòng tụt về viền xám mặc định —
   nên trong "Lịch sử liên hệ", SÁU TRÊN BẢY mã kết quả đều xám như nhau, kể cả "Hủy – không
   mua". Đo trên trình duyệt: data-r="crit" cho ra đúng cùng màu với data-r rỗng. */
.hist__row[data-r="ok"]   { border-left-color: var(--c-ok);   } .hist__row[data-r="ok"] b   { color: var(--c-ok); }
.hist__row[data-r="huy"]  { border-left-color: var(--c-crit); } .hist__row[data-r="huy"] b  { color: var(--c-crit); }
.hist__row[data-r="crit"] { border-left-color: var(--c-crit); } .hist__row[data-r="crit"] b { color: var(--c-crit); }
.hist__row[data-r="warn"] { border-left-color: var(--c-warn); } .hist__row[data-r="warn"] b { color: var(--c-warn); }
.hist__row[data-r="hoan"] { border-left-color: var(--c-hoan); } .hist__row[data-r="hoan"] b { color: var(--c-hoan); }
.hist__row[data-r="giao"]      { border-left-color: var(--c-giao);      } .hist__row[data-r="giao"] b      { color: var(--c-giao); }
.hist__row[data-r="hoan-xong"] { border-left-color: var(--c-hoan-xong); } .hist__row[data-r="hoan-xong"] b { color: var(--c-hoan-xong); }
.hist__row[data-r="hoan-loi"]  { border-left-color: var(--c-hoan-loi);  } .hist__row[data-r="hoan-loi"] b  { color: var(--c-hoan-loi); }
.hist__row[data-r="lac"]  { border-left-color: var(--c-lac);  } .hist__row[data-r="lac"] b  { color: var(--c-lac); }
.hist__row[data-r="info"] { border-left-color: var(--c-info); } .hist__row[data-r="info"] b { color: var(--c-info); }
.hist__row[data-r="hen"]  { border-left-color: var(--c-hen);  } .hist__row[data-r="hen"] b  { color: var(--c-hen); }
.hist__row[data-r="idle"] { border-left-color: var(--c-idle); } .hist__row[data-r="idle"] b { color: var(--c-idle); }

/* Nền nhạt cùng tông cho dòng lịch sử LIÊN HỆ. Chỉ viền trái 3px thì ở danh sách bảy tám
   dòng vẫn phải nhìn kỹ mới thấy dòng nào là dòng nào; thêm mảng nền là quét mắt một cái
   ra ngay. Không áp cho .khachcu (lịch sử đơn cũ) — ở đó nền trắng đang phân biệt dòng đơn
   với nền khối, đổi đi là mất ranh giới. */
.hist--kq .hist__row[data-r="ok"]   { background: var(--c-ok-wash); }
.hist--kq .hist__row[data-r="crit"] { background: var(--c-crit-wash); }
.hist--kq .hist__row[data-r="warn"] { background: var(--c-warn-wash); }
.hist--kq .hist__row[data-r="hoan"] { background: var(--c-hoan-wash); }
.hist--kq .hist__row[data-r="giao"]      { background: var(--c-giao-wash); }
.hist--kq .hist__row[data-r="hoan-xong"] { background: var(--c-hoan-xong-wash); }
.hist--kq .hist__row[data-r="hoan-loi"]  { background: var(--c-hoan-loi-wash); }
.hist--kq .hist__row[data-r="lac"]  { background: var(--c-lac-wash); }
.hist--kq .hist__row[data-r="info"] { background: var(--c-info-wash); }
.hist--kq .hist__row[data-r="hen"]  { background: var(--c-hen-wash); }
.hist--kq .hist__row[data-r="idle"] { background: var(--c-idle-wash); }

/* ---------- 9. NHÃN TRẠNG THÁI ---------- */
.badge {
  display: inline-flex; align-items: center; gap: 4px;
  font-family: var(--f-mono); font-size: 10px; font-weight: 650; line-height: 13px;
  letter-spacing: .05em; text-transform: uppercase;
  padding: 2px 6px; border-radius: var(--radius-sm); white-space: nowrap;
  background: var(--c-idle-wash); color: var(--c-idle);
}
.badge--ok   { background: var(--c-ok-wash);   color: var(--c-ok); }
.badge--warn { background: var(--c-warn-wash); color: var(--c-warn); }
.badge--crit { background: var(--c-crit-wash); color: var(--c-crit); }
.badge--info { background: var(--c-info-wash); color: var(--c-info); }
.badge--idle { background: var(--c-idle-wash); color: var(--c-idle); }
/* Hai lớp của kết quả gọi — xem Data/KetQuaGoi.cs */
.badge--hoan { background: var(--c-hoan-wash); color: var(--c-hoan); }
.badge--lac  { background: var(--c-lac-wash);  color: var(--c-lac); }
.badge--hen  { background: var(--c-hen-wash);  color: var(--c-hen); }
.badge--jt   { background: var(--c-jt-wash);   color: var(--c-jt); }
.badge--ss   { background: var(--c-ss-wash);   color: var(--c-ss); }

/* ---------- Nhãn nhà mạng của số điện thoại ----------
   Đứng ngay cạnh số nên phải NHỎ hơn số và nhạt hơn số: số là thứ người ta gọi, nhãn chỉ để
   liếc qua. Chữ hoa nhỏ + giãn chữ là cách làm nhãn phụ đã dùng ở .badge của dự án.

   `nm--khac` cố ý không có màu riêng — xem lý do ở khối token. */
.nm {
  display: inline-flex; align-items: center; gap: 4px; vertical-align: middle;
  padding: 1px 6px; border-radius: 999px;
  font-family: var(--f-sans); font-size: 10px; font-weight: 650;
  letter-spacing: .04em; white-space: nowrap;
  /* --c-ink-2 chứ không --c-ink-3: nhãn này chỉ 10px, mà ink-3 trên surface-2 đo được
     3,31:1 — dưới mức đọc được. Bốn nhãn có màu riêng đều 4,7–5,7:1, nhãn trung tính không
     có lý do gì phải mờ hơn hẳn phần còn lại. */
  background: var(--c-surface-2); color: var(--c-ink-2);
}
.nm--viettel { background: var(--c-nm-viettel-wash); color: var(--c-nm-viettel); }
.nm--mobi    { background: var(--c-nm-mobi-wash);    color: var(--c-nm-mobi); }
.nm--vina    { background: var(--c-nm-vina-wash);    color: var(--c-nm-vina); }
.nm--vnm     { background: var(--c-nm-vnm-wash);     color: var(--c-nm-vnm); }
.nm--itel    { background: var(--c-nm-itel-wash);    color: var(--c-nm-itel); }
.nm--wintel  { background: var(--c-nm-wintel-wash);  color: var(--c-nm-wintel); }
.nm--gmobile { background: var(--c-nm-gmobile-wash); color: var(--c-nm-gmobile); }

/*  Hai mức của cái nhãn — [THÊM 20/08/2026, chủ dự án chốt].

    Trước bản này nhãn chỉ đọc ĐẦU SỐ, tức nhà mạng được cấp kho số, và sai với 3–5% thuê bao
    đã chuyển mạng giữ số. Giới hạn ấy nằm trong chú thích mã nguồn — chỗ mà người trực không
    bao giờ đọc. Nay chính cái nhãn nói ra:

      ?  theo đầu số, là phỏng đoán
      ✓  đã hỏi dịch vụ tra cứu, là nhà mạng thật

    Dấu để mờ và nhỏ: nó là chú thích cho cái nhãn, không phải thứ tranh chỗ với tên nhà mạng. */
.nm__dau { font-size: 9px; opacity: .65; margin-left: 1px; font-weight: 700; }
.nm--that { box-shadow: inset 0 0 0 1px currentColor; }

/* "đã chuyển từ MobiFone" — chỉ hiện đúng ở số đã chuyển mạng, tức ca mà nhãn cũ nói sai. */
.nm__doi {
  font-size: 10px; color: var(--c-ink-3); font-style: italic;
  margin-left: 4px; vertical-align: middle; white-space: nowrap;
}

/* Chấm tròn mang ĐÚNG màu logo của hãng.
   Đây là chỗ duy nhất trong nhãn dùng được mã màu thương hiệu nguyên bản: chấm là khối đặc
   nên không có chuyện đọc không ra chữ, và nó cố định ở cả nền sáng lẫn nền tối — logo hãng
   không đổi màu theo giao diện của người xem. Chữ bên cạnh thì phải nhường độ đọc (xem token).

   Ba hãng nhỏ cuối rơi vào cùng họ đỏ–cam với Viettel và Vietnamobile. Chấp nhận được: chúng
   chiếm phần rất nhỏ thuê bao và gần như không bao giờ đứng cạnh nhau trên cùng màn hình. */
.nm__cham { width: 6px; height: 6px; border-radius: 50%; flex: none; background: currentColor; }
.nm--viettel .nm__cham { background: #EE0033; }   /* đỏ Viettel, sau tái định vị 2021 */
.nm--mobi    .nm__cham { background: #0066B3; }   /* xanh dương MobiFone */
.nm--vina    .nm__cham { background: #00A0E3; }   /* xanh nước VinaPhone — sáng hơn hẳn MobiFone */
.nm--vnm     .nm__cham { background: #F58220; }   /* cam Vietnamobile */
.nm--itel    .nm__cham { background: #F15A24; }   /* cam đỏ Itelecom */
.nm--wintel  .nm__cham { background: #E4002B; }   /* đỏ Wintel */
.nm--gmobile .nm__cham { background: #78BE20; }   /* xanh lá Gmobile */
/* [XOÁ 20/08/2026] Ở đây từng có `.nm::after { content: "?" }` — dấu chấm hỏi tự động gắn vào
   mọi nhãn để nhắc rằng đó là đầu số gốc.

   Nó thành tàn dư từ hôm nhãn có HAI MỨC: dấu nay do .nm__dau in ra, vì chỉ Razor mới biết
   nhãn này là phỏng đoán (?) hay đã xác minh (✓). Để lại quy tắc cũ thì mọi nhãn đều mang
   thêm một dấu hỏi nữa, và hỏng nhất là ở nhãn ĐÃ XÁC MINH: nó hiện ra "MobiFone ✓ ?", tức
   cái nhãn tự phủ định chính mình ngay trên màn hình người trực đang đọc.

   Đo trên bản chạy 20/08: /telesale hiện "MobiFone ? ?" ở mọi số chưa tra. */
.badge--ghtk { background: var(--c-ghtk-wash); color: var(--c-ghtk); }
.badge--vtp  { background: var(--c-vtp-wash);  color: var(--c-vtp); }
.badge--shop { background: var(--c-shop-wash); color: var(--c-shop); }
.badge--lg   { font-size: 11px; padding: 3px 8px; }

/* vạch mức độ ở đầu dòng — thấy ngay đơn nào cần chú ý */
.dt tbody td:first-child { position: relative; }
.dt tbody tr[data-flag] td:first-child::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
}
.dt tbody tr[data-flag="crit"] td:first-child::before { background: var(--c-crit); }
.dt tbody tr[data-flag="warn"] td:first-child::before { background: var(--c-warn); }
.dt tbody tr[data-flag="ok"]   td:first-child::before { background: var(--c-ok); }
/* [THÊM 19/08/2026] Bậc info — dòng "đang về" của lịch sử nhập hàng ở panel /san-pham. Thiếu
   luật này thì vạch màu trong suốt và bậc ấy im lặng biến mất, đúng kiểu hỏng đã ghi ở
   KetQuaGoi: gắn lớp mà quên định nghĩa thì không ai thấy, kể cả người gắn. */
.dt tbody tr[data-flag="info"] td:first-child::before { background: var(--c-info); }

/* ============================================================
   9b. VÙNG LÀM VIỆC: danh sách gọn + panel chi tiết
   Thay cho kiểu bảng nhồi mọi thứ vào một ô của bản cũ.
   Danh sách để QUÉT MẮT (dòng cao đều nhau), panel để LÀM VIỆC.
   ============================================================ */
.ws { display: grid; gap: 12px; align-items: start; min-width: 0; }
/* Chỉ chia đôi khi thật sự có panel — chưa mở panel thì danh sách dùng trọn bề ngang */
@media (min-width: 1180px) {
  .ws:has(.ws__detail) { grid-template-columns: minmax(0, 1fr) minmax(378px, 30%); }
  /* .ws--rong dùng cho hai màn hình mà panel là NƠI LÀM VIỆC chứ không phải chỗ xem thêm:
     /telesale ghi kết quả gọi ngay trong panel, /cham-soc cũng vậy. Danh sách bên trái chỉ
     cần đủ để chọn dòng, nên nhường bề ngang cho panel. */
  .ws--rong:has(.ws__detail) { grid-template-columns: minmax(0, 1fr) minmax(460px, 44%); }
}
/* Dòng danh sách xếp theo BỀ RỘNG CỦA CỘT DANH SÁCH, không theo bề rộng cửa sổ.
   Quan trọng: ở laptop 1366px, khi panel chi tiết mở ra thì cột danh sách chỉ còn
   ~700px — hẹp hơn cả tablet. Dùng media query theo cửa sổ sẽ không bắt được
   trường hợp này và các cột bị cắt mất. */
.ws__list { min-width: 0; container-type: inline-size; container-name: dslist; }
/* Panel là khung tham chiếu cho những gì nằm trong nó (cụm chọn nhiều cột ở /telesale):
   panel rộng hay hẹp phụ thuộc bố cục hai cột, không phụ thuộc bề rộng cửa sổ. */
.ws__detail { min-width: 0; container-type: inline-size; container-name: dtpanel; }
@media (min-width: 1180px) {
  .ws__detail {
    position: sticky; top: calc(var(--topbar-h) + 12px);
    max-height: calc(100vh - var(--topbar-h) - 24px); overflow: auto;
  }
}

/* --- một dòng trong danh sách --- */
.rows {
  background: var(--c-surface); border: 1px solid var(--c-rule-soft);
  border-radius: var(--radius); box-shadow: var(--shadow-1); overflow: hidden;
}
.rowhd {
  display: grid; align-items: center; gap: 10px;
  grid-template-columns: var(--cols);
  padding: 6px 12px; background: var(--c-surface-2);
  border-bottom: 1px solid var(--c-rule);
  font-family: var(--f-mono); font-size: 10px; font-weight: 650;
  letter-spacing: .09em; text-transform: uppercase; color: var(--c-ink-2);
}
.row-item {
  display: grid; align-items: center; gap: 10px;
  grid-template-columns: var(--cols);
  padding: 0 12px; min-height: var(--row-h);
  border-bottom: 1px solid var(--c-rule-soft);
  border-left: 3px solid transparent;
  cursor: pointer; position: relative;
  transition: background .1s;
  width: 100%; text-align: left; background: none; font: inherit; color: inherit;
}
.row-item:last-child { border-bottom: 0; }
.row-item:hover { background: var(--c-surface-2); }
.row-item[aria-selected="true"] { background: var(--c-accent-wash); border-left-color: var(--c-accent); }
.row-item[data-flag="crit"] { border-left-color: var(--c-crit); }
.row-item[data-flag="warn"] { border-left-color: var(--c-warn); }
.row-item[data-flag="ok"]   { border-left-color: var(--c-ok); }
.row-item[aria-selected="true"][data-flag] { border-left-color: var(--c-accent); }
.row-item:focus-visible { outline: 2px solid var(--c-accent-hi); outline-offset: -2px; }

/* mọi ô đều một dòng, cắt bớt bằng dấu … để chiều cao dòng luôn bằng nhau */
/* line-height cố định cho cả ô: khi chữ thường và chữ mono nằm chung một dòng,
   hộp dòng lấy theo font cao hơn — để tự động thì dòng nào có mã/giờ sẽ cao hơn 1px. */
.rc {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--fs-table); line-height: 16px;
}
/* Ô hai dòng: chữ chính xuống được hai dòng rồi mới cắt, dòng phụ (.rc small) vẫn đứng
   riêng bên dưới. Chữ chính PHẢI bọc trong .rc__chinh — -webkit-line-clamp đếm mọi dòng
   nằm trong hộp của nó, đặt thẳng lên ô thì dòng phụ cũng bị tính và địa chỉ biến mất. */
.rc--2 { white-space: normal; }
.rc--2 > .rc__chinh {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; line-height: 16px;
}
.rc b { font-weight: 640; }
/* line-height cố định: font mono có hộp dòng cao hơn font thường, nếu để tự động
   thì dòng nào có giờ/mã sẽ cao hơn dòng khác 1px và bảng trông không đều. */
.rc small {
  display: block; font-size: 11px; color: var(--c-ink-3);
  overflow: hidden; text-overflow: ellipsis;
  line-height: 15px; height: 15px;
}
.rc-code { font-family: var(--f-mono); font-size: 12px; font-weight: 650; letter-spacing: -.02em; }
.rc-money { font-family: var(--f-mono); font-variant-numeric: tabular-nums; font-weight: 650; text-align: right; white-space: nowrap; }
.rc-money small { text-align: right; font-weight: 400; }
/* Ô tick chọn đơn — to hơn mặc định của trình duyệt cho dễ bấm,
   kể cả khi dùng chuột. Vùng bấm nới rộng ra quá viền ô. */
.rc-tick { display: grid; place-items: center; }
.rc-tick input[type="checkbox"] {
  cursor: pointer; margin: 0;
  width: 19px; height: 19px;
  accent-color: var(--c-accent);
}
.rc-tick input[type="checkbox"]::before {
  content: ""; position: absolute;
  inset: -9px;                    /* nới vùng bấm mà không đổi kích thước hình */
}
.rc-tick { position: relative; }
.rowhd .rc-tick input[type="checkbox"] { width: 17px; height: 17px; }
/* Đơn đã bàn giao: ô tick TẮT — vẫn là một checkbox nên cột đọc thành một cột, chỉ là không
   bấm được. Xem DonHang/_Bang.cshtml: thanh gom chỉ chuyển được đơn chưa bàn giao. */
.rc-tick input[type="checkbox"]:disabled {
  cursor: not-allowed; opacity: .3; accent-color: var(--c-ink-3);
}
@media (pointer: coarse) {
  .rc-tick input[type="checkbox"] { width: 24px; height: 24px; }
}
/* Nút sửa / xóa ngay trên dòng danh sách */
.rc-act { display: flex; align-items: center; justify-content: center; gap: 3px; }
.rc-act .btn--icon.btn--sm { width: 26px; min-height: 26px; }
.rc-act .btn svg { width: 13px; height: 13px; }
.rc-act__khoa { display: grid; place-items: center; color: var(--c-ink-3); opacity: .45; }
.rc-act__khoa svg { width: 14px; height: 14px; stroke-width: 1.8; }
/* Chỉ hiện rõ khi rê chuột vào dòng — đỡ rối mắt khi quét danh sách */
.rc-act .btn { opacity: .55; transition: opacity .12s; }
.row-item:hover .rc-act .btn,
.row-item[aria-selected="true"] .rc-act .btn,
.rc-act .btn:focus-visible { opacity: 1; }
@media (pointer: coarse) { .rc-act .btn { opacity: 1; } }

/* Chặng "Đang xử lý" — vòng quay thay cho một nhãn chữ (Pages/Shared/_NhanChang.cshtml).

   SVG tô bằng currentColor: không có nền, ăn theo màu của .chang, nên đúng ở cả nền sáng lẫn
   nền tối bằng MỘT hình. Bản GIF trước đó có nền trắng nướng sẵn trong tệp.

   11px — nhỏ hơn cỡ chữ của dòng (12,5px) một chút để nó là dấu phụ đứng cạnh chữ, không phải
   thứ đầu tiên mắt nhìn thấy khi quét cả cột. */
.chang { display: inline-flex; align-items: center; gap: 4px; color: var(--c-info); }
.chang svg {
  flex: none; display: block; width: 11px; height: 11px;
  transform-origin: 50% 50%;
  animation: chang-quay 900ms linear infinite;
}
.chang__chu { white-space: nowrap; }
@keyframes chang-quay { to { transform: rotate(360deg); } }
/* Bật "giảm chuyển động" thì vòng đứng yên — nó vẫn là một vòng dở dang, vẫn đọc ra "đang
   chạy", chỉ không quay. Ẩn hẳn thì mất luôn dấu hiệu. */
@media (prefers-reduced-motion: reduce) { .chang svg { animation: none; } }

/* Nhân viên xử lý — icon người cho dễ phân biệt với phần trạng thái bên cạnh */
.nv { display: inline-flex; align-items: center; gap: 3px; color: var(--c-ink-2); }
.nv svg { width: 11px; height: 11px; flex: none; opacity: .7; }
.vach { color: var(--c-rule); margin: 0 4px; }

/* Ba thông tin phụ của đơn, mỗi loại một màu để nhận ra ngay không cần đọc kỹ */
.sp-tang, .sp-ghichu, .sp-thutien { margin-right: 8px; }
.sp-tang    { color: var(--c-info); }
.sp-ghichu  { color: var(--c-crit); }
.sp-thutien { color: var(--c-vtp); font-weight: 700; }

/* Nhãn miễn phí ship — icon xe tải cho dễ nhận ra hơn chữ */
.fship {
  display: inline-flex; align-items: center; gap: 3px;
  color: var(--c-ok); font-weight: 700; font-size: 10px; letter-spacing: .04em;
}
.fship svg { width: 13px; height: 13px; flex: none; }

.rc-go { color: var(--c-ink-3); display: grid; place-items: center; }
.rc-go svg { width: 15px; height: 15px; stroke-width: 2; }
.row-item[aria-selected="true"] .rc-go { color: var(--c-accent); }

/* dấu hiệu nhỏ: có ghi chú, khách mua lại, đơn gấp */
.dots { display: inline-flex; gap: 3px; vertical-align: middle; margin-left: 4px; }
.dots i {
  width: 6px; height: 6px; border-radius: 50%; display: block;
  background: var(--c-ink-3);
}
.dots i[data-d="note"] { background: var(--c-info); }
.dots i[data-d="lai"]  { background: var(--c-accent); }
.dots i[data-d="gap"]  { background: var(--c-crit); }

/* --- cột danh sách vừa (bỏ 2 cột phụ, vẫn một dòng) --- */
@container dslist (max-width: 940px) {
  .rc--noi { display: none; }
  .rowhd > .rc-hd--noi { display: none; }
  .row-item, .rowhd { grid-template-columns: var(--cols-vua, var(--cols)); }
}

/* Ngưỡng 940px ở trên tính cho danh sách BẢY cột của /don-hang. Danh sách của .ws--rong
   chỉ có năm cột và mỗi cột hẹp hơn, nên nó vẫn đủ chỗ ở khoảng 700–940px — mà đó đúng là
   khoảng nó rơi vào sau khi panel chi tiết được nới rộng. Không có luật này thì nới panel
   lại thành ra làm MẤT cột "Nguồn" của /telesale, ngược hẳn ý định. */
@container dslist (min-width: 700px) {
  .ws--rong .rc--noi { display: block; }
  .ws--rong .rowhd > .rc-hd--noi { display: block; }
  .ws--rong .row-item, .ws--rong .rowhd { grid-template-columns: var(--cols); }
}

/* --- cột danh sách hẹp: xếp thành 2 hàng, bỏ các cột phụ ---
   Áp dụng cho cả điện thoại lẫn laptop đang mở panel chi tiết.
   Thông tin bỏ đi ở đây vẫn xem đầy đủ trong panel. */
@container dslist (max-width: 560px) {
  .rowhd { display: none; }
  .row-item {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: "tick code tien" "tick khach giao";
    gap: 1px 10px; padding: 9px 12px; min-height: 0;
  }
  .rc--tick  { grid-area: tick; align-self: center; }
  .rc--code  { grid-area: code; }
  .rc--khach { grid-area: khach; }
  .rc--tien  { grid-area: tien; }
  .rc--giao  { grid-area: giao; text-align: right; }
  /* Ô nào KHÔNG có grid-area ở trên thì BẮT BUỘC phải nằm trong danh sách này. Ô lạc ngoài
     cả hai sẽ bị lưới tự xếp vào cột 1 — cột "tick" — rồi phình theo nội dung, ép cột
     minmax(0,1fr) bên cạnh xuống 0px và nuốt mất tên khách lẫn thời gian chờ. Đã xảy ra
     thật ở /telesale khi ô "Quan tâm" đổi từ .rc--sp sang .rc--2. */
  .rc--noi, .rc--sp, .rc--an-hep, .rc-go, .rc-act { display: none; }
  .rc--code small { display: inline; margin-left: 6px; }
  .rc--giao small { display: inline; }
}
.bulkbar {
  position: sticky; bottom: 0; z-index: 20;
  display: none; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 9px 12px; background: var(--c-ink); color: var(--c-surface);
  border-radius: var(--radius); box-shadow: var(--shadow-3); margin-top: 8px;
}
.bulkbar[data-hien="1"] { display: flex; }
.bulkbar b { font-family: var(--f-mono); font-variant-numeric: tabular-nums; }
.bulkbar .btn { background: transparent; border-color: rgba(255,255,255,.32); color: var(--c-surface); }
.bulkbar .btn:hover { background: rgba(255,255,255,.14); border-color: rgba(255,255,255,.55); }
.bulkbar .btn--primary { background: var(--c-accent); border-color: var(--c-accent); color: var(--c-accent-ink); }

/* --- panel chi tiết --- */
.dt-panel { background: var(--c-surface); border: 1px solid var(--c-rule-soft); border-radius: var(--radius); box-shadow: var(--shadow-1); }
.dt-panel__hd {
  display: flex; align-items: flex-start; gap: 10px; flex-wrap: wrap;
  padding: 12px 14px; border-bottom: 1px solid var(--c-rule-soft); background: var(--c-surface-2);
}
.dt-panel__id { font-family: var(--f-mono); font-size: 16px; font-weight: 680; letter-spacing: -.02em; }
.dt-panel__x { margin-left: auto; }
.dt-sec { padding: 12px 14px; border-bottom: 1px solid var(--c-rule-soft); }
.dt-sec:last-child { border-bottom: 0; }
.dt-sec__t {
  font-size: 10px; font-weight: 650; letter-spacing: .07em; text-transform: uppercase;
  color: var(--c-ink-3); margin-bottom: 7px;
}
.dt-kv { display: grid; grid-template-columns: 74px minmax(0,1fr); gap: 3px 10px; font-size: 13px; }
.dt-kv dt { color: var(--c-ink-3); font-size: 11.5px; padding-top: 1px; }
.dt-kv dd { margin: 0; min-width: 0; }
.dt-phone { font-family: var(--f-mono); font-size: 18px; font-weight: 650; color: var(--c-accent); letter-spacing: -.02em; }
.dt-phone:hover { text-decoration: none; color: var(--c-accent-hi); }

/* Dòng sản phẩm trong panel chi tiết.

   Cả dòng vẫn mở được sản phẩm ở /san-pham, nhưng khung ngoài KHÔNG còn là thẻ <a>: từ
   20/08/2026 trong dòng có thêm link "Xem web" trỏ ra website, mà HTML không cho lồng <a>
   trong <a> — trình duyệt tự đóng thẻ ngoài và cả dòng vỡ bố cục. Nay tên sản phẩm là link
   thật, phủ hết dòng bằng .dt-sp__mo::after; link "Xem web" nổi lên trên lớp phủ đó bằng
   z-index, nên hai đích đến không giẫm lên nhau.

   Vùng bấm rộng thêm 8px mỗi bên rồi lùi lại bằng margin âm, để mép trái mép phải của panel
   cũng bấm được mà chữ vẫn thẳng hàng với các mục khác. */
.dt-sp { display: flex; gap: 9px; align-items: flex-start; padding: 7px 0; border-bottom: 1px dashed var(--c-rule-soft); }
.dt-sp--link { position: relative; padding-left: 8px; padding-right: 8px; margin-left: -8px; margin-right: -8px; border-radius: var(--radius); }
.dt-sp--link:hover { background: var(--c-surface-2); }
.dt-sp--link:hover .dt-sp__mo { color: var(--c-accent); }
.dt-sp__mo { color: inherit; text-decoration: none; }
.dt-sp__mo::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.dt-sp__mo:focus-visible { outline: none; }
.dt-sp__mo:focus-visible::after { outline: 2px solid var(--c-accent-hi); outline-offset: -2px; }
/* Đứng trên lớp phủ của .dt-sp__mo — nếu không thì cú bấm rơi vào link sản phẩm. */
.dt-sp__web { position: relative; z-index: 1; }
/*  [SỬA 20/08/2026 — chủ dự án chốt] Ảnh trong panel chi tiết to hơn lưới: 59px thay cho
    34px (44px ở mật độ thoáng) của --thumb.

    Ở lưới, ảnh chỉ để nhận ra dòng nào là dòng nào giữa hai mươi dòng — nhỏ là đúng. Ở panel
    thì nó là tấm ảnh DUY NHẤT của món hàng đang xem, và người dùng đọc nó để đối chiếu với
    thứ đang cầm trên tay. Đặt trên .dt-sp chứ không riêng .dt-sp--link: dòng của người không
    có quyền mở /san-pham cũng là cùng một dòng hàng, không có cớ gì ảnh lại nhỏ hơn.  */
.dt-sp .thumb { width: 59px; height: 59px; }
.dt-sp + .dt-sp { margin-top: 5px; }
.dt-sp:last-child { border-bottom: 0; }
.dt-sp__n { flex: 1; min-width: 0; font-size: 13px; line-height: 1.4; }
.dt-sp__q { font-family: var(--f-mono); font-variant-numeric: tabular-nums; font-size: 12.5px; white-space: nowrap; text-align: right; }

.dt-tong { display: grid; grid-template-columns: 1fr auto; gap: 3px 10px; font-size: 13px; }
.dt-tong .v { font-family: var(--f-mono); font-variant-numeric: tabular-nums; text-align: right; }
.dt-tong .tt { font-weight: 700; font-size: 17px; color: var(--c-accent); padding-top: 4px; }
.dt-tong .tt-l { font-weight: 650; padding-top: 4px; }

/* --- dòng thời gian hành trình giao hàng --- */
.tline { list-style: none; margin: 0; padding: 0 0 0 16px; position: relative; }
.tline::before {
  content: ""; position: absolute; left: 4px; top: 6px; bottom: 6px;
  width: 2px; background: var(--c-rule); border-radius: 1px;
}
.tline__i { position: relative; padding: 5px 0 7px; }
.tline__i + .tline__i { border-top: 1px dashed var(--c-rule-soft); margin-top: 5px; }
.tline__i::before {
  content: ""; position: absolute; left: -16px; top: 10px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--c-surface); border: 2px solid var(--c-rule);
}
/* Chấm mốc của từng bước — chín bậc của thang màu trạng thái, xem Data/NhanTrangThai.cs.

   [SỬA 17/08/2026] Trước đây chỉ có ok và crit, mà BuocGiaoHang.Lop cũng chỉ sinh ra hai lớp
   đó cộng chuỗi rỗng: 24 tên trạng thái "đang chạy" (hơn 2.000 đơn — "Kiện đến", "Xuất kho
   trung chuyển", "Đang giao hàng"…) đều rơi vào chuỗi rỗng, nên cả hành trình là một cột chấm
   trắng viền xám không đọc được gì. Nay mỗi bước mang màu theo nghĩa của chính nó. */
.tline__i[data-r="ok"]::before   { border-color: var(--c-ok);   background: var(--c-ok); }
.tline__i[data-r="info"]::before { border-color: var(--c-info); background: var(--c-info); }
.tline__i[data-r="warn"]::before { border-color: var(--c-warn); background: var(--c-warn); }
.tline__i[data-r="hoan"]::before { border-color: var(--c-hoan); background: var(--c-hoan); }
.tline__i[data-r="crit"]::before { border-color: var(--c-crit); background: var(--c-crit); }
.tline__i[data-r="idle"]::before { border-color: var(--c-idle); background: var(--c-idle); }
.tline__i[data-r="giao"]::before      { border-color: var(--c-giao);      background: var(--c-giao); }
.tline__i[data-r="hoan-xong"]::before { border-color: var(--c-hoan-xong); background: var(--c-hoan-xong); }
.tline__i[data-r="hoan-loi"]::before  { border-color: var(--c-hoan-loi);  background: var(--c-hoan-loi); }
/* Bước MỚI NHẤT: chỉ thêm một vòng sáng quanh chấm, KHÔNG đổi màu chấm.

   [SỬA 17/08/2026] Trước đây luật này ghi đè cả border-color và background bằng màu nhấn, nên
   bước mới nhất — đúng cái bước người ta mở panel ra để xem — là chấm duy nhất KHÔNG mang màu
   trạng thái. "Đang trả hàng" và "Giao kiện thành công" cho ra cùng một chấm xanh petrol.
   Vòng sáng đủ để nói "đây là mới nhất", còn màu vẫn dành cho trạng thái. */
.tline__i.is-moi::before { box-shadow: 0 0 0 3px var(--c-accent-wash); }
.tline__i[data-an] { display: none; }
.tline[data-mo] .tline__i[data-an] { display: block; }

.tline__t {
  font-family: var(--f-mono); font-size: 10.5px; color: var(--c-ink-3);
  font-variant-numeric: tabular-nums;
}
.tline__n { font-size: 13px; line-height: 1.4; display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.tline__i.is-moi .tline__n { font-weight: 650; color: var(--c-ink); }
/* Chữ chỉ đổi màu ở những bậc ĐÁNG DỪNG LẠI ĐỌC. Bậc info ("đang trên đường") và idle giữ
   mực thường: một hành trình 12 bước mà bước nào cũng có màu thì không bước nào nổi lên, mà
   phần lớn các bước là bậc info — tô hết là tô cả cột. Chấm mốc bên lề vẫn đủ màu cho cả
   chín bậc, nên thông tin không mất.

   [SỬA 18/08/2026] Bậc giao ("shipper đang mang tới khách") ĐƯỢC tô chữ dù cũng là bước
   đang đi: trong cả hành trình nó là bước duy nhất còn can thiệp kịp, và mỗi đơn chỉ có
   một hai bước như vậy nên không có chuyện tô cả cột. */
.tline__i[data-r="ok"]   .tline__n { color: var(--c-ok); }
.tline__i[data-r="warn"] .tline__n { color: var(--c-warn); }
.tline__i[data-r="hoan"] .tline__n { color: var(--c-hoan); }
.tline__i[data-r="crit"] .tline__n { color: var(--c-crit); }
.tline__i[data-r="giao"]      .tline__n { color: var(--c-giao); }
.tline__i[data-r="hoan-xong"] .tline__n { color: var(--c-hoan-xong); }
.tline__i[data-r="hoan-loi"]  .tline__n { color: var(--c-hoan-loi); }
.tline__ma {
  font-size: 10px; color: var(--c-ink-3); background: var(--c-surface-2);
  padding: 1px 5px; border-radius: 2px;
}
.tline__d { font-size: 11.5px; color: var(--c-ink-3); margin-top: 2px; overflow-wrap: anywhere; }

.nguoigiao {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin-top: 7px; padding: 6px 10px; font-size: 12.5px;
  background: var(--c-surface-2); border-radius: var(--radius);
  border-left: 3px solid var(--c-rule);
}
.nguoigiao a { font-weight: 650; font-size: 13.5px; }

/* panel thành tấm trượt trên thiết bị hẹp — CHỪA NGUYÊN THANH TIÊU ĐỀ phía trên.
   Trước đây để inset:0 nên tấm này che mất cả banner: người dùng không còn thấy
   mình đang ở trang nào, cũng không bấm được nút mở menu / đổi nền. */
@media (max-width: 1179px) {
  .ws__detail {
    position: fixed; inset: var(--topbar-h) 0 0 0; z-index: 60; overflow: auto;
    background: var(--c-ground); padding: 10px;
    animation: sheet .16s ease;
  }
  .ws__detail .dt-panel { min-height: 100%; }
  @keyframes sheet { from { transform: translateY(14px); opacity: 0; } }
}
/* 1101–1179px: menu trái vẫn là một cột thật, đừng để tấm chi tiết đè lên nó */
@media (min-width: 1101px) and (max-width: 1179px) {
  .ws__detail { left: var(--rail-w); }
  :root[data-menu="an"] .ws__detail { left: 0; }
}

/* --- chip lọc nhanh --- */
.chips { display: flex; gap: 5px; flex-wrap: wrap; }
.chip-f {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 11px; border-radius: 999px; font-size: 12.5px; font-weight: 550;
  border: 1px solid var(--c-rule); color: var(--c-ink-2); background: var(--c-surface);
  white-space: nowrap; transition: background .12s, border-color .12s, color .12s;
}
.chip-f:hover { border-color: var(--c-ink-3); color: var(--c-ink); text-decoration: none; }
.chip-f.is-on { background: var(--c-accent); border-color: var(--c-accent); color: var(--c-accent-ink); }
.chip-f .n { font-family: var(--f-mono); font-size: 11px; opacity: .75; }
@media (pointer: coarse) { .chip-f { padding: 8px 14px; } }

/* ---------- 10. BẢNG THẬT TRÊN MÀN HÌNH HẸP ----------
   Chỗ này trước đây là bộ thẻ (.cards / .ocard) thay cho bảng dưới 900px, kèm luật
   `@media (max-width: 900px) { .tablewrap { display: none } .cards { display: flex } }`.
   Ba màn hình danh sách sau đó được làm lại theo kiểu .rows/.row-item nên bộ thẻ
   thành mã chết — KHÔNG trang nào còn dựng .cards nữa. Nhưng luật ẩn bảng thì vẫn
   còn, nên mọi trang còn dùng bảng thật (Bảng kê giao, Nhập hàng, Cần nhập hàng,
   Người dùng) hiện ra TRẮNG TRƠN trên điện thoại — desktop vẫn bình thường nên rất
   khó phát hiện. Nay bảng luôn hiện và cuộn ngang trong khung của chính nó. */
@media (max-width: 900px) {
  .tablescroll { -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain; }
  /* Hạ bề rộng tối thiểu để bớt phải cuộn ngang; các ô số vẫn nowrap nên không vỡ.
     Dùng min() để bảng nào vốn đã hẹp hơn (bảng trong panel đặt --dt-min: 0) giữ nguyên. */
  .dt { min-width: min(var(--dt-min, 900px), 720px); }
  .dt thead th, .dt tbody td { padding-left: 8px; padding-right: 8px; }
}

/* ---------- 11. PHÂN TRANG ---------- */
.pager {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 12px; border-top: 1px solid var(--c-rule-soft);
  background: var(--c-surface-2); font-size: 12.5px;
}
.pager__info { color: var(--c-ink-2); font-family: var(--f-mono); font-size: 11.5px; font-variant-numeric: tabular-nums; }
.pager__spacer { flex: 1; }
.pager__links { display: flex; gap: 3px; align-items: center; }
.pager__links a, .pager__links span {
  min-width: 30px; height: 30px; padding: 0 8px;
  display: grid; place-items: center; border-radius: var(--radius);
  font-family: var(--f-mono); font-size: 12px; font-variant-numeric: tabular-nums;
  color: var(--c-ink-2); border: 1px solid transparent;
}
.pager__links a:hover { background: var(--c-surface); border-color: var(--c-rule); text-decoration: none; }
.pager__links [aria-current="page"] { background: var(--c-accent); color: var(--c-accent-ink); font-weight: 650; }
.pager__links .gap { color: var(--c-ink-3); min-width: 18px; padding: 0; }

/* ---------- 12. THỐNG KÊ NHANH ---------- */
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); gap: 8px; margin-bottom: 12px; }
.kpi {
  background: var(--c-surface); border: 1px solid var(--c-rule-soft);
  border-radius: var(--radius); padding: 9px 12px; box-shadow: var(--shadow-1);
  border-left: 3px solid var(--c-rule);
}
.kpi[data-tone="accent"] { border-left-color: var(--c-accent); }
.kpi[data-tone="ok"]     { border-left-color: var(--c-ok); }
.kpi[data-tone="warn"]   { border-left-color: var(--c-warn); }
.kpi[data-tone="crit"]   { border-left-color: var(--c-crit); }
.kpi__v {
  font-family: var(--f-mono); font-size: 19px; font-weight: 660;
  letter-spacing: -.03em; font-variant-numeric: tabular-nums; line-height: 1.1;
}
.kpi__k { font-size: 11px; color: var(--c-ink-3); margin-top: 2px; }

/* ---------- 13. TRẠNG THÁI RỖNG / ĐANG TẢI ---------- */
.empty { padding: 48px 20px; text-align: center; color: var(--c-ink-3); }
.empty svg { width: 36px; height: 36px; stroke-width: 1.3; margin-bottom: 10px; opacity: .5; }
.empty h3 { font-size: 14px; color: var(--c-ink-2); margin-bottom: 4px; }
.empty p { font-size: 12.5px; margin: 0; }

.topload {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 100;
  background: linear-gradient(90deg, transparent, var(--c-accent), transparent);
  background-size: 40% 100%; background-repeat: no-repeat;
  animation: slide 1s linear infinite;
}
@keyframes slide { 0% { background-position: -40% 0; } 100% { background-position: 140% 0; } }
/* Làm mờ nhẹ vùng đang chờ dữ liệu, KHÔNG che — người dùng vẫn đọc được số cũ */
.htmx-request .dt tbody { opacity: .5; transition: opacity .12s; }

/* ---------- 14. THÔNG BÁO ---------- */
.toasts { position: fixed; bottom: 14px; right: 14px; z-index: 90; display: flex; flex-direction: column; gap: 7px; }
.toast {
  background: var(--c-surface); border: 1px solid var(--c-rule);
  border-left: 3px solid var(--c-ok);
  border-radius: var(--radius); box-shadow: var(--shadow-2);
  padding: 9px 13px; font-size: 13px; min-width: 210px; max-width: 340px;
  animation: pop .18s ease;
}
.toast[data-tone="crit"] { border-left-color: var(--c-crit); }
.toast[data-tone="warn"] { border-left-color: var(--c-warn); }
@keyframes pop { from { opacity: 0; transform: translateY(6px); } }
@media (max-width: 620px) { .toasts { left: 10px; right: 10px; bottom: 10px; } .toast { max-width: none; } }

/* ---------- 14b. HỘP THOẠI TRONG TRANG ----------
   Thay confirm()/prompt() của trình duyệt (xem app.js §Hộp thoại).
   Dùng <dialog> nên tiêu điểm bị khoá trong hộp và phím Esc chạy sẵn. */
.hop {
  border: 1px solid var(--c-rule); border-radius: var(--radius);
  background: var(--c-surface); color: var(--c-ink);
  box-shadow: var(--shadow-3);
  padding: 0; width: min(440px, calc(100vw - 24px)); max-width: none;
  font-size: var(--fs-base);
}
.hop::backdrop { background: rgba(19, 26, 31, .48); }
.hop[open] { animation: hop-vao .14s ease; }
@keyframes hop-vao { from { opacity: 0; transform: translateY(-6px) scale(.99); } }
.hop__than { padding: 16px 18px 4px; display: flex; flex-direction: column; gap: 10px; }
/* Thuộc tính hidden chỉ là display:none của trình duyệt, nên mọi display tường minh
   đều thắng nó. .hop__o kế thừa .field{display:flex} → hộp chỉ-hỏi vẫn hiện một ô
   nhập trống. Phải nói lại cho rõ, cho cả ô nhập lẫn nhãn và dòng báo lỗi. */
/* (luật [hidden] toàn cục nằm ở §3 RESET, không cần lặp riêng cho hộp thoại nữa) */
.hop__tieu { font-size: 15px; font-weight: 600; margin: 0; }
/* pre-line: câu hỏi có ký tự xuống dòng, giữ nguyên cách ngắt dòng đã viết */
.hop__loi { margin: 0; color: var(--c-ink-2); line-height: 1.5; white-space: pre-line; }
.hop__o { gap: 4px; }
.hop__o .input { min-height: 34px; font-size: 15px; }   /* gõ được bằng ngón tay */
.hop__sai {
  margin: 0; font-size: 13px; color: var(--c-crit);
  background: var(--c-crit-wash); border-radius: var(--radius-sm); padding: 6px 9px;
}
.hop__nut { display: flex; justify-content: flex-end; gap: 8px; padding: 14px 18px 16px; }
@media (max-width: 480px) {
  .hop { width: calc(100vw - 20px); }
  .hop__nut { flex-direction: column-reverse; }
  .hop__nut .btn { width: 100%; min-height: 38px; justify-content: center; }
}

/* ---------- 14c. Ô ĐẾM CÓ NÚT TĂNG/GIẢM ---------- */
.dem { display: flex; align-items: stretch; gap: 0; min-width: 0; }
.dem input {
  flex: 1 1 auto; min-width: 0; text-align: center;
  border-radius: 0; border-left-width: 0; border-right-width: 0;
}
.dem__nut {
  flex: none; width: 30px; min-height: 32px;
  display: flex; align-items: center; justify-content: center;
  font-size: 16px; line-height: 1; font-weight: 600;
  background: var(--c-surface-2); color: var(--c-ink);
  border: 1px solid var(--c-rule); cursor: pointer;
  user-select: none; -webkit-user-select: none;
}
.dem__nut:first-child { border-radius: var(--radius) 0 0 var(--radius); }
.dem__nut:last-child  { border-radius: 0 var(--radius) var(--radius) 0; }
.dem__nut:hover { background: var(--c-surface-3); border-color: var(--c-ink-3); }
.dem__nut:active { transform: translateY(.5px); }
/* Bỏ mũi tên nhỏ xíu của trình duyệt: đã có hai nút to hơn ngay cạnh */
.dem input::-webkit-outer-spin-button,
.dem input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.dem input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
@media (max-width: 620px) { .dem__nut { width: 38px; min-height: 38px; } }

/* ---------- 14d. GỢI Ý SỐ ĐIỆN THOẠI (ô tra cứu /telesale) ---------- */
.goiy { position: relative; }
.goiy__dd {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 40; margin-top: 3px;
  max-height: 300px; overflow-y: auto;
  background: var(--c-surface); border: 1px solid var(--c-rule);
  border-radius: var(--radius); box-shadow: var(--shadow-2);
}
.goiy__m { padding: 6px 10px; cursor: pointer; border-bottom: 1px solid var(--c-rule-soft); }
.goiy__m:last-child { border-bottom: 0; }
.goiy__m:hover, .goiy__m[aria-selected] { background: var(--c-accent-wash); }
.goiy__so { font-size: 14px; letter-spacing: .2px; }
.goiy__so mark {
  background: var(--c-warn-wash); color: var(--c-ink);
  font-weight: 700; border-radius: 2px; padding: 0 1px;
}
.goiy__phu { font-size: 12px; color: var(--c-ink-3); margin-top: 1px; }
.goiy__trong { padding: 8px 10px; font-size: 12.5px; color: var(--c-ink-3); }

/* ---------- 14f. MÀU CHỦ ĐẠO THEO MÀN HÌNH ----------
   Ba màn hình làm việc chính có ba nhóm người ngồi cả ngày trên đó. Đổi màu NHẤN theo
   trang để liếc mắt là biết mình đang ở đâu — chỉ màu nhấn, còn nền/chữ/khung giữ nguyên,
   nếu không thì thành ba ứng dụng khác nhau.

   Đặt trên <body data-trang="…">, sau mọi khối token nên nó ghi đè được cả ba chế độ
   (sáng, tối theo hệ, tối do người chọn). Bản tối phải sáng màu hơn hẳn: cùng một mã màu
   trên nền #0D1317 thì tối thui, bấm vào không biết có gì. */
/* Xanh LÁ CỎ (hue 125°), không phải xanh lục-lam. Hai khoảng cách phải giữ, và cả hai đều
   đã đo chứ không ước lượng bằng mắt:

     · Cách xanh petrol của /don-hang (hue 190°) 65° — đủ xa để liếc mắt là biết đang ở
       trang nào, đúng lý do bảng màu theo trang này tồn tại.
     · Cách --c-ok (hue 158°) 33°. Đây mới là khoảng cách khó: MỖI dòng lead trên trang này
       mang một badge "Thành công" tô bằng --c-ok, nên nếu màu nhấn cũng là xanh lục-lam thì
       nút bấm, mục menu đang mở và nhãn "Thành công" hoà làm một — màu hết mang nghĩa.
       Nghiêng hẳn về phía cỏ (vàng hơn) là cách giữ cho --c-ok còn nói được điều của nó.

   Tương phản trên nền trắng 6,21:1 (bản xanh dương cũ 7,52; --c-ok 6,44) — chữ trắng trên
   nút vẫn đọc tốt ở mức AA cho cả chữ thường. */
body[data-trang="telesale"] {
  --c-accent:      #2C6E31;   --c-accent-hi: #37853D;   --c-accent-wash: #E2F0E3;
}
body[data-trang="cham-soc"] {
  --c-accent:      #9C4A1B;   --c-accent-hi: #B25720;   --c-accent-wash: #FAEAE0;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) body[data-trang="telesale"] {
    --c-accent: #74C86A; --c-accent-hi: #8CD483; --c-accent-wash: #15291A; --c-accent-ink: #08210C;
  }
  :root:not([data-theme="light"]) body[data-trang="cham-soc"] {
    --c-accent: #E09A63;  --c-accent-hi: #EFAF7C;  --c-accent-wash: #33210F;  --c-accent-ink: #2A1808;
  }
}
:root[data-theme="dark"] body[data-trang="telesale"] {
  --c-accent: #74C86A; --c-accent-hi: #8CD483; --c-accent-wash: #15291A; --c-accent-ink: #08210C;
}
:root[data-theme="dark"] body[data-trang="cham-soc"] {
  --c-accent: #E09A63;  --c-accent-hi: #EFAF7C;  --c-accent-wash: #33210F;  --c-accent-ink: #2A1808;
}

/* ---------- 14f-bis. DANH SÁCH LOẠI TRẠNG THÁI ĐƠN (/cham-soc) ----------
   Vừa là danh sách bấm được vừa là biểu đồ ngang — một thứ, không phải hai. Tách làm hai
   khối riêng thì người dùng phải đối chiếu bằng mắt giữa cái bảng và cái biểu đồ, mà chúng
   nói đúng cùng một điều.

   Thay cho ô <select> cũ: ô sổ xuống giấu mất chính thứ đáng nhìn — trạng thái nào đang
   đông, trạng thái nào đang có sự cố — và bắt bấm hai lần mới đọc được một con số. */
.tt-card { margin-bottom: 12px; }
.tt-card .card__body { padding-top: 8px; padding-bottom: 8px; }

/* Cao tối đa ~9 dòng rồi cuộn: danh sách trạng thái của một hãng có thể tới vài chục dòng,
   mà phần việc chính của màn hình là cái bảng bên dưới — không để danh sách đẩy nó ra khỏi
   màn hình. */
.tt-list { display: flex; flex-direction: column; gap: 1px; max-height: 340px; overflow-y: auto; }

.tt-nhom {
  display: flex; align-items: baseline; gap: 10px;
  font-family: var(--f-mono); font-size: 10px; letter-spacing: .09em; text-transform: uppercase;
  color: var(--c-ink-3); margin: 8px 0 3px; padding-top: 7px; border-top: 1px solid var(--c-rule-soft);
}
/* Mốc 100% của nhóm. Hai nhóm dùng hai thang khác nhau nên con số này là thứ duy nhất giữ
   cho người đọc không so nhầm thanh của nhóm này với thanh của nhóm kia. */
.tt-nhom__moc { margin-left: auto; text-transform: none; letter-spacing: 0; opacity: .8; }

/* Dòng gộp không có thanh, phần giữa là câu giải thích ngắn thay vào chỗ đó. */
.tt-i__ghi { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tt-list > .tt-nhom:first-child { margin-top: 2px; border-top: 0; padding-top: 0; }

.tt-i {
  display: grid; grid-template-columns: minmax(0, 15em) minmax(60px, 1fr) auto 4.2em;
  gap: 10px; align-items: center;
  padding: 4px 6px; border-radius: var(--radius-sm);
  color: var(--c-ink); font-size: 12.5px; line-height: 1.3;
}
.tt-i:hover { background: var(--c-surface-2); text-decoration: none; }
.tt-i.is-on { background: var(--c-accent-wash); box-shadow: inset 2px 0 0 var(--c-accent); }
.tt-i__ten { display: flex; align-items: center; gap: 6px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tt-i__so { font-variant-numeric: tabular-nums; font-size: 12.5px; white-space: nowrap; text-align: right; }
/* Phần trăm trên TỔNG mọi trạng thái của hãng — cả cột cộng lại ra 100%. Bề rộng ghim
   4,2em và căn phải để dấu % của mọi dòng thẳng hàng, mắt chạy dọc được. */
.tt-i__pt { font-variant-numeric: tabular-nums; font-size: 11.5px; white-space: nowrap; text-align: right; }

/* Thanh: hai lớp CHỒNG LÊN nhau, không nối tiếp nhau. Lớp dưới là tổng đơn, lớp trên là
   phần cần chăm sóc — nên đọc được ngay "trạng thái này đông, nhưng phần có vấn đề chỉ
   chừng này" mà không phải trừ nhẩm. */
.tt-i__thanh { position: relative; height: 8px; border-radius: 999px; background: var(--c-surface-3); overflow: hidden; }
.tt-i__thanh i { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 999px; min-width: 2px; }
/* Màu thanh lấy đúng quy ước [data-lop] có sẵn của dự án (§ ngay dưới, dùng chung với chấm
   tròn và các nhãn khác) — chín bậc của thang màu trạng thái, xem Data/NhanTrangThai.cs.

   [SỬA 18/08/2026] Bỏ hết opacity. Thanh và chấm tròn của cùng một dòng phải ra ĐÚNG MỘT
   MÀU: hạ thanh xuống .85 (và idle xuống .55) là cố tình làm hai dấu hiệu của cùng một
   trạng thái khác nhau, ngay cạnh nhau, để so. Lý do cũ — "chừa chỗ cho kẻ sọc chồng lên" —
   hết hiệu lực từ khi lớp sọc thôi mang màu riêng (xem .khan ngay dưới). */
.tt-i__thanh i[data-lop] { opacity: 1; }

/* Lớp "cần chăm sóc" chồng lên: KHÔNG có màu nền riêng, chỉ là vân kẻ.

   Nó không mang [data-lop] nên vốn đã trong suốt; luật này viết ra để nói rõ ý định, và để
   ai đó gắn màu vào nó sau này sẽ thấy mình đang đi ngược lại một quyết định. Gắn màu vào
   đây là xoá màu trạng thái của cả thanh — xem chú thích ở ChamSoc/_TrangThai.cshtml. */
.tt-i__thanh i.khan { background-color: transparent; opacity: 1; }

/* Mục gộp "Cần chăm sóc sớm" — đây là mặc định của màn hình nên nó đứng riêng một bậc. */
.tt-i--gom { font-weight: 620; padding-top: 6px; padding-bottom: 6px; }
.tt-i--gom .tt-i__so { font-size: 14px; }

@media (max-width: 620px) {
  /* Khổ hẹp: tên trạng thái đầy đủ trên một hàng, thanh · số · phần trăm xuống hàng dưới.
     Bốn cột ở 390px chỉ chừa ~70px cho tên, mà tên trạng thái của hãng thì dài. */
  .tt-i { grid-template-columns: minmax(0, 1fr) auto 4.2em; row-gap: 3px; }
  .tt-i__ten { grid-column: 1 / -1; white-space: normal; }
}

/* ---------- 14g. GỢI Ý SẢN PHẨM (ô tìm ở /kho) ---------- */
.goiy-sp { position: relative; }
.goiy-sp__dd {
  position: absolute; top: 100%; left: 0; z-index: 40; margin-top: 3px;
  min-width: 100%; width: max-content; max-width: 420px;
  max-height: 360px; overflow-y: auto;
  background: var(--c-surface); border: 1px solid var(--c-rule);
  border-radius: var(--radius); box-shadow: var(--shadow-2);
}
.goiy-sp__m {
  display: flex; align-items: center; gap: 8px; padding: 6px 9px; cursor: pointer;
  border-bottom: 1px solid var(--c-rule-soft);
}
.goiy-sp__m:last-child { border-bottom: 0; }
.goiy-sp__m:hover, .goiy-sp__m[aria-selected] { background: var(--c-accent-wash); }
.goiy-sp__m .thumb { flex: none; }
.goiy-sp__khonganh {
  width: var(--thumb); height: var(--thumb); flex: none; border-radius: var(--radius-sm);
  background: var(--c-surface-2); border: 1px dashed var(--c-rule);
}
.goiy-sp__ten { font-size: 12.5px; line-height: 1.3; }
.goiy-sp__phu { font-size: 11.5px; color: var(--c-ink-2); font-family: var(--f-mono); margin-top: 1px; }
.goiy-sp__trong { padding: 8px 10px; font-size: 12.5px; color: var(--c-ink-3); }

/* ---------- 14e. DẢI CẢNH BÁO CỦA KHO ---------- */
.canh-bao-kho {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 12px; padding: 10px 13px;
  background: var(--c-crit-wash); color: var(--c-ink);
  border: 1px solid color-mix(in srgb, var(--c-crit) 35%, transparent);
  border-left: 3px solid var(--c-crit);
  border-radius: var(--radius); font-size: 13px;
}
.canh-bao-kho svg { width: 18px; height: 18px; flex: none; color: var(--c-crit); stroke-width: 1.9; }

/* ---------- 15. TIỆN ÍCH ---------- */
.row { display: flex; align-items: center; gap: 8px; }
.row--wrap { flex-wrap: wrap; }
/* Hai ô đúng bằng nhau, không phụ thuộc chữ bên trong dài ngắn ra sao. Dùng lưới chứ không
   dùng flex: `flex: 1` chia phần CÒN LẠI sau khi trừ nội dung, nên nút chữ dài vẫn rộng hơn. */
/* minmax(0, 1fr) chứ không phải 1fr: `1fr` là viết tắt của `minmax(auto, 1fr)`, mà nút có
   white-space:nowrap nên sàn min-content của nó bằng bề rộng nguyên câu chữ — cột chứa nút
   chữ dài bị đẩy rộng ra, đúng thứ luật này sinh ra để chặn. Ở khổ rộng không thấy vì dư
   chỗ; ở panel 325px thì lệch 32px. */
.row--2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: stretch; }
.col { display: flex; flex-direction: column; gap: 8px; }
.mono { font-family: var(--f-mono); }
.muted { color: var(--c-ink-3); }
.tiny { font-size: 11px; }
.sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.hide-sm { }
@media (max-width: 620px) { .hide-sm { display: none !important; } }

/* Bộ đếm ký tự dưới ô có maxlength (U2). Chạm trần thì đổi màu — ô ngừng nhận phím
   mà không nói gì thì người dùng tưởng bàn phím hỏng. */
.dem-kytu { font-size: 11px; color: var(--c-ink-3); margin-top: 3px; text-align: right; }
.dem-kytu[data-het="1"] { color: var(--c-warn); font-weight: 600; }

/* ---------- 15b. TAB ---------- */
/* Dải tab phải tự cuộn ngang, không được kéo rộng cả trang. Trước đây mọi trang chỉ có
   2-4 tab nên vừa màn hình điện thoại; dải 5 tab của Báo cáo làm lộ ra thiếu sót này
   (đo được 120px cuộn ngang ở khổ 390px). */
.tabs {
  display: flex; gap: 2px; padding: 2px; background: var(--c-surface-2);
  border-radius: var(--radius); min-width: 0; overflow-x: auto; scrollbar-width: thin;
}
.tabs > .tab { flex: none; }
.tab {
  display: flex; align-items: center; gap: 6px;
  padding: 5px 12px; border-radius: 3px; font-size: 12.5px; font-weight: 570;
  color: var(--c-ink-2); white-space: nowrap; transition: background .12s, color .12s;
}
.tab:hover { background: var(--c-surface); color: var(--c-ink); text-decoration: none; }
.tab.is-on { background: var(--c-surface); color: var(--c-ink); font-weight: 650; box-shadow: var(--shadow-1); }
.tabs--sm .tab { padding: 3px 9px; font-size: 11.5px; }
.dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.dot--jt { background: var(--c-jt); }
.dot--ss { background: var(--c-ss); }
/* Đơn shop tự giao: dùng ở tab nhóm của /van-chuyen và ở báo cáo shop gửi hàng. Mã màu đã có
   sẵn cho nhãn .badge--shop từ trước, chỉ thiếu đúng biến thể chấm tròn. */
.dot--shop { background: var(--c-shop); }
@media (pointer: coarse) { .tab { padding: 9px 14px; } }

/* ---------- 15c. BỐ CỤC HAI CỘT (danh sách + chi tiết) ---------- */
.splitview { display: grid; gap: 12px; align-items: start; }
/* Cột chi tiết rộng hơn cột danh sách một bậc: nội dung của nó là bảng ba cột trong đó có
   ĐỊA CHỈ giao hàng — ở 460px thì mỗi địa chỉ xuống bốn dòng và một phiên 30 đơn dài gấp
   đôi cần thiết. Danh sách phiên bên trái thì chỉ có mã, ngày và vài con số nên nhường
   được. Nới thêm một bậc ở màn hình rộng thay vì cho một giá trị lớn ở mọi nơi: 1250px là
   ngưỡng vừa đủ chia đôi, ép 720px vào đó là bóp danh sách xuống còn nửa. */
@media (min-width: 1250px) {
  .splitview:has(.splitview__side) { grid-template-columns: minmax(0, 1fr) minmax(440px, 560px); }
}
@media (min-width: 1600px) {
  .splitview:has(.splitview__side) { grid-template-columns: minmax(0, 1fr) minmax(560px, 720px); }
}
.splitview__main, .splitview__side { min-width: 0; }
@media (min-width: 1250px) {
  .splitview__side { position: sticky; top: calc(var(--topbar-h) + 12px); max-height: calc(100vh - var(--topbar-h) - 24px); overflow: auto; }
}
.dt tbody tr.is-open { background: var(--c-accent-wash); box-shadow: inset 3px 0 0 var(--c-accent); }

/* Bảng soạn hàng của tab "Xuất kho" (/bang-ke). Ô tick là sổ tay của người soạn, không
   phải dữ liệu — không có gì gửi lên máy chủ. Dòng đã lấy phải đọc ra là ĐÃ XONG chỉ bằng
   liếc mắt, nên vừa mờ vừa gạch tên: người soạn cầm điện thoại đi giữa kệ hàng, họ không
   dò từng ô tick nhỏ. */
/* Ô tick to đúng bằng hình sản phẩm cùng dòng: cả hai lấy chung --thumb, nên đổi mật độ
   hiển thị (34px ↔ 44px) là chúng đi cùng nhau, không phải sửa hai chỗ. Người soạn hàng
   cầm điện thoại một tay, tay kia bê hàng — ô 17px là ô bấm trượt. */
.soanhang__o { text-align: center; width: calc(var(--thumb) + 22px); }
/* Tự vẽ chứ không dùng ô tick mặc định: phóng ô mặc định lên 44px thì ở nền tối nó mất
   viền và thành một khối xám đặc — "chưa lấy" trông y như "đã lấy tô màu khác". Vẽ tay
   thì trạng thái chưa tick là một Ô RỖNG có viền, đúng thứ người soạn hàng cần đọc lướt. */
.soanhang__o input {
  appearance: none; -webkit-appearance: none;
  width: var(--thumb); height: var(--thumb); margin: 0;
  border: 2px solid var(--c-rule); border-radius: var(--radius-sm);
  background: var(--c-surface); cursor: pointer;
  display: inline-grid; place-content: center;
  transition: background .12s, border-color .12s;
  /* Dấu tick đo bằng em, không bằng %: ::after là ô lưới duy nhất nên track của nó không
     có kích thước xác định, và % rơi về gần 0 — dấu tick teo thành một chấm. Neo vào
     font-size thì nó vẫn co giãn theo --thumb mà không phụ thuộc cách lưới đo track. */
  font-size: calc(var(--thumb) / 2.6);
}
.soanhang__o input:hover { border-color: var(--c-ok); }
.soanhang__o input:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }
.soanhang__o input:checked { background: var(--c-ok); border-color: var(--c-ok); }
/* Dấu tick vẽ bằng hai cạnh của một hình vuông xoay 45° — không cần phông chữ hay ảnh. */
.soanhang__o input::after {
  content: ""; width: .5em; height: .95em; margin-top: -.15em;
  border: solid var(--c-surface); border-width: 0 .18em .18em 0;
  transform: rotate(45deg); opacity: 0;
}
.soanhang__o input:checked::after { opacity: 1; }
/*  Lưới phiên bảng kê — cột Thao tác mang màu hãng.

    Dùng đúng hai biến của .dot--jt / .dot--ss (--c-jt, --c-ss) chứ không đặt màu mới: hai tab
    J&T và SuperShip đã nhận diện bằng cặp màu ấy ở khắp hệ thống, và bấm nhầm hãng ở cột này
    là gửi cả bảng kê đi sai chỗ. Nút chính giữ nguyên nền của nó, chỉ đổi màu chữ và viền —
    tô nền cả cột thì cột thao tác lấn át phần dữ liệu bên trái.  */
.bk-thaotac--jt { --c-hang: var(--c-jt); }
.bk-thaotac--ss { --c-hang: var(--c-ss); }
.bk-thaotac .btn { color: var(--c-hang); border-color: color-mix(in srgb, var(--c-hang) 40%, transparent); }
.bk-thaotac .btn:hover { border-color: var(--c-hang); background: color-mix(in srgb, var(--c-hang) 10%, transparent); }
.bk-thaotac .btn--primary { background: var(--c-hang); border-color: var(--c-hang); color: #fff; }
.bk-thaotac .btn--primary:hover { background: color-mix(in srgb, var(--c-hang) 85%, #000); color: #fff; }

/* Cả dòng phiên bấm được để mở danh sách đơn — con trỏ và nền hover nói ra điều đó. */
.bk-phien__dong { cursor: pointer; }

/* Mũi tên cuối dòng: mờ sẵn để không rối mắt lúc quét danh sách, rõ hẳn khi rê chuột và ở
   dòng đang mở — cùng nếp với nút sửa/xoá mờ sẵn ở lưới /don-hang. */
.bk-phien__mui { width: 26px; padding-left: 0; padding-right: 6px; text-align: right; }
.bk-phien__mui svg { width: 15px; height: 15px; color: var(--c-ink-3); opacity: .45; transition: opacity .12s, color .12s; }
.bk-phien__dong:hover .bk-phien__mui svg { opacity: 1; color: var(--c-accent); }
.bk-phien__dong.is-open .bk-phien__mui svg { opacity: 1; color: var(--c-accent); }
.bk-phien tbody tr.bk-phien__dong:focus-visible { outline: 2px solid var(--c-accent); outline-offset: -2px; }

/*  Bảng đơn trong panel bảng kê — [SỬA 20/08/2026, chủ dự án chốt] ba cột thay cho bốn.

    Ô tick vào chung ô với mã đơn: một cột 34px chỉ để chứa hình vuông là 34px lấy mất của địa
    chỉ, trong một panel vốn đã hẹp. Cột giữa gom ảnh hàng + khách + địa chỉ, và ba tầng chữ ở
    đó mang ba màu khác nhau theo thứ tự dùng tới — trước đây cùng một sắc nên phải đọc mới
    phân biệt được đâu là tên, đâu là địa chỉ.  */
.bk-don__ma { display: flex; align-items: center; gap: 6px; }
.bk-don__ma input[type="checkbox"] { flex: none; margin: 0; }
.bk-don__ma-nhap { display: flex; gap: 4px; margin-top: 3px; }
.bk-don__ma-nhap .input { width: 100px; }

/*  Địa chỉ ở bảng này KHÔNG giới hạn bề ngang — chủ dự án chốt 20/08/2026.

    .cell-addr dùng chung đặt max-width: 34ch, hợp cho lưới /don-hang nơi địa chỉ chỉ là một
    cột trong tám. Ở đây nó là NỘI DUNG CHÍNH của cột giữa và là thứ người trực đọc để xếp
    kiện; cắt ở 34ch nghĩa là xuống dòng sớm và bỏ trống nửa cột. Bỏ trần trong phạm vi
    .bk-don thôi, không đụng các màn hình khác. */
.bk-don .cell-addr { max-width: none; }

/* Ảnh xếp chồng nhau một nửa: ba tấm chỉ tốn chỗ của hai, mà vẫn đếm được bằng mắt.
   Nằm ở cột "Đơn" (dưới mã vận đơn) nên cách phần trên một nhịp. */
.bk-don__anh { display: flex; padding-left: 9px; margin-top: 5px; }
.bk-don__anh .thumb { width: 38px; height: 38px; margin-left: -9px; border-width: 2px; background: var(--c-surface); }
.bk-don__anh .thumb:hover { position: relative; z-index: 2; }
.bk-don__them {
  align-self: center; margin-left: 3px; font-size: 11px; font-weight: 600;
  color: var(--c-ink-3); font-family: var(--f-mono);
}

/* Số điện thoại là thứ hay dùng nhất ở đây (gọi khách trước khi giao) nên mang màu nhấn. */
.bk-don__dt { color: var(--c-accent); text-decoration: none; }
.bk-don__dt:hover { text-decoration: underline; }

/* Tỉnh đứng đầu dòng địa chỉ: xếp kiện lên xe là xếp theo tỉnh, nên nó phải quét mắt ra được
   mà không phải đọc hết dòng. */
.bk-don__tinh { margin-right: 4px; vertical-align: baseline; }

/* Người lên đơn đứng cuối cụm tiền — cùng cột nên phải canh phải như mọi con số ở đó. */
.bk-don__nv { text-align: right; margin-top: 3px; }

/*  Mỗi món hàng một dòng — partial _TenSanPham.

    DH_List.SanPham gộp mọi món vào một chuỗi, in nguyên ra là hai tên hàng dính liền thành một
    câu dài. Món thứ hai trở đi lùi vào một nhịp để nhìn ra ngay đây là một danh sách, không
    phải một câu bị xuống dòng. */
.sp-dong + .sp-dong { margin-top: 2px; }
.sp-dong:not(:only-child) { padding-left: 8px; text-indent: -8px; }

/*  Ghi chú của đơn — thứ NỔI BẬT NHẤT trong dòng.

    Đây là câu người lên đơn dặn kho ("gọi trước khi giao", "không cho xem hàng"). Đọc sót nó
    là gói hàng đi sai cách rồi quay đầu, mất cả tiền ship hai chiều lẫn một khách. Nên nó
    không đi chung kiểu chữ với tên hàng: nền hổ phách, vạch màu bên trái, chữ đậm và to hơn
    một nhịp so với .cell-sub xung quanh.

    Không dùng .alert: khối đó có padding của một hộp thông báo cả trang, đặt trong ô bảng thì
    đẩy chiều cao dòng lên gấp đôi. */
.bk-don__ghichu {
  display: flex; align-items: flex-start; gap: 5px;
  margin-top: 5px; padding: 4px 7px;
  background: var(--c-warn-wash); color: var(--c-warn);
  border-left: 3px solid var(--c-warn); border-radius: var(--radius-sm);
  font-size: 12px; font-weight: 600; line-height: 1.35;
}
.bk-don__ghichu svg { width: 14px; height: 14px; flex: none; margin-top: 1px; }

/* Cả dòng bấm được để tick "đã lấy" — con trỏ và nền hover phải nói ra điều đó, nếu không
   người dùng vẫn nhắm vào mỗi ô vuông 34px. */
.soanhang__dong { cursor: pointer; }
.soanhang tbody tr.soanhang__dong:hover { background: var(--c-surface-2); }
.soanhang tbody tr.soanhang__dong:focus-visible { outline: 2px solid var(--c-accent); outline-offset: -2px; }
.soanhang tbody tr.da-lay { opacity: .5; }
.soanhang tbody tr.da-lay td:nth-child(2) { text-decoration: line-through; }
/* Trừ nút "Xem web": dấu gạch ở đây nói "món này đã lấy khỏi kệ", không nói link đã hỏng —
   mà một link gạch ngang thì đọc đúng như thế. */
.soanhang tbody tr.da-lay td:nth-child(2) [data-xem-web] { text-decoration: none; }
/* Dòng thiếu hàng đã lấy vẫn phải nổi: nó là thứ người soạn cần báo lại, tick hay không. */
.soanhang tbody tr.da-lay[data-flag="crit"] { opacity: .72; }

/* ---------- 16. FORM LÊN ĐƠN ---------- */
.lendon__grid { display: grid; gap: 12px; align-items: start; }
@media (min-width: 1150px) { .lendon__grid { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); } }

/* nhóm nút chọn kiểu radio — thay cho radio rời rạc của bản cũ */
.segbar { display: flex; flex-wrap: wrap; gap: 0; border: 1px solid var(--c-rule); border-radius: var(--radius); overflow: hidden; width: fit-content; max-width: 100%; }
.segbar label { position: relative; flex: 0 0 auto; }
.segbar input { position: absolute; opacity: 0; pointer-events: none; }
.segbar span {
  display: block; padding: 7px 13px; font-size: 12.5px; font-weight: 550;
  color: var(--c-ink-2); cursor: pointer; white-space: nowrap;
  border-right: 1px solid var(--c-rule); transition: background .12s, color .12s;
}
.segbar label:last-child span { border-right: 0; }
.segbar span:hover { background: var(--c-surface-2); }
.segbar input:checked + span { background: var(--c-accent); color: var(--c-accent-ink); }
.segbar input:focus-visible + span { outline: 2px solid var(--c-accent-hi); outline-offset: -2px; }
@media (pointer: coarse) { .segbar span { padding: 11px 15px; font-size: 13.5px; } }

/* Biến thể LƯỚI: từ bốn lựa chọn trở lên, một dải ngang liền mạch hoặc bị tràn ra ngoài,
   hoặc xuống dòng thành hình răng cưa. Xếp thành cột đều nhau thì mắt quét được cả cụm.
   Số cột đặt bằng --cot ở chỗ dùng, vì nó phụ thuộc độ dài nhãn chứ không phải quy tắc chung.

   Ở đây mỗi ô là một thẻ riêng (có viền, bo góc, cách nhau bằng gap) chứ không phải một
   đoạn của dải liền — nên phải trả lại viền phải mà .segbar đã bỏ cho ô cuối. */
.segbar--luoi {
  display: grid; grid-template-columns: repeat(var(--cot, 2), minmax(0, 1fr));
  gap: 6px; width: 100%; border: 0; border-radius: 0; overflow: visible;
}
.segbar--luoi span,
.segbar--luoi label:last-child span {
  border: 1px solid var(--c-rule); border-radius: var(--radius-sm);
  padding: 8px 10px; white-space: normal; line-height: 1.3;
}
/* Ô đang chọn: nền bạc hà, viền và chữ xanh lá đậm hơn — do chủ dự án chọn, cùng tông với
   màu nhấn xanh lá của /telesale.

   Nền là màu CỐ ĐỊNH, không đổi theo chế độ sáng/tối, nên màu chữ cũng phải cố định:
   để var(--c-ink) thì ở nền tối chữ thành gần trắng nằm trên nền bạc hà, không đọc nổi.

   Chữ #007A48 trên nền #C1F7E1 cho tương phản 4,55:1 — vừa qua mức 4,5:1 mà chữ cỡ 12,5px
   cần. Bản đầu chọn #00854F, đo ra 3,95:1; đậm thêm một nấc là đủ mức mà nhìn gần như
   không khác. Đậm thêm nữa thì có #007041 (5,20:1) nếu sau này thấy vẫn nhạt. */
.segbar--luoi input:checked + span {
  background: #C1F7E1; border-color: #92DDBF;
  color: #007A48; font-weight: 650;
}
/* Một mục "nóng" trong cụm: mục đóng khách lại, không cùng loại với năm mục còn lại.
   Cùng cách tô nhưng đổi sang tông ấm để không bấm nhầm — xem data-nong ở _HoSo.cshtml.

   Phải so GIÁ TRỊ chứ không chỉ hỏi "có thuộc tính không": Razor dựng `data-nong="@(… : null)"`
   thành `data-nong=""` cho MỌI ô chứ không bỏ hẳn thuộc tính, nên `[data-nong]` khớp cả cụm
   và ô nào được chọn cũng hoá màu nóng. */
.segbar--luoi input[data-nong="1"]:checked + span {
  background: #FFDCD2; border-color: #FFB9A6; color: #6B1D10;
}
@media (pointer: coarse) { .segbar--luoi span { padding: 10px 11px; } }

/* Số cột theo bề rộng PANEL, không theo bề rộng cửa sổ: panel co giãn theo bố cục hai cột
   nên cùng một cửa sổ có thể cho panel rộng hay hẹp khác nhau. data-cot là số cột MONG MUỐN
   khi rộng rãi; hẹp dần thì bậc xuống 2 rồi 1. */
.segbar--luoi { --cot: 1; }
@container dtpanel (min-width: 340px) { .segbar--luoi { --cot: 2; } }
@container dtpanel (min-width: 560px) {
  .segbar--luoi[data-cot="3"] { --cot: 3; }
  .segbar--luoi[data-cot="4"] { --cot: 4; }
}

/* --- một dòng sản phẩm ---
   Xếp lưới theo vùng đặt tên để bố cục nói rõ thứ tự đọc:
   số thứ tự · ảnh · tên sản phẩm (+ nhãn tồn/ưu đãi) · cụm tiền · nút xóa.
   Ở khổ điện thoại cụm tiền tụt xuống hàng dưới, chiếm hết bề ngang. */
.sprow {
  display: grid; gap: 8px 10px; align-items: center;
  grid-template-columns: minmax(0, 1fr) auto auto;
  grid-template-areas: "sp tien xoa";
  padding: 9px 11px; background: var(--c-surface-2);
  border: 1px solid var(--c-rule-soft); border-radius: var(--radius);
  transition: border-color .12s, background .12s;
}
/* Dòng ở trang lên đơn có số thứ tự + ảnh; dòng phiếu nhập chỉ có ảnh. Dùng :has() để mỗi
   bên chỉ nhận đúng số cột nó cần, không bên nào thừa một cột rỗng kèm khoảng hở. */
.sprow:has(.sprow__stt) {
  grid-template-columns: auto auto minmax(0, 1fr) auto auto;
  grid-template-areas: "stt anh sp tien xoa";
}
.sprow:has(.sprow__anh):not(:has(.sprow__stt)) {
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  grid-template-areas: "anh sp tien xoa";
}
.sprow:focus-within { border-color: var(--c-accent); background: var(--c-surface); }
.sprow.is-trong { border-style: dashed; }        /* chưa chọn sản phẩm */

.sprow__stt {
  grid-area: stt; width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--c-accent); color: var(--c-accent-ink);
  font-family: var(--f-mono); font-size: 11px; font-weight: 700;
}
.sprow.is-trong .sprow__stt { background: var(--c-rule); color: var(--c-ink-3); }

.sprow__anh {
  grid-area: anh; width: 42px; height: 42px; flex: none;
  border: 1px solid var(--c-rule-soft); border-radius: var(--radius);
  background: var(--c-surface); overflow: hidden;
}
.sprow__anh:empty { border-style: dashed; }
.sprow__anh img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sprow__anh a { display: block; width: 100%; height: 100%; }
.badge--link { color: var(--c-accent); background: var(--c-accent-wash); text-decoration: none; }
.badge--link:hover { text-decoration: underline; }

.sprow__sp  { grid-area: sp; min-width: 0; }
.sprow__tien { grid-area: tien; }
.sprow__xoa { grid-area: xoa; }
.sprow__ton { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }
.sprow__ton:empty { display: none; }
.sprow__tt {
  font-family: var(--f-mono); font-variant-numeric: tabular-nums; font-weight: 650;
  min-height: 32px; display: flex; align-items: center; justify-content: flex-end;
  padding-right: 3px; font-size: 13px;
}

/* Cụm tiền (Giá · SL · Thành tiền) — đóng khung riêng để tách khỏi ô chọn sản phẩm.
   Tiêu đề và ô nhập đều canh phải: mắt dò theo mép phải của cột số, đúng thói quen
   đọc số tiền, và ba dòng sản phẩm xếp chồng lên nhau thì các số thẳng hàng. */
.sprow__tien {
  display: flex; gap: 8px; align-items: flex-start; flex: 0 0 auto;
  padding: 5px 8px; border: 1px solid var(--c-rule); border-radius: var(--radius);
  background: var(--c-surface);
}
.sprow__tien .field__label { text-align: right; white-space: nowrap; }
.sprow__tien .input { text-align: right; }
/* Bỏ nút tăng/giảm của input number: nó chiếm chỗ bên phải làm số canh phải bị lệch. */
.sprow__tien input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
.sprow__tien input[type="number"]::-webkit-inner-spin-button,
.sprow__tien input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
/* Bề rộng phải đặt cứng: để "auto" thì ô nhập number đóng góp bề rộng mặc định
   của nó (~200px) vào phép tính co giãn và cột Giá phình ra gấp đôi cần thiết. */
.sprow__tien .sprow__n--gia { flex: 0 0 100px; }
.sprow__tien .sprow__n--gia-rong { flex: 0 0 116px; }  /* chỗ cho nhãn "Giá nhập (nghìn)" */
/* 112px chứ không 60px như trước: ô SL nay có hai nút tăng/giảm hai bên (mục 14c) */
.sprow__tien .sprow__n--sl  { flex: 0 0 112px; }
.sprow__tien .sprow__n--tt  { flex: 0 0 96px; }
/* Nhãn giảm giá mua nhiều, nằm ngay dưới thành tiền của từng dòng */
.sprow__km { font-size: 11px; line-height: 1.3; color: var(--c-ink-3); margin-top: 2px; text-align: right; }
.sprow__km[data-tone="ok"] { color: var(--c-ok); font-weight: 600; }
@media (pointer: coarse) { .sprow__tien .sprow__tt { min-height: 40px; } }

@media (max-width: 620px) {
  .sprow {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "sp  xoa"
                         "tien tien";
  }
  .sprow:has(.sprow__stt) {
    grid-template-columns: auto auto minmax(0, 1fr) auto;
    grid-template-areas: "stt anh sp  xoa"
                         "tien tien tien tien";
  }
  .sprow:has(.sprow__anh):not(:has(.sprow__stt)) {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: "anh sp  xoa"
                         "tien tien tien";
  }
  .sprow__tien .sprow__n--gia,
  .sprow__tien .sprow__n--tt { flex: 1 1 0; min-width: 0; }
}

.tinh-tien {
  padding: 10px 12px; border-radius: var(--radius);
  background: var(--c-accent-wash); border: 1px solid color-mix(in srgb, var(--c-accent) 22%, transparent);
}
.tong-tien {
  font-family: var(--f-mono); font-size: 25px; font-weight: 680;
  letter-spacing: -.035em; color: var(--c-accent); font-variant-numeric: tabular-nums; line-height: 1.1;
}

/* Bảng cộng tiền: mỗi khoản một dòng nhãn — số, để người lên đơn dò được vì sao ra tổng đó */
.tt-dong { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: 30px; }
.tt-nhan { font-size: 13px; color: var(--c-ink-2); min-width: 0; }
.tt-so {
  display: flex; align-items: center; gap: 6px;
  font-family: var(--f-mono); font-variant-numeric: tabular-nums; font-size: 13.5px; font-weight: 600;
}
.tt-o { width: 78px; min-height: 28px; padding: 3px 8px; text-align: right; }
.tt-o[readonly] { opacity: .5; cursor: not-allowed; }
.tt-o[type="number"] { -moz-appearance: textfield; appearance: textfield; }
.tt-o[type="number"]::-webkit-inner-spin-button,
.tt-o[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.tt-dv { font-size: 11px; color: var(--c-ink-3); font-family: var(--f-sans); font-weight: 400; }
.tt-vi-sao { font-size: 12px; line-height: 1.4; color: var(--c-ink-3); padding-bottom: 6px; }
.tt-vi-sao[data-tone="ok"] { color: var(--c-ok); font-weight: 550; }
.tt-dong--cuoi {
  margin-top: 2px; padding-top: 7px;
  border-top: 1px solid color-mix(in srgb, var(--c-accent) 26%, transparent);
}

/* cảnh báo khách đã có đơn */
.khachcu {
  border: 1px solid var(--c-warn); background: var(--c-warn-wash);
  border-radius: var(--radius); padding: 8px 10px;
}
.khachcu__h { font-size: 12px; font-weight: 650; color: var(--c-warn); margin-bottom: 5px; }
.khachcu .hist__row { background: var(--c-surface); margin-bottom: 2px; padding: 3px 7px; }
.khachcu--moi { border-color: var(--c-ok); background: var(--c-ok-wash); color: var(--c-ok); font-size: 12.5px; font-weight: 550; }

/* ---------- 16b. TELESALE ---------- */

/* hành trình duyệt web của khách */
.hanhtrinh__list {
  list-style: none; margin: 0; padding: 0;
  display: flex; gap: 5px; overflow-x: auto; padding-bottom: 4px;
}
.hanhtrinh__list li {
  flex: 0 0 auto; min-width: 74px; text-align: center;
  border: 1px solid var(--c-rule); border-radius: var(--radius);
  padding: 5px 7px; background: var(--c-surface);
  position: relative;
}
.hanhtrinh__list li + li::before {
  content: "›"; position: absolute; left: -6px; top: 50%; transform: translateY(-50%);
  color: var(--c-ink-3); font-size: 12px;
}
.hanhtrinh__list li.is-ads { border-color: var(--c-crit); background: var(--c-crit-wash); }
.hanhtrinh__nhan { display: block; font-family: var(--f-mono); font-size: 10px; font-weight: 650; letter-spacing: .04em; }
.hanhtrinh__list li.is-ads .hanhtrinh__nhan { color: var(--c-crit); }
.hanhtrinh__giay { display: block; font-family: var(--f-mono); font-size: 12px; font-weight: 650; color: var(--c-accent); }
.hanhtrinh__gio { display: block; font-size: 9.5px; color: var(--c-ink-3); font-family: var(--f-mono); }

/* ---------- 16c. LƯỚI PHÂN QUYỀN ---------- */
.qgrid { display: grid; grid-template-columns: repeat(2, auto); gap: 2px 6px; justify-content: center; }
.qcell { display: flex; align-items: center; gap: 3px; cursor: pointer; }
.qcell span { font-size: 10.5px; color: var(--c-ink-3); }
.qcell input { margin: 0; cursor: pointer; }
.qcell input:checked + span { color: var(--c-accent); font-weight: 620; }
.qcell input:disabled { cursor: not-allowed; }
.qcell input:disabled + span { opacity: .5; }
@media (pointer: coarse) { .qcell input { width: 18px; height: 18px; } }

/* ---------- 16c-bis. NHÓM "CÙNG MỘT KHÁCH" TRONG DANH SÁCH LEAD ---------- */
/* Mấy dòng cùng một người phải đọc ra là MỘT CỤM chỉ bằng cách liếc. Hai dấu hiệu, cố ý
   thừa một chút vì đây là thứ đọc lướt: một nhãn chữ có số nhóm, và một vạch màu ở mép
   trái dòng.

   Vạch dùng màu shop (tím) — màu duy nhất trong bảng token chưa mang nghĩa nào ở màn hình
   danh sách, nên nó không đụng với bốn màu ngữ nghĩa ok/warn/crit/info đang nói về mức gấp
   của dòng. Nhóm khác nhau xoay tông bằng hue-rotate để phân biệt được cụm này với cụm kia
   mà không phải khai báo sẵn N màu. */
.nhomkh {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 0 5px; border-radius: 999px;
  background: var(--c-shop-wash); color: var(--c-shop);
  font-family: var(--f-sans); font-size: 10px; font-weight: 600;
  /* Cột trạng thái chỉ rộng 112px ở khổ hẹp nhất. Cắt bằng ba chấm thay vì để chữ chạy
     tràn ra ngoài ô rồi bị lưới xén cụt giữa chữ. */
  white-space: nowrap; vertical-align: 1px; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis;
}
.nhomkh > i {
  width: 5px; height: 5px; border-radius: 50%; background: currentColor; flex: none;
}
/* Vạch mép trái. Dòng đã có [data-flag] thì vạch đó là mức gấp — không đè lên nhau: vạch
   nhóm nằm ở ::after, lùi vào trong 3px, mảnh hơn. */
.row-item.is-nhom { position: relative; }
.row-item.is-nhom::after {
  content: ""; position: absolute; left: 3px; top: 6px; bottom: 6px; width: 2px;
  border-radius: 2px; background: var(--c-shop);
  filter: hue-rotate(calc(var(--nhom, 0) * 62deg));
}

/* ---------- 16d. GỢI Ý Ở ĐẦU MỖI MÀN HÌNH ---------- */
/* Một dòng, nền nhạt, không viền đậm: nó phải đọc được khi cần mà biến mất khỏi tầm chú ý
   khi không cần. Nằm trong luồng trang chứ không dính (sticky) — cuộn xuống làm việc thì nó
   đi khỏi màn hình, đúng như mong muốn. */
.meo {
  display: flex; align-items: center; gap: 9px;
  padding: 6px 8px 6px 11px; margin-bottom: 12px;
  border: 1px solid var(--c-rule-soft); border-radius: var(--radius);
  background: var(--c-surface); color: var(--c-ink-2);
}
:root[data-meo="an"] .meo { display: none; }
.meo__den { width: 15px; height: 15px; flex: none; stroke-width: 1.7; color: var(--c-warn); }
.meo__txt { margin: 0; min-width: 0; font-size: 12.5px; line-height: 1.45; }
.meo__txt b { color: var(--c-ink); font-weight: 620; }
.meo__mo { flex: none; margin-left: auto; white-space: nowrap; }
@media (max-width: 720px) {
  /* Khổ điện thoại: chữ gợi ý xuống dòng riêng, hai nút giữ nguyên hàng trên. */
  .meo { flex-wrap: wrap; }
  .meo__txt { order: 3; flex: 1 0 100%; }
  .meo__mo { margin-left: auto; }
}

/* --- Hộp "Cách dùng màn hình này" --- */
/* Rộng hơn hộp hỏi/đáp thường, vì đây là chữ để ĐỌC chứ không phải một câu hỏi để bấm. */
.hop--hd { max-width: min(620px, 94vw); }
.hop--hd .hop__than { max-height: min(72vh, 620px); overflow-y: auto; }
.hop-hd__dau { display: flex; align-items: flex-start; gap: 10px; }
.hop-hd__dau .hop__tieu { flex: 1; margin: 0; }
.hop-hd__tomtat { margin: 6px 0 0; font-size: 13px; color: var(--c-ink-2); }
.hop-hd__muc { margin-top: 14px; }
.hop-hd__muc h3 {
  margin: 0 0 6px; font-size: 11px; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--c-ink-3);
}
.hop-hd__muc ul { margin: 0; padding-left: 17px; display: flex; flex-direction: column; gap: 5px; }
.hop-hd__muc li { font-size: 12.5px; line-height: 1.5; color: var(--c-ink-2); }
.hop-hd__muc li b { color: var(--c-ink); }
.hop--hd .hop__nut { align-items: center; }

/* ---------- 16e. HƯỚNG DẪN NHANH (/huong-dan) ---------- */
/* Năm chặng của một đơn hàng. Đánh số thay vì vẽ mũi tên giữa các ô: ở khổ hẹp các ô xuống
   dòng, mũi tên nằm ngang khi đó chỉ sai hướng — còn con số thì đọc đúng ở mọi khổ. */
.qtr { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.qtr > li { flex: 1 1 148px; display: flex; }
.qtr a {
  flex: 1; display: flex; flex-direction: column; gap: 1px;
  padding: 9px 11px; border: 1px solid var(--c-rule); border-radius: var(--radius);
  background: var(--c-surface); color: inherit; text-decoration: none;
  transition: border-color .12s, background .12s;
}
.qtr a:hover { border-color: var(--c-accent); background: var(--c-accent-wash); text-decoration: none; }
.qtr__n { font-family: var(--f-mono); font-size: 9.5px; letter-spacing: .06em; color: var(--c-ink-3); }
.qtr b { font-size: 13px; font-weight: 620; }
.qtr a > span:last-child { font-size: 11.5px; line-height: 1.35; color: var(--c-ink-3); }

/* Các thẻ hướng dẫn: tự xếp cột theo bề ngang, KHÔNG kéo bằng chiều cao (align-items:start)
   — thẻ hai gạch đầu dòng không việc gì phải cao bằng thẻ bốn gạch. */
.hd-luoi {
  display: grid; gap: 12px; align-items: start;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
}
/* Mục vừa được hỏi tới từ nút "?" — viền nhấn để mắt bắt được ngay sau khi trang cuộn tới. */
.hd-luoi > .is-hoi { border-color: var(--c-accent); box-shadow: 0 0 0 1px var(--c-accent) inset; }
.hd-tomtat { margin: 0 0 8px; font-size: 13px; }
.hd-buoc { margin: 0; padding-left: 17px; display: flex; flex-direction: column; gap: 5px; }
.hd-buoc li { font-size: 12.5px; line-height: 1.45; color: var(--c-ink-2); }
.hd-luuy {
  margin: 9px 0 0; padding: 7px 9px; border-radius: var(--radius);
  background: var(--c-warn-wash); color: var(--c-warn);
  font-size: 12px; line-height: 1.45;
}
/* Tám dòng ngắn: xếp cột theo bề ngang thay vì kéo một cột dài suốt trang rộng, để phần
   bên phải khung không rỗng trơ ra. */
.hd-kyhieu {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 7px 18px;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
.hd-kyhieu li { font-size: 12.5px; line-height: 1.5; color: var(--c-ink-2); }
.hd-kyhieu .badge, .hd-kyhieu .dots { margin-right: 4px; vertical-align: 1px; }
/* Vòng đời (/huong-dan/vong-doi/…): một chặng một dòng, xếp DỌC chứ không ngang.
   Ngang thì đẹp hơn nhưng mỗi chặng chỉ còn chỗ cho vài chữ — mà thứ đáng đọc ở đây là dấu
   vết chặng ấy để lại trong dữ liệu, và dòng đó dài. Đường nối chạy dọc mép trái các chấm số
   để mắt vẫn thấy đây là một dãy liên tục. */
.vd { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.vd__i { display: grid; grid-template-columns: 26px minmax(0, 1fr); gap: 0 12px; position: relative; }
/* Đường nối: vẽ từ chấm số của chặng này xuống chặng sau. Chặng cuối không có :not() nào ở
   dưới nữa nên cắt đi, nếu không đường thừa ra một đoạn cụt dưới chấm cuối. */
.vd__i:not(:last-child)::before {
  content: ""; position: absolute; left: 12.5px; top: 26px; bottom: 0;
  width: 1px; background: var(--c-rule);
}
.vd__so {
  width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--f-mono); font-size: 12px; font-weight: 700; color: #fff;
  background: var(--c-idle);
}
.vd__than { padding-bottom: 16px; }
.vd__dau { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 9px; }
.vd__ten { font-size: 14px; font-weight: 640; line-height: 26px; }
.vd__noi { font-size: 11.5px; color: var(--c-ink-3); }
/* Dấu vết trong dữ liệu: chữ mono trên nền chìm — nó là thứ đem đi đối chiếu với DB, không
   phải một câu văn, nên nó không được trông giống câu văn. */
.vd__vet {
  margin: 6px 0 8px; padding: 5px 9px; border-radius: var(--radius);
  background: var(--c-surface-2); border: 1px solid var(--c-rule-soft);
  font-family: var(--f-mono); font-size: 11.5px; line-height: 1.5; color: var(--c-ink-2);
}
.vd code, .hd-buoc code, .hd-tomtat code {
  font-family: var(--f-mono); font-size: .92em;
  padding: 0 3px; border-radius: var(--radius-sm); background: var(--c-surface-2);
}
@media (max-width: 560px) {
  .vd__i { grid-template-columns: 22px minmax(0, 1fr); gap: 0 9px; }
  .vd__i:not(:last-child)::before { left: 10.5px; top: 22px; }
  .vd__so { width: 22px; height: 22px; font-size: 11px; }
  .vd__ten { line-height: 22px; }
}

kbd {
  display: inline-block; padding: 1px 6px; border-radius: var(--radius-sm);
  border: 1px solid var(--c-rule); border-bottom-width: 2px; background: var(--c-surface-2);
  font-family: var(--f-mono); font-size: 11.5px; line-height: 1.5; color: var(--c-ink);
}

/* ---------- 17. TRANG ĐĂNG NHẬP ---------- */
.login { min-height: 100vh; display: grid; place-items: center; padding: 20px; background: var(--c-ground); }
.login__box { width: 100%; max-width: 348px; }
.login__brand { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; }
.login__brand .rail__mark { width: 34px; height: 34px; font-size: 14px; }
.login__card { background: var(--c-surface); border: 1px solid var(--c-rule-soft); border-radius: 6px; box-shadow: var(--shadow-2); padding: 20px; }
.login__card .field { margin-bottom: 12px; }
.alert {
  padding: 8px 11px; border-radius: var(--radius); font-size: 12.5px;
  background: var(--c-crit-wash); color: var(--c-crit);
  border: 1px solid color-mix(in srgb, var(--c-crit) 25%, transparent);
  margin-bottom: 12px;
}

/* Băng báo THÀNH CÔNG.

   [THÊM 21/08/2026] `.alert` trần luôn mang màu đỏ, nên mười một màn hình muốn báo một việc
   đã xong đều tự viết lại cùng ba khai báo màu ngay trong thuộc tính style của thẻ:

       style="background:var(--c-ok-wash);color:var(--c-ok);border-color:var(--c-ok)"

   Chép mười một lần thì lần thứ mười hai là lần gõ thiếu, và đó là chuyện đã xảy ra: màn hình
   /lich-chay viết `class="alert alert--ok"` — một lớp chưa từng tồn tại — nên băng báo thành
   công của nó hiện ra màu ĐỎ như báo lỗi.

   Đặt tên cho biến thể ở đây, và sửa cả mười một chỗ về dùng nó. */
.alert--ok {
  background: var(--c-ok-wash); color: var(--c-ok);
  border-color: color-mix(in srgb, var(--c-ok) 25%, transparent);
}

/* ============================================================
   18. BÁO CÁO — thành phần dùng chung cho 5 màn hình thống kê
   Nguyên tắc: mọi thanh/cột đều là CSS thuần, không thư viện biểu đồ,
   và luôn kèm con số bằng chữ để đọc được cả khi in ra giấy.
   ============================================================ */

/* Hai cột: khối chính rộng, khối phụ hẹp. Dưới 1100px xếp chồng. */
.bc-2cot { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: 12px; align-items: start; }
@media (max-width: 1100px) { .bc-2cot { grid-template-columns: minmax(0, 1fr); } }

/* --- Bảng "doanh thu đi về đâu" / phân rã theo dòng --- */
/* margin/padding = 0: bỏ dấu đầu dòng thì phải bỏ luôn chỗ trình duyệt chừa sẵn cho nó.
   <ul> mặc định có padding-inline-start: 40px để chứa dấu chấm, mà list-style:none không
   đụng tới khoảng đó — nên cả danh sách thụt vào 40px với một khoảng trống rỗng bên trái. */
.wf { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.wf__i {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(60px, 24%) 88px 58px;
  align-items: center; gap: 10px; padding: 6px 2px;
  border-bottom: 1px solid var(--c-rule-soft);
}
.wf__i:last-child { border-bottom: 0; }
.wf__t { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.wf__n { font-size: 13px; font-weight: 560; display: flex; align-items: center; gap: 6px; }
.wf__t small { font-size: 11px; line-height: 1.25; }
.wf__bar { height: 7px; border-radius: 999px; background: var(--c-surface-2); overflow: hidden; }
.wf__bar > i { display: block; height: 100%; border-radius: 999px; background: var(--c-accent); }
.wf__v { text-align: right; font-size: 13.5px; font-weight: 640; font-variant-numeric: tabular-nums; }
.wf__p { text-align: right; font-size: 11.5px; font-variant-numeric: tabular-nums; }
.wf__v[data-tone="ok"]   { color: var(--c-ok); }
.wf__v[data-tone="warn"] { color: var(--c-warn); }
.wf__v[data-tone="crit"] { color: var(--c-crit); }
.wf__i--tru .wf__v { color: var(--c-crit); }
.wf__i--tru .wf__bar > i { background: var(--c-crit); }
.wf__i--tong { border-top: 2px solid var(--c-rule); margin-top: 4px; padding-top: 9px; }
.wf__i--tong .wf__n { font-weight: 700; }
.wf__i--tong .wf__v { color: var(--c-ok); font-size: 15px; }
.wf__i--tong .wf__bar > i { background: var(--c-ok); }
@media (max-width: 720px) {
  .wf__i { grid-template-columns: minmax(0, 1fr) 84px 54px; }
  .wf__bar { display: none; }
}

/* Màu theo ngữ nghĩa dùng chung cho thanh, chấm, ô biểu đồ */
[data-lop="ok"]   { background: var(--c-ok)   !important; }
[data-lop="warn"] { background: var(--c-warn) !important; }
[data-lop="crit"] { background: var(--c-crit) !important; }
[data-lop="info"] { background: var(--c-info) !important; }
[data-lop="shop"] { background: var(--c-shop) !important; }
/* Bốn bậc của họ "đang đi" và "hàng quay về" — xem Data/NhanTrangThai.cs. */
[data-lop="giao"]      { background: var(--c-giao)      !important; }
[data-lop="hoan"]      { background: var(--c-hoan)      !important; }
[data-lop="hoan-xong"] { background: var(--c-hoan-xong) !important; }
[data-lop="hoan-loi"]  { background: var(--c-hoan-loi)  !important; }
/* Hai lớp của kết quả gọi, và idle cho mã "Khác" — xem Data/KetQuaGoi.cs.
   Thiếu chúng thì thanh và chấm ở "Kết quả các cuộc gọi" của /bao-cao/tai-don-hang
   trong suốt, tức mất hẳn cột màu. */
[data-lop="lac"]  { background: var(--c-lac)  !important; }
[data-lop="hen"]  { background: var(--c-hen)  !important; }
[data-lop="idle"] { background: var(--c-idle) !important; }

.cham { width: 8px; height: 8px; border-radius: 50%; background: var(--c-accent); flex: none; }

/* Tiền ship, ở MỌI màn hình. Chủ dự án chốt: nhìn màu là biết đó là phí ship, không phải
   tiền hàng. Đặt thành một lớp chứ không tô tay từng chỗ — bốn màn hình đang hiện con số
   này (lưới phiếu nhập, panel, bảng công nợ, lưới đơn hàng). */
.tien-ship { color: var(--c-ship); }

/* Khoản GIẢM cho khách. Mượn --c-hoan (cam đất) chứ không mượn --c-crit: giảm giá không phải
   một cái hỏng, nó là khoản mình chủ động cho đi. Nhưng cũng không để màu mực thường — dòng
   này là con số duy nhất trong khối thanh toán mang dấu trừ, và mắt phải bắt được điều đó. */
.tien-giam { color: var(--c-hoan); }

/* --- Thanh tỷ trọng một dòng --- */
.thanh { display: flex; height: 16px; border-radius: 999px; overflow: hidden; background: var(--c-surface-2); }
.thanh > i, .thanh > a { display: block; min-width: 2px; }
/* Mảng bấm được (báo cáo tỉnh thành): sáng lên khi rê chuột, y như cột theo ngày. */
.thanh > a { transition: filter .12s; }
.thanh > a:hover { filter: brightness(1.25); }

/* Thanh cơ cấu đặt vào ô thứ hai của .wf__i thay cho .wf__bar một màu (báo cáo tỉnh thành).
   Ẩn cùng lúc với .wf__bar ở màn hình hẹp: dưới 720px lưới còn 3 cột, để lại 4 ô thì ô cuối
   rơi xuống dòng dưới và cả danh sách lệch hàng. */
.wf__i > .thanh { height: 12px; }
@media (max-width: 720px) { .wf__i > .thanh { display: none; } }

/* --- Bảng chéo tỉnh × hãng: ô hai tầng, tỷ lệ trên, số đơn dưới --- */
.o2 { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; }
.o2 .minibar { width: 100%; min-width: 54px; }
.o2 > b { font-size: 13px; font-variant-numeric: tabular-nums; }
/* Tỷ lệ đo trên quá ít đơn: vẫn in ra, nhưng nhạt đi để không bị đọc ngang hàng số có đủ mẫu. */
.o2.is-mong > b { color: var(--c-ink-3); font-weight: 500; }
.o2.is-mong .minibar > i { opacity: .4; }

/* --- Thanh nhỏ trong ô bảng --- */
.minibar { height: 5px; border-radius: 999px; background: var(--c-surface-2); overflow: hidden; margin-top: 3px; }
.minibar > i { display: block; height: 100%; background: var(--c-accent); border-radius: 999px; }
.minibar--mo > i { opacity: .45; }
.tyle { display: flex; flex-direction: column; align-items: flex-end; gap: 0; }
.tyle .minibar { width: 100%; min-width: 62px; }

/* --- Biểu đồ cột theo ngày --- */
.cotngay {
  display: flex; gap: 3px; align-items: flex-end;
  height: 190px; overflow-x: auto; overflow-y: hidden; padding-bottom: 2px;
}
.cotngay__c {
  flex: 1 0 26px; min-width: 26px; height: 100%;
  display: flex; flex-direction: column; justify-content: flex-end; gap: 3px;
  border-radius: var(--radius-sm);
}
.cotngay__c.is-ct { background: color-mix(in srgb, var(--c-accent) 7%, transparent); }
.cotngay__so {
  font-family: var(--f-mono); font-size: 10px; text-align: center; color: var(--c-ink-3);
  font-variant-numeric: tabular-nums;
}
.cotngay__cot {
  display: flex; flex-direction: column-reverse; min-height: 3px;
  border-radius: 2px; overflow: hidden; background: var(--c-surface-2);
}
.cotngay__cot > a { display: block; min-height: 0; transition: filter .12s; }
.cotngay__cot > a:hover { filter: brightness(1.25); }
.cotngay__n {
  font-family: var(--f-mono); font-size: 9.5px; text-align: center; color: var(--c-ink-3);
  white-space: nowrap;
}

/* --- Chú giải màu --- */
.chugiai { display: flex; flex-wrap: wrap; gap: 4px 12px; }
.chugiai__i { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; color: var(--c-ink-3); }
.chugiai__i > i { width: 9px; height: 9px; border-radius: 2px; flex: none; }
/* Ô màu tròn — dùng khi chú giải đứng cạnh một danh sách vẽ chấm tròn, để hình dạng của
   chú giải khớp hình dạng thứ nó giải thích (xem Pages/Shared/_ChuGiaiTrangThai.cshtml). */
.chugiai--cham > .chugiai__i > i { width: 8px; height: 8px; border-radius: 50%; }
/* Đứng trong thân khung chứ không ở đầu khung thì cần một đường kẻ tách khỏi danh sách. */
.tt-list > .chugiai { margin-top: 9px; padding-top: 8px; border-top: 1px solid var(--c-rule-soft); }

/* --- Phễu / danh sách chỉ số dạng nhãn – số --- */
/* Cùng lý do như .wf ở trên: bỏ dấu đầu dòng thì bỏ luôn chỗ chừa cho nó. */
.phieu { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1px; }
.phieu li {
  display: flex; align-items: center; gap: 8px; padding: 6px 0;
  border-bottom: 1px solid var(--c-rule-soft); font-size: 13px;
}
.phieu li:last-child { border-bottom: 0; }
.phieu__n { flex: 1; min-width: 0; }
.phieu li > b { font-variant-numeric: tabular-nums; font-size: 14px; }
.phieu__cach { margin-top: 6px; border-top: 2px solid var(--c-rule); padding-top: 9px !important; }

/* --- Cột HÌNH của lưới phiếu nhập ---
   Bản cũ /OrderImportList.aspx có hai cột ảnh 50px cạnh nhau; ở đây gộp một ô: ảnh hiện trạng
   là hình, hoá đơn VAT là một nhãn nhỏ bên cạnh. */
.ct { gap: 5px; justify-content: center; }
.ct__trong { color: var(--c-ink-3); font-family: var(--f-mono); }
.ct__vat {
  font-family: var(--f-mono); font-size: 9px; font-weight: 700; letter-spacing: .05em;
  padding: 2px 4px; border-radius: 3px; white-space: nowrap;
  background: var(--c-info-wash); color: var(--c-info); text-decoration: none;
}
.ct__vat:hover { text-decoration: none; filter: brightness(1.1); }
/* Ảnh gãy (tên tệp có trong phiếu nhưng tệp không nằm trên máy chủ này) — không để một ô
   trống không giải thích gì. Ảnh cũ của bản cũ nằm trên ổ đĩa máy chủ IIS cũ. */
.ct a[data-hong="1"] img { display: none; }
.ct a[data-hong="1"]::after {
  content: "?"; display: grid; place-items: center;
  width: var(--sp-anh, 32px); height: var(--sp-anh, 32px);
  border: 1px dashed var(--c-rule); border-radius: var(--radius-sm);
  color: var(--c-ink-3); font-family: var(--f-mono); font-size: 13px;
}

/* --- Bất thường của phiếu, hiện trong panel --- */
.dt-sec--bt { background: var(--c-surface-2); }
.bt-ds { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.bt-ds li {
  border-left: 3px solid var(--c-rule); padding-left: 9px;
  font-size: 12.5px; line-height: 1.45;
}
.bt-ds li[data-muc="crit"] { border-left-color: var(--c-crit); }
.bt-ds li[data-muc="warn"] { border-left-color: var(--c-warn); }
.bt-ds li b { display: block; font-size: 13px; }
.bt-ds li[data-muc="crit"] b { color: var(--c-crit); }
.bt-ds li[data-muc="warn"] b { color: var(--c-warn); }
.bt-ds li span { color: var(--c-ink-2); }

/* --- Hai ô chứng từ trong panel --- */
.ct-hai { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
@container dtpanel (max-width: 380px) { .ct-hai { grid-template-columns: 1fr; } }
.ct-o {
  display: flex; flex-direction: column; gap: 6px; align-items: flex-start;
  padding: 9px 10px; border: 1px solid var(--c-rule-soft); border-radius: var(--radius);
  background: var(--c-surface-2);
}
.ct-o__t { font-size: 11px; color: var(--c-ink-3); line-height: 1.3; }
.ct-o__anh { display: block; line-height: 0; }
.ct-o__anh img {
  width: 100%; max-height: 118px; object-fit: cover;
  border-radius: var(--radius-sm); border: 1px solid var(--c-rule-soft); background: var(--c-surface);
}
.ct-o__pdf {
  display: grid; place-items: center; height: 62px; width: 100%;
  border: 1px solid var(--c-rule); border-radius: var(--radius-sm); background: var(--c-surface);
  font-family: var(--f-mono); font-size: 13px; font-weight: 700; color: var(--c-crit);
}
.ct-o__ten { font-size: 10px; color: var(--c-ink-3); overflow-wrap: anywhere; }
.ct-o__chua { padding: 6px 0; }
/* Câu "tệp không còn" chỉ hiện khi ảnh thật sự gãy — xem onerror ở _ChiTiet.cshtml. */
.ct-o__hong { display: none; color: var(--c-warn); }
.ct-o[data-hong="1"] .ct-o__anh { display: none; }
.ct-o[data-hong="1"] .ct-o__hong { display: block; }
.input--sm { font-size: 11.5px; padding: 4px 6px; min-height: 0; width: 100%; }

/* --- Tấm phủ xem chứng từ phóng to --- */
.anhto {
  border: 0; padding: 0; background: transparent;
  width: min(94vw, 1100px); max-width: 94vw; max-height: 92vh;
  color: var(--c-ink);
}
.anhto::backdrop { background: rgba(6, 10, 12, .78); }
.anhto__hd {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 11px; background: var(--c-surface);
  border: 1px solid var(--c-rule); border-bottom: 0;
  border-radius: var(--radius) var(--radius) 0 0;
  font-size: 13px;
}
.anhto__than {
  display: grid; place-items: center; min-height: 180px;
  max-height: calc(92vh - 46px); overflow: auto;
  background: var(--c-surface-2);
  border: 1px solid var(--c-rule); border-radius: 0 0 var(--radius) var(--radius);
  padding: 10px;
}
.anhto__than img { max-width: 100%; max-height: calc(92vh - 70px); object-fit: contain; border-radius: var(--radius-sm); }
.anhto__than iframe { width: 100%; height: calc(92vh - 70px); border: 0; background: var(--c-surface); }
.anhto__hong { margin: 0; padding: 26px 16px; text-align: center; color: var(--c-warn); line-height: 1.6; }
.anhto__cho { margin: 0; padding: 26px 16px; color: var(--c-ink-3); }

/* --- Tấm phủ xem nhanh MỘT TRANG (thẻ kho ở /kho) ---
   Rộng hơn tấm ảnh vì bên trong là bảng nhiều cột, và thân tự cuộn để tiêu đề luôn thấy. */
.hoptrang {
  border: 0; padding: 0; background: transparent;
  width: min(96vw, 1180px); max-width: 96vw; max-height: 92vh;
  color: var(--c-ink);
}
.hoptrang::backdrop { background: rgba(6, 10, 12, .78); }
.hoptrang__hd {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 11px; background: var(--c-surface);
  border: 1px solid var(--c-rule); border-bottom: 0;
  border-radius: var(--radius) var(--radius) 0 0;
  font-size: 13px;
}
.hoptrang__than {
  max-height: calc(92vh - 46px); overflow: auto;
  background: var(--c-ground); padding: 12px;
  border: 1px solid var(--c-rule); border-radius: 0 0 var(--radius) var(--radius);
}
/* Bảng bên trong tấm phủ đã có khung cuộn riêng; bỏ bề rộng tối thiểu để nó không đẩy cả
   tấm phủ rộng ra ở khổ hẹp. */
.hoptrang__than .dt { --dt-min: 0; }

/* --- Ba vế "ai ứng bao nhiêu" của phiếu nhập (_VeThanhToan.cshtml) ---
   auto-fit chứ không phải ba cột cứng: cụm ô này nằm cả trong panel chi tiết rộng ~460px lẫn
   giữa trang thanh toán rộng cả màn hình. Ba cột cứng thì trong panel mỗi ô còn ~130px, hẹp
   hơn cả con số tiền nó phải chứa. */
.ve-tt { display: grid; grid-template-columns: repeat(auto-fit, minmax(196px, 1fr)); gap: 10px; }
.ve-tt .ve {
  display: flex; flex-direction: column; gap: 6px;
  padding: 9px 10px; border: 1px solid var(--c-rule-soft); border-radius: var(--radius);
  background: var(--c-surface-2);
}
/* Hai TÔNG cho ba vế — chủ dự án chốt 18/08/2026: nhìn màu là biết vế nào có hoá đơn VAT,
   không phải đọc nhãn.

   Vế 1 và vế 3 đều là VAT nên cùng tông NÓNG (đó cũng chính là lý do vế 3 tồn tại: cột
   UserPaymentVAT2 sinh ra cho người ứng phần VAT thứ hai). Vế 2 là phần không VAT — tông
   LẠNH. Thứ tự ba vế giữ nguyên.

   Dùng nền -wash + chữ đậm màu của chính tông: cả hai bộ đều đã được cân cho nền sáng lẫn
   nền tối trong bảng biến, nên không phải tự chế màu mới cho từng chế độ. */
.ve-tt .ve[data-kieu="vat"] {
  background: var(--c-hoan-wash);
  border-color: color-mix(in srgb, var(--c-hoan) 34%, transparent);
}
.ve-tt .ve[data-kieu="vat"] .field__label { color: var(--c-hoan); }

.ve-tt .ve[data-kieu="thuong"] {
  background: var(--c-hoan-xong-wash);
  border-color: color-mix(in srgb, var(--c-hoan-xong) 34%, transparent);
}
.ve-tt .ve[data-kieu="thuong"] .field__label { color: var(--c-hoan-xong); }

/* Nhãn phụ (" · hóa đơn VAT") nhạt hơn để tên vế vẫn là thứ đọc trước. */
.ve-tt .field__label .muted { opacity: .78; }

/* Vế đã có người ứng nổi lên bằng một vạch bên trái — quét mắt là biết phiếu chia mấy phần,
   không phải đọc từng ô select. Vạch dùng màu của chính tông vế đó, đậm hơn viền. */
.ve-tt .ve:has([data-tra] option:checked:not([value="All"])) {
  border-left-width: 3px; border-left-style: solid;
}
.ve-tt .ve[data-kieu="vat"]:has([data-tra] option:checked:not([value="All"])) {
  border-left-color: var(--c-hoan);
}
.ve-tt .ve[data-kieu="thuong"]:has([data-tra] option:checked:not([value="All"])) {
  border-left-color: var(--c-hoan-xong);
}
.ve-tt .field__label { margin: 0; }

/* --- Khối giả định có thể mở ra --- */
.gd { margin-top: 14px; border-top: 1px solid var(--c-rule-soft); padding-top: 10px; }
.gd > summary {
  cursor: pointer; font-size: 12.5px; font-weight: 560; color: var(--c-accent);
  list-style: none; display: inline-flex; align-items: center; gap: 6px;
}
.gd > summary::-webkit-details-marker { display: none; }
.gd > summary::before { content: "▸"; font-size: 10px; }
.gd[open] > summary::before { content: "▾"; }

/* --- Chênh lệch tăng/giảm --- */
.delta { font-family: var(--f-mono); font-size: 12px; font-weight: 620; }
.delta--up { color: var(--c-ok); }
.delta--down { color: var(--c-crit); }

/* --- Số âm / cần chú ý trong bảng --- */
.dt .am, .am { color: var(--c-crit); }
.dt .chot { color: var(--c-ok); font-family: var(--f-mono); font-size: 11px; margin-left: 3px; }
.dt tr.is-cuoituan > td:first-child { box-shadow: inset 3px 0 0 color-mix(in srgb, var(--c-accent) 40%, transparent); }
/* Bảng gọn nằm trong thẻ card hẹp: bỏ bề rộng tối thiểu 900px mặc định, nếu không nó
   kéo rộng cả cột lưới và làm CẢ TRANG cuộn ngang (đo được 249px thừa ở /bao-cao). */
.dt--gon { --dt-min: 0; }
.dt--gon th, .dt--gon td { padding-top: 5px; padding-bottom: 5px; }
.dt tfoot th {
  position: sticky; bottom: 0; background: var(--c-surface-2);
  border-top: 2px solid var(--c-rule); font-variant-numeric: tabular-nums;
}
/* --- Lưới quản lý sản phẩm: sửa tại chỗ, ô nhập chìm vào bảng --- */
.input--nen {
  background: transparent; border-color: transparent; box-shadow: none;
  padding-left: 5px; padding-right: 5px; width: 100%;
}
.input--nen:hover { border-color: var(--c-rule); }
.input--nen:focus { background: var(--c-surface); border-color: var(--c-accent); }
.input--nen[readonly] { border-color: transparent; cursor: default; }
.input--nen.num, .dt td.num .input--nen { text-align: right; }
.dt td .input--nen[type="number"]::-webkit-inner-spin-button,
.dt td .input--nen[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }

.sp-ql td { vertical-align: top; }
.sp-ql tr.is-doi > td:first-child { box-shadow: inset 3px 0 0 var(--c-accent); }
.sp-ql tr.is-doi .input--nen { background: var(--c-accent-wash); }

.sp-ten { display: flex; gap: 8px; align-items: flex-start; min-width: 0; }
.sp-ten .thumb { flex: none; }
.sp-meta { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; margin-top: 3px; font-size: 11px; }

/* Dòng bảng mở được panel — cùng cách đánh dấu với .row-item, nhưng .row-item là lưới CSS
   nên không dùng lại được cho một <tr> thật. Chỉ ba luật: con trỏ, nền dòng đang chọn, và
   viền tiêu điểm bàn phím. */
.dt tbody tr[data-mo] { cursor: pointer; }
.dt tbody tr[data-mo][aria-selected="true"] > td { background: var(--c-accent-wash); }
.dt tbody tr[data-mo]:focus-visible { outline: 2px solid var(--c-accent-hi); outline-offset: -2px; }

/* Cột Trạng thái của lưới sản phẩm: xếp DỌC, mỗi nhãn một dòng. Nhãn khuyến mãi dài gấp ba
   nhãn trạng thái, để chúng cùng dòng thì nhãn ngắn bị đẩy đi đâu tuỳ bề ngang cột — mà nhãn
   ngắn ("Ngừng bán") mới là thứ phải bắt được bằng một cái liếc. */
.sp-tt { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; }
.sp-tt .badge { max-width: 100%; }

.sp-tick { display: flex; flex-wrap: wrap; gap: 3px 10px; font-size: 11.5px; }
.sp-tick label { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; cursor: pointer; }
.sp-tick--rong { gap: 6px 16px; font-size: 12.5px; }
@media (pointer: coarse) { .sp-tick input { width: 18px; height: 18px; } }

/* --- Đối soát --- */
.buoc { padding-left: 18px; display: flex; flex-direction: column; gap: 6px; font-size: 13px; }
.buoc li { line-height: 1.45; }
.apdung {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  padding: 12px; margin-top: 12px;
  border-top: 2px solid var(--c-rule); background: var(--c-surface-2);
}
.dt tr.is-chon > td { background: var(--c-accent-wash); }
/* Kẻ sọc chéo — dấu hiệu THỨ HAI đặt lên một mảng đã có màu, khi cần nói thêm một điều mà
   màu đã dùng để nói điều khác. Nay chỉ còn hai chỗ dùng: phần "cần chăm sóc" chồng lên thanh
   trạng thái ở /cham-soc, và lát "lead trùng" ở /bao-cao/tai-don-hang.

   [SỬA 17/08/2026] Thêm !important. Không có nó thì luật này KHÔNG BAO GIỜ có tác dụng:
   `[data-lop="…"] { background: … !important }` là thuộc tính GỘP, nên nó đặt luôn
   background-image về none, và có !important nên thắng bất kể thứ tự. Mọi mảng gắn class
   này từ trước tới nay đều hiện ra một khối màu đặc — sọc chỉ có trong chú thích. */
.soc {
  background-image: repeating-linear-gradient(
    45deg, transparent 0 3px, rgba(255,255,255,.55) 3px 6px) !important;
}
/* ============================================================
   MÀN HÌNH QUÉT MÃ VẠCH  (/kho/quet)
   Thiết kế cho MỘT TAY cầm điện thoại, tay kia bê thùng hàng:
   ô nhập và số đếm to hẳn, mọi nút bấm đủ rộng cho ngón cái.
   ============================================================ */
.quet-bang {
  display: grid; gap: 12px; margin-bottom: 12px;
  grid-template-columns: minmax(0, 1fr) minmax(0, 320px);
}
@media (max-width: 760px) { .quet-bang { grid-template-columns: 1fr; } }

.quet-nhap {
  background: var(--c-surface); border: 1px solid var(--c-rule);
  border-radius: var(--radius); padding: 14px;
}
/* Ô mã to gấp rưỡi ô thường: đây là ô duy nhất người ta nhìn khi đang quét,
   và trên điện thoại chữ nhỏ hơn 16px làm Safari tự phóng to cả trang. */
.quet-nhap #oMa { flex: 1; font-size: 18px; height: 46px; letter-spacing: .04em; }
.quet-nhap .btn { height: 46px; }

.quet-cam { position: relative; border-radius: var(--radius); overflow: hidden; background: #000; }
.quet-cam video { display: block; width: 100%; height: 100%; max-height: 260px; object-fit: cover; }
/* Vạch ngắm — không phải trang trí: nó nói cho người quét biết đưa mã vào đâu. */
.quet-cam__vach {
  position: absolute; left: 8%; right: 8%; top: 50%; height: 2px;
  background: var(--c-crit); box-shadow: 0 0 8px var(--c-crit); opacity: .85;
}
.quet-cam__tat { position: absolute; right: 8px; bottom: 8px; }

.quet-kq {
  background: var(--c-surface); border: 1px solid var(--c-rule);
  border-left: 4px solid var(--c-idle);
  border-radius: var(--radius); padding: 14px; box-shadow: var(--shadow-1);
}
.quet-kq[data-trang="thay"] { border-left-color: var(--c-ok); }
.quet-kq[data-trang="chon"] { border-left-color: var(--c-warn); }
.quet-kq[data-trang="la"]   { border-left-color: var(--c-accent); }

.quet-kq__than { display: flex; gap: 12px; align-items: flex-start; }
.quet-kq__chu  { display: flex; gap: 12px; align-items: center; min-width: 0; flex: 1; }
.quet-kq__ten  { font-weight: 650; font-size: 15px; line-height: 1.3; }
/* Con số này là thứ đọc được từ xa một sải tay, nên nó to nhất trang. */
.quet-kq__dem {
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  font-size: 40px; font-weight: 700; line-height: 1; color: var(--c-ok);
  min-width: 56px; text-align: right;
}
.quet-kq__ma {
  font-family: var(--f-mono); font-size: 22px; font-weight: 600;
  letter-spacing: .06em; word-break: break-all;
}
.quet-kq__canh { font-size: 13px; color: var(--c-ink-2); margin-top: 6px; }

/*  Mã vạch của sản phẩm — [THÊM 20/08/2026, chủ dự án chốt].

    Dãy số là thứ người cầm hộp hàng đối chiếu bằng mắt với chữ in trên vỏ, nên nó phải là
    chữ ĐƠN CÁCH và giãn chữ hơn bình thường: đọc từng ký tự một, không đọc thành từ.

    Mã vừa quét tô đậm để tách khỏi các mã khác của cùng sản phẩm — một hộp có thể mang mã
    nhà sản xuất, mã thùng, và tem nội bộ mình dán thêm. */
.quet-ma { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }
.quet-ma__o {
  font-family: var(--f-mono); font-size: 12px; letter-spacing: .04em;
  padding: 2px 7px; border-radius: var(--radius-sm);
  background: var(--c-surface-2); color: var(--c-ink-2);
  border: 1px solid var(--c-rule-soft);
}
.quet-ma__o.la-nay {
  background: var(--c-accent-wash); color: var(--c-accent);
  border-color: var(--c-accent); font-weight: 600;
}
.quet-ma--trong {
  font-family: var(--f-sans); font-size: 12px; color: var(--c-ink-3); font-style: italic;
}
.quet-ma--nho { margin-top: 3px; }

/* Dải mã vạch ở thẻ kho — một hàng ngang dưới dãy KPI, không chiếm một khối riêng. */
.the-ma { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin: 10px 0 0; }
.the-ma__k {
  font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--c-ink-3);
}
.the-ma .quet-ma { margin-top: 0; }
.quet-ma--nho .quet-ma__o { font-size: 11px; padding: 1px 5px; }

.thumb--lon { width: 64px; height: 64px; }

.quet-tim { margin-top: 12px; }
.quet-ds { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; max-height: 320px; overflow-y: auto; }
.quet-ds__muc {
  display: flex; gap: 10px; align-items: center; text-align: left; width: 100%;
  padding: 8px; font: inherit; font-size: 13px; cursor: pointer;
  background: var(--c-surface-2); color: var(--c-ink);
  border: 1px solid var(--c-rule-soft); border-radius: var(--radius);
}
.quet-ds__muc:hover { background: var(--c-accent-wash); border-color: var(--c-accent); }
.quet-ds__muc:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 1px; }
.quet-ds__muc .thumb { width: 40px; height: 40px; }

/* Lưới số liệu của thẻ tra cứu — tám con số thủ kho hay hỏi nhất, đọc một lượt
   không phải bấm sang trang khác giữa lúc đang đứng trong kho. */
.quet-luoi {
  display: grid; gap: 1px; margin-top: 12px;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  background: var(--c-rule-soft); border: 1px solid var(--c-rule-soft);
  border-radius: var(--radius); overflow: hidden;
}
.quet-o { background: var(--c-surface); padding: 8px 10px; }
.quet-o__k { font-size: 11px; color: var(--c-ink-3); text-transform: uppercase; letter-spacing: .05em; }
.quet-o__v {
  font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  font-size: 18px; font-weight: 650; margin-top: 2px;
}
.quet-o__v[data-tone="ok"]   { color: var(--c-ok); }
.quet-o__v[data-tone="crit"] { color: var(--c-crit); }
.quet-o__v[data-tone="idle"] { color: var(--c-ink-3); }

/* Nút quét mã trên thanh trên cùng: sáng lên khi đang ở chính màn hình quét, để
   không ai bấm lại nút đưa mình về đúng chỗ đang đứng. */
.topbar .btn--icon.is-on {
  background: var(--c-accent-wash); color: var(--c-accent); border-color: var(--c-accent);
}

/* Logo bấm được để về trang chính. Giữ nguyên hình dáng cũ — người dùng không cần
   thấy nó "trông như một liên kết", chỉ cần bấm được; nên chỉ thêm con trỏ và một
   chút sáng lên khi rê chuột. */
.rail__home {
  display: flex; align-items: center; gap: 9px; min-width: 0;
  color: inherit; text-decoration: none; border-radius: var(--radius-sm);
  padding: 4px; margin: -4px;
}
/* Rê chuột KHÔNG gạch chân: đây là khối logo, không phải một liên kết trong câu chữ.
   Gạch chân làm hai dòng tên dính vào nhau trông như lỗi hiển thị. */
.rail__home, .rail__home:hover, .rail__home:focus { text-decoration: none; }
.rail__home:hover .rail__name { color: var(--c-accent); }
.rail__home:hover .rail__mark { background: var(--c-accent-hi); }
.rail__home:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 1px; }

/* ============================================================================
   Trang tổng quan (/tong-quan)

   Không dựng thành phần mới nếu thứ đã có dùng được: thẻ số vẫn là .kpi, dòng việc
   vẫn là .row-item, khung vẫn là .card. Chỉ thêm bốn thứ mà trang khác chưa cần.
   ========================================================================= */

/* Thẻ số bấm được — mỗi con số là một cánh cửa sang đúng danh sách đứng sau nó,
   nên phải trông như bấm được, không chỉ trông như một ô số. */
.kpi--nhay { display: block; color: inherit; text-decoration: none; transition: border-color .1s, background .1s; }
.kpi--nhay:hover { background: var(--c-surface-2); text-decoration: none; }
.kpi--nhay:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 1px; }

.tq-2cot { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; align-items: start; }
@media (max-width: 1000px) { .tq-2cot { grid-template-columns: minmax(0, 1fr); } }

/* Dòng việc: chữ bên trái, lời mời bấm bên phải. .row-item cần --cols. */
.tq-2cot .row-item, .card .row-item { --cols: minmax(0, 1fr) auto; color: inherit; text-decoration: none; }
.card .row-item:hover { text-decoration: none; }

/* Ba con số hiện trạng kho — không theo khoảng ngày, nên tách khỏi dải KPI ở trên. */
.tq-ton { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 8px; margin-top: 10px; }
.tq-ton__i {
  padding: 8px 10px; border: 1px solid var(--c-rule-soft); border-radius: var(--radius-sm);
  color: inherit; text-decoration: none; background: var(--c-surface-2);
}
.tq-ton__i:hover { border-color: var(--c-accent); text-decoration: none; }
.tq-ton__i b { display: block; font-size: 16px; font-weight: 660; letter-spacing: -.01em; }
.tq-ton__i span { font-size: 10.5px; color: var(--c-ink-3); }

/* Nhật ký gần đây: ba cột cố định để mắt chạy dọc được, không phải đọc từng dòng. */
.tq-hd {
  display: grid; grid-template-columns: 78px 92px minmax(0, 1fr); gap: 8px; align-items: baseline;
  padding: 5px 2px; border-bottom: 1px solid var(--c-rule-soft); font-size: 12px;
}
.tq-hd:last-child { border-bottom: 0; }
.tq-hd__t { font-size: 11px; color: var(--c-ink-3); }
.tq-hd__n { font-size: 11.5px; color: var(--c-ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tq-hd__v { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tq-hd__v small { margin-left: 6px; font-size: 11px; }
/* Việc chạm vào tiền, tồn kho hay quyền thì đậm hơn — đó là dòng người ta cần thấy. */
.tq-hd.is-chuy .tq-hd__v { font-weight: 620; }
.tq-hd.is-chuy { border-left: 2px solid var(--c-warn); padding-left: 6px; margin-left: -8px; }
/* Trên điện thoại, ba cột 78px + 92px + phần còn lại chỉ chừa ~170px cho tên việc — mà đó
   mới là thứ người ta đọc; giờ và tên người chỉ để đối chiếu. Xếp làm hai hàng thì tên việc
   được trọn bề rộng thay vì bị cắt bằng dấu … ngay sau vài chữ đầu. */
@media (max-width: 620px) {
  .tq-hd { grid-template-columns: 78px minmax(0, 1fr); row-gap: 2px; }
  /* overflow-wrap: anywhere là bắt buộc, không phải cho đẹp: một dòng nhật ký thật đang mang
     2.500 ký tự base64 liền không dấu cách. Cho xuống dòng bình thường mà không cho ngắt giữa
     từ thì khối chữ đó đẩy cả trang rộng ra 2.551px và người dùng phải cuộn ngang mọi màn
     hình. Vẫn giữ overflow: hidden của luật cơ sở làm chốt cuối. */
  .tq-hd__v { grid-column: 1 / -1; white-space: normal; overflow-wrap: anywhere; }
}

/* Mũi tên so với kỳ trước. Không tô đỏ/xanh theo hướng: doanh thu tăng là tốt, chi phí
   nhập tăng thì chưa chắc — gán màu là gán luôn kết luận thay người đọc. */
.kpi__doi {
  font-size: 11px; font-weight: 600; margin-left: 6px; letter-spacing: 0;
  color: var(--c-ink-3); white-space: nowrap;
}
.kpi__doi[data-h="len"]   { color: var(--c-ink-2); }
.kpi__doi[data-h="xuong"] { color: var(--c-ink-3); }


/* ---------------------------------------------------------------------------
   Biểu đồ cột chồng ba tầng: giao thành công · đang giao · đã hủy.

   Dựng bằng div chứ không SVG, vì cột có NHÃN. SVG kéo giãn ngang (preserveAspectRatio
   = none) làm méo luôn chữ bên trong; div thì chiều cao tính bằng %, chữ giữ nguyên.
   ------------------------------------------------------------------------ */
.tq-chu { display: flex; gap: 12px; flex-wrap: wrap; }
.tq-chu span { display: inline-flex; align-items: center; gap: 4px; }
.tq-chu i, .tq-cot__than i { border-radius: 1px; }
.tq-chu i { width: 9px; height: 9px; display: inline-block; }

i[data-n="xong"] { background: var(--c-ok); }
i[data-n="dang"] { background: var(--c-warn); }
i[data-n="huy"]  { background: var(--c-crit); }

.tq-bd {
  display: grid; grid-template-columns: repeat(var(--n), minmax(0, 1fr));
  gap: 3px; align-items: end; min-height: 170px;
}
.tq-cot { display: flex; flex-direction: column; justify-content: flex-end; min-width: 0; height: 100%; }

/* Nhãn nổi trên đỉnh cột, KHÔNG nằm trong luồng: để nó trong luồng thì cột cao nhất
   đẩy nhãn tràn khỏi khung và bị cắt mất một nửa. */
.tq-cot__nhan {
  position: absolute; bottom: 100%; left: -2px; right: -2px; margin-bottom: 3px;
  font-size: 9.5px; line-height: 1.25; text-align: center; color: var(--c-ink-3);
  pointer-events: none;
}
.tq-cot__nhan b { display: block; color: var(--c-ink-2); font-weight: 620; white-space: nowrap; }
.tq-cot__nhan span { white-space: nowrap; }

/* Thân cột: chiều cao theo tổng, các tầng chia theo tỷ lệ trong chính cột đó.
   column-reverse để thứ tự viết trong HTML (thành công → đang giao → hủy) đúng bằng
   thứ tự từ ĐÁY cột lên, khỏi phải đọc ngược khi sửa. */
.tq-cot__than {
  position: relative; height: var(--h); min-height: 2px;
  display: flex; flex-direction: column-reverse; border-radius: 2px;
}
.tq-cot__than i { height: var(--p); width: 100%; display: block; transition: opacity .1s; }
.tq-cot:hover .tq-cot__than i { opacity: .82; }

.tq-cot__ngay { font-size: 10px; color: var(--c-ink-3); text-align: center; margin-top: 4px; white-space: nowrap; }
.tq-ngan { display: none; }


/* Mật độ nhãn theo SỐ CỘT (data-mat do server đặt), không theo bề rộng màn hình: một kỳ
   46 ngày trên màn hình rộng vẫn chỉ cho mỗi cột ~27px, không đủ cho "56,1 tr₫". */

/* thưa (≤16 cột): nhãn nằm ngang, đọc thẳng */
.tq-bd[data-mat="thua"] .tq-cot__nhan { font-size: 9.5px; }

/* vừa (17–31 cột): quay nhãn dọc theo cột — chỗ duy nhất còn trống khi cột hẹp lại.

   Chiều xoay: đọc từ DƯỚI LÊN, nghiêng đầu sang TRÁI. Một mình writing-mode: vertical-rl
   cho chữ Latin nằm theo chiều kim đồng hồ — phải nghiêng đầu sang PHẢI mới đọc được, ngược
   với mọi biểu đồ người ta quen nhìn, và trên điện thoại thì thành khó chịu thật sự.
   rotate(180deg) lật lại đúng chiều. (writing-mode: sideways-lr làm đúng việc này chỉ bằng
   một dòng, nhưng Safari trên iPhone — đúng cái máy đang cầm — mới hỗ trợ gần đây.)

   Căn giữa: hộp nhãn cũ căng left:-2px/right:-2px nên rộng bằng cả cột, mà dòng chữ dọc
   thì dính vào một mép hộp — nhãn lệch hẳn sang một bên so với cột. width:max-content cho
   hộp co đúng bằng bề dày dòng chữ, rồi left:50% + translateX(-50%) đặt nó vào giữa cột. */
.tq-bd[data-mat="vua"] .tq-cot__nhan {
  writing-mode: vertical-rl; text-orientation: mixed;
  left: 50%; right: auto; width: max-content;
  transform: translateX(-50%) rotate(180deg);
  margin: 0 0 3px; max-height: 96px; font-size: 9px;
}
.tq-bd[data-mat="vua"] .tq-cot__nhan b { display: inline; }
.tq-bd[data-mat="vua"] .tq-cot__nhan span { display: none; }   /* bỏ "· 76 đơn", giữ tiền */

/* dày (≥32 cột): bỏ hẳn nhãn tiền và rút ngày còn số ngày. Không cố nhét chữ vào 27px —
   nhét được cũng thành một hàng vạch mờ không ai đọc. Số đầy đủ vẫn có khi rê chuột. */
.tq-bd[data-mat="day"] .tq-cot__nhan { display: none; }
.tq-bd[data-mat="day"] .tq-day { display: none; }
.tq-bd[data-mat="day"] .tq-ngan { display: inline; }
.tq-bd[data-mat="day"] .tq-cot__ngay { font-size: 9px; }

/* Màn hình hẹp: mọi mức mật độ đều thu thêm một bậc, vì bề ngang chia cho cùng số cột. */
@media (max-width: 900px) {
  .tq-bd { gap: 2px; }
  /* Xoay dọc và căn giữa y như mức "vừa" ở trên — xem giải thích chiều xoay tại đó. */
  .tq-bd[data-mat="thua"] .tq-cot__nhan {
    writing-mode: vertical-rl; text-orientation: mixed;
    left: 50%; right: auto; width: max-content;
    transform: translateX(-50%) rotate(180deg);
    margin: 0 0 3px; max-height: 92px; font-size: 9px;
  }
  .tq-bd[data-mat="thua"] .tq-cot__nhan b { display: inline; }
  .tq-bd[data-mat="thua"] .tq-cot__nhan span { display: none; }
  .tq-bd[data-mat="vua"] .tq-cot__nhan { display: none; }
  .tq-day { display: none; }
  .tq-ngan { display: inline; }
}
/* Điện thoại: nhãn tiền vẫn hiện, quay DỌC theo cột — đó là yêu cầu, và cũng là chỗ
   duy nhất còn trống khi cột chỉ rộng ~28px. Chỉ bỏ nhãn khi cột nhiều tới mức không
   còn nhét được (mức "vừa" và "dày" bên dưới). */
@media (max-width: 560px) {
  .tq-bd { min-height: 150px; gap: 2px; }
  .tq-bd[data-mat="thua"] .tq-cot__nhan { max-height: 68px; font-size: 8.5px; }
  .tq-bd[data-mat="vua"] .tq-cot__nhan,
  .tq-bd[data-mat="day"] .tq-cot__nhan { display: none; }
}

/* Nhãn nổi ra ngoài thân cột nên khung phải chừa chỗ ở trên, nếu không nhãn của cột cao
   nhất bị cắt. Mỗi mức mật độ chừa một khoảng khác nhau vì nhãn nằm ngang hay nằm dọc. */
.tq-bd[data-mat="thua"] { padding-top: 26px; }
.tq-bd[data-mat="vua"]  { padding-top: 92px; }
.tq-bd[data-mat="day"]  { padding-top: 4px; }
@media (max-width: 900px) {
  .tq-bd[data-mat="thua"] { padding-top: 88px; }   /* nhãn xoay dọc ở khổ hẹp */
  .tq-bd[data-mat="vua"]  { padding-top: 4px; }    /* nhãn đã ẩn */
}
@media (max-width: 560px) {
  .tq-bd[data-mat="thua"] { padding-top: 72px; }
  .tq-bd[data-mat="vua"], .tq-bd[data-mat="day"] { padding-top: 4px; }
}

/* --- Dòng "số liệu tính lúc" của /bao-cao ---
   Trang này là màn hình DUY NHẤT có cache (xem Data/ThongKeRepo.SongCache). Dòng này là
   cái giá phải trả để được cache mà không phá luật "người dùng ra quyết định trên con số
   đang nhìn": nó nói thẳng số cũ bao lâu và để sẵn nút tính lại. Đặt ngay dưới bộ lọc
   ngày, trước mọi con số — đọc được trước khi mắt rơi vào KPI đầu tiên. */
.tinhluc {
  display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: center; justify-content: space-between;
  margin-bottom: 12px; padding: 7px 11px;
  border: 1px dashed var(--c-rule); border-radius: var(--radius);
  background: var(--c-surface-2);
}
.tinhluc__t { font-size: 12.5px; color: var(--c-ink-2); }
.tinhluc__t b { font-family: var(--f-mono); font-variant-numeric: tabular-nums; color: var(--c-ink); }

/* ---------- Công tắc tra nhà mạng — /bao-cao/nha-mang ----------
   [THÊM 20/08/2026] Đây là chức năng DUY NHẤT trong hệ thống tiêu tiền theo mỗi lượt gọi ra
   ngoài. Câu hỏi đầu tiên của người mở trang là "nó đang bật hay đang tắt", nên khối này nằm
   trên cùng, cao hơn hẳn một dòng chữ, và trả lời bằng MÀU trước khi người ta kịp đọc chữ.

   Không dùng .alert: alert là để báo một sự việc vừa xảy ra rồi biến mất. Cái này là trạng
   thái thường trực, và nó phải trông như một cái công tắc chứ không như một lời thông báo. */
.ctac {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; margin-bottom: 12px;
  background: var(--c-surface); border: 1px solid var(--c-rule-soft);
  border-left: 3px solid var(--c-ink-3);
  border-radius: var(--radius); box-shadow: var(--shadow-1);
}
.ctac[data-bat="1"] { border-left-color: var(--c-warn); background: var(--c-warn-wash); }

/* Đèn báo: khối đặc, đọc được từ xa và không phụ thuộc vào việc đọc chữ.
   Bật thì màu CẢNH BÁO chứ không phải màu "ok" — bật nghĩa là đang tiêu tiền, đó là trạng
   thái cần để mắt tới, không phải trạng thái đáng mừng. */
.ctac__den { width: 12px; height: 12px; border-radius: 50%; flex: none; background: var(--c-ink-3); }
.ctac[data-bat="1"] .ctac__den { background: var(--c-warn); box-shadow: 0 0 0 4px color-mix(in srgb, var(--c-warn) 22%, transparent); }

.ctac__chu { flex: 1; min-width: 0; }
.ctac__ten { font-size: 13px; font-weight: 640; letter-spacing: .01em; }
.ctac[data-bat="1"] .ctac__ten { color: var(--c-warn); }
.ctac__phu { font-size: 11.5px; color: var(--c-ink-3); margin-top: 2px; }
.ctac__phu code { font-family: var(--f-mono); font-size: 11px; }

/* Chấm trạng thái của một lượt tra. Cùng ngôn ngữ màu với .kpi[data-tone]. */
.ttcham {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  margin-right: 5px; vertical-align: middle; background: var(--c-ink-3);
}
.ttcham[data-tone="ok"]   { background: var(--c-ok); }
.ttcham[data-tone="warn"] { background: var(--c-warn); }
.ttcham[data-tone="crit"] { background: var(--c-crit); }

/* Hai form tra thử. Xuống dòng được: ô số + nút trên màn hình hẹp không nhét chung một hàng. */
.nmthu { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 8px; }
.nmthu .input { width: 160px; }
.nmthu select.input { width: auto; }

/* Nút "Kiểm tra nhà mạng" — đứng cạnh nhãn nhà mạng ở hồ sơ khách /telesale.
   Nhỏ và nhạt: nó là một tuỳ chọn, không phải việc phải làm. Người trực vào là để bấm gọi,
   còn nhà mạng thật chỉ đáng hỏi khi họ thật sự cần biết. */
.nm-nut { min-height: 22px; padding: 0 7px; font-size: 11px; margin-left: 6px; vertical-align: middle; }

/* ═══════════════════════════════════════════════════════════════════════════
   KẾT NỐI GOOGLE MERCHANT — /ket-noi-gmc

   Một dòng ở màn hình này mang TÁM giá trị lấy từ ba nơi khác nhau của Google, và ba
   trong số đó (mã tài khoản · mã nguồn dữ liệu · nhãn feed) trông giống hệt nhau: đều là
   chuỗi ngắn, đều gõ tay, đều không có gì báo khi điền nhầm ô. Ngày 22/08/2026 chủ dự án
   điền TÊN nguồn vào ô NHÃN FEED, và lỗi chỉ hiện ra ở một màn hình khác.

   Nên bố cục ở đây không phải chuyện thẩm mỹ: các ô được gom thành ba MỤC theo đúng câu
   hỏi chúng trả lời — «kết nối này là của ai», «lấy quyền bằng gì», «đẩy vào đâu» — mỗi
   mục một tiêu đề nhỏ và một đường kẻ. Ô nào lạc mục là nhìn ra ngay.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Lưới ô nhập: tự xuống dòng theo bề ngang, không cần đặt flex-basis cho từng ô. */
.kn-luoi {
  display: grid; gap: 12px 14px; align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
.kn-luoi > .kn-rong { grid-column: 1 / -1; }

/* Một mục của biểu mẫu. Mục đầu không có kẻ trên — nó đã sát mép thẻ rồi. */
.kn-muc { padding: 14px 0 0; border-top: 1px solid var(--c-rule-soft); margin-top: 14px; }
.kn-muc:first-child { padding-top: 0; border-top: 0; margin-top: 0; }
.kn-muc__t {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin: 0 0 10px;
  font-size: 10px; font-weight: 650; letter-spacing: .07em; text-transform: uppercase;
  color: var(--c-ink-3);
}
/* Câu giải thích đi kèm tiêu đề mục: viết thường, không giãn chữ — nó là câu văn, không phải nhãn. */
.kn-muc__t span {
  font-size: 11px; font-weight: 400; letter-spacing: 0; text-transform: none;
  color: var(--c-ink-3);
}

/* Hàng chân biểu mẫu: ô tick, người sửa, nút Lưu. */
.kn-chan {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--c-rule-soft);
}
.kn-chan__day { margin-left: auto; }

/* Hàng thao tác, chia theo NHÓM chứ không rải một dãy nút ngang nhau: năm nút cùng cỡ
   cùng màu thì người mới không đoán được nên bấm cái nào trước. */
.kn-thao {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--c-rule-soft);
}
.kn-nhom { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.kn-nhom__t {
  font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--c-ink-3); margin-right: 2px;
}

/* Tên tài nguyên sản phẩm dựng từ ba ô — bày ra ngay dưới chúng để đối chiếu bằng mắt. */
.kn-ten {
  font-family: var(--f-mono); font-size: 11.5px;
  background: var(--c-surface-2); border: 1px solid var(--c-rule-soft);
  border-radius: var(--radius); padding: 3px 7px;
}

/* Bản kết luận của Chẩn đoán / Xem nguồn dữ liệu. */
.kn-kq {
  margin: 6px 0 0; padding: 10px 12px; white-space: pre-wrap;
  background: var(--c-surface-2); border: 1px solid var(--c-rule-soft);
  border-radius: var(--radius); max-height: 260px; overflow: auto;
}
