  /* ============ DANH SÁCH LỚP ============ */
  /* ---- Tiêu đề chia nhóm CƠ SỞ ----
     Bản trước chỉ là dòng chữ xám 14px, lẫn vào giữa rừng thẻ lớp nên rất khó
     nhận ra ranh giới giữa các cơ sở (cô Quỳnh báo 25/07/2026). Giờ: chữ to,
     đậm, có dải màu teal bên trái, nền nhạt, và một vạch kẻ tách hẳn nhóm trên. */
  .nhom-coso { margin-top:26px; }
  .nhom-coso + .nhom-coso { margin-top:34px; padding-top:24px; border-top:2px solid var(--vien); }
  /* 🏫 THIẾT KẾ LẠI 08/09/2026 — Boss: *"cái title cơ sở màu xanh nước biển Nguyễn
     Tuân tôi thấy thiết kế quá đơn giản và vuông góc"*.
     Trước: khối chữ nhật VUÔNG HOÀN TOÀN (`--r-lg` là 0 nên `border-radius` cũ không
     bo được góc nào), nền phẳng một màu, icon nhà trôi nổi cạnh chữ.
     Nay: bo 10px cả bốn góc · icon ngồi trong ô tròn trắng · số lớp thành viên riêng
     nền trắng, tách hẳn khỏi tên · dải teal bên trái giữ nguyên nhưng bo theo góc.
     ⛔ KHÔNG đổi `--r-lg`: đó là số đã chốt cho cả app (xem BANG-MAU-VA-CHU mục 4).
        Bo tại chỗ bằng số cứng, y như đã làm cho nút hộp thoại.
     ⛔ Gradient rất nhẹ (hai bậc cùng tông) chứ không đổi màu — dải màu loè là thứ
        Boss gọi "lộ ui AI". Ở nền tối luật riêng bên dưới trả về nền phẳng. */
  /* ⛔⛔ 08/09/2026 (lần 2) — BOSS CHÊ "TRÔNG GIỐNG AI QUÁ", VÀ ĐÚNG.
     Bản trước tôi dựng mắc ĐÚNG BA THỨ trong danh sách *mười thứ làm giao diện lộ ra
     là máy làm* (BANG-MAU-VA-CHU mục 9):
       ① nền chuyển màu (gradient) — chính là mục số 5 của danh sách ấy
       ② ô TRÒN TRẮNG bọc icon nhà — Boss: *"cái icon nhà còn bị trắng xóa nữa chứ"*.
          Mảng trắng 30px giữa dải xanh nhạt hút mắt hơn cả tên cơ sở.
       ③ số lớp thành VIÊN bo tròn 999px — huy hiệu kiểu thẻ quảng cáo
     Ba thứ chồng lên nhau thành bốn tầng nền trong một dải cao 50px.

     Mẫu gốc của app là GOOGLE SHEETS: nền phẳng, viền mảnh, không huy hiệu.
     ⛔ ĐỪNG dựng lại gradient, ô tròn, hay viên bo tròn ở đây.
     ⛔ NHƯNG cũng đừng trả về vuông góc: Boss chê *"thiết kế quá đơn giản và vuông
        góc"* ngay trước đó. Bo 8px là chỗ đứng giữa hai lời chê — đủ mềm để không
        thô, đủ phẳng để không loè.
     Thứ giữ lại từ bản trước: bo góc, và số lớp đẩy sang phải (đọc ra hai mẩu tin
     chứ không thành một câu "Nguyễn Tuân 37 lớp"). */
  .nhom-coso h2 { display:flex; align-items:center; flex-wrap:wrap; gap:9px;
                  font-size:19px; font-weight:700; color:var(--xanh-dam);
                  text-transform:none; letter-spacing:-.01em;
                  margin:0 0 14px; padding:10px 14px;
                  background:var(--xanh-nhat);
                  border-left:4px solid var(--xanh);
                  border-radius:8px; }
  .nhom-coso h2 > span:first-child { display:inline-flex; align-items:center; gap:9px;
                                     min-width:0; }
  /* Icon nhà TRẦN, ăn màu chữ của tiêu đề — không ô, không nền, không viền. */
  .nhom-coso h2 i { flex:none; width:19px; height:19px; margin:0; padding:0;
                    background:var(--xanh-dam); }
  /* Số lớp: chữ thường màu mờ, đẩy sang phải. Không viền, không nền, không bo tròn. */
  .nhom-coso h2 .dem-nhom { font-size:13px; font-weight:600; color:var(--mo);
                            margin-left:auto; flex:none; }
  /* ---- CỤM THEO THỨ, LỒNG TRONG TỪNG CƠ SỞ (cô Quỳnh 25/07/2026) ----
     Nhạt hơn tiêu đề cơ sở một bậc để nhìn ra ngay cái nào bọc cái nào. */
  .nhom-thu { margin:0 0 18px; }
  .nhom-thu h3 { display:flex; align-items:center; flex-wrap:wrap; gap:9px;
                 font-size:14.5px; font-weight:700; color:#3A4A57;
                 margin:0 0 9px; padding:6px 0 6px 12px;
                 border-left:4px solid var(--vien); }
  .nhom-thu h3 .dem-nhom { font-size:12.5px; font-weight:700; color:var(--mo); }
  /* Cụm của HÔM NAY: tô cam cho bật hẳn lên — đây là thứ trợ giảng cần tìm nhất */
  .nhom-thu.hom-nay h3 { color:#B26A00; border-left-color:var(--cam); }
  .nhan-homnay { background:var(--cam); color:#fff; font-size:11px; font-weight:700;
                 border-radius:var(--r-xl); padding:3px 10px; }

  /* ✨ ĐỔI CƠ SỞ THÌ THẤY NÓ ĐỔI — Boss chốt 08/09/2026
     *"khi chọn cơ sở mới thay đổi thì phải có animation các block lớp nó hiện lên chứ
     tôi thấy lúc tôi đổi cơ sở xong ko rõ đổi chưa vì ko cảm nhận đc sự thay đổi"*.
     Danh sách vẽ lại tức thì nên mắt không bắt được gì đã đổi — nhất là khi hai cơ sở
     có số lớp na ná nhau.

     ⛔ CHỈ chạy khi ĐỔI CƠ SỞ và khi MỞ MÀN, KHÔNG chạy lúc gõ tìm: gõ mỗi ký tự là
        vẽ lại một lần, cho cả danh sách nhấp nháy theo từng phím là chóng mặt. Việc
        bật/tắt nằm ở `veKetQuaLop(hieuUng)` trong js/tinh-nang.js — xem chú thích ở đó.
     ⛔ So le chỉ 10 thẻ đầu. Cơ sở đông có hơn trăm thẻ; so le hết thì thẻ cuối phải
        chờ mấy giây mới hiện, thành ra chậm chứ không mượt.
     ⛔ `prefers-reduced-motion` phải tắt hẳn: người say chuyển động bật cờ ấy trong
        máy thì mọi hiệu ứng phải nằm im, không nhấp nháy. */
  @keyframes dslHien { from { opacity:0; transform:translateY(9px); } to { opacity:1; transform:none; } }
  #ketQuaLop.dsl-vao .nhom-coso h2 { animation:dslHien .34s cubic-bezier(.22,.9,.28,1) both; }
  #ketQuaLop.dsl-vao .the-lop { animation:dslHien .30s cubic-bezier(.22,.9,.28,1) both; }
  #ketQuaLop.dsl-vao .the-lop:nth-child(1)  { animation-delay:.02s; }
  #ketQuaLop.dsl-vao .the-lop:nth-child(2)  { animation-delay:.04s; }
  #ketQuaLop.dsl-vao .the-lop:nth-child(3)  { animation-delay:.06s; }
  #ketQuaLop.dsl-vao .the-lop:nth-child(4)  { animation-delay:.08s; }
  #ketQuaLop.dsl-vao .the-lop:nth-child(5)  { animation-delay:.10s; }
  #ketQuaLop.dsl-vao .the-lop:nth-child(6)  { animation-delay:.12s; }
  #ketQuaLop.dsl-vao .the-lop:nth-child(7)  { animation-delay:.14s; }
  #ketQuaLop.dsl-vao .the-lop:nth-child(8)  { animation-delay:.16s; }
  #ketQuaLop.dsl-vao .the-lop:nth-child(9)  { animation-delay:.18s; }
  #ketQuaLop.dsl-vao .the-lop:nth-child(n+10) { animation-delay:.20s; }
  @media (prefers-reduced-motion: reduce) {
    #ketQuaLop.dsl-vao .nhom-coso h2,
    #ketQuaLop.dsl-vao .the-lop { animation:none; }
  }

  .luoi-lop { display:grid; grid-template-columns:repeat(auto-fill, minmax(240px, 1fr)); gap:12px; }
  /* 🔲 05/08 — SẮC NÉT: thẻ lớp vuông vắn hơn, viền rõ, bóng nét */
  .the-lop { background:var(--the); border:1px solid var(--vien); border-radius:9px; padding:16px;
             cursor:pointer; transition:box-shadow .12s, border-color .12s; }
  .the-lop:hover { box-shadow:0 2px 4px rgba(15,90,92,.12), 0 6px 14px rgba(15,90,92,.10);
             border-color:var(--xanh); }

  /* ---- VIỀN THEO GIỜ HỌC + AI ĐANG Ở TRONG LỚP (cô Quỳnh 26/07/2026) ----
     Mục đích cô nói rõ: *"cho nó dễ nhận biết với người mới"* → phải nhìn PHÁT
     RA, nên dùng viền dày 2px + nền nhạt + nhãn chữ, không chỉ đổi màu mờ mờ.
     ⚠️ Dùng `box-shadow` làm viền thay cho `border`: border làm thẻ to thêm 4px
     → cả lưới thẻ xô lệch mỗi khi tới giờ học (họ hàng bẫy §6.16 và bẫy ô
     "đang sửa" ở bảng điểm). */
  .the-lop.dang-hoc { box-shadow:0 0 0 2px var(--o-tot); background:#F2FAF5; }
  .the-lop.sap-hoc  { box-shadow:0 0 0 2px var(--cam);   background:#FFF9F2; }
  /* Có người đang mở lớp này → thêm quầng tím, KHÔNG đè lên viền giờ học */
  .the-lop.co-nguoi { box-shadow:0 0 0 2px #7C5BD0, 0 6px 18px rgba(124,91,208,.18); }
  .the-lop.co-nguoi.dang-hoc { box-shadow:0 0 0 2px var(--o-tot), 0 0 0 5px rgba(124,91,208,.28); }
  .the-lop.co-nguoi.sap-hoc  { box-shadow:0 0 0 2px var(--cam),   0 0 0 5px rgba(124,91,208,.28); }
  /* ⛔ CHẤM TRÒN VẼ BẰNG CSS, KHÔNG DÙNG EMOJI — Boss chốt 08/09/2026.
     Trước: chuỗi chữ mở đầu bằng 🟢 / 🟠. Emoji nằm trong danh sách "mười thứ làm
     giao diện lộ ra là máy làm", lại mỗi máy vẽ một kiểu (Android tròn dẹt, Windows
     viền đen) nên không bao giờ khớp màu app.
     `currentColor` cho chấm ăn theo màu chữ của chính nhãn, nên nền tối tự đúng. */
  .nhan-gio { display:inline-flex; align-items:center; gap:6px;
              font-size:11px; font-weight:700; border-radius:999px;
              padding:2px 9px; margin-bottom:6px; background:#fff; border:1px solid var(--vien); }
  .nhan-gio::before { content:""; width:7px; height:7px; flex:none;
                      border-radius:50%; background:currentColor; }
  .the-lop.dang-hoc .nhan-gio { color:#12613A; border-color:var(--o-tot); background:#E8F6EC; }
  .the-lop.sap-hoc  .nhan-gio { color:#9A6400; border-color:var(--cam);   background:#FFF3D9; }
  /* Tên người đang ở trong lớp — hiện THẲNG trên thẻ vì điện thoại không rê chuột được */
  .ai-trong-lop { display:flex; flex-wrap:wrap; gap:4px; margin-top:8px; }
  .ai-nho { display:inline-flex; align-items:center; gap:4px; font-size:11px; font-weight:700;
            color:#4A3B7A; background:#EDE9FB; border-radius:999px; padding:2px 8px 2px 3px; }
  .ai-nho .cham-mau { width:13px; height:13px; border-radius:50%; display:inline-block; }
  /* 👤 04/08 (cô Quỳnh): Avatar ẢNH THẬT + chữ tắt cho người đang ở lớp */
  .ai-nho .ai-anh { width:18px; height:18px; border-radius:50%; object-fit:cover; display:inline-block; flex:none; }
  .ai-nho .ai-tat { width:18px; height:18px; border-radius:50%; display:inline-flex; align-items:center;
                    justify-content:center; font-size:9px; font-weight:700; color:#fff; flex:none; }
  /* 🎨 04/08 (cô Quỳnh): MÀU THEO CHỨC VỤ ở khung lớp —
     trợ giảng(staff)=VÀNG · giáo vụ(giaovu)=TÍM · admin=ĐỎ · giáo viên(teacher)=XANH LÁ · owner=CẦU VỒNG */
  .ai-nho.vt-staff, .ai-nho.vt-giaovu, .ai-nho.vt-admin, .ai-nho.vt-teacher {
    border:2px solid var(--vt); background:var(--the); color:var(--chu); padding:1px 8px 1px 2px; }
  .ai-nho.vt-staff   { --vt:#E0A200; }
  .ai-nho.vt-giaovu  { --vt:#8B5CF6; }
  .ai-nho.vt-admin   { --vt:#E5484D; }
  .ai-nho.vt-teacher { --vt:#20A171; }
  .ai-nho.vt-staff .ai-tat, .ai-nho.vt-giaovu .ai-tat,
  .ai-nho.vt-admin .ai-tat, .ai-nho.vt-teacher .ai-tat { background:var(--vt); }
  .ai-nho.vt-owner { color:var(--chu); border:2px solid transparent; padding:1px 8px 1px 2px;
    background:linear-gradient(var(--the),var(--the)) padding-box,
      linear-gradient(90deg,#ff004c,#ff9a00,#ffe600,#33d17a,#00b4d8,#7b2ff7,#ff004c) border-box; }
  .ai-nho.vt-owner .ai-tat { background:conic-gradient(from 0deg,#ff004c,#ff9a00,#ffe600,#33d17a,#00b4d8,#7b2ff7,#ff004c); }
  .the-lop .ten { font-size:19px; font-weight:700; line-height:1.2; }
  /* ⏰ GIỜ HỌC — mẩu tin NỔI BẬT NHẤT sau tên lớp, Boss chốt 08/09/2026
     *"cái giờ … trở nên nổi bật và sắp xếp rõ ràng hơn đi chứ nó nối tiếp nhau thế
     nếu lớp mà có nhiều giờ học thì nhìn rối mắt lắm"*.
     Trước: giờ nằm lẫn trong dòng chữ mờ cùng thứ và phòng, hai ca dính thành một
     chuỗi số dài. Nay: đứng riêng, màu chữ CHÍNH (không mờ), mỗi ca MỘT DÒNG.

     ⛔ `tabular-nums` là chỗ ăn tiền: phông hệ thống vẽ số 1 hẹp hơn số 0, nên hai
        dòng "17:30–19:15" và "10:00–11:45" lệch cột nhau trông như gõ ẩu. Bật nó
        thì mọi chữ số rộng bằng nhau, hai dòng thẳng cột như trong bảng tính.
     ⛔ KHÔNG tô nền, KHÔNG viền, KHÔNG bo tròn cho mẩu giờ — Boss vừa chê dải cơ sở
        "trông giống AI quá" đúng vì mấy thứ ấy. Nổi bật bằng ĐỘ ĐẬM và MÀU CHỮ. */
  .the-lop .tl-gio { display:flex; flex-direction:column; gap:1px; margin-top:5px; }
  .the-lop .tl-gio span { font-size:13.5px; font-weight:700; color:var(--chu);
                          line-height:1.35; font-variant-numeric:tabular-nums;
                          letter-spacing:.01em; }
  /* 21/09/2026 — lớp học nhiều thứ: dòng của thứ KHÁC nhóm đang xem thì lùi xuống
     màu chữ phụ, để mắt bắt ngay ca của chính ngày ấy. Vẫn giữ nét đậm vừa (600) để
     không thành chữ mờ khó đọc — Boss vừa chê chữ nền tối mờ. */
  .the-lop .tl-gio span.khac-thu { color:var(--mo); font-weight:600; }
  .the-lop .phu { color:var(--mo); font-size:12.5px; margin-top:4px; }
  /* 👤 Tên giáo viên TÁCH RIÊNG một dòng (08/09/2026). Trước nó nhét trong `.phu`
     sau một thẻ `<br>`, nên lịch học và tên người dính thành một khối chữ mờ. */
  .the-lop .tl-gv { color:var(--chu); font-size:12.5px; margin-top:3px;
                    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  /* ⛔ HÀNG ĐÁY: `flex-wrap` + `nowrap` từng mẩu — Boss chốt 08/09/2026.
     Trước: `justify-content:space-between` trên một hàng không cho xuống dòng, nên
     trong thẻ 181px của điện thoại CẢ HAI mẩu cùng bị bẻ làm đôi — "12 HS ·" một
     dòng, "11/31 buổi" dòng dưới, nhãn "Đang học DAY 12" cũng hai dòng. Bốn dòng
     cho hai mẩu tin.
     Nay mẩu nào không đủ chỗ thì xuống NGUYÊN mẩu: hai dòng, và gọn hơn hẳn. */
  .the-lop .duoi { display:flex; align-items:center; justify-content:space-between;
                   flex-wrap:wrap; gap:6px; margin-top:11px; }
  .the-lop .siso { font-size:12.5px; color:var(--mo); white-space:nowrap; }
  .the-lop .duoi > .nhan { white-space:nowrap; }
  .nhan { font-size:11px; font-weight:700; border-radius:var(--r-xl); padding:3px 10px; }
  .nhan.mo { background:#FEF3E2; color:#B26A00; border:1px solid #F4C883; }
  .nhan.xong { background:#E7F4EC; color:var(--o-tot); border:1px solid #BCDFC9; }
  .nhan.het  { background:#FDE7E7; color:#B0281C; border:1px solid #F0B4AE; }   /* Lớp đã kết thúc */
  /* Chưa có buổi nào mở — nút TẠO BUỔI phải nổi bật vì đó là việc đầu tiên trợ
     giảng cần làm khi vào lớp (cô Quỳnh chốt 25/07/2026). */
  .nhan.cho-tao { background:var(--nen2); color:var(--mo); border:1px solid var(--vien); }
  /* Hết khối DAY trống trên Sheet — KHÔNG phải "lớp học xong", phải nhìn ra là
     cảnh báo cần xử lý chứ không phải trạng thái bình thường. */
  .nhan.het-cho { background:#FDF0E3; color:#9A4B00; border:1px solid #F0C08A;
    display:inline-block; line-height:1.5; }
  /* 🚫 Dải "hôm nay lớp nghỉ vì giáo vụ đã huỷ buổi" — đứng ĐÚNG CHỖ trước đây bày
     nút "Tạo buổi học hôm nay", vì bấm nút ấy là đẻ ra buổi thứ hai cùng ngày. */
  .nhan.da-huy { background:#FDE7E7; color:#B0281C; border:1px solid #F0B4AE;
    display:inline-block; line-height:1.5; }
  /* ⏳ Dải "BUỔI LỠ" — buổi hôm trước không ai bấm mở, vẫn điền bù được. Màu VÀNG
     (nhắc việc còn phải làm) chứ không đỏ như buổi huỷ: đây không phải lỗi, cũng
     không phải lệnh cấm, chỉ là một việc bỏ quên đang chờ giáo vụ mở lại. */
  /* ⛔ Đè lại cỡ chữ và độ đậm của `.nhan` (11px, weight 800): đó là cỡ cho một
     con tem một dòng. Dải này dài BA dòng — để nguyên thì thành một khối chữ nhỏ
     mà đậm sì, đọc mỏi mắt và nhìn "lộ ui AI". */
  .nhan.buoi-lo { background:#FDF6E3; color:#7A4E00; border:1px solid #EBD08A;
    display:block; line-height:1.55; margin:10px 0 6px;
    font-size:12.5px; font-weight:400; border-radius:var(--r-lg); padding:9px 13px; }
  .nhan.buoi-lo b { font-weight:700; }
  /* ⚠️ Dải "TAB BÊN SHEET ĐÃ BỊ XOÁ" trên thẻ lớp ở sảnh — 01/09/2026.
     Màu VÀNG-CAM như `buoi-lo` chứ KHÔNG đỏ: lớp không hỏng, không mất gì, chỉ là
     Sheet thôi cập nhật cho nó — đỏ là doạ người ta rằng dữ liệu đã bay.
     Cùng cỡ chữ nhẹ (12px, weight 400) vì đây là hai dòng văn, không phải con tem. */
  .nhan.mat-tab { background:#FDF0E3; color:#9A4B00; border:1px solid #F0C08A;
    display:block; line-height:1.5; margin:10px 0 0;
    font-size:12px; font-weight:400; border-radius:var(--r-md); padding:8px 11px; }
  .nhan.mat-tab b { font-weight:700; }
  .nut-tao-buoi { background:var(--cam); color:#fff; border:0; border-radius:var(--r-lg);
    padding:10px 16px; font-weight:700; font-size:14px; cursor:pointer;
    box-shadow:0 2px 8px rgba(245,130,31,.3); }
  .nut-tao-buoi:hover { filter:brightness(1.06); }
  .nut-tao-buoi:disabled { opacity:.6; cursor:default; }
  @media (max-width:640px) { .nut-tao-buoi { width:100%; padding:13px; font-size:15px; } }

  /* ============ MÀN HÌNH LỚP ============ */
  .dau-lop { display:flex; align-items:center; gap:14px; flex-wrap:wrap; margin-bottom:14px; }
  .dau-lop .ten { font-size:22px; font-weight:700; }
  .dau-lop .phu { color:var(--mo); font-size:13px; }
  .dau-lop .day { flex:1; }

  /* ---- Thanh công cụ của lớp ----
     Gom hết nút thao tác về MỘT chỗ. Trước đây các nút nằm lẫn trong dòng tiêu đề
     lớp, trên điện thoại bị xuống dòng lộn xộn, nút bé, bấm hay trượt
     (cô Quỳnh báo 25/07/2026). Trên điện thoại thanh này rơi xuống ĐÁY màn hình,
     luôn nhìn thấy, ngón cái với tới được. */
  .thanh-cong-cu { display:flex; gap:8px; flex-wrap:wrap; margin-bottom:12px; }
  /* ⏭ Cặp nút chuyển học sinh của Progress test — cô Quỳnh 21/08/2026.
     Đẩy sang phải để không lẫn với nút "← Danh sách học sinh"; con số ở giữa cho
     biết đang ở em thứ mấy trên tổng bao nhiêu, khỏi phải đếm. */
  .pt-chuyen { margin-left:auto; display:inline-flex; align-items:center; gap:8px; }
  .pt-chuyen-so { font-size:12.5px; color:var(--mo); font-variant-numeric:tabular-nums;
    white-space:nowrap; }
  .pt-chuyen button:disabled { opacity:.4; cursor:default; }
  @media (max-width:640px) { .pt-chuyen { margin-left:0; flex:1 1 100%; justify-content:space-between; } }
  .thanh-cong-cu button { min-height:38px; }
  .nut-phieu { border:1px solid var(--vien); background:#fff; color:var(--chu);
               border-radius:var(--r-md); padding:8px 13px; font-size:13px; font-weight:700; }
  .nut-phieu:hover { border-color:var(--xanh); color:var(--xanh); }
  .nut-caption { border:1px solid var(--xanh); background:var(--xanh); color:#fff;
                 border-radius:var(--r-md); padding:8px 13px; font-size:13px; font-weight:700; }
  .nut-caption:hover { background:var(--xanh-dam); border-color:var(--xanh-dam); }

  /* Ô soạn caption — dài, chữ đều nhau cho dễ soát */
  .ht-chu textarea { width:100%; min-height:52vh; border:1px solid var(--vien); border-radius:var(--r-o, 8px);
                     padding:12px 14px; font-size:14px; line-height:1.65; font-family:inherit;
                     resize:vertical; background:#fff; color:var(--chu); }
  .ht-chu textarea:focus { outline:2px solid var(--xanh); border-color:transparent; }
  /* Nút chép mã cửa nhận Drive (22/08/2026) — đứng riêng một hàng trên các ô nhập. */
  .dr-chep { display:flex; gap:10px; align-items:center; flex-wrap:wrap;
             margin:0 0 14px; padding:10px 12px; border:1px solid var(--vien);
             border-radius:var(--r-md); background:var(--nen2); }
  .dr-chep button { padding:7px 13px; font-size:13px; }
  .dr-chep span { font-size:12px; color:var(--mo); flex:1; min-width:180px; }
  .nut-xoacot { border:1px solid #E7B4AE; background:#FDF1EF; color:var(--do);
                border-radius:var(--r-md); padding:8px 13px; font-size:13px; font-weight:700; }
  .nut-xoacot:hover { background:var(--do); border-color:var(--do); color:#fff; }
  /* Mỗi nút có HAI nhãn: bản dài cho máy tính, bản ngắn cho điện thoại.
     Cắt cụt bản dài kiểu "＋ cột" / "📸 phiếu" đọc rất tối nghĩa. */
  .chu-ngan { display:none; }
  /* Nút chỉ dành cho một loại màn hình */
  .chi-dien-thoai { display:none; }
  /* Nút DONE TO trong thanh công cụ — chỉ hiện trên điện thoại.
     ⛔ Vì sao cần: chế độ mặc định trên điện thoại là "Điền từng em" (thẻ), mà
     thẻ KHÔNG có nút DONE nào — nút DONE nằm trong tiêu đề khối DAY của bảng,
     tận ngoài rìa phải. Trợ giảng điền xong cả lớp rồi… không chốt được. */
  .nut-done-lon { border:none; border-radius:var(--r-lg); background:var(--cam); color:#fff;
                  font-size:13.5px; font-weight:700; padding:11px 14px;
                  box-shadow:0 4px 14px rgba(244,157,55,.35); }
  .nut-done-lon:disabled { opacity:.6; }
  .nut-cam { border:none; border-radius:var(--r-lg); background:var(--cam); color:#fff;
             padding:10px 16px; font-size:14px; font-weight:700; box-shadow:0 4px 14px rgba(244,157,55,.35); }
  .nut-cam:hover { filter:brightness(1.06); }

  /* ---- Thanh tìm lớp (125 lớp nên bắt buộc phải có) ---- */
  .thanh-tim { display:flex; gap:9px; align-items:center; margin-bottom:16px; flex-wrap:wrap; }
  .thanh-tim input { flex:1; min-width:220px; height:40px; border:1px solid var(--vien); border-radius:var(--r-o, 8px);
                     padding:0 13px; font-size:14px; background:#fff; }
  .thanh-tim input:focus { outline:2px solid var(--xanh); border-color:transparent; }
  .loc-coso { display:flex; gap:6px; flex-wrap:wrap; }
  .chip { border:1px solid var(--vien); background:#fff; border-radius:var(--r-xl); padding:7px 14px;
          font-size:13px; font-weight:600; color:var(--mo); }
  .chip.chon { background:var(--xanh); border-color:var(--xanh); color:#fff; }
  /* 🗄️ Nút gạt hiện/ẩn lớp đã kết thúc — off (đang ẩn) nền đỏ nhạt, on (đang hiện) đỏ đậm. */
  .chip-kt { cursor:pointer; border-color:#F0B4AE; background:#FDE7E7; color:#B0281C; margin-top:2px; }
  .chip-kt:hover { background:#FBD9D3; }
  .chip-kt.bat { background:#B0281C; border-color:#B0281C; color:#fff; }
  .dem-lop { font-size:13px; color:var(--mo); }
  /* 🏫 Tạo lớp trong app (cô Quỳnh 03/08/2026) */
  .taolop-thanh { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:0 0 14px; }
  .taolop-ghi { font-size:12.5px; color:var(--mo); }
  .lop-app-thanh { display:flex; align-items:center; gap:9px; flex-wrap:wrap; margin:8px 0 4px; padding:8px 12px;
    background:#EAF6EE; border:1px solid #A5D6A7; border-radius:var(--r-lg); }
  .lop-app-nhan { font-size:12.5px; font-weight:700; color:#2E7D32; margin-right:auto; }
  /* Dòng chỉ đường sang Quản lý lớp — thay cho ba nút vừa bỏ (09/08/2026). */
  .lop-app-chiduong { font-size:11.5px; color:var(--mo); }
  .lop-app-chiduong b { color:var(--chu); font-weight:700; }
  /* 🏫 Công cụ Quản lý lớp */
  /* ══════════════════════════════════════════════════════════════════════════════
     THẺ LỚP — cô Quỳnh 21/08/2026: *"trong 1 block lớp nhìn khá lôn xọn các nút sắp
     xếp rất xấu … sửa lại thật chuyên nghiệp business đẹp"*.
     ⛔ Thẻ RỘNG HƠN (258 → 300px): bảy nút nhồi vào 258px thì hàng nào cũng gãy hai
        ba dòng, và đó chính là cái "lộn xộn" cô Quỳnh nhìn thấy.
     ⛔ CHIỀU CAO ĐỀU NHAU trong một hàng lưới: phần thông tin giãn ra (`flex:1`) nên
        hai tầng nút của mọi thẻ nằm THẲNG HÀNG với nhau. Bản cũ mỗi thẻ một chiều
        cao, nút so le nhau như răng cưa.
     ⛔ Không đổ bóng đậm, không bo góc to, không màu nền — thẻ là một khung giấy có
        viền mảnh. Đúng luật giao diện cô Quỳnh chốt 08/08. */
  .ql-luoi { display:grid; grid-template-columns:repeat(auto-fill,minmax(300px,1fr)); gap:12px;
    align-items:stretch; }
  .ql-the { border:1px solid var(--vien); border-radius:var(--r-xl); padding:13px 15px 12px; background:var(--the);
    display:flex; flex-direction:column; gap:4px; }
  .ql-the:hover { border-color:var(--xanh); }
  /* Hàng đầu: tên lớp + nhãn tình trạng. Chừa 26px bên phải cho ô tick góc. */
  .ql-the-dau { display:flex; align-items:center; gap:8px; flex-wrap:wrap; padding-right:26px; }
  .ql-the-ten { font-size:16px; font-weight:700; letter-spacing:-.01em; }
  .ql-the-cs { font-size:12.5px; color:var(--mo); margin-bottom:8px; }
  /* Ba dòng thông tin: cột nhãn RỘNG CỐ ĐỊNH để mọi thẻ thẳng hàng nhau. */
  .ql-the-tin { flex:1 1 auto; display:flex; flex-direction:column; gap:3px;
    padding:9px 0; border-top:1px solid var(--vien); }
  .ql-tin-hang { display:flex; gap:8px; font-size:12.5px; line-height:1.45; }
  .ql-tin-hang > span { flex:none; width:66px; color:var(--mo); }
  .ql-tin-hang > b { flex:1; min-width:0; font-weight:600; color:var(--chu); }
  /* Tầng nút TRÊN — việc hàng ngày. */
  .ql-the-nut { display:flex; flex-wrap:wrap; gap:6px; }
  .ql-the-nut .nut-chinh { width:auto; flex:1 1 100%; height:36px; font-size:13px; }
  .ql-the-nut .nut-nho { flex:1 1 auto; justify-content:center; }
  /* Tầng nút DƯỚI — việc thỉnh thoảng. Không viền, chữ nhỏ, ngăn bằng một nét mảnh. */
  .ql-the-nut2 { display:flex; flex-wrap:wrap; gap:2px; margin-top:9px; padding-top:8px;
    border-top:1px solid var(--vien); }
  .ql-b2 { display:inline-flex; align-items:center; gap:5px; border:none; background:none;
    color:var(--mo); font-family:inherit; font-size:12px; padding:5px 7px; border-radius:var(--r-md);
    cursor:pointer; }
  .ql-b2:hover { background:var(--nen2); color:var(--chu); }
  .ql-b2 i { background:currentColor; }
  /* "Xoá" đứng cuối hàng, tách hẳn ra — bấm nhầm là mất cả lớp. */
  .ql-b2.do { margin-left:auto; color:var(--do); }
  .ql-b2.do:hover { background:var(--tt-dung-nen); color:var(--tt-dung-chu); }
  /* ══════════════════════════════════════════════════════════════════════════════
     BẢNG SỬA HỌC SINH CỦA MỘT LỚP — cô Quỳnh 21/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     *"thiết kế lại cái bảng sửa thông tin học sinh thật chuyên nghiệp phủ rộng toàn
     màn hình tùy độ rộng từng máy và để thật business"*.
     Bản cũ là danh sách THẺ, mỗi em ~130px cao → lớp 20 em dài 2.600px. Nay là bảng,
     mỗi em một hàng ~44px. Khối CSS cũ (`.ql-hs-ds` · `.ql-hs-luoi` · `.ql-hs-chan`)
     đã bỏ cùng lượt này vì không còn chỗ nào dùng.
     ⛔ Bảng CUỘN NGANG TRONG KHUNG RIÊNG (`.qlh-cuon`), không để cả trang trượt ngang.
     ⛔ Hàng tiêu đề dính đỉnh: lớp 40 em cuộn tới giữa mà mất tiêu đề thì không biết
        cột nào là ngày bắt đầu, cột nào là ngày kết thúc — hai cột nhìn y hệt nhau. */
  .qlh-thanh { align-items:center; }
  .qlh-dem { font-size:13px; color:var(--mo); }
  .qlh-dem b { color:var(--chu); font-size:15px; }
  .qlh-chip { font-size:11.5px; font-weight:700; padding:3px 9px; border-radius:var(--r-xl);
    border:1px solid transparent; }
  /* Ba chip đếm dùng CHUNG ba sắc với ba màu ô trạng thái ngay dưới — nhìn chip là
     đoán được màu hàng, khỏi phải học hai bảng màu. */
  .qlh-chip.chay { background:var(--tt-chay-nen); color:var(--tt-chay-chu); border-color:var(--tt-chay-vien); }
  .qlh-chip.di   { background:var(--tt-di-nen);   color:var(--tt-di-chu);   border-color:var(--tt-di-vien); }
  .qlh-chip.dung { background:var(--tt-dung-nen); color:var(--tt-dung-chu); border-color:var(--tt-dung-vien); }
  /* Nút "Cả lớp Stop" đứng tách hẳn khỏi nút "Thêm học sinh" — xem lý do ở chỗ dựng. */
  .qlh-thanh .qlh-stop { margin-left:auto; }
  .qlh-cuon { overflow:auto; max-height:calc(100vh - 200px - var(--dnc-du, 0px)); border:1px solid var(--vien);
    border-radius:var(--r-sheet); background:var(--the); }
  .qlh-bang { width:100%; border-collapse:separate; border-spacing:0; font-size:13.5px; }
  /* ⛔ BỎ IN HOA + giãn ký tự — cùng lý do với `.lt-bang th` ở trên. */
  .qlh-bang thead th { position:sticky; top:0; z-index:3; background:var(--dau-bang-nen);
    color:var(--dau-bang-chu);
    font-size:12px; font-weight:700;
    text-align:left; padding:9px 10px; border-bottom:1px solid var(--dau-bang-vien); white-space:nowrap; }
  .qlh-bang tbody td { padding:4px 8px; border-bottom:1px solid var(--vien); vertical-align:middle; }
  .qlh-bang tbody tr:last-child td { border-bottom:none; }
  .qlh-bang tbody tr:hover td { background:var(--nen2); }
  .qlh-bang .qlh-stt { width:38px; text-align:right; color:var(--mo); font-size:12px;
    font-variant-numeric:tabular-nums; padding-right:10px; }
  .qlh-bang .nv-in { width:100%; height:34px; font-size:13.5px; }
  .qlh-bang .qlh-ma { width:120px; } .qlh-bang .qlh-ma .nv-in { font-variant-numeric:tabular-nums; }
  .qlh-bang .qlh-ten { min-width:190px; }
  .qlh-bang .qlh-tt { width:146px; }
  .qlh-bang .qlh-ngay { width:158px; }
  .qlh-bang .qlh-chuyen { min-width:150px; }
  .qlh-bang .qlh-nut { width:110px; white-space:nowrap; text-align:right; }
  .qlh-bang .qlh-b { padding:5px 8px; }
  .qlh-den { display:inline-block; width:20px; text-align:center; font-size:13px; }
  /* ══════════════════════════════════════════════════════════════════════════════
     MÀU Ô TRẠNG THÁI — cô Quỳnh 21/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     *"on going sẽ có màu xanh lá cây cả ô, move out màu xám, move in màu xanh lá cây
     như on going, Stop màu đỏ làm nổi bật tình trạng các em lên"*.
     "Cả ô" nên tô nền cả ô <td> chứ không chỉ viền ô chọn — liếc dọc cột là thấy ngay
     lớp còn mấy em học.
     ⛔ NỀN NHẠT, CHỮ ĐẬM MÀU. Tô nền đặc màu xanh lá / đỏ cho 20 hàng liền nhau thì
        bảng thành cái cầu vồng, đúng thứ cô Quỳnh đã chê ba lần ("lộ rõ ui AI").
        Nền ~8% + chữ đậm là đủ nổi mà vẫn đọc được số trong ô.
     ⛔ KHÔNG chỉ dựa vào màu: chữ trong ô vẫn ghi rõ "On Going" / "Stop". Người mù
        màu đỏ-lục đọc chữ, không đọc màu.
     ⛔ Khai màu bằng BIẾN ở đây rồi dùng lại cho chip đếm phía trên. Nền tối chỉ
        cần đè lại sáu biến này, không phải viết lại cả khối. */
  :root {
    /* ⛔ Hình icon dùng lại cho `::before`/`::after` — 08/09/2026.
       Lớp `.ic-*` chỉ dùng được khi có thẻ `<i>` thật trong HTML. Mấy chỗ Boss
       bảo bỏ chữ (nút Làm mới · cặp đang chờ/đã xử lý · bốn ô số) thì icon phải
       do CSS vẽ ra, nên cùng một hình phải để được ở cả hai nơi. Đổi hình thì
       đổi ở khai báo `.ic-*` phía dưới VÀ ở đây, không thì hai chỗ lệch nhau. */
    --mi-dongho: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.6'/%3E%3Cpath d='M12 7v5.2l3.2 2'/%3E%3C/svg%3E");
    --mi-lich: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.5' y='5' width='17' height='16' rx='2'/%3E%3Cpath d='M3.5 10h17M8 3v4M16 3v4'/%3E%3C/svg%3E");
    --mi-xong: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 12.6l4.8 4.8L19.6 7.1'/%3E%3C/svg%3E");
    --mi-canhbao: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.2L22 20.4H2z'/%3E%3Cpath d='M12 9.4v4.6'/%3E%3Ccircle cx='12' cy='17.4' r='.9' fill='%23000' stroke='none'/%3E%3C/svg%3E");
    --mi-vongtron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8'%3E%3Ccircle cx='12' cy='12' r='8.4'/%3E%3C/svg%3E");
 --tt-chay-nen:#E8F5EC; --tt-chay-chu:#256B39; --tt-chay-vien:#B6DDC3;
          --tt-di-nen:#EFEFEE;   --tt-di-chu:#5C5A56;   --tt-di-vien:#D3D1CD;
          --tt-dung-nen:#FBEAE7; --tt-dung-chu:#A8352A; --tt-dung-vien:#EBC3BD; }
  body.toi { --tt-chay-nen:#16291D; --tt-chay-chu:#7FD6A0; --tt-chay-vien:#2B4634;
             --tt-di-nen:#242729;   --tt-di-chu:#9A9490;   --tt-di-vien:#33383C;
             --tt-dung-nen:#2A1D1C; --tt-dung-chu:#E5766C; --tt-dung-vien:#4A2C28; }
  .qlh-bang td.qlh-tt.tt-chay { background:var(--tt-chay-nen); }
  .qlh-bang td.qlh-tt.tt-di   { background:var(--tt-di-nen); }
  .qlh-bang td.qlh-tt.tt-dung { background:var(--tt-dung-nen); }
  .qlh-bang td.qlh-tt.tt-chay .nv-in { color:var(--tt-chay-chu); border-color:var(--tt-chay-vien); font-weight:700; }
  .qlh-bang td.qlh-tt.tt-di   .nv-in { color:var(--tt-di-chu);   border-color:var(--tt-di-vien);   font-weight:700; }
  .qlh-bang td.qlh-tt.tt-dung .nv-in { color:var(--tt-dung-chu); border-color:var(--tt-dung-vien); font-weight:700; }
  .qlh-bang td.qlh-tt .nv-in { background:transparent; }
  /* Hàng của em đã dừng / đã chuyển đi thì mờ nhẹ cả hàng — nhưng CHỈ mờ, không
     khoá: cô Quỳnh vẫn phải sửa lại được nếu bấm nhầm. */
  .qlh-bang tr:has(td.tt-dung) .qlh-ten .nv-in,
  .qlh-bang tr:has(td.tt-di) .qlh-ten .nv-in { color:var(--mo); }
  .ql-badge { font-size:11px; font-weight:700; padding:2px 8px; border-radius:var(--r-xl);
    width:fit-content; white-space:nowrap; }
  .ql-badge.congkhai { background:#E4F5EB; color:#2E7D32; }
  .ql-badge.nhap { background:#FFF3D9; color:#9A6A00; }
  .ql-badge.sheet { background:#E4EFFB; color:#1F63B8; }
  /* ⚠️ 01/09/2026 — lớp mà tab bên Google Sheet đã bị xoá. Con tem THAY tem
     "Google Sheet" (không đứng thêm bên cạnh): hai tem cùng nói về Sheet trên một
     hàng với tên lớp thì đẩy tên lớp xuống dòng, mà tem này đã hàm ý nguồn Sheet. */
  .ql-badge.mat-tab { background:#FDF0E3; color:#9A4B00; }
  /* 🎒 06/09/2026 — hai con tem trong hàng HỌC SINH (không phải hàng lớp).
     ⛔ `display:inline-block` chứ đừng để `width:fit-content` của tem cha đẩy nó
        xuống dòng riêng: ô Tên đã có sẵn ô nhập, tem phải nằm ngay bên cạnh.
     ⛔ Xanh cho "đã biết đi đâu", cam cho "cần xem lại" — cùng bộ màu với tem
        `mat-tab` ở trên, đừng nghĩ ra màu mới. */
  .ql-badge.da-roi-lop, .ql-badge.mat-tren-file {
    display:inline-block; margin-left:6px; font-size:10.5px; vertical-align:middle; }
  .ql-badge.da-roi-lop { background:#E4EFFB; color:#1F63B8; }
  .ql-badge.mat-tren-file { background:#FDF0E3; color:#9A4B00; }
  /* Dải chỉ việc phải làm tiếp, đặt ngay trên dãy nút của chính thẻ đó — đọc xong
     là bấm được luôn, không phải đi tìm màn khác (luật công-cụ-cho-người-thật). */
  .ql-mat-tab { margin:0 0 10px; padding:9px 12px; border-radius:var(--r-md);
    background:#FDF0E3; color:#9A4B00; border:1px solid #F0C08A;
    font-size:12px; line-height:1.55; }
  .ql-mat-tab b { font-weight:700; }
  .ql-the.ql-sheet { opacity:.97; }
  .ql-the { position:relative; }
  .ql-the.ql-chon { border-color:var(--xanh); box-shadow:0 0 0 2px rgba(20,160,160,.25); }
  .ql-tick { position:absolute; top:8px; right:8px; cursor:pointer; }
  .ql-tick input { width:18px; height:18px; cursor:pointer; accent-color:var(--xanh); }
  .ql-chon-thanh { display:flex; flex-wrap:wrap; align-items:center; gap:10px; margin:0 0 12px;
    padding:9px 13px; background:#E1F4F3; border:1px solid #9FD9D6; border-radius:var(--r-lg); position:sticky; top:0; z-index:5; }
  .ql-chon-so { font-size:13.5px; color:var(--muc); } .ql-chon-so b { font-size:15px; }
  /* 🗄️ Tab Đang chạy / Đã kết thúc trong Quản lý lớp */
  .ql-tab { display:flex; gap:8px; margin:10px 0 4px; flex-wrap:wrap; }
  .ql-tab-nut { font-size:14px; font-weight:700; padding:8px 16px; border-radius:var(--r-xl); cursor:pointer;
    border:1px solid var(--vien); background:var(--the); color:var(--muc); display:flex; align-items:center; gap:7px; }
  .ql-tab-nut:hover { border-color:var(--xanh); }
  .ql-tab-nut.chon { background:var(--xanh); color:#fff; border-color:var(--xanh); }
  .ql-tab-so { font-size:12px; font-weight:700; background:rgba(0,0,0,.12); border-radius:var(--r-xl); padding:1px 9px; }
  .ql-tab-nut.chon .ql-tab-so { background:rgba(255,255,255,.28); }
  /* 📗 06/09/2026 — HÀNG TAB LỌC THỨ HAI (đã / chưa lên điểm danh — Boss).
     Nhỏ và nhẹ hơn hàng trên có chủ đích: hàng trên chọn KHO lớp (đang chạy / đã
     kết thúc), hàng này chỉ lọc trong kho ấy. Hai hàng nút y hệt nhau xếp chồng là
     người đọc không biết cái nào bao cái nào.
     ⛔ ĐỪNG đổi thành viền đứt hay chữ nhạt để "cho khác": lúc đang chọn nó vẫn phải
        là nút xanh đặc như hàng trên, không thì không nhìn ra mình đang lọc cái gì. */
  .ql-tab-len { margin:2px 0 8px; }
  .ql-tab-len .ql-tab-nut { font-size:13px; font-weight:600; padding:5px 12px; }
  .ql-tab-len .ql-tab-so { font-size:11px; font-weight:700; padding:1px 7px; }
  .ql-the.ql-kt { opacity:.9; border-style:dashed; }

  /* ---- Lưới kiểu Sheets ---- */
  /* `overscroll-behavior-x:contain` chặn kéo ngang lan ra ngoài (trên điện thoại
     hay bị vuốt ngang một cái là trình duyệt hiểu nhầm thành "lùi trang").
     ⚠️ CỐ Ý chỉ chặn trục X. Đặt `contain` cả hai trục thì cuộn dọc hết bảng sẽ
     KHÔNG đẩy tiếp được trang — ngón tay bị kẹt trong bảng, đúng cái khó mà
     cô Quỳnh báo 25/07/2026. */
  /* ⭐ `touch-action:none` = app TỰ LO cả hai chiều — PHẢN HỒI TỨC THÌ.
     Bắt buộc phải tự lo: gần như mọi ô đều là <select>/<input> phủ kín, ngón tay
     đặt vào là trình duyệt hiểu "chạm ô nhập" chứ không phải "vuốt" (bẫy §6.18).

     ⛔ ĐÃ THỬ `pan-y` (nhường chiều dọc cho trình duyệt) và PHẢI BỎ: trình duyệt
     cần "đoán" xem đang vuốt ngang hay dọc trước khi chịu gửi sự kiện, nên kéo
     **rất chậm và ì** — cô Quỳnh báo ngay 25/07/2026. Chữa cái giật mà đẻ ra cái ì.

     Cái LÀM GIẬT không phải `touch-action:none`, mà là đoạn code TỰ GỌI
     `window.scrollTo` khi bảng hết chỗ cuộn dọc: cuộn trang làm toạ độ ngón tay
     đổi → vòng lặp → nhảy loạn (§6.28). Bỏ đúng đoạn đó là hết giật, mà vẫn
     nhanh. Đừng khôi phục lại nó. */
  /* ══════════════════════════════════════════════════════════════════════════════
     KHUNG ÔM SÁT BẢNG — cô Quỳnh 13/08/2026 (màn 27 inch)
     ──────────────────────────────────────────────────────────────────────────────
     Cô Quỳnh: *"lúc tôi vừa vào 1 lớp lại lòi ra 1 đoạn khoảng trắng xa vậy, khả
     năng cao là do màn hình tôi rộng 27 inch"*. Cô đoán đúng chỗ, và đây là cơ chế.

     ⛔ ĐÂY LÀ TÁC DỤNG PHỤ CỦA CHÍNH BẢN VÁ TỐI 13/08 CỦA TÔI (lúc 21:28). Bản đó
        sửa lỗi "kéo cột cuối là mất tên học sinh" bằng hai việc: cộng đủ bề rộng hai
        cột dính vào tổng (đúng, phải giữ), và THÔI ÉP `width` khi tổng còn hẹp hơn
        khung nhìn (chỗ sinh ra khoảng trắng này).

        Bỏ `width` thì thẻ `<table>` co lại vừa đúng nội dung — bảng không bao giờ tự
        nở ra bằng khối cha. Nhưng `.khung-cuon` là thẻ `<div>`, mà `<div>` thì LUÔN
        rộng hết phần cha. Trên màn 2340px, bảng một buổi chỉ có 14 cột nên dừng ở
        khoảng giữa, còn cái khung viền xám bo tròn nền trắng vẫn chạy tiếp hết bề
        ngang — thành một mảng trắng trơn to tướng bên phải.

     ⛔ CÁCH SỬA: cho KHUNG ôm sát bảng thay vì bắt BẢNG nở ra cho đầy khung.
        Bắt bảng nở đầy sẽ kéo giãn mọi cột theo tỉ lệ, tức là phá đúng cái bề rộng
        cột mà cô Quỳnh vừa yêu cầu lưu riêng cho từng tài khoản hôm nay. Không đáng.
     ⛔ `fit-content` chứ KHÔNG phải `max-content`: bảng rộng hơn chỗ trống thì khung
        vẫn chỉ lấy đúng chỗ đang có rồi cho cuộn ngang như cũ. Dùng `max-content` là
        khung phình theo bảng và đẩy cả trang ra, hỏng hẳn.
     ⛔ Làm bằng CSS chứ không đo trong JS: đo bề ngang của chính khung rồi lại đặt bề
        ngang cho nó là tự quay vòng — lần đo sau ra số khác lần trước.
     ══════════════════════════════════════════════════════════════════════════════ */
  .khung-cuon { overflow:auto; border:1px solid var(--vien); border-radius:var(--r-xl); background:#fff;
                max-height:calc(100vh - 190px - var(--dnc-du, 0px));
                width:fit-content; max-width:100%;
                /* ⛔ `-x` chứ KHÔNG phải trần. Chú thích ⚠️ ngay trên đã dặn "CỐ Ý chỉ
                   chặn trục X", nhưng mã lại viết `overscroll-behavior:contain` — chặn
                   luôn cả trục Y, tức cuộn dọc hết bảng thì ngón tay KẸT trong bảng,
                   không đẩy tiếp được trang. Đúng cái khó cô Quỳnh báo 25/07/2026 mà
                   dòng chú thích ấy sinh ra để chống. Vá 23/08/2026. */
                touch-action:none; overscroll-behavior-x:contain; }
  /* Kéo bảng bằng chuột trên máy tính (điện thoại vẫn dùng cuộn sẵn có của
     trình duyệt cho mượt — xem hàm gaKeoBang) */
  .khung-cuon.keo-duoc { cursor:grab; }
  /* Ô nhập trong khung cuộn: con trỏ chữ, để biết là bôi chọn được (10/08/2026). */
  .khung-cuon.keo-duoc textarea, .khung-cuon.keo-duoc select, .khung-cuon.keo-duoc [contenteditable],
  .khung-cuon.keo-duoc input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=submit]) { cursor:auto; }
  .khung-cuon.dang-keo { cursor:grabbing; user-select:none; }
  .khung-cuon.dang-keo select, .khung-cuon.dang-keo input { pointer-events:none; }

  /* ---- Thanh nhảy giữa các buổi ----
     Bảng rộng cả trăm cột; vuốt tay tới buổi cần điền là cực hình trên điện thoại.
     Nút ◀ ▶ nhảy đúng một khối DAY, nút "Buổi đang điền" nhảy thẳng về chỗ cần làm. */
  .dh-day { display:flex; align-items:center; gap:7px; margin:0 0 9px; flex-wrap:wrap; }
  .dh-day button { border:1px solid var(--vien); background:#fff; border-radius:var(--r-md);
                   padding:8px 12px; font-size:13px; font-weight:700; color:var(--chu); }
  .dh-day button:hover:not(:disabled) { border-color:var(--xanh); color:var(--xanh); }
  .dh-day button:disabled { opacity:.4; cursor:default; }
  /* ⛔ BỀ RỘNG CỐ ĐỊNH — cô Quỳnh chốt 25/07/2026: "nút không bị di chuyển theo
     số lượng chữ". Tên buổi dài ngắn khác nhau ("DAY 9" vs "DAY 10 (old)") mà để
     ô chữ co giãn thì hai nút ◀ ▶ nhảy qua nhảy lại, bấm liên tiếp là trượt tay.
     `flex:0 0 auto` + `width` cố định: chữ dài thì cắt bằng "…", nút đứng im. */
  /* ---- AVATAR + MENU TÀI KHOẢN ---- */
  /* Ba nút cũ đã gom hết vào menu avatar → ẨN đi cho thanh trên gọn.
     ⛔ ĐỪNG XOÁ khỏi HTML: menu avatar bấm hộ chúng (`$("#nutTaiKhoan").click()`),
     xoá là các mục trong menu chết câm. Chỉ giấu bằng CSS. */
  #nutCaiDat, #nutTaiKhoan, #nutThoat { display:none !important; }
  .tk-boc { position:relative; margin-left:auto; }
  .tk-nut { display:flex; align-items:center; gap:8px; background:transparent; border:1px solid var(--vien);
    border-radius:999px; padding:4px 10px 4px 4px; cursor:pointer; color:var(--chu); font:inherit; }
  .tk-nut:hover { background:var(--nen2); }
  /* 👤 Hình người mặc định — xem khối lý do ở `AV_NGUOI` trong phần mã.
     ⛔ `fill:currentColor` là chỗ mấu chốt: một hình dùng chung cho sáu ô có nền
        khác nhau, mỗi ô tự quyết màu bằng `color` của chính nó. */
  .av-nguoi { width:100%; height:100%; display:block; fill:currentColor; }
  /* ⛔ Ô ảnh đại diện KHÔNG còn tô màu sinh theo tên nữa (bỏ ngày 22/08/2026) —
     nền xám nhạt, hình người xám, đúng kiểu Facebook. Xem `AV_NGUOI`. */
  .tk-anh { width:30px; height:30px; border-radius:50%; display:grid; place-items:center;
    background:var(--nen2); color:var(--mo); border:1px solid var(--vien);
    box-sizing:border-box; flex:0 0 auto; }
  .tk-anh.to { width:42px; height:42px; font-size:15px; }
  .tk-anh { overflow:hidden; }                                   /* để ảnh avatar tròn khít */
  .tk-anh img { width:100%; height:100%; object-fit:cover; border-radius:50%; }
  .tk-ten { font-weight:700; font-size:13px; max-width:150px; overflow:hidden;
    text-overflow:ellipsis; white-space:nowrap; }
  .tk-mui { font-size:10px; opacity:.6; }
  /* ══════════════════════════════════════════════════════════════════════════
     👤 MENU AVATAR PHẢI DÍNH VÀO NÚT TRÒN — Boss 10/09/2026
     ──────────────────────────────────────────────────────────────────────────
     Boss: *"cái block avatar ở trên cùng thanh màn hình tròn tròn bé bé ấn vào
     hiện ra mục này thì tôi muốn bạn trang trí lại cho tôi mục này nó gắn liền
     với cái block tròn hơn đi chứ nó tách ra lơ lửng giữa màn hình quá, và ấn
     phát hiện luôn gây giật mình nên tôi muốn nó có animation nó mở kéo xuống
     nhẹ nhàng."*

     BA THỨ SỬA, mỗi thứ chữa đúng một nửa câu Boss:
       ① Khe hở 6px → 4px, và có MỘT MŨI TÊN nhỏ trỏ lên đúng tâm nút tròn. Hộp
          không còn trôi tự do: mắt nối được nó với nút vừa bấm.
       ② Bóng đổ nhẹ đi (32px → 22px) và thêm viền trên đậm hơn một nấc — bóng quá
          dày làm hộp trông như đang bay lơ lửng bên trên trang.
       ③ Mở ra thì TRƯỢT XUỐNG 6px + hiện dần trong 0,16 giây, gốc biến đổi ở góc
          trên–phải (đúng chỗ nút tròn) nên nó trông như bung ra TỪ cái nút.

     ⛔ DÙNG `animation`, KHÔNG DÙNG `transition`. Menu bật/tắt bằng thuộc tính
        `hidden` (`#tkMenu.hidden`), mà phần tử vừa từ `display:none` hiện ra thì
        KHÔNG có trạng thái đầu để transition chạy từ đó — trình duyệt nhảy thẳng
        tới trạng thái cuối, y hệt không có hiệu ứng. `animation` thì chạy ngay
        khi phần tử xuất hiện, không cần JS đụng vào.
     ⛔ CHỈ 0,16 GIÂY. Đây là menu người ta bấm mỗi ngày; dài hơn là thấy chậm.
     ⛔ TÔN TRỌNG `prefers-reduced-motion`: có người tắt hiệu ứng vì chóng mặt.
     ⛔ MŨI TÊN vẽ bằng hai hình vuông xoay 45°, KHÔNG dùng border-triangle: cần cả
        viền lẫn nền, mà tam giác bằng border thì không có viền riêng. Lớp dưới là
        viền, lớp trên là nền — đúng cách Bootstrap/Popper vẫn làm.
     ⛔ Mũi tên đặt ở `right:14px` — tâm nút tròn 30px trên điện thoại (padding 3px)
        rơi vào quãng đó. Đo lại nếu đổi cỡ `.tk-anh`.
     ══════════════════════════════════════════════════════════════════════════ */
  .tk-menu { position:absolute; right:0; top:calc(100% + 4px); z-index:60; min-width:232px;
    /* ⛔ MỘT BIẾN CHO CẢ HỘP LẪN MŨI TÊN. Trước đây hộp gõ thẳng #fff còn mũi tên
       lấy var(--the) — nền tối là hai màu lệch nhau, mũi tên lộ ra như miếng vá.
       Ai đổi màu menu sau này chỉ phải sửa đúng một chỗ. */
    --tk-nen:#fff;
    background:var(--tk-nen); border:1px solid var(--vien); border-radius:var(--r-xl); padding:6px;
    box-shadow:0 8px 22px rgba(0,0,0,.13);
    transform-origin:top right;
    animation:tkMenuXuong .16s cubic-bezier(.22,.68,.36,1) both; }
  /* Mũi tên: lớp dưới là viền, lớp trên là nền — đè lên nhau lệch 1px. */
  .tk-menu::before, .tk-menu::after {
    content:""; position:absolute; right:14px; width:11px; height:11px;
    transform:rotate(45deg); border-radius:2px; }
  .tk-menu::before { top:-6px; background:var(--vien); }
  .tk-menu::after  { top:-5px; background:var(--tk-nen); }
  @keyframes tkMenuXuong {
    from { opacity:0; transform:translateY(-6px) scale(.985); }
    to   { opacity:1; transform:none; } }
  @media (prefers-reduced-motion:reduce) { .tk-menu { animation:none; } }
  .tk-menu .tk-dau { display:flex; gap:10px; align-items:center; padding:8px 10px 10px;
    border-bottom:1px solid var(--vien); margin-bottom:6px; }
  .tk-menu .tk-dau small { display:block; opacity:.65; font-size:11.5px; margin-top:2px; }
  .tk-menu button { display:block; width:100%; text-align:left; background:transparent; border:0;
    padding:9px 10px; border-radius:var(--r-md); cursor:pointer; font:inherit; font-size:13.5px; color:var(--chu); }
  .tk-menu button:hover { background:var(--nen2); }
  .tk-menu button.do { color:#c0392b; }
  /* 🌗 03/09/2026 — ĐỔI NỀN NGAY TRONG MENU AVATAR (cô Quỳnh, mẫu Supabase).
     ⛔ Hai nút nằm NGANG trong một hàng, khác mọi mục khác vốn xếp dọc — nên phải
        gỡ `display:block; width:100%` mà luật `.tk-menu button` ở trên áp cho
        MỌI nút trong menu, không thì hai nút chồng nhau thành hai dòng.
     ⛔ Dấu ĐANG CHỌN vẽ theo `body.toi`, không theo một biến JS: nền tối bật/tắt
        từ ⚙ Cài đặt hay từ đây thì dấu ở đây vẫn luôn đúng, khỏi đồng bộ tay. */
  .tk-menu .tk-nhan-nho { padding:8px 10px 3px; font-size:11px; font-weight:600;
 color:var(--mo); text-transform:none; }
  .tk-menu .tk-chedo { display:flex; gap:5px; padding:0 6px 4px; }
  .tk-menu .tk-chedo button { display:flex; align-items:center; justify-content:center;
    gap:6px; width:auto; flex:1 1 0; text-align:center; font-size:12.5px;
    padding:7px 6px; border:1px solid var(--vien); background:var(--the); }
  body:not(.toi) .tk-menu .tk-chedo [data-tkchedo="sang"],
  body.toi .tk-menu .tk-chedo [data-tkchedo="toi"] {
    background:var(--xanh-nhat); border-color:var(--xanh); color:var(--muc);
    font-weight:600; }
  .tk-menu .tk-vach { height:1px; background:var(--vien); margin:6px 4px; }
  /* ⛔ 03/09/2026 — BỐN MỤC NÀY ẨN KHỎI MENU AVATAR, KHÔNG XOÁ.
     Cô Quỳnh xin menu gọn kiểu Supabase ("gmail, màn hình tối hay trắng, đăng
     xuất thế thôi"). Bốn mục dưới đây ĐỀU CÒN ĐƯỜNG VÀO KHÁC — đã soi tận nơi:
       · Quản lý tài khoản · Quyền theo chức vụ · Lớp tôi phụ trách → ngăn
         "Quản trị" của thanh dọc (`TK_QUANLY`)
       · Cài đặt → nút "Cài đặt" của thanh dọc (trang ⚙ Cài đặt, `TK_CANHAN`)
     ⛔ ẨN chứ KHÔNG XOÁ THẺ: `chayMucTK` và vài đoạn khác còn tìm các id này.
        Xoá là chúng nổ, mà nổ lúc khởi động thì app đứng trước khi vào màn nào.
     ⛔ Mục nào SAU NÀY mất đường ở thanh dọc thì phải gỡ lớp này trả nó về menu —
        đừng để người dùng cụt cả hai cửa. */
  .tk-menu .tk-co-duong-khac { display:none; }
  @media (max-width:640px) { .tk-nut { padding:3px; border:0; } .tk-menu { min-width:210px; } }

  .dh-day .dh-chu { font-size:13px; font-weight:700; color:var(--mo);
    flex:0 0 auto; width:150px; text-align:center;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  /* Thanh KÉO nhanh giữa các buổi — lớp 40-80 buổi bấm ◀▶ không xuể */
  .dh-day .dh-keo { flex:1 1 120px; min-width:90px; max-width:320px; accent-color:var(--xanh);
    height:22px; cursor:grab; touch-action:none; }
  .dh-day .dh-keo:active { cursor:grabbing; }
  /* Nới rộng + cho chữ thở: 190px làm nhãn "4. DAY 1 (24/7/2026) ← đang điền" bị
     nhồi dính cục (cô Quỳnh báo 25/07/2026). */
  /* 📜 02/09/2026 — Ô CHỌN BUỔI ĐỔI TỪ <select> SANG BẢNG TỰ VẼ CÓ CUỘN.
     Cô Quỳnh: *"lớp nào mà có nhiều day thì nó sẽ dài kinh khủng… thiết kế cái
     chức năng kéo lên xuống để không bị dài quá"*.
     ⛔ ĐỪNG QUAY VỀ <select>. Bảng xổ của <select> do HỆ ĐIỀU HÀNH vẽ, CSS không
        với tới được chiều cao của nó — max-height viết vào cũng vô nghĩa. Lớp 54
        buổi là danh sách chạy gần hết màn hình, đúng cái cô Quỳnh chỉ.
     ⛔ Chiều cao hãm bằng min(46vh, 340px): trên màn thấp thì 46vh nhỏ hơn nên
        bảng không tràn khỏi màn; trên màn cao thì 340px chặn lại cho khỏi dài
        quá. Thiếu một trong hai vế là hỏng ở đúng loại màn còn lại.
     ⛔ overscroll-behavior:contain — cuộn hết bảng thì DỪNG, không đẩy tiếp cho
        trang nền cuộn theo. Không có nó thì cuộn tới đáy danh sách buổi là cả
        bảng điểm danh phía sau chạy mất chỗ. */
  .dh-day .dh-chon-boc { position:relative; flex:0 1 auto; min-width:150px; max-width:290px; }
  .dh-day .dh-chon { display:flex; align-items:center; gap:6px; width:100%;
    font-size:12.5px; padding:6px 8px; line-height:1.5; text-align:left; font-weight:500;
    border:1px solid var(--vien); border-radius:var(--r-md);
    background:#fff; color:var(--chu); cursor:pointer; }
  /* ⛔ Ba lớp chứ không hai: luật `.dh-day button:hover:not(:disabled)` ở trên có
     trọng số CAO HƠN `.dh-day .dh-chon:hover`, nên viết ngắn là chữ trên nút hoá
     teal theo luật kia. Thêm `.dh-chon-boc` cho đủ sức đè. */
  .dh-day .dh-chon-boc .dh-chon:hover { border-color:var(--xanh); color:var(--chu); }
  .dh-day .dh-chon-chu { flex:1; min-width:0; overflow:hidden;
    text-overflow:ellipsis; white-space:nowrap; }
  .dh-day .dh-chon-mui { flex:none; font-size:10px; color:var(--mo); }
  .dh-day .dh-chon-menu { position:absolute; left:0; right:auto; top:calc(100% + 4px);
    z-index:70; min-width:100%; width:max-content; max-width:min(460px, 86vw);
    max-height:min(46vh, 340px); overflow-y:auto; overflow-x:hidden;
    overscroll-behavior:contain; padding:4px;
    background:var(--the); border:1px solid var(--vien); border-radius:var(--r-md);
    box-shadow:0 12px 32px rgba(0,0,0,.16); }
  /* Chuyen dong MO RA — Boss chot 08/09/2026: *"cai nut an vao chon day ngay thi
     no ko co aniamtion keo cai cot xuong ma bup phat hien ra giat minh nen toi muon
     co saniamtion tha xuong lua chon de tim day"*.
     Menu nay bat/tat bang thuoc tinh `hidden` chu khong dung/xoa phan tu, nen chi
     can bam vao `:not([hidden])` la du — khong phai sua JS.
     Cung khuon voi bang tha cua nut chon co so (`dncThaXuong`), de hai cho mo ra
     giong nhau; nhung giu keyframes rieng vi menu nay do tu `.dh-chon-boc` chu
     khong phai fixed theo man.
     KHONG dung `scale`: menu co `overflow-y:auto` va `max-height`, keo gian la chu
     ben trong meo theo. */
  @keyframes dhMenuXuong { from { opacity:0; transform:translateY(-6px); }
                           to   { opacity:1; transform:none; } }
  .dh-day .dh-chon-menu:not([hidden]) {
    animation:dhMenuXuong .15s cubic-bezier(.22,.9,.28,1) both; }
  @media (prefers-reduced-motion: reduce) {
    .dh-day .dh-chon-menu:not([hidden]) { animation:none; }
  }
  /* 🔎 20/09/2026 — Ô TÌM trong bảng chọn buổi (Boss xin "thanh tìm kiếm").
     ⛔ Ô tìm DÍNH trên đỉnh (`position:sticky`) còn danh sách thì cuộn riêng
        bên dưới — cuộn tới buổi 40 mà ô tìm trôi mất thì muốn sửa chữ vừa gõ
        phải cuộn ngược lên đầu.
     ⛔ Nền phải ĐẶC (`var(--the)`), không trong suốt: chữ của mấy dòng buổi
        cuộn qua bên dưới sẽ chạy xuyên qua ô tìm. */
  .dh-day .dh-chon-tim { position:sticky; top:0; z-index:2; display:flex;
    align-items:center; gap:0; margin:-4px -4px 4px; padding:4px;
    background:var(--the); border-bottom:1px solid var(--vien-nhe); }
  .dh-day .dh-chon-tim i[class^="ic-"] { position:absolute; left:14px;
    width:13px; height:13px; margin:0; color:var(--mo); pointer-events:none; }
  .dh-day .dh-chon-tim input { width:100%; height:32px; padding:0 9px 0 30px;
    border:1px solid var(--vien); border-radius:var(--r-sm); background:var(--nen-o);
    color:var(--chu); font-family:inherit; font-size:12.5px; }
  .dh-day .dh-chon-tim input:focus { outline:none; border-color:var(--xanh); }
  /* Chrome vẽ sẵn một nút X trong `type=search`; nó lệch tông với cả app. */
  .dh-day .dh-chon-tim input::-webkit-search-cancel-button {
    -webkit-appearance:none; appearance:none; }
  .dh-day .dh-chon-trong { margin:0; padding:12px 9px; font-size:12.5px;
    color:var(--mo); line-height:1.5; }
  /* Vùng chạm 44px trên điện thoại — đây là đường đi chính tới từng buổi.
     Số 44 theo chuẩn Apple; Google đòi 48dp nhưng bảng này nằm trong một menu
     thả xuống có giới hạn chiều cao, 44 là mức vừa đủ mà vẫn thấy được 5 dòng. */
  @media (max-width:820px) {
    .dh-day .dh-chon-tim input { height:40px; font-size:14px; }
    .dh-day .dh-chon-menu .dh-mucbuoi { min-height:44px; display:flex;
      align-items:center; }
  }
  .dh-day .dh-chon-menu .dh-mucbuoi { display:block; width:100%; text-align:left;
    background:transparent; border:0; border-radius:var(--r-sm); padding:7px 9px;
    font:inherit; font-size:12.5px; font-weight:500; color:var(--chu); cursor:pointer;
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .dh-day .dh-chon-menu .dh-mucbuoi:hover { background:var(--nen2); color:var(--chu); }
  .dh-day .dh-chon-menu .dh-mucbuoi.chon { background:var(--xanh-nhat); font-weight:700; }
  @media (max-width:640px) { .dh-day .dh-chon-boc { max-width:100%; flex:1 1 100%; } }
  .dh-day .dh-toi { border-color:var(--cam); background:#FFF6EA; color:#B26A00;
                    display:inline-flex; align-items:center; justify-content:center;
                    gap:6px; }
  .dh-day .dh-toi:hover { background:var(--cam); color:#fff; }
  table.luoi { border-collapse:separate; border-spacing:0; font-size:13px; }
  .luoi th, .luoi td { border-right:1px solid #E5E9EE; border-bottom:1px solid #E5E9EE;
                       padding:0; white-space:nowrap; background:#fff; }

  /* ---- VẠCH NGĂN GIỮA CÁC KHỐI DAY ----
     Cột đầu của mỗi khối có vạch dày; khối kế tiếp nhìn phát là tách hẳn ra,
     không bị lẫn sang khối bên cạnh (user yêu cầu 24/07/2026). */
  .luoi .batdau-day { border-left:3px solid #253449 !important; }
  .luoi td.batdau-day { border-left:3px solid #C3CBD6 !important; }
  .luoi .h-day { border-left:3px solid #101A28 !important; }

  /* hàng tiêu đề khối DAY */
  .luoi .h-day { position:sticky; top:0; z-index:5; color:#fff; text-align:center;
                 font-weight:700; font-size:12.5px; padding:7px 8px; }
  .h-day.nau  { background:var(--day-nau); }
  .h-day.navy { background:var(--day-navy); }
  .h-day .ngay { font-weight:600; opacity:.85; margin-left:6px; font-size:11.5px; }
  .h-day .done { display:inline-block; margin-left:8px; background:rgba(255,255,255,.18);
                 border-radius:var(--r-xl); padding:1px 9px; font-size:10.5px; }
  /* 🚫 31/08/2026 — BUỔI GIÁO VỤ ĐÃ HUỶ. Phải ĐỎ và đọc được ngay trên đầu khối:
     trước đây buổi huỷ trông y hệt buổi thường, trợ giảng bấm mãi không gõ được ô
     nào mà không một chữ nào nói vì sao. */
  .h-day .done.dahuy { background:#B0281C; color:#fff; font-weight:700; }
  .h-day.dangmo { outline:3px solid var(--cam); outline-offset:-3px; }
  .h-day .nut-done { margin-left:9px; border:none; border-radius:var(--r-md); background:var(--cam); color:#fff;
                     font-size:11px; font-weight:700; padding:4px 12px; cursor:pointer; }
  .h-day .nut-done:hover { filter:brightness(1.12); }
  .h-day .nut-done:disabled { opacity:.6; cursor:default; }
  /* Ô cho trợ giảng TỰ GHI tên buổi (sheet để trống, không ghi sẵn DAY N) */
  .o-ten-day { width:96px; border:none; border-radius:var(--r-o, 8px); padding:3px 8px; font-size:12px;
               font-weight:700; text-align:center; background:rgba(255,255,255,.92); color:#1C2530; }
  .o-ten-day:focus { outline:2px solid var(--cam); }
  .o-ten-day::placeholder { color:#8A93A0; font-weight:600; }
  /* Ô tiêu đề cột: bấm đúp đổi tên · GIỮ RỒI KÉO để đổi chỗ cột */
  .h-cot { cursor:pointer; }
  .h-cot:hover { background:#E4EAF0; }
  .h-cot.moi { background:#E8F4EC; }
  /* Chỉ khi BẬT nút "Đổi chỗ cột" thì tiêu đề mới thành chỗ để kéo cột.
     Lúc tắt, tiêu đề để trống cho việc vuốt bảng đi ngang. */
  #app.keo-cot-bat .h-cot[data-cot] { cursor:grab; background:#FFF4E5; }
  #app.keo-cot-bat .h-cot[data-cot]::after {
    content:"↔"; display:block; margin-top:2px; font-size:12px; color:var(--cam-dam); }
  #app.keo-cot-bat .h-cot.khoa-mo[data-cot] { background:#FFEBCC; }
  body.dang-keo-cot { user-select:none; }
  body.dang-keo-cot .h-cot[data-cot] { cursor:grabbing; }
  /* nút bật/tắt */
  .nut-keocot { border:1px solid var(--vien); background:#fff; color:var(--chu);
                border-radius:var(--r-md); padding:8px 13px; font-size:13px; font-weight:700; }
  .nut-keocot:hover { border-color:var(--cam); color:var(--cam-dam); }
  .nut-keocot.dang-bat { background:var(--cam); border-color:var(--cam); color:#fff;
                         box-shadow:0 3px 12px rgba(245,130,31,.35); }
  .cot-dang-cam { box-shadow:inset 0 0 0 2px var(--cam); opacity:.97; }
  th.cot-dang-cam { z-index:9; }
  td.cot-dang-cam { position:relative; z-index:4; }
  /* các cột né sang nhường chỗ — đây là phần "animation" cô Quỳnh muốn */
  .cot-nhuong { transition:transform .16s cubic-bezier(.2,.8,.3,1); }
  /* Nút thêm cột — để trên THANH CÔNG CỤ của lớp, không nhét cuối bảng.
     Cuối bảng là sau hơn 100 cột, phải cuộn sang phải mãi mới thấy (user báo 24/07). */
  .nut-themcot { border:1px dashed var(--xanh); background:var(--xanh-nhat); color:var(--xanh-dam);
                 border-radius:var(--r-md); padding:8px 13px; font-size:13px; font-weight:700; }
  .nut-themcot:hover { background:var(--xanh); color:#fff; border-style:solid; }
  .nut-molai { border:1px solid var(--cam); background:#FFF6EA; color:#B26A00;
               border-radius:var(--r-md); padding:8px 13px; font-size:13px; font-weight:700; }
  .nut-molai:hover { background:var(--cam); color:#fff; }

  /* ---- hàng tên cột con ----
     ⚠️ Tên cột tiếng Việt rất dài: "Số câu sai phần luyện tập kiến thức mới".
     Bản cũ bó trong 86px + chữ 10.5px nên nó xếp thành 6–7 dòng chữ li ti dồn
     cục vào nhau, đọc không nổi (cô Quỳnh báo 25/07/2026). Nới rộng + tăng cỡ
     chữ + giãn dòng. Bảng có rộng thêm cũng không sao: đã có nút ◀ ▶ nhảy buổi. */
  .luoi .h-cot { position:sticky; top:33px; z-index:5; background:#F2F5F8; color:#2C3742;
                 font-size:11.5px; font-weight:700; padding:7px 7px; text-align:center;
                 white-space:normal; overflow-wrap:break-word;
                 min-width:70px; max-width:152px; line-height:1.35; vertical-align:middle; }
  .h-cot.khoa-mo { background:#FEF3E2; }
  /* Cột chỉ có trong app, Sheet không có chỗ tương ứng → đánh dấu cho khỏi hiểu nhầm */
  .h-cot.chi-app { background:#F3EEFB; }
  .h-cot.chi-app.khoa-mo { background:#EFE6FB; }
  .dau-chiapp { display:block; margin-top:3px; font-size:9.5px; font-weight:700;
 color:#6B4FA8; }

  /* ---- Cột NGÀY ĐIỂM DANH (đầu mỗi khối DAY, giống sheet thật) ----
     Máy tự điền cho cả lớp theo ngày của buổi, không ai gõ tay. */
  .luoi .h-ngay { min-width:84px; max-width:98px; color:#1F2A5A; }
  .luoi td.o-ngay { min-width:84px; background:#F7F9FB; }
  .luoi td.o-ngay.dangmo { background:#FFF7E8; }
  .o-ngay .gt-ngay { font-size:11.5px; font-weight:700; color:#46525F; white-space:nowrap; }
  /* Máy tính: ngày đủ 4 số năm. Điện thoại: bản ngắn (xem @media bên dưới). */
  .o-ngay .ngay-ngan { display:none; }

  /* cột cố định bên trái */
  .luoi .c-ma  { position:sticky; left:0;    z-index:6; min-width:72px; background:#FAFBFC;
                 color:var(--mo); font-size:11.5px; padding:0 8px; }
  /* ⭐⭐ TÊN HỌC SINH XUỐNG DÒNG, KHÔNG CẮT — cô Quỳnh đề nghị 13/08/2026:
     *"cột tên vẫn không lấy theo tên dài nhất… bạn có thể thiết kế giống cột tên của
     điện thoại, nếu khó quá thì các tên dài sẽ xuống dòng"*.

     Bản điện thoại làm vậy từ lâu và chạy tốt (xem khối @media). Nay áp cho cả màn
     rộng. Cách này CHẮC HƠN HẲN cách đo bề rộng: dù cột bị bóp hẹp vì lý do gì —
     người kéo tay, bảng tính tổng thiếu, màn hình nhỏ — thì tên cũng chỉ XUỐNG DÒNG
     chứ không bao giờ mất chữ. Không phải đoán, không phải đo.

     ⛔ Hàng lưới cao 32px; tên hai dòng ở cỡ chữ 13px lọt vừa, số hàng nhìn thấy
        không đổi. Tên nào dài tới ba dòng thì hàng đó cao thêm — chấp nhận được, vì
        thà hàng cao hơn còn hơn gọi nhầm tên học sinh.
     ⛔ `break-word` chứ KHÔNG `break-all`: phải ngắt ở khoảng trắng giữa các tiếng,
        không được cắt ngang một tiếng thành "Nguy / ễn". */
  .luoi .c-ten { position:sticky; left:72px; z-index:6; min-width:158px; background:#FAFBFC;
                 font-weight:600; padding:3px 10px; border-right:2px solid #CBD4DC;
                 white-space:normal; line-height:1.2; overflow-wrap:break-word;
                 word-break:normal; }
  .luoi thead .c-ma, .luoi thead .c-ten { z-index:8; background:#F2F5F8; font-size:11.5px;
                 color:#3D4854; font-weight:700; text-align:left; padding:6px 10px; }

  /* hàng tổng */
  .luoi .tong td { background:#FBF6EC; color:#8A6D1B; font-weight:700; text-align:center;
                   font-size:12px; height:26px; }
  .luoi .tong .c-ma, .luoi .tong .c-ten { background:#FBF6EC; text-align:left; }

  /* ô dữ liệu */
  /* `position:relative` để ô CHỮ đang gõ neo được vào đúng ô của nó khi nổi lên
     (xem `.o textarea.o-chu:focus`). Không ảnh hưởng ô thường. */
  .luoi td.o { text-align:center; min-width:70px; height:32px; position:relative; }
  .o span.gt { display:block; padding:6px 5px; font-weight:700; font-size:12.5px; }
  .o.khoa { background:#FAFAF8; }
  .o.khoa span.gt { opacity:.92; }

  /* màu theo giá trị — cả ô khoá lẫn ô đang điền */
  .gt-tot   { background:var(--o-tot);   color:#fff; }
  .gt-nghi  { background:var(--o-nghi);  color:#fff; }
  .gt-thieu { background:var(--o-thieu); color:#3A2A00; }
  .gt-quen  { background:var(--o-quen);  color:#fff; }

  /* ô đang điền: select/input tràn kín ô */
  .o select, .o input { width:100%; height:30px; border:none; background:transparent; text-align:center;
                        font-size:12.5px; font-weight:700; padding:0 2px; appearance:auto; }
  .o select:focus, .o input:focus { outline:2px solid var(--cam); outline-offset:-2px; }
  .o.dangmo { background:#FFFDF7; }
  /* Ô buổi ĐÃ KHOÁ nhưng giáo vụ vẫn sửa được — nền tím nhạt cho phân biệt rõ */
  .o.gvsua { background:#F5F1FB; }
  .o.gvsua select, .o.gvsua input { font-weight:700; }
  .o input { font-variant-numeric:tabular-nums; }
  /* ⭐ 29/08/2026 — VẠCH BÁO ĐANG GIỮ Ô ĐẦU CỘT ĐẦU ĐIỂM (xem `hoiDoiTongCot`).
     Giữ 3 giây mà màn hình đứng im thì người ta buông tay ở giây thứ hai. Vạch chạy
     từ trái sang phải cho biết còn bao lâu nữa.
     ⛔ Chỉ vẽ vạch, KHÔNG đổi nền hay chữ của ô — ô vẫn phải đọc được, vì giữ hụt là
        trợ giảng gõ điểm tiếp ngay tại đó.
     Dùng nền chèn của chính ô nên không cần thêm thẻ nào; giữ hụt thì gỡ lớp là hết. */
  .o input.o-giu-tong {
    background-image:linear-gradient(var(--xanh-dam,#0B7A6E),var(--xanh-dam,#0B7A6E));
    background-repeat:no-repeat; background-position:left bottom;
    background-size:0 2px; animation:oGiuTong 2.6s linear forwards;
  }
  @keyframes oGiuTong { from { background-size:0 2px; } to { background-size:100% 2px; } }
  @media (prefers-reduced-motion:reduce) {
    /* Người tắt hiệu ứng vẫn phải biết là đang giữ — đứng yên nhưng hiện đủ vạch. */
    .o input.o-giu-tong { animation:none; background-size:100% 2px; }
  }
  /* ══════════════════════════════════════════════════════════════════════════════
     Ô VIẾT CHỮ: NẰM YÊN TRONG BẢNG, CHỈ CAO DẦN — cô Quỳnh 16/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     *"lúc viết dài ra thì cái ô đó phải mở rộng ra ở phía bên phải chứ không phải
     nhảy giữa bảng. Mở rộng ra như các công cụ giáo vụ có sheet khác á, nó cố định
     và đẹp."*

     Bề ngang do CỘT quyết định — `.luoi td.o-cot-chu` cho cột rộng sẵn 260px, đó
     chính là phần "rộng ra ở phía bên phải". Chiều cao do cơ chế chung `o-bang` lo,
     giống hệt Follow up · Chăm sóc · Lịch thi.

     ⛔⛔ TUYỆT ĐỐI KHÔNG cho ô này `position:absolute` hay `fixed` khi gõ. Đã thử
        HAI LẦN trong ngày 16/08 và cả hai lần ô đều BAY RA GIỮA TRANG, rời khỏi hàng
        của nó — cô Quỳnh gửi ảnh chụp. Ô phải ở yên đúng ô của nó.
     ══════════════════════════════════════════════════════════════════════════════ */
  .luoi td.o-cot-chu { min-width:260px; text-align:left; }
  /* ⛔⛔ CHỮ TĨNH CỦA BUỔI ĐÃ KHOÁ KHÔNG ĐƯỢC ĐÒI BỀ RỘNG — Boss cho sửa riêng lỗi này 22/09/2026
     (ngoài lỗi này màn Điểm danh vẫn cấm đụng).
     Trợ giảng lùi về buổi đã khoá (nút ◀) thì ô nhận xét là `span.gt` chứ không phải ô gõ. Đo
     Chrome thật 22/09, nhận xét ~470 chữ: cột nhận xét 2.835px một dòng (bảng 3.296px ở màn
     1600, 3.165px ở màn điện thoại 390), kéo hẹp cột không co, bấm vào không mở khung xem.
     Buổi đang mở cùng lớp: ô 260px (390: 70px), 4 dòng rồi cắt — đúng luật ㊱ Boss chốt 11/09.
     GỐC: `capNhatTong` (gaKeoCot) cố ý chỉ đặt `min-width` cho bảng (vá 11/09 cho Dự giờ), bảng
     không có bề rộng cụ thể thì Chrome BỎ `table-layout:fixed`, đo cột theo chữ; mà `span`
     mang `nowrap` (luật chung bảng Sheet) nên cả đoạn nằm một dòng và đẩy cột ra.
     ⇒ Chữ tĩnh theo ĐÚNG số của ô gõ: `width:0; min-width:100%` = không góp bề rộng nào vào
       cột, rồi phủ đủ ô · xuống dòng · trần 80px = 4 dòng × 20px (khối ㊱) · cắt gọn, không dấu.
       Bấm vào ô bị cắt thì khung xem sẵn có (`sheetMoKhungXem`) mở đủ chữ — không viết thêm JS.
     ⛔ ĐỪNG gắn `.sheet-hang` vào bộ chọn: `gaKeoCot` đo và GHIM bề rộng cột TRƯỚC khi `sheetGan`
        gắn lớp ấy cho hàng. Đã đo: bộ chọn có `.sheet-hang` thì cột bị ghim 560px (trần kéo cột).
     ⛔ ĐỪNG đổi sang `width:100%`: đo 22/09 (Chrome thật) thì ở màn 1600 cột bị ghim 560px (trần
        kéo cột) chứ không về 260px như buổi đang mở. `width:0` mới là thứ không góp bề rộng.
     ⛔ ĐỪNG kẹp dòng bằng `-webkit-line-clamp`: nó tự vẽ "…", mà Boss đã bỏ dấu ấy 21/09.
     ⛔ Chỉ ô CHỮ (kiểu "chu"). Ô tích nhiều mục (`.o-tich-xem`) cũng mang `o-cot-chu` — không đụng.
     Bài canh: kiem-thu/thu-o-khoa-nhan-xet-22-09.js */
  .luoi td.o.khoa.o-cot-chu > span.gt:not(.o-tich-xem) {
    display:block; width:0; min-width:100%;
    white-space:pre-wrap; overflow-wrap:anywhere; text-align:left;
    max-height:80px; overflow:hidden;
  }
  .o textarea.o-chu { width:100%; box-sizing:border-box; display:block;
                      text-align:left; font-size:13px; font-family:inherit;
                      font-variant-numeric:normal; letter-spacing:0;
                      border:none; outline:none; background:transparent; color:inherit;
                      resize:none; overflow:hidden; white-space:pre-wrap;
                      padding:5px 7px; line-height:1.45; min-height:30px; }
  /* Đang gõ: CHỈ tô viền cho biết đang ở ô nào. Không dời, không đổi bề ngang. */
  .o textarea.o-chu:focus { box-shadow:inset 0 0 0 2px var(--muc); background:var(--the);
                            border-radius:var(--r-o, 8px); }
  /* Ô chữ chưa gõ gì: chữ gợi ý mờ hẳn cho khỏi rối mắt giữa một bảng toàn số. */
  .o textarea.o-chu::placeholder { color:var(--mo); opacity:.55; }

  /* ⛔ PHẢI đặt CẢ NỀN cho <select>, không chỉ màu chữ.
     Dòng `.o select { background:transparent }` ở trên có độ ưu tiên CAO HƠN
     `.gt-tot` (2 phần chọn so với 1), nên nó đè mất nền màu — kết quả là
     chữ TRẮNG nằm trên nền TRẮNG, người dùng chọn "Đủ" xong thấy ô trống trơn
     và tưởng bị mất (user báo 24/07/2026). Bốn dòng dưới có độ ưu tiên cao hơn
     nên thắng. ĐỪNG rút gọn thành chỉ đặt `color`. */
  .o select.gt-tot   { background:var(--o-tot);   color:#fff; }
  .o select.gt-nghi  { background:var(--o-nghi);  color:#fff; }
  .o select.gt-thieu { background:var(--o-thieu); color:#3A2A00; }
  .o select.gt-quen  { background:var(--o-quen);  color:#fff; }
  /* Ô chọn còn trống: viền đứt cho thấy "chỗ này chưa điền" */
  .o select:not([class*="gt-"]) { background:#fff; color:var(--mo);
                                  box-shadow:inset 0 0 0 1px #E0E6EC; border-radius:var(--r-o, 8px); }
  /* Danh sách xổ ra phải luôn chữ đen nền trắng, không thừa hưởng màu của ô */
  .o select option { background:#fff; color:#1C2530; font-weight:600; }

  /* ---- HÀNG CỦA HỌC SINH NGHỈ: TÔ XÁM + KHOÁ (cô Quỳnh 25/07/2026) ----
     "bôi đen ... để đỡ điền nhầm". Dùng xám đậm chứ không đen kịt: phải nhìn ra
     ngay là hàng chết, nhưng vẫn đọc được tên em đó là ai.
     ⛔ Ô "Điểm danh" CỐ Ý không bị khoá — tích nhầm còn có đường sửa lại. */
  .luoi tr.hs-nghi .c-ma,
  .luoi tr.hs-nghi .c-ten { background:#D5DAE0; color:#5A646E; text-decoration:line-through; }
  .luoi tr.hs-nghi td.o { background:#DFE3E8; }

  /* ---- HỌC SINH NGHỈ HẲN (Move Out / Stop) — cô Quỳnh 26/07/2026 ----
     Đậm hơn hẳn kiểu "nghỉ một buổi": em này không bao giờ điền nữa, phải nhìn
     ra ngay từ xa để khỏi lỡ tay. Nhưng vẫn đọc được tên (còn tra cứu). */
  .luoi tr.hs-nghi-han .c-ma,
  .luoi tr.hs-nghi-han .c-ten { background:#B9C0C8; color:#3B444D; text-decoration:line-through; }
  .luoi tr.hs-nghi-han td.o { background:#C6CCD3; }
  .luoi tr.hs-nghi-han td.o.o-nghi-khoa { background:#BEC5CC; }
  .nhan-nghi-han { display:block; margin-top:2px; font-size:9.5px; font-weight:700;

                   color:#fff; background:#7A848E; border-radius:var(--r-sm);
                   padding:1px 5px; width:fit-content; text-decoration:none; }
  .luoi td.o.o-nghi-khoa { background:#CFD5DB; }

  /* ---- DẢI "ĐANG ẨN N EM ĐÃ NGHỈ" (cô Quỳnh 14/08/2026) ----
     Giấu hàng thì PHẢI nói ra là đang giấu, kèm nút bật lại. Giấu im lặng thì giáo
     viên đếm thiếu một em rồi tưởng app làm mất học sinh của lớp. */
  .dai-an-nghi { display:flex; align-items:center; gap:10px; flex-wrap:wrap;
                 margin:8px 0 0; padding:7px 11px; font-size:12.5px;
                 color:var(--mo); background:var(--nen2);
                 border:1px solid var(--vien); border-radius:var(--r-md); }
  .dai-an-nghi b { color:var(--chu); font-weight:700; }
  .dai-an-nghi button { border:1px solid var(--vien); background:var(--the);
                        color:var(--chu); border-radius:var(--r-md); padding:5px 11px;
                        font-size:12.5px; font-weight:600; cursor:pointer;
                        font-family:inherit; }
  .dai-an-nghi button:hover { border-color:var(--xanh); color:var(--xanh); }
  /* Lớp mà CẢ LỚP đã nghỉ (đo thật 14/08/2026: 6/125 lớp) → lưới rỗng trơn, phải
     có câu giải thích chứ không thì nhìn như app hỏng. */
  .luoi tr.hang-trong-nghi td { padding:20px 12px; text-align:center;
                                color:var(--mo); font-size:13px; }

  /* ---- HÀNG HỌC BÙ (giả lập, chỉ trong app) — cô Quỳnh 28/07/2026 ----
     Nền vàng nhạt + nhãn để phân biệt rõ với học sinh thật của lớp; dữ liệu điền
     vào KHÔNG bao giờ lên Google Sheet. */
  .luoi tr.hs-bu .c-ma,
  .luoi tr.hs-bu .c-ten { background:#FFF6DE; }
  .luoi tr.hs-bu td.o { background:#FFFCF2; }
  /* 🎙️ Đã nộp bài nói → cả hàng xanh lá (cô Quỳnh 03/08/2026). */
  .luoi tr.hs-nop-noi td { background:#E4F5EB; }
  .luoi tr.hs-nop-noi .c-ma, .luoi tr.hs-nop-noi .c-ten { background:#D2EEDD; }
  .luoi tr.hs-nop-noi .c-ten { color:#155F35; }
  .nhan-noi { margin-right:3px; }
  .nhan-bu { display:block; margin-top:2px; font-size:9.5px; font-weight:700;
 color:#8A5A00; background:#FFE7A8;
             border:1px solid #F0CE77; border-radius:var(--r-sm);
             padding:0 5px; width:fit-content; text-decoration:none; }
  .hs-xoabu { float:right; margin-left:4px; border:none; background:transparent;
              cursor:pointer; font-size:13px; line-height:1; padding:1px 2px;
              border-radius:var(--r-sm); opacity:.75; }
  .hs-xoabu:hover { opacity:1; background:#FBD9D3; }

  /* Ô bị khoá: làm mờ hẳn và bỏ con trỏ chuột cho khỏi mời bấm (bẫy §6.9) */
  .o select:disabled, .o input:disabled {
    background:transparent; color:#8A939C; cursor:not-allowed; opacity:1;
    -webkit-text-fill-color:#8A939C;      /* Safari tự làm nhạt thêm nếu không chặn */
  }
  .luoi tr.hs-nghi td.o.o-nghi-khoa select:not([class*="gt-"]) { box-shadow:none; background:transparent; }

  /* ---- AI ĐANG Ở Ô NÀO — giống Google Sheet (cô Quỳnh 26/07/2026) ----
     Viền màu quanh ô + thẻ tên nhỏ ở góc trên. Màu sinh từ TÊN nên mỗi người một
     màu cố định, trùng đúng màu avatar của họ — nhìn phát biết ai.
     ⚠️ `outline` chứ không phải `border`: border làm ô rộng thêm 4px → cả bảng
     xô lệch mỗi lần có người bước vào ô (bẫy họ hàng với §6.16). */
  .luoi td.o.dang-sua { outline:2px solid var(--mau-nguoi); outline-offset:-2px; position:relative; }
  .luoi td.o.dang-sua::after {
    content: attr(data-ai);
    position:absolute; left:-2px; top:-15px; z-index:4;
    background:var(--mau-nguoi); color:#fff;
    font-size:9.5px; font-weight:700; line-height:1;
    padding:2px 5px; border-radius:var(--r-sm) var(--r-sm) var(--r-sm) 0;
    white-space:nowrap; pointer-events:none;
  }
  /* Hàng đầu bảng: thẻ tên chui lên trên mất → lật xuống dưới ô */
  .luoi tbody tr:first-child td.o.dang-sua::after { top:auto; bottom:-15px; border-radius:0 var(--r-sm) var(--r-sm) var(--r-sm); }

  /* Thanh "đang cùng xem lớp này" trên đầu bảng */
  .thanh-cung-xem { display:flex; align-items:center; gap:7px; flex-wrap:wrap;
                    margin:0 0 8px; font-size:12px; color:var(--mo); }
  .thanh-cung-xem .ai { display:inline-flex; align-items:center; gap:5px;
                        background:#fff; border:1px solid var(--vien); border-radius:999px;
                        padding:3px 10px 3px 4px; font-weight:700; color:var(--chu); }
  .thanh-cung-xem .cham-mau { width:16px; height:16px; border-radius:50%; display:inline-block; }

  .ghi-chu-khoa { font-size:12px; color:var(--mo); margin-top:8px; }
  /* Khối hướng dẫn gập lại được (cô Quỳnh 23/08/2026 — xem chú thích ở chỗ dựng).
     ⛔ `list-style:none` + `::-webkit-details-marker` để bỏ tam giác mặc định — mỗi
        trình duyệt vẽ một kiểu, để nguyên là mỗi máy nhìn một khác. */
  .ghi-chu-gap { margin-top:10px; }
  .ghi-chu-gap > summary { cursor:pointer; list-style:none; display:inline-flex;
    align-items:center; gap:6px; font-size:12.5px; color:var(--mo);
    padding:8px 12px; border:1px solid var(--vien); border-radius:var(--r-md);
    background:var(--the); min-height:38px; box-sizing:border-box; }
  .ghi-chu-gap > summary::-webkit-details-marker { display:none; }
  .ghi-chu-gap > summary::after { content:"▾"; font-size:11px; opacity:.7; }
  .ghi-chu-gap[open] > summary::after { content:"▴"; }
  .ghi-chu-gap > summary:hover { border-color:var(--xanh); color:var(--xanh); }
  .ghi-chu-gap[open] > .ghi-chu-khoa { margin-top:10px; }

  /* ============ GHI CHÚ CỦA BUỔI ============ */
  .khung-note { background:#fff; border:1px solid var(--vien); border-radius:var(--r-xl); padding:12px 14px; margin-top:12px; }
  .khung-note h4 { margin:0 0 8px; font-size:13px; color:var(--mo); }
  .khung-note textarea { width:100%; min-height:74px; border:1px solid var(--vien); border-radius:var(--r-o, 8px);
                         padding:10px 12px; font-size:14px; font-family:inherit; resize:vertical; line-height:1.5; }
  .khung-note textarea:focus { outline:2px solid var(--xanh); border-color:transparent; }
  .khung-note textarea[readonly] { background:#F7F8FA; color:var(--mo); }
  .note-duoi { display:flex; gap:9px; align-items:center; margin-top:9px; flex-wrap:wrap; }
  .note-luu { font-size:12.5px; color:var(--o-tot); font-weight:700; opacity:0; transition:opacity .25s; }
  .note-luu.hien { opacity:1; }

  /* ============ PHIẾU BUỔI (để chụp ảnh) ============
     Đây là thứ cô Quỳnh chụp màn hình gửi phụ huynh, nên phải ĐẸP và DỄ ĐỌC.
     Bản cũ: bảng 11 cột nhồi trong hộp thoại rộng 560px, chữ 11.5px, tên cột dài
     dồn thành nhiều dòng dính nhau — "xấu khó nhìn" (cô báo 25/07/2026).
     Cách chữa: hộp thoại rộng hẳn ra, chữ to lên, cột thở ra, hai cột đầu
     (số thứ tự + tên) DÍNH bên trái để cuộn ngang vẫn biết đang xem em nào. */
  .phieu { background:#fff; border-radius:var(--r-xl); padding:20px 20px 16px; }
  .phieu-dau { border-bottom:2px solid var(--xanh); padding-bottom:12px; margin-bottom:14px;
               display:flex; justify-content:space-between; align-items:center; gap:14px; }
  .phieu-dau .lop { font-size:21px; font-weight:700; letter-spacing:-.01em; }
  .phieu-dau .phu { font-size:13.5px; color:var(--mo); margin-top:5px; line-height:1.5; }
  /* 🏷 Logo MyPAS bên phải đầu phiếu (30/07, sửa 31/07) — dùng lại đúng khối
     `.logo-mypas` của app (My cam + PAS teal), chỉ dồn chữ về mép phải. */
  .phieu-logo { flex:none; }
  .phieu-logo .logo-mypas { align-items:flex-end; }
  /* 📝 Ghi chú buổi NGOÀI khung ảnh — góc phải dưới phiếu (31/07). Nằm ngoài
     #khungPhieu nên "Lưu ảnh phiếu" không bao giờ chụp trúng. */
  /* `white-space:pre-line` — GIỮ XUỐNG DÒNG người dùng gõ trong ghi chú (cô Quỳnh
     31/07: gõ xuống dòng mà phiếu hiện dồn một dòng). Text căn TRÁI cho dễ đọc
     khi nhiều dòng, cả khối vẫn dồn về phải bằng margin-left:auto. */
  .phieu-note-ngoai { text-align:left; margin:8px 4px 0 auto; max-width:min(92%, 520px);
                      white-space:pre-line; font-size:13px; line-height:1.5; color:#4A555C;
                      background:#FFF9E8; border:1px dashed #E3C96B; border-radius:var(--r-md);
                      padding:7px 11px; }
  .phieu-note-ngoai .nhan-note { display:block; font-weight:700; color:#8A6D1F; margin-bottom:3px; }
  /* Ô/tiêu đề phiếu đang trỏ vào để gõ tự do — viền mảnh cho biết chỗ đang sửa
     (viền chỉ hiện lúc focus nên KHÔNG dính vào ảnh chụp) */
  .phieu [contenteditable]:focus { outline:2px solid var(--xanh); outline-offset:-1px; border-radius:var(--r-sm); }
  /* ---- Khung phiếu: TỰ THU NHỎ CHO VỪA, không bắt cuộn ngang ----
     Cô Quỳnh 25/07/2026: "phần chụp ảnh của 2 thiết bị đều phải nhìn được hết
     tất cả các cột" + "kéo sang trái phải vẫn khó".
     → Bỏ hẳn chuyện cuộn ngang: bảng lấy bề ngang tự nhiên (`max-content`) rồi
     `transform: scale()` thu lại vừa khung (hàm `canhPhieu`). Ảnh chụp bắt trọn
     mọi cột trong một khung hình, không phải kéo đi đâu cả. */
  .phieu-cuon { overflow:hidden; border:1px solid #E3E8ED; border-radius:var(--r-lg); }
  table.phieu-bang { border-collapse:separate; border-spacing:0; font-size:13.5px;
                     width:max-content; min-width:100%; }
  .phieu-bang th, .phieu-bang td { border-right:1px solid #E3E8ED; border-bottom:1px solid #E3E8ED;
                                   padding:8px 9px; text-align:center; background:#fff; }
  .phieu-bang tr > *:last-child { border-right:none; }
  .phieu-bang tbody tr:last-child > * { border-bottom:none; }
  .phieu-bang th { background:var(--xanh-nhat); font-weight:700; font-size:12px; color:#28414A;
                   line-height:1.35; white-space:normal; overflow-wrap:break-word;
                   min-width:76px; max-width:124px; vertical-align:middle; padding:9px 8px; }
  .phieu-bang td { height:34px; font-weight:600; }
  .phieu-bang tbody tr:nth-child(even) > td { background:#FAFBFC; }
  /* ⛔ KHÔNG dùng `position:sticky` cho hai cột đầu nữa: bảng đang bị
     `transform: scale()`, mà phần tử có transform trở thành khung chứa mới nên
     sticky bám sai chỗ. Không cần nữa — phiếu đã vừa khung, chẳng phải cuộn. */
  .phieu-bang .c-stt { min-width:34px; width:34px; color:var(--mo); font-size:12px; }
  .phieu-bang .c-hs  { min-width:150px; text-align:left; font-weight:700; white-space:nowrap;
                       border-right:2px solid #CBD4DC; }
  .phieu-bang td[contenteditable]:focus { outline:2px solid var(--cam); background:#FFFBF2; }
  /* ✏️ Ô CỘT VIẾT CHỮ TRONG PHIẾU — cô Quỳnh 16/08/2026.
     `pre-wrap` là chỗ quan trọng nhất: nó giữ DẤU XUỐNG DÒNG người viết đã gõ.
     Không có nó thì HTML nuốt xuống dòng thành một dấu cách, cả câu dồn thành một
     dòng dài, kéo cột phình ngang và bóp hết các cột còn lại — và ảnh chụp gửi phụ
     huynh cũng mất luôn cách trình bày mà giáo viên cố ý viết.
     Trần 260px: rộng hơn nữa thì một cột nhận xét chiếm nửa tờ phiếu. */
  .phieu-bang td.c-chu { white-space:pre-wrap; overflow-wrap:break-word; word-break:break-word;
                         text-align:left; vertical-align:top; height:auto;
                         min-width:150px; max-width:260px; font-weight:500;
                         font-size:12.5px; line-height:1.4; }
  .phieu-bang th.c-chu-dau { max-width:260px; }
  /* tô màu giá trị trong phiếu y như trong bảng — nhìn phát biết ngay em nào thiếu */
  .phieu-bang td.v-tot   { background:#E7F4EC !important; color:#14603A; }
  .phieu-bang td.v-nghi  { background:#FBEBEA !important; color:#8E2F28; }
  .phieu-bang td.v-thieu { background:#FEF5E0 !important; color:#7A5600; }
  .phieu-bang td.v-quen  { background:#EEF0F4 !important; color:#414B5C; }
  .phieu-note { margin-top:14px; padding:11px 13px; background:#F7F8FA; border-radius:var(--r-md);
                font-size:13.5px; line-height:1.6; white-space:pre-line; }
  .phieu-huong-dan { font-size:13px; color:var(--mo); margin:14px 0 0; line-height:1.6; }
  .phieu-an-cot { margin:10px 0 0; font-size:13px; color:var(--mo); }
  .phieu-an-cot button { border:1px solid var(--vien); background:#fff; border-radius:var(--r-md);
                         padding:7px 12px; font-size:12.5px; font-weight:700; color:var(--xanh-dam); }
  .phieu-an-cot button:hover { border-color:var(--xanh); background:var(--xanh-nhat); }

  /* Nhãn trạng thái ngay cạnh tên buổi — xem phiếu buổi cũ phải biết ngay nó đã
     chốt hay đang điền, không thì sửa nhầm mà tưởng đang xem buổi hôm nay. */
  .phieu-nhan { display:inline-block; margin-left:10px; vertical-align:middle;
                font-size:11.5px; font-weight:700; border-radius:var(--r-xl); padding:4px 11px;
                background:#EEF1F5; color:var(--mo); }
  .phieu-nhan.khoa { background:#E7F4EC; color:var(--o-tot); }
  .phieu-nhan.mo { background:#FEF3E2; color:#B26A00; }

  /* Lật qua lại giữa các buổi ngay trong phiếu */
  .phieu-lat { display:flex; align-items:center; gap:9px; margin:12px 0 0; flex-wrap:wrap; }
  .phieu-lat button { border:1px solid var(--vien); background:#fff; border-radius:var(--r-md);
                      padding:8px 13px; font-size:12.5px; font-weight:700; color:var(--chu); }
  .phieu-lat button:hover:not(:disabled) { border-color:var(--xanh); color:var(--xanh); }
  .phieu-lat button:disabled { opacity:.4; cursor:default; }
  .phieu-lat-chu { font-size:12.5px; font-weight:700; color:var(--mo); }
  .phieu-lat .pl-anh { background:var(--xanh); border-color:var(--xanh); color:#fff; }
  .phieu-lat .pl-anh:hover:not(:disabled) { background:var(--xanh-dam); color:#fff; }
  .phieu-lat .pl-anh:disabled { opacity:.6; }

  /* ---- 🧊 MÀN PHỦ "ĐANG CHỈNH CỘT" (cô Quỳnh 29/07/2026) ----
     Thêm/xoá/đổi chỗ/đổi tên cột đang chạy → phủ kín app, KHÔNG điền được gì,
     chờ dấu ✓ XANH hiện rồi mới thao tác tiếp. Máy chủ cũng chặn thật (409) —
     màn phủ chỉ là lớp ngoài cho khỏi mời bấm. z thấp hơn modal(150)/toast(200). */
  #phuSuaCot { position:fixed; inset:0; z-index:140; background:rgba(16,32,38,.45);
               display:flex; align-items:center; justify-content:center; }
  .psc-hop { background:#fff; border-radius:var(--r-xl); padding:22px 30px; text-align:center;
             max-width:min(88vw,380px); box-shadow:0 12px 40px rgba(0,0,0,.25); }
  .psc-hop b { display:block; font-size:15.5px; margin:10px 0 6px; color:#1F2A33; }
  .psc-hop small { color:#5A646E; font-size:12.5px; line-height:1.45; display:block; }
  .psc-xoay { width:34px; height:34px; margin:0 auto; border-radius:50%;
              border:4px solid #D8E4E4; border-top-color:var(--xanh); animation:pscQuay 1s linear infinite; }
  @keyframes pscQuay { to { transform:rotate(360deg); } }
  .psc-tick { width:44px; height:44px; margin:0 auto; border-radius:50%; background:#1E7C45;
              color:#fff; font-size:26px; font-weight:900; line-height:44px; }

  /* Nút "bỏ bài đang sửa" dưới ô soạn caption (28/07/2026). Cố ý làm NHỎ và
     nhạt: nó là đường xoá chữ, không phải việc chính — đừng mời bấm. */
  .nut-bo-nhap { margin-top:7px; padding:5px 11px; font-size:12.5px; font-weight:600;
                 border:1px solid #D8DEE5; border-radius:var(--r-md); background:#F6F8FA;
                 color:#5A646E; cursor:pointer; }
  .nut-bo-nhap:hover { background:#ECEFF3; color:#333B44; }
  .nut-bo-nhap.hoi { background:#FDE7E7; border-color:#F0B4AE; color:#B0281C; }

  /* 📊 BẢNG ĐIỂM TRONG HỘP CAPTION (cô Quỳnh 29/08/2026) — xem `veBangDiemCaption`.
     Dáng bám mẫu Google Sheets: nền trắng, tiêu đề cột nền xanh lá chữ trắng, đường
     kẻ mảnh, số căn giữa và dùng chữ số đều bề ngang (`tabular-nums`) cho cột thẳng.
     ⛔ KHUNG CUỘN RIÊNG. Lớp 25 em × 8 cột mà để bảng đẩy hộp thoại rộng ra thì nút
        "Xong — gửi đi" trôi khỏi màn hình — bảng phải cuộn trong `.bdc-cuon`, không
        phải cả trang cuộn theo.
     ⛔ CAO TỐI ĐA 220px. Bảng cao hơn ô soạn là lấn mất việc chính (soạn caption). */
  .bdc { margin-bottom:12px; }
  .bdc-dau { display:flex; align-items:baseline; gap:8px; flex-wrap:wrap;
             font-size:12.5px; font-weight:700; color:var(--mo); margin-bottom:5px; }
  .bdc-dem { font-weight:600; color:var(--mo); opacity:.75; }
  .bdc-cuon { max-height:220px; overflow:auto; border:1px solid var(--vien); border-radius:var(--r-sheet); background:#fff; }
  .bdc-bang { border-collapse:separate; border-spacing:0; width:max-content; min-width:100%;
              font-size:12.5px; font-variant-numeric:tabular-nums; }
  .bdc-bang th, .bdc-bang td { padding:4px 9px; border-right:1px solid #E3E7EB;
                               border-bottom:1px solid #E3E7EB; text-align:center; white-space:nowrap; }
  .bdc-bang thead th { position:sticky; top:0; z-index:2; background:#1E8E4E; color:#fff;
                       font-weight:600; max-width:150px; overflow:hidden; text-overflow:ellipsis; }
  .bdc-bang .bdc-ten { position:sticky; left:0; z-index:1; background:#fff; text-align:left;
                       font-weight:600; color:var(--chu); max-width:170px;
                       overflow:hidden; text-overflow:ellipsis; }
  .bdc-bang thead .bdc-ten { z-index:3; background:#1E8E4E; color:#fff; }
  .bdc-bang tbody tr:nth-child(even) td { background:#FAFBFC; }
  .bdc-bang tbody tr:nth-child(even) .bdc-ten { background:#FAFBFC; }
  .bdc-bang .bdc-rong { color:#C3C9D0; }
  body.toi .bdc-cuon, body.toi .bdc-bang .bdc-ten { background:var(--the); }
  body.toi .bdc-bang th, body.toi .bdc-bang td { border-color:#343B42; }
  body.toi .bdc-bang tbody tr:nth-child(even) td,
  body.toi .bdc-bang tbody tr:nth-child(even) .bdc-ten { background:#242A30; }

  /* ---- Sửa tạm tên cột + đổi chỗ cột NGAY TRONG PHIẾU ----
     Chỉ để chụp ảnh cho gọn; không đụng app hay Google Sheet. */
  .pc-ten { display:block; cursor:text; border-radius:var(--r-sm); padding:1px 3px; }
  .pc-ten:hover { background:#FFF6E5; outline:1px dashed var(--cam); }
  .pc-ten:focus { outline:2px solid var(--cam); background:#FFFBF2; }
  /* Tay nắm kéo đổi chỗ cột. `touch-action:none` để ngón tay kéo được trên
     điện thoại (không thì trình duyệt cuộn trang, nuốt mất cú kéo). */
  .pc-keo { display:block; margin:3px auto 0; width:26px; cursor:grab;
            color:#9AA3AE; font-size:12px; line-height:1.2;
            border-radius:var(--r-sm); touch-action:none; user-select:none; }
  .pc-keo:hover { background:var(--xanh-nhat); color:var(--xanh-dam); }
  body.dang-keo-cot .pc-keo { cursor:grabbing; }
  /* Nút ẩn tạm MỘT cột khỏi phiếu (cô Quỳnh 27/07/2026). Chỉ đổi trong phiếu này. */
  .pc-an { display:inline-block; margin:2px auto 0; padding:0 5px; cursor:pointer;
           color:#B9424E; font-size:12px; font-weight:700; line-height:1.3;
           border-radius:var(--r-sm); border:1px solid transparent; user-select:none; }
  .pc-an:hover { background:#FDECEE; border-color:#E7B4BA; }
  /* Nút ✕ ẩn HÀNG học sinh trong phiếu (cô Quỳnh 28/07/2026) — nhỏ, đứng trước tên. */
  .hs-an { display:inline-block; margin-right:6px; width:18px; height:18px; line-height:16px;
           text-align:center; border-radius:50%; border:1px solid #E7B4BA; background:#FDECEE;
           color:#B9424E; font-size:11px; font-weight:700; cursor:pointer; vertical-align:middle; padding:0; }
  .hs-an:hover { background:#F7C9CE; }
  .phieu-bang .c-hs { white-space:nowrap; }
  /* Ô được tô màu thủ công trong phiếu (cô Quỳnh 27/07/2026). Vàng đậm, đè cả màu
     nền của ô chọn. `!important` để thắng lớp màu `mauNut`. Màu này ĐI VÀO ảnh. */
  .phieu-bang td.o-tomau { background:#FFE14D !important; font-weight:700; }
  .phieu-bang.dang-to-mau td { cursor:pointer; }
  .phieu-bang.dang-to-mau { outline:2px dashed #F5A623; outline-offset:3px; }
  .phieu-bang th.pc-dich { outline:2px solid var(--cam); outline-offset:-2px; background:#FFF1DC; }
  .phieu-bang .pc-dang-cam { opacity:.45; }
  /* Hộp thoại RỘNG — chỉ bật khi đang mở phiếu (xem moPhieu / dongHopThoai) */
  .modal.rong { width:min(97vw, 1060px); }

  /* ============ ĐIỆN THOẠI ============
     Nhân viên dùng điện thoại là chính. Lưới 100+ cột không thể điền trên màn hình
     nhỏ → chuyển hẳn sang chế độ THẺ: mỗi học sinh một thẻ, bấm nút to để chọn. */
  /* ⛔ Chế độ "Điền từng em" (thẻ) ĐÃ BỎ ngày 25/07/2026 — cô Quỳnh đổi ô đó
     thành TẠO CAPTION. Lưới đã vuốt được thoải mái trên điện thoại nên không
     cần chế độ thẻ nữa. */

  @media (max-width: 820px) {
    /* chừa chỗ cho THANH CÔNG CỤ dính đáy màn hình */
    .noi-dung { padding:12px 10px 96px; }
    /* ⛔ MÉP 0 — ĐỔI 08/09/2026, cho khớp `body.man-cong-cu .noi-dung` ở cùng mốc
       màn hình này (nó cũng vừa về margin 0). Boss chỉ thẳng vào chỗ này:
       *"ở trên cùng tách ra 1 chút so với cái thông báo ở dưới"* — cái "tách ra 1
       chút" chính là `margin:0 8px 8px` cũ: 8px hai bên và 8px dưới.
       ⛔ BA CHỖ MỘT CON SỐ, ĐỔI LÀ ĐỔI CẢ BA: `.thanh-tren` (đây) · `.dnc-dai` ·
          `body.man-cong-cu .noi-dung`. Lệch một chỗ là bài đo trên màn thật
          (thu-thanh-nut-cong-cu, mục "hai mép trái/phải khớp nhau") bắt ngay.
       ⛔ `thu-home-plus.js` đọc NGUYÊN VĂN dòng dưới. Sửa dòng này phải sửa cả
          phép canh bên đó, không thì đỏ mà lời báo lỗi nói về chuyện khác. */
    .thanh-tren { padding:4px 10px; gap:7px; margin:0; }
    /* ☰ 08/09/2026 — BA GẠCH, CHỈ MỌC Ở ĐÂY (điện thoại). Boss muốn đúng nếp
       Facebook: ba gạch góc trái, ấn ra ngăn kéo công cụ trượt từ bên trái sang.
       ⛔ Ô chạm 40x40 chứ không phải 24x24 bằng đúng ba cái gạch. Ngón cái không
          bấm trúng ô 24px — đó là lý do app cũ phải để nút "Thêm" to ở thanh đáy.
       ⛔ Ba gạch vẽ bằng ba thẻ <span> đặc, KHÔNG dùng ký tự "☰": mỗi máy một phông,
          ký tự ấy lúc mảnh lúc dày, lúc lệch khỏi tâm ô. */
    /* ⛔ 08/09/2026 — THU GỌN, nhưng GIỮ NGUYÊN Ô CHẠM 40px. Boss: *"để chỗ này chữ và
       nút gọn hơn cho tôi chứ tôi thấy nó chiếm màn quá"*. Đo trước khi sửa: thanh cao
       57px, và chính nút này (40px) là thứ ép chiều cao ấy.
       Cách thu: nút vẫn 40×40 để ngón cái bấm trúng, nhưng `margin:-4px 0` kéo nó THÒ
       RA khỏi dòng nên chỉ còn chiếm 32px chiều cao thanh.
       ⛔ ĐỪNG thu bằng cách hạ `height` xuống 32px — thế là thu cả ô chạm, và quay lại
          đúng lỗi mà khối chú thích ngay trên đã dặn tránh: ngón cái không bấm trúng ô
          nhỏ, rồi lại phải bày một nút to ở chỗ khác để bù. */
    .tt-bagach { display:flex; flex-direction:column; justify-content:center;
      align-items:center; gap:4px; flex:none;
      width:40px; height:40px; margin:-4px 0 -4px -8px;
      padding:0; border:0; background:none; cursor:pointer;
      border-radius:var(--r-lg); -webkit-tap-highlight-color:transparent;
      transition:background .18s ease, transform .18s ease; }
    .tt-bagach span { display:block; width:18px; height:2px; border-radius:2px;
      background:var(--chu); }
    .tt-bagach:active { background:var(--nen2); transform:scale(.92); }
    .tt-bagach:focus-visible { outline:2px solid var(--xanh); outline-offset:1px; }
    /* Chữ MyPAS 20 → 17px và bỏ phần đệm quanh logo: hai thứ này cùng với nút ba gạch
       ở trên là toàn bộ chiều cao thừa của thanh. Vẫn là chữ to nhất trên thanh. */
    .thanh-tren .logo-mypas { padding:0; }
    .thanh-tren .logo-mypas .ten { font-size:17px; }
    .thanh-tren .ten-app { font-size:13px; white-space:nowrap; padding-left:7px; }
    .thanh-tren .nut-nho { padding:7px 9px; font-size:15px; line-height:1; }
    .logo-dn .ten { font-size:23px; }
    .ten-toi { display:none; }
    .luoi-lop { grid-template-columns:1fr 1fr; gap:9px; }
    /* tiêu đề cơ sở trên điện thoại: vẫn phải nổi bật nhưng gọn hơn */
    .nhom-coso h2 { font-size:16.5px; padding:9px 12px; gap:7px; border-left-width:5px; }
    .nhom-coso h2 .dem-nhom { font-size:12.5px; }
    .nhom-coso + .nhom-coso { margin-top:26px; padding-top:18px; }
    /* 🗂 BÓP CHO GỌN — Boss 08/09/2026 *"các block lớp phải rõ ràng hơn gọn hơn"*.
       ⛔ Bóp ĐỆM và KHOẢNG CÁCH DÒNG, KHÔNG bỏ mẩu tin nào và KHÔNG hạ cỡ chữ dưới
          11,5px: năm mẩu (tên · lịch · giáo viên · sĩ số · trạng thái) đều là thứ
          trợ giảng cần liếc là thấy, bỏ mẩu nào cũng phải mở lớp ra mới biết.
       ⛔ Nhãn trạng thái KHÔNG nhấc lên cạnh tên được: "Đang học DAY 12" cần ~100px
          mà tên "4C12" đã ăn 55px trong lòng thẻ 149px — nhấc lên là nó bị bóp cụt.
          Đã đo trước khi bỏ ý ấy. */
    .the-lop { padding:12px 12px 11px; }
    .the-lop .ten { font-size:17px; }
    .the-lop .phu { font-size:11.5px; margin-top:3px; }
    /* ⛔ Giờ KHÔNG hạ theo dòng phụ. Đây là mẩu tin Boss bảo phải nổi bật, hạ bằng
       chữ mờ là xoá đúng thứ vừa làm. 12,5px vẫn to hơn dòng phụ 11,5px một bậc. */
    .the-lop .tl-gio { margin-top:4px; }
    .the-lop .tl-gio span { font-size:12.5px; }
    .the-lop .tl-gv { font-size:11.5px; margin-top:2px; }
    .the-lop .duoi { margin-top:8px; gap:5px; }
    .the-lop .siso { font-size:11.5px; }
    .the-lop .nhan-gio { margin-bottom:5px; }
    .dau-lop { gap:8px; margin-bottom:10px; }
    .dau-lop .ten { font-size:19px; }
    .dau-lop .phu { font-size:11.5px; width:100%; }
    /* 🔎 Ô TÌM + NÚT CƠ SỞ VỀ CÙNG MỘT HÀNG — Boss chốt 08/09/2026
       *"trong màn hình điểm danh tôi muốn cái thanh tìm kiem phải gọn hơn và bé hơn
       để cái nút chọn cơ sở bên cạnh cho gọn"*.

       ⛔ THỦ PHẠM CŨ chính là luật ở đây: `min-width:100%` ép ô tìm chiếm TRỌN bề
          ngang, nên nút cơ sở luôn bị đẩy xuống hàng hai — thanh tìm ngốn 85px.
          Nay `flex:1 1 0` + `min-width:0` cho ô co lại vừa đủ, nút ngồi cạnh.
       ⛔ `min-width:0` là BẮT BUỘC, không phải trang trí: ô `<input>` có bề rộng
          mặc định của trình duyệt (~170px) làm sàn co, thiếu dòng này thì `flex:1`
          vẫn không ép nó nhỏ hơn được và nút lại rơi xuống hàng.
       ⛔ 36px cho khớp khuôn chung của app, KHÔNG hạ thấp hơn — đó là sàn đích bấm.
       ⛔ Cỡ chữ vẫn 16px: dưới 16px là iPhone tự phóng to cả trang khi chạm vào ô. */
    .thanh-tim { flex-wrap:nowrap; gap:8px; }
    .thanh-tim input { flex:1 1 0; min-width:0; height:36px; font-size:16px; }
    .thanh-tim .dnc-cs { flex:none; height:36px; }
    /* ⛔ CHIP CƠ SỞ CŨNG PHẢI 36px. Trung tâm chỉ có MỘT cơ sở thì app không gom dải
       chip thành nút thả xuống nữa (một lựa chọn thì cần gì ô chọn) — lúc ấy chính
       CHIP đứng cạnh ô tìm, mà luật chung cho chip ở màn hẹp là cao 44px. Thiếu dòng
       này thì hàng cao 44px và chip thò lên 8px so với ô tìm, nhìn như xô lệch.
       Đã bắt được bằng bài kiểm — dữ liệu thử của nó đúng là một cơ sở. */
    .thanh-tim .loc-coso { display:flex; flex:none; gap:6px; }
    .thanh-tim .loc-coso .chip { min-height:36px; height:36px; padding:0 12px; }
    .o-nhap input { height:46px; }

    /* ---- Nút bấm: tối thiểu 44px cho ngón tay ----
       Google/Apple đều khuyên 44px. Trước đây nút cao ~38px, cô Quỳnh bấm hay
       trượt sang nút bên cạnh. */
    .nut-nho, .nut-themcot, .nut-molai, .nut-phieu, .nut-xoacot, .nut-keocot, .nut-caption, .chip {
      min-height:44px; padding:11px 14px; font-size:13.5px; }
    .nut-cam { min-height:46px; }
    .ht-nut button { padding:14px 18px; font-size:15px; min-height:48px; flex:1; }
    .modal { padding:16px; }
    .ht-o input, .ht-o select { height:48px; font-size:15px; }

    /* ---- THANH CÔNG CỤ rơi xuống đáy màn hình ----
       Luôn nhìn thấy, không phải cuộn lên đầu trang mới bấm được. */
    .thanh-cong-cu { position:fixed; left:0; right:0; bottom:0; z-index:45;
                     background:#fff; border-top:1px solid var(--vien); margin:0;
                     padding:8px 10px calc(8px + env(safe-area-inset-bottom, 0px));
                     /* ⛔ PHẢI cho XUỐNG HÀNG. Cô Quỳnh chốt 25/07/2026: DONE +
                        Thêm cột + Đổi chỗ cột luôn phải ở ngoài. Nhồi 6 nút vào
                        MỘT hàng thì nút nào cũng ~55px, chữ cụt, bấm là trượt —
                        thà hai hàng mà nút to, bấm trúng. */
                     gap:6px; flex-wrap:wrap; justify-content:stretch;
                     box-shadow:0 -4px 18px rgba(15,45,50,.12); }
    .thanh-cong-cu button { flex:1 1 30%; min-width:0; padding:10px 4px; font-size:11.5px;
                            min-height:46px; white-space:nowrap;
                            overflow:hidden; text-overflow:ellipsis; }
    /* chữ dài chỉ hiện trên máy tính, điện thoại để chữ ngắn cho vừa */
    .chu-dai { display:none; }
    /* ⛔ LOGO LÀ NGOẠI LỆ CỦA LUẬT `.chu-dai` NGAY TRÊN — Boss chốt 08/09/2026
       *"logo mypas sai bị thiếu perserer… như trên máy tính"*. Luật `.chu-dai` vốn
       để giấu chữ dài trên NÚT thanh công cụ (giữ nút khỏi tràn), nhưng khẩu hiệu
       "Perseverance and Success" của logo cũng lỡ mang đúng class ấy nên bị giấu lây
       — không ai cố ý bỏ nó trên điện thoại cả.
       ⛔ Bản máy tính (khối @media min-width:821px) đã đo: `.ten` 17px + khẩu hiệu
          7,5px + đệm 2px = 26,5px, vừa dải 43px. Điện thoại thanh trên còn hẹp hơn
          nên lấy 7px và đệm 1px.
       ⛔ `white-space:nowrap` của `.cham` PHẢI giữ: khẩu hiệu xuống dòng là cụm cao
          gấp đôi, thanh trên vỡ bố cục. */
    .thanh-tren .logo-mypas .cham.chu-dai {
      display:block; font-size:7px; letter-spacing:.03em; margin-top:1px;
      white-space:nowrap; }
    .chu-ngan { display:inline; }
    /* Điện thoại phục vụ TRỢ GIẢNG là chính, nên thanh đáy giữ sẵn:
       DONE · ＋ Cột · ↔ Đổi cột · Caption · Phiếu · ⋯ Khác.
       Chỉ còn Xoá cột / Mở lại buổi / Tải lại nằm trong "⋯ Khác" — đó là việc
       của giáo vụ, hoạ hoằn mới dùng. */
    .chi-may-tinh { display:none; }
    .chi-dien-thoai { display:block; }
    /* Xếp lại thành ĐÚNG 2 HÀNG, hàng đầu là 3 việc trợ giảng cần nhất
       (cô Quỳnh chốt 25/07/2026). Để nguyên thứ tự trong HTML thì nó rơi thành
       3 hàng, cao gần 150px, ăn mất chỗ nhìn dữ liệu — dùng `order` xếp lại cho
       điện thoại mà không phải đụng thứ tự nút trên máy tính.
         hàng 1:  ✔ DONE  ·  ＋ Cột  ·  ↔ Đổi cột
         hàng 2:  📝 Caption · 📸 Phiếu · ⋯ Khác                                  */
    .thanh-cong-cu .nut-done-lon { order:1; font-size:12px; font-weight:700; }
    .thanh-cong-cu .nut-themcot  { order:2; }
    .thanh-cong-cu .nut-keocot   { order:3; }
    .thanh-cong-cu .nut-caption  { order:4; }
    .thanh-cong-cu .nut-phieu    { order:5; }
    .thanh-cong-cu #nutKhac      { order:6; }
    /* 33% chứ không 30%: 3 nút + 2 khe gap phải vừa đúng một hàng, không thừa
       chỗ cho nút thứ 4 nhảy lên cùng hàng. */
    .thanh-cong-cu button { flex:1 1 28%; }

    /* ---- Lưới trên điện thoại ----
       ⛔ ĐÂY LÀ CHỖ TRƯỚC ĐÂY KHÓ DÙNG NHẤT: hai cột dính bên trái (Mã HS 72px +
       Học sinh 158px) chiếm 230px trên màn hình rộng 375px — chỉ còn ~145px để
       nhìn dữ liệu, tức là chưa nổi 3 cột. Bỏ hẳn cột Mã HS trên điện thoại
       (mã HS đã có trong chế độ thẻ) và thu cột tên lại. */
    .luoi .c-ma { display:none; }
    /* ---- TÊN HỌC SINH: HIỆN ĐỦ, KHÔNG CẮT CỤT (cô Quỳnh 25/07/2026) ----
       Cô báo: *"cột tên học sinh đang bị che khuất, có cách nào hiển thị được hết
       mà không bị chữ quá bé không"*. Bản cũ `nowrap` + `ellipsis` nên tên dài
       thành "Nguyễn Đức …" — mà tiếng Việt thì phần BỊ CẮT lại chính là TÊN, chỗ
       để phân biệt các em. Trợ giảng không biết đang điền cho ai.
       ⭐ Cho XUỐNG DÒNG thay vì cắt — KHÔNG phải thu nhỏ chữ, cũng KHÔNG phải nới
       cột (nới cột là ăn mất chỗ nhìn điểm).
       📊 Đo 505 học sinh thật: dài nhất 26 ký tự · 99% dưới 23 · giữa là 14.
          Cột 104px chứa ~15 ký tự MỖI DÒNG → 2 dòng thừa sức chứa cả tên dài nhất.
       ⭐ `line-height:1.15` là chỗ mấu chốt: 2 dòng × 12px × 1.15 = 27,6px, vẫn
       LỌT trong hàng cao 32px sẵn có → hiện đủ tên mà KHÔNG mất thêm chỗ nào,
       số hàng nhìn thấy giữ nguyên. Nới rộng 104→112px cho phần lớn tên đủ 1 dòng. */
    .luoi .c-ten { left:0; min-width:112px; max-width:112px; font-size:12px; padding:2px 6px;
                   white-space:normal; overflow:hidden; line-height:1.15;
                   word-break:normal; overflow-wrap:break-word; }
    .luoi thead .c-ten { padding:6px 7px; }
    /* ---- CHIỀU CAO BẢNG: PHẢI DỪNG NGAY TRÊN THANH NÚT ----
       Cô Quỳnh: *"muốn kéo xuống thì hơi khó chịu"*. Đo ra lý do:
         màn hình 812px · bảng bắt đầu ở 313px · bảng cao 512px → đáy ở 825px
         mà THANH NÚT (cố định, cao 115px) bắt đầu ở 697px
       → **128px cuối của bảng nằm KHUẤT SAU thanh nút.** Kéo xuống thì mấy em
       cuối chui vào dưới thanh nút rồi biến mất, phải cuộn thêm CẢ TRANG mới
       thấy → hai thứ cùng cuộn, đúng cái "khó chịu".
       ⛔ `padding-bottom` ở `#noiDung` KHÔNG chữa được: nó chỉ chèn khoảng trống
       SAU bảng, không hề bóp bảng lại.
       → Chặn chiều cao bảng = màn hình − chỗ phía trên − thanh nút − lề.
         Sau khi thu gọn thanh chọn buổi (dưới đây), bảng bắt đầu ~263px:
         812 − 263 − 115 − 12 ≈ 422px, tức `100vh − 390px`.
       Kết quả: bảng ngắn hơn 90px nhưng NHÌN THẤY nhiều hơn 38px, và không còn
       hàng nào bị nuốt mất sau thanh nút. */
    .khung-cuon { max-height:calc(100vh - 390px); border-radius:var(--r-lg); }
    #noiDung { padding-bottom:120px; }

    /* Điện thoại hẹp nên cột gọn hơn máy tính, nhưng vẫn phải đọc được:
       giữ cỡ chữ 11px chứ không tụt về 10.5px như bản cũ. */
    .luoi td.o { min-width:64px; }
    .luoi .h-cot { min-width:64px; max-width:98px; font-size:11px; padding:6px 4px;
                   line-height:1.35; word-break:normal; overflow-wrap:anywhere; }

    /* ---- CHỮ TRONG Ô CHO DỄ NHÌN TRÊN ĐIỆN THOẠI (cô Quỳnh 25/07/2026:
       "chữ khá rối và không được đưa vào giữa, nhìn ríu rít") ----
       ⭐ Mấu chốt là BỎ MŨI TÊN mặc định của <select>: nó ăn ~20px mỗi ô, mà một
       hàng có cả chục ô → mất cả trăm pixel chỉ để vẽ mũi tên. Bỏ đi thì chữ
       "Đủ"/"Thiếu" được đưa vào GIỮA ô, thở ra, đọc thoáng hẳn.
       Ô vẫn bấm ra danh sách bình thường — và ô có màu nền nên vẫn nhìn ra ngay
       là ô chọn được, không sợ tưởng là chữ chết. */
    .o select {
      -webkit-appearance:none; appearance:none;
      text-align:center; text-align-last:center;
      padding:0 3px; font-size:12px; font-weight:700;
      text-overflow:ellipsis;
    }
    /* ---- ⛔ ĐỪNG HẠ CỠ CHỮ Ô NHẬP XUỐNG DƯỚI 16px TRÊN ĐIỆN THOẠI ----
       Cô Quỳnh: *"mỗi lần ấn vào ô điền số là lại bị zoom gần vào rất khó chịu"*.
       Đây KHÔNG phải lỗi của app: **Safari trên iPhone tự phóng to trang mỗi khi
       người dùng bấm vào ô nhập có cỡ chữ NHỎ HƠN 16px** (nó cho là chữ quá bé
       không đọc nổi). Phóng xong không tự thu lại → phải tự chụm tay thu về, mỗi
       ô một lần.
       ⭐ Cách chữa: cho đúng **16px**. Đủ ngưỡng là Safari thôi phóng.
       Số điểm chỉ 1–2 chữ số, ô rộng 64px nên 16px vẫn thừa chỗ.
       ⛔ ĐỪNG chữa bằng `maximum-scale=1` / `user-scalable=no` ở thẻ viewport:
       cách đó chặn luôn quyền TỰ chụm tay phóng to của người dùng — cô Quỳnh vẫn
       cần phóng để nhìn bảng (§2 "bé thì zoom vào"). */
    .o input { text-align:center; font-size:16px; padding:0 3px; }
    /* Các ô gõ chữ khác cũng dính đúng nết đó — nâng hết lên 16px */
    .o-ten-day, #oNote, .tim-lop input, .ht-o input, .ht-o textarea,
    .man-dn input, .cap-soan textarea { font-size:16px; }
    .luoi td.o-ngay .gt-ngay { font-size:11.5px; }
    /* Đổi sang ngày rút gọn "24/07/26" — xem lý do đo được ở chỗ vẽ ô ngày. */
    .luoi .o-ngay .ngay-dai  { display:none; }
    .luoi .o-ngay .ngay-ngan { display:inline; }
    /* Chừa thêm chỗ cho chắc: ô có đệm hai bên, và phông máy thật có thể to hơn. */
    .luoi td.o-ngay { padding-left:2px; padding-right:2px; }
    /* Ô KHOÁ (buổi đã chốt) cũng canh giữa cho đều hàng */
    .luoi td.o.khoa .gt { display:block; text-align:center; }
    .luoi .h-ngay, .luoi td.o-ngay { min-width:78px; max-width:84px; }
    /* 📅 04/09/2026 — ô NGÀY bấm được thì phải TRÔNG như bấm được, và ô đã đổi
       ngày phải nhìn ra ngay. Dùng gạch chân chấm + con trỏ tay, KHÔNG đổi màu nền
       — nền của ô này đã mang nghĩa "buổi đang mở / đã khoá" rồi, chồng thêm một
       nghĩa nữa lên cùng chỗ là không ai đọc ra cái nào. */
    .luoi td.o-ngay.ngay-sua { cursor:pointer; }
    .luoi td.o-ngay.ngay-sua .gt-ngay { text-decoration:underline dotted; text-underline-offset:2px; }
    .luoi td.o-ngay.ngay-lech .gt-ngay { font-weight:600; }
    .luoi td.o-ngay .ngay-dau-bu { color:var(--cam,#d97706); margin-left:2px; font-weight:700; }

    /* ---- Phiếu chụp ảnh trên điện thoại ----
       Màn hình 375px mà bảng chục cột thì kiểu gì cũng phải cuộn ngang, mà ảnh
       chụp màn hình chỉ bắt được phần đang nhìn thấy → mất cột. Nên ở đây bóp
       mọi thứ nhỏ hết mức còn đọc được, và BỎ cột "Ngày điểm danh" vì ngày đã
       nằm sẵn ngay dòng đầu phiếu rồi, để lại chỉ tổ chiếm chỗ. */
    .modal.rong { width:97vw; padding:14px 10px; }
    .phieu { padding:12px 10px 10px; }
    .phieu-dau .lop { font-size:17px; }
    .phieu-dau .phu { font-size:12.5px; }
    .phieu-nhan { font-size:10.5px; padding:3px 9px; margin-left:7px; }
    .phieu-lat button { flex:1; min-height:44px; font-size:12px; padding:10px 6px; }
    .phieu-lat-chu { width:100%; order:-1; text-align:center; }
    /* Trên điện thoại phiếu sẽ bị thu nhỏ để vừa khung, nên ở đây CỐ Ý để cỡ chữ
       to hơn bình thường một chút — thu xong vẫn còn đọc được. */
    .phieu-bang th { min-width:58px; max-width:88px; font-size:12px; padding:7px 5px; }
    .phieu-bang td { padding:7px 5px; font-size:13px; height:32px; }
    .phieu-bang .c-stt { min-width:26px; width:26px; font-size:11.5px; padding:7px 3px; }
    /* ⚠️ Cột tên để `nowrap` thì nó NỞ RA theo tên dài nhất lớp → bảng rộng ngoác
       → tỉ lệ thu nhỏ tụt xuống, chữ bé tí. Cho tên xuống dòng và chặn bề ngang. */
    .phieu-bang .c-hs { min-width:100px; max-width:116px; font-size:12.5px;
                        white-space:normal; overflow-wrap:break-word; line-height:1.35; }
    /* ---- THU GỌN THANH CHỌN BUỔI: 3 HÀNG → 2 HÀNG ----
       Thanh này đang ăn 134px trên đầu bảng (◀ tên-buổi ▶ · thanh kéo · ô chọn ·
       nút "Buổi đang điền" — rơi thành 3 hàng). Cắt bớt để nhường chỗ cho bảng.
       ⭐ Bỏ dòng chữ tên buổi `.dh-chu` trên điện thoại: Ô CHỌN ngay dưới đã ghi
       đúng thông tin đó rồi ("8. buổi 8 · 25/07/2026 ← đang điền") — bày hai lần
       là phí mất một hàng.
       ⛔ VẪN GIỮ thanh kéo `.dh-keo` — cô Quỳnh yêu cầu đích danh ("lớp có 40 mấy
       DAY bấm đến bao giờ cho xong, vẫn phải có cái kéo sang"). Chỉ xếp lại cho
       nó nằm CÙNG HÀNG với ◀ ▶ chứ không chiếm riêng một hàng. */
    /* 08/09/2026 — HA VE 36px NHU CA APP. Boss: *"may cai nut o tren cung dang bi
       to kinh khung gay ton dien tich"*. Do that tren man 390px: thanh nay cao
       94px, xep thanh HAI DONG, moi nut 44px.
       Luat cu giu 44px la san dich bam cho ngon tay; nhung ca app da chot ve 36px
       (Boss duyet cung ngay cho man Tuyen sinh), giu rieng cho nay 44px la lech
       khuon ma van ton cho. */
    .dh-day button { min-height:36px; padding:7px 10px; font-size:13px; }
    .dh-day .dh-chu { display:none; }
    /* `flex-basis:auto` la CHO VO HANG. Trinh duyet xep dong theo BASIS chu khong
       co truoc roi moi xep: `<input type=range>` co be rong mac dinh ~170px, nen
       basis:auto lam tong hang thanh 37+37+170+120+36+28 = 428 > 370 → nut cuoi bi
       day xuong dong rieng, du co lai thi thua chan cho.
       Dat basis 70px (dung bang min-width) thi tong con 328px, ca hang du cho; cot
       grow van cho thanh keo an het cho thua sau do. */
    .dh-day .dh-keo { flex:1 1 70px; min-width:70px; margin:0 2px; }
    /* ⛔ Luật ở trên (dòng ~291) đặt `flex:1 1 100%` cho ô chọn → nó CHIẾM TRỌN
       một hàng, đẩy nút "⤓ Buổi đang điền" xuống hàng thứ ba. Cho nó co lại để
       hai thứ đứng chung hàng: 150px + 134px = 284px, thừa sức trong 355px. */
    /* ⚠️ `flex-basis:auto` là ô chọn lấy bề ngang theo NỘI DUNG ("8. buổi 8 ·
       25/07/2026 ← đang điền" rất dài) → không còn chỗ cho nút bên cạnh, nút bị
       đẩy xuống hàng riêng. Đặt basis nhỏ (120px) để nó co được rồi giãn ra sau. */
    .dh-day .dh-chon-boc { flex:1 1 120px; max-width:100%; min-width:120px; }
    /* THU VE CON ICON. 134px chu la thu day nut nay xuong hang rieng: hang tren da
       kin (◀ 34 + ▶ 34 + thanh keo 70 + o chon 120 + 4 khe = 262 trong 370px), them
       134 nua la vo hang, an mat 50px dau man.
       KHONG bo han nut: no la duong nhay ve buoi dang dien, tro giang bam hang ngay.
       Chu van con trong `title`/`aria-label`, va mau cam giu nguyen de con nhan ra. */
    .dh-day .dh-toi { flex:0 0 auto; padding:0; width:36px; min-width:36px; gap:0; }
    .dh-day .dh-toi .dh-toi-chu { display:none; }
    .dh-day .dh-toi .dh-toi-ico { font-size:16px; line-height:1; }

    /* Khung soạn caption trên điện thoại */
    .cap-soan textarea { min-height:44vh; font-size:14px; }
  }

  /* ============ TOAST + MODAL ============ */
  /* ⛔⛔ VÁ 04/09/2026 — TOAST PHẢI ĐỌC ĐƯỢC KHI CÂU BÁO DÀI.
     Bản cũ không có `max-width` lẫn cách xuống dòng, mà mấy câu báo quan trọng
     nhất của app lại là câu DÀI và CÓ XUỐNG DÒNG — ví dụ câu chặn trùng tên cột
     (≈250 ký tự, hai đoạn) hay câu "tên cột dài quá". Kết quả: chữ kéo thành một
     vệt tràn khỏi màn, `\n` không xuống dòng, và người dùng chỉ đọc được khúc
     giữa. Câu báo viết công phu để chỉ đường mà không ai đọc nổi thì bằng không.
     · `max-width` theo màn hình, còn chỗ thở hai bên trên điện thoại
     · `pre-line` để `\n` trong câu báo xuống dòng thật (`toast()` dùng
       `textContent` nên không thể chèn <br>)
     · `text-align:left` vì đoạn nhiều dòng canh giữa rất khó đọc
     ⛔ ĐỪNG bỏ `pointer-events:none` ở đây — thanh Hoàn tác tự bật lại ở
        `.toast-ht`; bật chung là toast thường chắn mất nút bên dưới nó. */
  .toast { position:fixed; left:50%; bottom:26px; transform:translateX(-50%); z-index:200;
           background:#20303C; color:#fff; border-radius:var(--r-xl); padding:11px 18px; font-size:13.5px;
           box-shadow:0 10px 30px rgba(0,0,0,.3); opacity:0; pointer-events:none; transition:opacity .2s;
           max-width:min(560px, calc(100vw - 32px)); white-space:pre-line;
           text-align:left; line-height:1.5; }
  .toast.hien { opacity:1; }
  /* Thanh Hoàn tác — bấm được, nên phải bật lại `pointer-events`. */
  .toast-ht { display:flex; align-items:center; gap:12px; padding:10px 12px 10px 18px; pointer-events:auto; }
  .toast-ht[hidden] { display:none; }
  .toast-ht button { border:0; cursor:pointer; font-size:13px; font-weight:700; border-radius:var(--r-md); padding:7px 13px; }
  #toastHTnut { background:#F5B301; color:#20303C; display:inline-flex; align-items:center; gap:5px; }
  #toastHTnut:hover { background:#FFC72C; }
  #toastHTnut i { background:#20303C; margin-right:0; }
  #toastHTdong { background:transparent; color:#9FB0BD; padding:7px 9px; }
  #toastHTdong:hover { color:#fff; }
  /* Danh sách trong hộp thoại Thùng rác. */
  .lt-rac { max-height:340px; overflow:auto; margin:4px 0 2px; }
  .lt-rac-mon { display:flex; align-items:center; gap:10px; padding:9px 2px; border-bottom:1px solid var(--vien); }
  .lt-rac-mon:last-child { border-bottom:0; }
  .lt-rac-tin { flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
  .lt-rac-tin b { font-size:13.5px; }
  .lt-rac-tin small { color:var(--mo); font-size:11.5px; }
  /* 🏫 Bảng điền học sinh lúc tạo lớp — gõ như trên Sheet (cô Quỳnh 09/08/2026). */
  .tl-khoi { margin-top:6px; }
  .tl-nhan { font-size:12.5px; font-weight:700; color:var(--mo);
 margin:10px 0 6px; }
  .tl-cuon { max-height:300px; overflow:auto; border:1px solid var(--vien); border-radius:var(--r-sheet); }
  .tl-bang { width:100%; }
  /* ⛔ Hàng tiêu đề dính đỉnh PHẢI có nền đục và một nét gạch chân, không thì cuộn
     lên là chữ của hàng dưới chạy xuyên qua nó. `box-shadow` chứ không `border`:
     viền của ô trong bảng dính đỉnh không cuộn theo, để lại một vệt lơ lửng. */
  .tl-bang th { position:sticky; top:0; background:var(--the); z-index:1; font-size:12px;
    box-shadow:inset 0 -1px 0 var(--vien); }
  .tl-bang th small { font-weight:400; color:var(--mo); }
  .tl-bang td { padding:0; }
  /* Sọc nhạt để mắt lần đúng hàng khi bảng dài 40 dòng — cùng một hàng ngang mà
     lệch sang cột SĐT là điền nhầm phụ huynh của em khác. */
  .tl-bang tbody tr:nth-child(even) { background:var(--nen2); }
  .tl-bang tbody tr:hover { background:var(--xanh-nhat); }
  /* Hàng đã điền tên: một vạch xanh mảnh bên trái, nhìn phát biết còn bao nhiêu
     dòng trống phía dưới mà không phải đếm. */
  .tl-bang tbody tr.tl-co-ten .tl-stt { box-shadow:inset 2px 0 0 var(--xanh); color:var(--muc); font-weight:700; }
  .tl-stt { width:38px; text-align:center; color:var(--mo); font-size:12px; }
  .tl-batbuoc { color:var(--do); }
  .tl-o { width:100%; border:0; background:transparent; padding:7px 9px; font-size:13.5px;
    color:var(--chu); outline:none; }
  .tl-o:focus { background:var(--xanh-nhat); box-shadow:inset 0 0 0 2px var(--xanh); border-radius:var(--r-sm); }
  .tl-bo { width:34px; text-align:center; }
  .tl-xoa { border:0; background:transparent; cursor:pointer; padding:4px; opacity:.5; }
  .tl-xoa:hover { opacity:1; }
  /* Hàng chưa có tên thì không có gì để xoá — giấu nút đi cho bảng đỡ rối, nhưng
     vẫn giữ chỗ để cột không nhảy qua nhảy lại lúc gõ. */
  .tl-bang tbody tr:not(.tl-co-ten) .tl-xoa { visibility:hidden; }
  .tl-xoa i { background:var(--do); margin-right:0; }
  .tl-dem { font-size:12px; color:var(--mo); margin-top:8px; padding-top:8px;
    border-top:1px solid var(--vien); display:flex; flex-wrap:wrap;
    gap:8px 16px; align-items:center; justify-content:space-between; }
  .tl-dem b { color:var(--muc); }
  .tl-them { display:flex; align-items:center; gap:7px; }
  .tl-them label { display:flex; align-items:center; gap:5px; white-space:nowrap; }
  .tl-them input { width:58px; padding:4px 6px; border:1px solid var(--vien); border-radius:var(--r-o, 8px);
    text-align:center; font-size:13px; background:var(--the); color:var(--chu); }
  .tl-them button { border:1px solid var(--vien); background:var(--the); color:var(--muc);
    border-radius:var(--r-md); padding:4px 10px; font-size:12px; font-weight:700; cursor:pointer; }
  .tl-them button:hover { border-color:var(--xanh); color:var(--xanh); }
  /* Hai ô chọn người nằm cạnh nhau cho gọn chiều dọc. */
  .tl-hang2 { display:flex; gap:12px; flex-wrap:wrap; margin-top:4px; }
  .tl-o-nguoi { flex:1 1 200px; min-width:0; }
  .tl-o-nguoi label { display:block; font-size:12.5px; font-weight:700; color:var(--muc); margin-bottom:4px; }
  /* ✏️ 20/09/2026 — ô chọn chế độ của Trợ giảng (Boss). Nằm ngay dưới nhãn, trên
     danh sách người. `.tl-hang2` vốn đã là flex-wrap nên BA ô tự thẳng hàng ở màn
     rộng và tự xếp dọc ở màn hẹp — không phải thêm luật bố cục nào. */
  .tl-tg-chedo { width:100%; box-sizing:border-box; margin-bottom:6px; font-size:12.5px; }
  /* 👥 Nhiều giáo viên / giáo vụ một lớp (cô Quỳnh 16/08/2026, cho iGreen English). */
  .tl-ds-nguoi { display:flex; flex-direction:column; gap:6px; }
  .tl-mot-nguoi { display:flex; align-items:center; gap:6px; }
  .tl-mot-nguoi .ont { flex:1; min-width:0; }
  .tl-them-nguoi { border:1px solid var(--vien); background:var(--the); color:var(--xanh);
    border-radius:var(--r-md); padding:1px 8px; font-size:11.5px; font-weight:700; cursor:pointer;
    font-family:inherit; margin-left:4px; }
  .tl-them-nguoi:hover:not(:disabled) { border-color:var(--xanh); background:var(--xanh-nhat); }
  .tl-them-nguoi:disabled { opacity:.4; cursor:default; }
  .tl-bo-nguoi { flex:none; width:26px; height:26px; border:1px solid var(--vien);
    background:var(--the); color:var(--mo); border-radius:var(--r-md); cursor:pointer;
    font-size:13px; line-height:1; font-family:inherit; }
  .tl-bo-nguoi:hover { border-color:var(--do); color:var(--do); }
  /* 📐 DẢI XEM TRƯỚC BỘ CỘT lúc tạo lớp — cô Quỳnh 31/08/2026 (xem `tlVeXemCot`).
     Nằm NGOÀI `.tl-lay` nên chạy hết bề ngang hộp, không bị cột trái 380px bóp lại.
     ⛔ `flex:none` — `#htThan` là flex dọc và để `overflow:hidden`; không khoá lại
        thì dải này co giãn tranh chỗ với bảng học sinh.
     ĐO THẬT 31/08/2026 (Playwright, bộ cột chuẩn 6 cột, hộp Tạo lớp toàn màn hình):
       dải cao 111px · bảng rộng vừa khít chỗ chứa (1300px ở màn 1366, 1854px ở 1920)
       → KHÔNG phải kéo ngang, đúng như đã nói ở `tlVeXemCot`.
     ⚠️ ĐÁNH ĐỔI ĐÃ BIẾT: dải này lấy 123px chiều cao của `.tl-lay`, nên cột trái phải
        cuộn thêm bấy nhiêu — đo được 436px → 559px ở màn 1366×768, và 124 → 247 ở
        1920×1080. Cột trái VỐN ĐÃ phải cuộn từ trước bản vá này, đây chỉ là tệ thêm.
        Nếu cô Quỳnh kêu chật thì cách rẻ nhất là bỏ hàng "Học sinh B" (được 28px),
        ĐỪNG hạ trần `max-height` — trần ấy hiện chưa gánh việc gì.
     Trần dưới đây là LƯỚI AN TOÀN cho ngày nào đó thêm hàng mẫu, chứ bản hiện tại
     chưa chạm tới (111px so với trần 172px). */
  .tl-xem { flex:none; margin-top:12px; padding-top:12px; border-top:1px solid var(--vien); }
  .tl-xem:empty { display:none; margin:0; padding:0; border-top:0; }
  .tl-xem .bdc { margin-bottom:0; }
  .tl-xem .bdc-cuon { max-height:172px; }
  /* ⛔ CẮT BỚT Ô QUÁ DÀI, và CHỈ ở dải này. Ô "tích nhiều ý" xem thử là hai mục nối
     nhau ("Tự tin, tương tác tốt · Cần cố gắng ôn tập thêm bài ở nhà" — 55 chữ), mà
     `.bdc-bang td` để `white-space:nowrap`: không chặn thì một cột kéo bảng rộng gấp
     đôi, cột sau tụt hết ra ngoài. Bảng điểm trong hộp caption KHÔNG bị (giá trị thật
     ngắn) nên đừng sửa `.bdc-bang` chung — chặn đúng trong `.tl-xem`. */
  .tl-xem .bdc-bang td { max-width:190px; overflow:hidden; text-overflow:ellipsis; }
  @media (max-width:640px) { .tl-xem .bdc-cuon { max-height:132px; } }
  /* Nút mở phần giải thích ở Báo cáo số (09/08/2026). */
  .bcs-hoi { border:1px solid var(--vien); background:var(--the); color:var(--muc);
    border-radius:var(--r-sm);
    border-radius:var(--r-md); padding:3px 10px; font-size:12px; font-weight:700; cursor:pointer; }
  .bcs-hoi:hover, .bcs-hoi.mo { border-color:var(--xanh); color:var(--xanh); }
  /* ⚠ 04/09/2026 — hộp kể tên lớp chưa khai ngày khai giảng (`qlKeLopThieuKG`). */
  .kg-nhom { margin:10px 0 0; }
  .kg-ds { display:flex; flex-wrap:wrap; gap:6px; margin-top:6px; }
  .ql-nhac-kg { color:var(--cam,#d97706); }
  .bcs-giai { font-size:12.5px; color:var(--mo); line-height:1.6; margin-top:6px;
    padding:9px 12px; border:1px solid var(--vien); border-radius:var(--r-lg); }
  .bcs-giai[hidden] { display:none; }
  /* 💬 GÓP Ý (09/08/2026) */
  .gy-soan { display:flex; flex-direction:column; gap:8px; }
  .gy-ta { width:100%; resize:vertical; min-height:80px; font-size:13.5px; }
  .gy-cong { display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
  .gy-them-anh { display:inline-flex; align-items:center; gap:5px; cursor:pointer;
    border:1px solid var(--vien); border-radius:var(--r-md); padding:6px 12px; font-size:12.5px; font-weight:700;
    color:var(--muc); background:var(--the); }
  .gy-them-anh:hover { border-color:var(--xanh); color:var(--xanh); }
  .gy-anh-cho { display:flex; gap:8px; flex-wrap:wrap; align-items:center; }
  .gy-anh-o { position:relative; display:inline-block; }
  .gy-anh-o img { width:66px; height:66px; object-fit:cover; border-radius:var(--r-md); border:1px solid var(--vien); }
  .gy-anh-o button { position:absolute; top:-6px; right:-6px; width:20px; height:20px; border-radius:50%;
    border:0; background:var(--do); color:#fff; cursor:pointer; font-size:12px; line-height:1; }
  .gy-anh-dem { font-size:12px; color:var(--mo); }
  /* Lịch sử — chỉ chủ tài khoản thấy */
  .gy-ls { margin-top:14px; border-top:1px solid var(--vien); padding-top:10px; }
  .gy-ls-dau { display:flex; align-items:center; gap:8px; font-size:12.5px; font-weight:700;
    color:var(--mo); margin-bottom:8px; }
  .gy-ls-dau span { background:var(--vien); color:var(--muc); border-radius:var(--r-xl); padding:1px 8px;
    font-size:11.5px; letter-spacing:0; }
  .gy-xoahet { margin-left:auto; border:1px solid var(--vien); background:var(--the); color:var(--do);
    border-radius:var(--r-md); padding:3px 10px; font-size:11.5px; font-weight:700; cursor:pointer;
    text-transform:none; letter-spacing:0; }
  .gy-xoahet:hover { border-color:var(--do); }
  .gy-mon { border:1px solid var(--vien); border-radius:var(--r-lg); padding:9px 12px; margin-bottom:8px; }
  .gy-dau { display:flex; align-items:center; gap:8px; font-size:13px; }
  .gy-luc { color:var(--mo); font-size:11.5px; }
  .gy-xoa { border:0; background:transparent; cursor:pointer; padding:3px; opacity:.5; }
  .gy-xoa:hover { opacity:1; }
  /* ❤️ 13/08/2026 — chủ app thả ♥ để người gửi biết Developer đã xem.
     Đây là DẤU HIỆU, không phải icon trang trí, nên dùng ký tự ♥ là đúng chỗ —
     giống ✓ Đ X trong bảng điểm danh (luật icon đã chốt cho phép). */
  .gy-tim { margin-left:auto; border:0; background:transparent; cursor:pointer;
    font-size:16px; line-height:1; padding:2px 5px; color:var(--mo); border-radius:var(--r-sm); }
  .gy-tim:hover { color:var(--do); background:var(--nen2); }
  .gy-tim.co { color:var(--do); }
  /* Bên người gửi thì ♥ chỉ để NHÌN, kèm chữ cho rõ nghĩa — không bấm được. */
  .gy-tim-xem { margin-left:auto; font-size:12px; font-weight:600; cursor:default;
    background:none; padding:2px 0; white-space:nowrap; }
  .gy-tim-xem:hover { background:none; }
  .gy-mon .gy-xoa { margin-left:8px; }
  .gy-xoa i { background:var(--do); margin-right:0; }
  .gy-chu { font-size:13.5px; margin-top:5px; white-space:pre-wrap; }
  .gy-anh-ds { display:flex; gap:7px; flex-wrap:wrap; margin-top:7px; }
  .gy-anh-ds img { width:88px; height:88px; object-fit:cover; border-radius:var(--r-md); border:1px solid var(--vien); }
  .gy-trong { color:var(--mo); font-size:13px; }
  /* ⚠️ VÁ 09/08/2026 — cô Quỳnh: *"thanh công cụ hơi che cái tạo lớp"*. Đúng vậy:
     thanh công cụ để z-index 11001, còn hộp thoại chỉ 150 → thanh đè lên hộp.
     Hộp thoại là thứ người dùng đang thao tác, phải nằm TRÊN CÙNG. */
  .modal-nen { position:fixed; inset:0; background:rgba(10,25,30,.5); display:none; z-index:12000;
               align-items:center; justify-content:center; padding:20px; }
  /* Hộp thoại toàn màn thì đệm quanh mép mỏng lại — 20px mỗi bên là 40px bề ngang
     bị bỏ không, thấy rõ trên laptop 13 inch. `:has()` để chỉ khối nền NÀO đang chứa
     hộp toàn màn mới co đệm, các hộp thoại thường giữ nguyên khoảng thở cũ. */
  .modal-nen:has(.modal.toan-man) { padding:10px; }
  .modal-nen.mo { display:flex; }
  .modal { background:#fff; border-radius:var(--r-xl); width:min(94vw, 560px); max-height:86vh; overflow:auto;
           padding:22px; }
  .modal h3 { margin:0 0 14px; }

  /* ══════════════════════════════════════════════════════════════════════════════
     ⛔⛔ 21/08/2026 — NÚT "ĐỒNG Ý" ĐÃ TỤT RA NGOÀI MÀN HÌNH, KHÔNG BẤM ĐƯỢC
     ──────────────────────────────────────────────────────────────────────────────
     Cô Quỳnh: *"1 số nút quan trọng bị tràn khuất màn hình luôn ko dùng được ko
     thấy luôn"*.

     Gốc lỗi: cả hộp thoại là MỘT khung cuộn (`max-height:86vh; overflow:auto`), và
     hàng nút nằm TRONG khung cuộn ấy, ở tận đáy. Hộp "Thêm học sinh vào sổ" có bảy ô
     nhập: đo trên laptop 1366×768 thì ruột cao hơn 86vh, nên hai nút "Huỷ" và "Dò
     trùng rồi tạo hàng" nằm dưới mép cuộn. Người dùng nhìn thấy một hộp thoại đầy ô
     nhập và KHÔNG có nút nào — không có gì gợi ý là phải lăn chuột bên trong hộp.

     Nay chia ba tầng cố định, đúng lối mà hộp TOÀN MÀN đã làm từ 20/08 (xem
     `.modal.toan-man` bên dưới): tiêu đề trên · ruột giữa cuộn · hàng nút dưới ghim.
     Thêm bao nhiêu ô nhập nữa cũng không đẩy được cái nút đi đâu.

     ⛔ `min-height:0` bắt buộc — thiếu nó thì ruột flex không chịu co, hộp phình
        quá màn hình và hàng nút lại tụt ra ngoài, y như cũ.
     ⛔ Bọc trong `#htNen` chứ không đặt thẳng lên `.modal`: trong trang còn một
        `.modal` nữa (#modalNen, khung cũ của Quản lý tài khoản) mà ruột nó không có
        `#htThan` — đổi nó sang flex + overflow:hidden là cắt cụt nội dung.
     ⛔ `:not(.toan-man)` để hộp toàn màn giữ nguyên bộ luật riêng của nó. */
  #htNen > .modal:not(.toan-man) {
    overflow:hidden; display:flex; flex-direction:column;
  }
  #htNen > .modal:not(.toan-man) > h3,
  #htNen > .modal:not(.toan-man) > .ht-loi { flex:none; }
  #htNen > .modal:not(.toan-man) > #htThan {
    flex:1 1 auto; min-height:0; overflow-y:auto; overflow-x:hidden;
    /* Chừa chỗ cho viền sáng của ô đang gõ, không thì nó bị khung cuộn xén mất. */
    padding:2px;  margin:-2px;
  }
  #htNen > .modal:not(.toan-man) > .ht-nut {
    flex:none; margin-top:14px; padding-top:14px; border-top:1px solid var(--vien);
  }

  /* ══════════════════════════════════════════════════════════════════════════════
     HỘP THOẠI TOÀN MÀN HÌNH — cô Quỳnh 20/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     *"nếu danh sách học sinh dài thì lúc tạo nó cứ khó … cứ kéo xuống, thiết kế
     chuyên nghiệp dễ dùng và toàn màn hình nhìn cho rõ phù hợp với các loại máy
     kích thước khác nhau"*.

     Cái sai của bản cũ là CUỘN LỒNG TRONG CUỘN: cả hộp thoại là một khung cuộn
     (`max-height:86vh; overflow:auto`), mà bên trong lại nhét thêm một khung cuộn
     nữa cho bảng học sinh (`.tl-cuon` cao 300px). Con lăn chuột đặt ở đâu thì cuộn
     cái đó — người dùng không đoán được mình đang cuộn cái nào, và bảng học sinh
     thì mãi mãi chỉ nhìn được 6 dòng dù màn hình cao 1100px.

     Nay chia BA TẦNG CỐ ĐỊNH: tiêu đề trên · ruột giữa · hàng nút dưới. Chỉ RUỘT
     cuộn, và trong ruột chỉ có ĐÚNG MỘT khung cuộn thật (bảng học sinh), nó cao
     bằng đúng chỗ còn thừa của màn hình.
     ⛔ `min-height:0` trên mọi tầng flex là bắt buộc — thiếu nó thì phần tử con
        không chịu co lại, hộp thoại phình quá màn hình và hàng nút tụt ra ngoài. */
  /* ⛔ Đo theo `100%` chứ KHÔNG theo `vw`/`vh`. Khung nền `.modal-nen` có đệm 20px
     quanh mép; lấy `98vw` là tính theo cả màn hình, không trừ phần đệm ấy — hộp
     rộng hơn chỗ chứa nó, tràn ra hai bên và ăn mất viền. `100%` thì trình duyệt
     tự trừ đệm hộ. */
  /* ⛔ 21/08/2026 — BỎ TRẦN 1680×1000. Cô Quỳnh: *"để cái giao diện của cả phần tạo
     lớp rộng ra phù hợp với các màn hình đi chứ ko phải hẹp lại ở giữa màn hình như
     vậy rất xấu và phí diện tích"*, và luật chung cùng ngày: *"bất cứ công cụ nào khi
     ấn vào thì giao diện của công cụ đó phải chiếm toàn màn hình"*.
     Trần cũ nghĩa là màn 2560px thì hộp chỉ dùng 1680px, chừa 440px trống mỗi bên.
     Nay đúng bằng chỗ chứa nó. Cột trái vẫn khoá 300–380px (`.tl-lay`) nên bề ngang
     thừa ra chảy hết vào BẢNG HỌC SINH — đúng chỗ cần rộng. */
  .modal.toan-man { width:100%; height:100%; max-height:100%;
    padding:20px 22px 16px; overflow:hidden; display:flex; flex-direction:column; }
  .modal.toan-man > h3 { flex:none; }
  .modal.toan-man > .ht-loi { flex:none; }
  .modal.toan-man > #htThan { flex:1 1 auto; min-height:0; display:flex; flex-direction:column;
    overflow:hidden; }
  /* Hàng nút KHÔNG cuộn theo — cô luôn nhìn thấy nút "Tạo lớp", không phải kéo
     xuống đáy một bảng 40 dòng mới bấm được. */
  .modal.toan-man > .ht-nut { flex:none; margin-top:14px; padding-top:14px;
    border-top:1px solid var(--vien); }
  .modal.toan-man .ht-mota { flex:none; margin-bottom:12px; }

  /* Bố cục hai cột: thông tin lớp bên trái, bảng học sinh bên phải.
     Máy hẹp thì tự xếp chồng — xem khối @media ở dưới. */
  .tl-lay { flex:1 1 auto; min-height:0; display:grid; gap:18px;
    grid-template-columns:minmax(300px, 380px) minmax(0, 1fr); }
  .tl-cot { min-height:0; display:flex; flex-direction:column; }
  /* Cột trái tự cuộn riêng khi máy thấp — nhưng nó ngắn nên hiếm khi phải cuộn. */
  .tl-trai { overflow:auto; padding-right:8px; gap:2px; }
  .tl-phai { min-width:0; }
  .tl-lay .tl-nhan { flex:none; }
  .tl-cot > .tl-nhan:first-child { margin-top:0; }
  /* Khung bảng học sinh: chiếm hết chiều cao còn lại của cột phải. */
  .tl-bang-boc { flex:1 1 auto; min-height:0; display:flex; flex-direction:column; }
  .modal.toan-man .tl-bang-boc > .tl-cuon { flex:1 1 auto; min-height:120px; max-height:none; }
  .modal.toan-man .tl-bang-boc > .tl-dem { flex:none; }
  /* Vạch ngăn dọc giữa hai cột — một nét mảnh, không nền màu. */
  @media (min-width:1000px) {
    .modal.toan-man .tl-trai { border-right:1px solid var(--vien); padding-right:18px; }
  }
  /* Máy hẹp (laptop nhỏ, máy bảng dựng đứng, điện thoại): xếp chồng, và lúc này
     bảng học sinh mới cần chiều cao chốt sẵn, nếu không nó co còn hai dòng. */
  @media (max-width:1000px) {
    .tl-lay { grid-template-columns:minmax(0, 1fr); overflow:auto; }
    .tl-cot { min-height:auto; }
    .tl-trai { overflow:visible; padding-right:0; }
    .modal.toan-man .tl-bang-boc > .tl-cuon { min-height:200px; max-height:46vh; }
  }
  /* Điện thoại: dùng đúng cả màn hình, bỏ bo góc cho khỏi phí chỗ. */
  @media (max-width:640px) {
    .modal-nen { padding:0; }
    .modal.toan-man { width:100vw; height:100%; max-height:none; border-radius:0;
      padding:14px 12px 10px; }
  }
  /* ⌨️ 03/10/2026 — BÀN PHÍM ĐIỆN THOẠI MỞ (Boss câu 10): khung nền hộp thoại co vừa đúng
     phần màn còn thấy, nên hàng nút ghim đáy hộp («Lưu», «Đồng ý») luôn nằm TRÊN bàn phím.
     Class + hai biến do `banPhimKhongChe` (js/tinh-nang.js) đặt; ô bảng Điểm danh được rào ra ở đó
     (hộp thoại mở từ trong Điểm danh thì vẫn áp — Boss bấm nút 03/10).
     ⛔ `max-height:100%` thay cho 86vh: `vh` vẫn tính theo cả màn (bàn phím không đổi nó),
        hộp cao 86vh trong khung nền đã co là lại tràn xuống dưới bàn phím.
     ⛔ Ô chữ dài (`.ht-chu`, cao 52vh lúc thường) co lại theo phần màn còn thấy; trong hộp
        toàn màn thì nó lấp chỗ còn lại — để nguyên 52vh là đáy ô bị cắt, con trỏ ở dòng cuối
        chui mất. */
  html.ban-phim-mo .modal-nen { top:var(--vv-tren, 0px); bottom:auto; height:var(--vv-cao, 100%); }
  html.ban-phim-mo .modal-nen > .modal { max-height:100%; }
  /* iPhone / iPad (iOS 26): ba nút tự điền + nút cất bàn phím nổi lấn 22px lên trên mép khung nhìn
     (Boss gửi ảnh 03/10). Hộp thường đã có đệm đáy 22px (`.modal{padding:22px}`) — đủ. Hộp TOÀN MÀN
     trên điện thoại chỉ đệm 10px → hàng nút bị lấn: nới đáy lên 22px.
     ⛔ 22px khớp `IOS_CHUA` trong `banPhimKhongChe` (js/tinh-nang.js). */
  html.ban-phim-mo.may-ios .modal.toan-man { padding-bottom:22px; }
  html.ban-phim-mo .ht-chu textarea { min-height:calc(var(--vv-cao, 100vh) * .3); }
  html.ban-phim-mo .modal.toan-man > #htThan > .ht-chu { flex:1 1 auto; min-height:0;
    display:flex; flex-direction:column; padding:2px; }      /* 2px: viền sáng ô đang gõ khỏi bị xén */
  html.ban-phim-mo .modal.toan-man > #htThan > .ht-chu > textarea { flex:1 1 auto; resize:none; }
  .hang-tk { display:flex; align-items:center; gap:9px; padding:9px 0; border-bottom:1px solid var(--vien); }
  .hang-tk .ten-tk { flex:1; min-width:0; }
  .hang-tk .ten-tk small { display:block; color:var(--mo); }
  .hang-tk select { height:32px; border-radius:var(--r-o, 8px); border:1px solid var(--vien); }
  /* ---- Bảng tài khoản: dễ nhìn hơn (cô Quỳnh yêu cầu 25/07/2026) ---- */
  .hang-tk { flex-wrap:wrap; }
  .hang-tk.cho-duyet { background:#fff8e6; border-radius:var(--r-lg); padding:9px 8px; }
  /* Thẻ nổi hiện họ tên đầy đủ khi chạm ô tên học sinh */
  #theTenHS { position:fixed; left:50%; bottom:130px; transform:translateX(-50%) translateY(8px);
    z-index:70; max-width:min(90vw,420px); background:#123; color:#fff; border-radius:var(--r-xl);
    padding:12px 18px; box-shadow:0 10px 30px rgba(0,0,0,.3); text-align:center;
    opacity:0; pointer-events:none; transition:opacity .16s, transform .16s; cursor:pointer; }
  #theTenHS.hien { opacity:1; transform:translateX(-50%) translateY(0); pointer-events:auto; }
  #theTenHS b { display:block; font-size:17px; line-height:1.35; }
  #theTenHS small { display:block; opacity:.75; font-size:12px; margin-top:4px; }
  #theTenHS small.tat { opacity:.5; font-size:11px; margin-top:6px; }
  /* 📇 Form thông tin học sinh (giáo vụ) — nền sáng, ô nhập rõ, đọng lại để sửa. */
  #theTenHS .ttHS-form { text-align:left; margin-top:10px; background:#fff; color:var(--chu);
    border-radius:var(--r-lg); padding:10px 12px; cursor:default; }
  #theTenHS .ttHS-form .nv-lb { margin:8px 0 3px; }
  #theTenHS .ttHS-form .nv-lb:first-child { margin-top:0; }
  #theTenHS .ttHS-nut { display:flex; align-items:center; gap:10px; margin-top:12px; }
  /* Ô tên bấm được thì phải nhìn ra là bấm được */
  .luoi .c-ten[data-hoten] { cursor:pointer; }

  /* Quản lý tài khoản giờ là TRANG RIÊNG (cô Quỳnh 26/07/2026) — nút thôi chiếm
     nguyên bề ngang như hồi còn nằm trong hộp thoại hẹp. */
  /* ⛔ Màu phải là var(--xanh) — app KHÔNG có biến --chinh. Viết var(--chinh) là
     nền thành TRONG SUỐT (chữ trắng trên nền trắng, nút như tàng hình) mà không
     báo lỗi gì. Đã dính 26/07/2026 ở đúng nút này. */
  /* 👔 05/08 — nút gọn, phẳng, vuông vắn; chỉ nút CHÍNH tô xanh, nút phụ để viền
     (bảng quản trị chuyên nghiệp không tô đặc mọi nút). */
  .nut-them-tk { background:var(--xanh); color:#fff; border:1px solid var(--xanh); border-radius:var(--r-md);
    padding:9px 14px; font-weight:700; font-size:13.5px; cursor:pointer; font-family:inherit; }
  .nut-them-tk:hover { filter:brightness(1.06); }
  .nut-them-tk.phu { background:var(--the); color:var(--chu); border-color:var(--vien); }
  .nut-them-tk.phu:hover { border-color:var(--xanh); color:var(--muc); filter:none; }
  .nut-them-tk.phu .ico-nut { color:var(--mo); }

  /* ══════════════════════════════════════════════════════════════════════════
     👥 10/09/2026 — HỘP "＋ MỜI THÀNH VIÊN" (thay hộp "Tạo tài khoản mới")
     ══════════════════════════════════════════════════════════════════════════ */
  /* Huy hiệu tròn ở đầu hộp: một dấu hiệu nhìn phát biết ngay đang ở hộp nào,
     thay cho ba đoạn chữ giải thích mà Boss đã bảo là "dài dòng và ko ai đọc". */
  .mtv-huy { width:40px; height:40px; border-radius:999px; display:flex;
    align-items:center; justify-content:center; margin:0 0 12px;
    background:var(--nen2); border:1px solid var(--vien); color:var(--chu); }
  .mtv-huy svg { width:20px; height:20px; }
  .mtv-nhan { font-size:12.5px; font-weight:700; color:var(--chu); margin:0 0 8px; }
  .mtv-ds { display:flex; flex-direction:column; gap:8px; }
  /* MỘT HÀNG = một người: ô Gmail co giãn + ô chức vụ ngay cạnh (Boss chốt) + nút gỡ.
     ⛔ `min-width:0` cho ô Gmail: thiếu nó thì ô nhập trong flex không chịu co,
        cả hàng tràn ra ngoài hộp thoại trên màn hẹp. */
  /* ⭐ 10/09/2026 — Boss: *"ko được để hở khoảng trắng mà cho hết block"*.
     Ba ô cùng dãn theo `flex:1 1 0`, nút × mới cố định. Trước đây ô chức vụ ghim
     cứng 132px nên hàng nào cũng thừa một khoảng trống bên phải. */
  .mtv-hang { display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
  .mtv-hang input { flex:1 1 0; min-width:0; height:40px; padding:0 12px;
    font-size:16px; font-family:inherit; color:var(--chu); background:var(--nen-o);
    border:1px solid var(--vien); border-radius:var(--r-o, 8px); }
  .mtv-hang input:focus { outline:none; border-color:var(--xanh);
    box-shadow:0 0 0 3px rgba(20,160,160,.18); }
  .mtv-hang select { flex:1 1 0; min-width:112px; height:40px; padding:0 8px;
    font-size:13.5px; font-family:inherit; color:var(--chu); background:var(--nen-o);
    border:1px solid var(--vien); border-radius:var(--r-o, 8px); cursor:pointer; }
  .mtv-hang select:focus { outline:none; border-color:var(--xanh); }
  .mtv-go { flex:0 0 auto; width:32px; height:32px; padding:0; cursor:pointer;
    background:none; border:0; color:var(--mo); font-size:19px; line-height:1;
    border-radius:var(--r-md); }
  .mtv-go:hover { color:#C0392B; background:var(--nen2); }
  .mtv-go:disabled { opacity:.25; cursor:default; background:none; color:var(--mo); }
  .mtv-hang.xong input { background:var(--nen2); color:var(--mo); }
  .mtv-hang.hong input { border-color:#C0392B; }
  .mtv-them { background:none; border:0; padding:0; margin:10px 0 0; cursor:pointer;
    font:inherit; font-size:13px; color:#1A6FD4; text-decoration:underline;
    text-underline-offset:2px; }
  .mtv-them:hover { color:#12539F; }
  .mtv-them:disabled { color:var(--mo); text-decoration:none; cursor:default; }
  .mtv-mk { font-size:12.5px; color:var(--chu-mo); margin:10px 0 0; line-height:1.55; }
  .mtv-mk b { color:var(--chu); font-family:ui-monospace, SFMono-Regular, Menlo, monospace; }
  .mtv-vach { border:0; border-top:1px solid var(--vien); margin:16px 0 14px; }
  /* Ô đường dẫn: CHỈ ĐỌC và có nút chép. Cho gõ vào thì người ta sửa nhầm rồi gửi
     đi một đường dẫn hỏng, mà chẳng ai biết cho tới lúc nhân viên bấm vào. */
  .mtv-link { display:flex; gap:8px; align-items:center; }
  .mtv-link input { flex:1 1 auto; min-width:0; height:40px; padding:0 12px;
    font-size:13px; font-family:ui-monospace, SFMono-Regular, Menlo, monospace;
    color:var(--chu-mo); background:var(--nen2); border:1px solid var(--vien);
    border-radius:var(--r-o, 8px); }
  .mtv-chep { flex:0 0 auto; width:40px; height:40px; cursor:pointer;
    background:var(--nen-o); border:1px solid var(--vien); border-radius:var(--r-o, 8px);
    color:var(--chu-mo); display:flex; align-items:center; justify-content:center; }
  .mtv-chep:hover { border-color:var(--xanh); color:var(--xanh); }
  .mtv-chep svg { width:15px; height:15px; }
  .mtv-loi { font-size:13px; color:#8E2A20; background:#FDECEA; border:1px solid #C0392B;
    border-radius:var(--r-md); padding:9px 12px; margin:12px 0 0; }
  .mtv-xong { font-size:13px; color:#256B39; background:#E8F5EC; border:1px solid #B6DDC3;
    border-radius:var(--r-md); padding:9px 12px; margin:12px 0 0; line-height:1.6; }
  /* Màn hẹp: ô chức vụ xuống hàng dưới ô Gmail chứ đừng bóp còn 60px — bóp lại thì
     đọc được mỗi "Trợ gi…", mà chọn nhầm chức vụ là người ta thấy nhầm cả app. */
  @media (max-width:460px) {
    .mtv-hang { flex-wrap:wrap; }
    .mtv-hang input { flex:1 1 100%; }
    .mtv-hang select { flex:1 1 auto; width:auto; }
  }

  /* ══════════════════════════════════════════════════════════════════════════
     👥 10/09/2026 — BẢNG DANH SÁCH THÀNH VIÊN (mẫu 21st.dev v-table-6)
     ══════════════════════════════════════════════════════════════════════════ */
  /* Khung thẻ bao ngoài bảng — "Frame" trong mẫu. `overflow:hidden` để góc bo cắt
     gọn hàng đầu và hàng cuối; cuộn ngang do lớp trong lo. */
  .mtb { border:1px solid var(--vien); border-radius:var(--r-md);
    background:var(--the); overflow:hidden; }
  .mtb-cuon { overflow-x:auto; }
  .mtb-bang { width:100%; border-collapse:collapse; min-width:560px; }
  .mtb-bang thead th { text-align:left; font-size:12px; font-weight:600;
    color:var(--chu-mo); padding:9px 14px; background:var(--nen2);
    border-bottom:1px solid var(--vien); white-space:nowrap; }
  .mtb-bang tbody td { padding:10px 14px; vertical-align:middle;
    border-top:1px solid var(--vien); }
  .mtb-bang tbody tr:first-child td { border-top:0; }
  .mtb-bang tbody tr:hover { background:var(--nen2); }
  /* Hàng đang chờ duyệt / đã nghỉ: một vạch màu mảnh bên trái, không tô cả hàng —
     tô cả hàng thì chữ trong hàng phải đổi màu theo, và ở nền tối là vỡ. */
  .mtb-bang tbody tr.cho-duyet td:first-child { box-shadow:inset 3px 0 0 var(--cam); }
  .mtb-bang tbody tr.luu-tru td:first-child { box-shadow:inset 3px 0 0 #C0392B; }
  .mtb-bang tbody tr.luu-tru { opacity:.72; }

  .mtb-ng { display:flex; align-items:center; gap:10px; }
  .mtb-ten { display:flex; flex-direction:column; min-width:0; }
  .mtb-ten b { font-size:13.5px; font-weight:600; color:var(--chu); line-height:1.35; }
  .mtb-ten small { font-size:12px; color:var(--chu-mo); line-height:1.35;
    word-break:break-all; }
  .mtb-the-hang { display:flex; flex-wrap:wrap; gap:5px; margin-top:5px; }

  /* Badge — bo 4px như shadcn `rounded-md`, KHÔNG bo tròn (xem lời dặn ở đầu khối). */
  .mtb-badge { display:inline-flex; align-items:center; gap:4px;
    font-size:11.5px; font-weight:600; line-height:1.6; padding:1px 7px;
    border-radius:var(--r-md); border:1px solid transparent; white-space:nowrap; }
  /* Chức vụ. Hai bậc quản trị dùng màu thương hiệu; năm bậc member để trung tính —
     tô bảy màu khác nhau thì bảng thành cái cầu vồng, không còn nhìn ra bậc nào cao. */
  .mtb-badge.vt-owner { background:var(--cam); color:#FFFFFF; border-color:var(--cam); }
  .mtb-badge.vt-admin { background:var(--xanh); color:#FFFFFF; border-color:var(--xanh); }
  .mtb-badge.vt-mem   { background:var(--nen2); color:var(--chu); border-color:var(--vien); }
  /* Trạng thái phụ (nền gõ cứng thì CHỮ CŨNG GÕ CỨNG — nền kem mà chữ để var(--chu)
     thì ở chế độ tối chữ hoá sáng và biến mất, đã dính đúng thế 10/09). */
  .mtb-badge.ok   { background:#E8F5EC; color:#256B39; border-color:#B6DDC3; }
  .mtb-badge.canh { background:#FFF8E1; color:#8A5A00; border-color:#E8D9A8; }
  .mtb-badge.do   { background:#FDECEA; color:#8E2A20; border-color:#EBC3BD; }
  .mtb-badge .ico-the { width:12px; height:12px; }

  /* Cột LỚP PHỤ TRÁCH. Con số là thứ bấm được — bấm vào mở thẳng màn gán lớp,
     đừng bắt người ta đi tìm nút trong menu ⋯ cho một việc làm hằng tuần. */
  .mtb-lop { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
  .mtb-lop-nut { background:none; border:0; padding:0; cursor:pointer; font:inherit;
    font-size:12.5px; color:#1A6FD4; text-decoration:underline; text-underline-offset:2px; }
  .mtb-lop-nut:hover { color:#12539F; }
  .mtb-lop-nut:focus-visible { outline:2px solid #1A6FD4; outline-offset:2px; }

  /* Cột cuối: nút ⋯ */
  .mtb-td-nut { width:44px; text-align:right; white-space:nowrap; }
  .mtb-cham { width:30px; height:30px; padding:0; cursor:pointer; background:none;
    border:1px solid transparent; border-radius:var(--r-md); color:var(--mo);
    display:inline-flex; align-items:center; justify-content:center; }
  .mtb-cham:hover { background:var(--nen-o); border-color:var(--vien); color:var(--chu); }
  .mtb-cham[aria-expanded="true"] { background:var(--nen-o); border-color:var(--xanh); color:var(--chu); }
  .mtb-cham svg { width:15px; height:15px; }

  /* Menu ⋯ — `fixed` để không bị khung cuộn ngang xén mất (xem lời dặn đầu khối).
     Toạ độ do JS đặt lúc mở. */
  .mtb-menu { position:fixed; z-index:60; min-width:196px; padding:5px;
    background:var(--the); border:1px solid var(--vien); border-radius:var(--r-md);
    box-shadow:0 8px 24px rgba(0,0,0,.14); display:flex; flex-direction:column; gap:2px; }
  .mtb-menu button { display:flex; align-items:center; gap:8px; width:100%;
    text-align:left; padding:8px 10px; min-height:34px; font:inherit; font-size:13px;
    color:var(--chu); background:none; border:0; border-radius:var(--r-md); cursor:pointer; }
  .mtb-menu button:hover { background:var(--nen2); }
  .mtb-menu button .ico-nut { width:15px; height:15px; color:var(--mo); flex:0 0 auto; }
  .mtb-menu button.nut-do { color:#C0392B; }
  .mtb-menu button.nut-do:hover { background:#FDECEA; }
  .mtb-menu button.nut-do .ico-nut { color:#C0392B; }

  /* Màn hẹp: bảng tự cuộn ngang trong khung của nó, thân trang KHÔNG được cuộn
     ngang theo — bóp cột lại cho vừa thì tên và email cụt hết. */
  @media (max-width:640px) {
    .mtb-bang thead th, .mtb-bang tbody td { padding:9px 10px; }
    .mtb-bang { min-width:520px; }
  }

  /* ════════════════════════════════════════════════════════════════════════
     🏫 10/09/2026 — MÀN "GÁN LỚP" theo cùng khuôn với bảng thành viên
     ════════════════════════════════════════════════════════════════════════ */
  /* Dải đầu màn: đang gán lớp CHO AI. Mở ba hộp liên tiếp mà không có nó là quên
     mất đang làm cho người nào — mà bấm nhầm ở đây là một cô mất sạch lớp. */
  .gl-dau { display:flex; align-items:center; gap:10px; padding:0 0 12px;
    margin:0 0 12px; border-bottom:1px solid var(--vien); }
  .gl-dau .mtb-ten { flex:1 1 auto; }
  .gl-tim { display:block; width:100%; height:40px; padding:0 12px; font-size:16px;
    font-family:inherit; color:var(--chu); background:var(--nen-o);
    border:1px solid var(--vien); border-radius:var(--r-o); }
  .gl-tim:focus { outline:none; border-color:var(--xanh); }
  .gl-thanh { display:flex; align-items:center; gap:6px; flex-wrap:wrap;
    font-size:12.5px; color:var(--chu-mo); margin:10px 0 8px; }
  .gl-thanh b { color:var(--chu); }
  .gl-thanh button { background:none; border:0; padding:0; cursor:pointer;
    font:inherit; font-size:12.5px; color:#1A6FD4; text-decoration:underline;
    text-underline-offset:2px; }
  .gl-thanh button:hover { color:#12539F; }
  .gl-ds { max-height:46vh; overflow:auto; border:1px solid var(--vien);
    border-radius:var(--r-md); background:var(--the); }
  /* ⛔ Vạch ngăn nằm ở mép TRÊN của dòng sau, không phải mép DƯỚI của mọi dòng:
     kiểu cũ vẽ thêm một vạch dưới dòng cuối, chồng lên viền khung. */
  .gl-mot { display:flex; gap:10px; align-items:center; padding:9px 12px;
    border-top:1px solid var(--vien); cursor:pointer; }
  .gl-mot:first-child { border-top:0; }
  .gl-mot:hover { background:var(--nen2); }
  .gl-mot input { margin:0; flex:0 0 auto; width:16px; height:16px; cursor:pointer; }
  .gl-mot.khoa { cursor:default; background:var(--nen2); }
  .gl-mot.khoa input { cursor:not-allowed; }
  .gl-ten { display:flex; flex-direction:column; min-width:0; gap:1px; }
  .gl-ten b { font-size:13.5px; font-weight:600; color:var(--chu); line-height:1.35; }
  .gl-ten small { font-size:12px; color:var(--chu-mo); line-height:1.35;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  /* Nhãn "theo tuần · tự gỡ" mặc cùng bộ đồ với badge trong bảng thành viên.
     Đè lên luật `.nhan-tuan` viên thuốc ở cuối tệp bằng độ ưu tiên cao hơn, chứ
     KHÔNG sửa luật ấy — chỗ khác trong app còn dùng. */
  .gl-mot .nhan-tuan { margin:0 0 0 auto; flex:0 0 auto; border-radius:var(--r-md);
    padding:2px 8px; font-size:11.5px; font-weight:600; }
  .gl-trong { padding:14px 12px; font-size:13px; color:var(--chu-mo); text-align:center; }

  /* ⭐ 10/09/2026 — Ô GÕ SAI THÌ ĐỎ ĐÚNG Ô ẤY (Boss: *"nếu sai nó hiện đỏ ở ô
     gmail đó"*). Trước đây tô đỏ cả dòng, người ta không biết sửa ô nào.
     ⛔ Không dùng mỗi màu để báo lỗi: câu giải thích ở `#mtvLoi` nói rõ sai chỗ nào,
        và `aria-invalid` để trình đọc màn hình cũng biết. */
  .mtv-hang input.hong, .mtv-hang select.hong {
    border-color:#C0392B; background:#FDECEA; }
  body.toi .mtv-hang input.hong, body.toi .mtv-hang select.hong {
    border-color:#E57368; background:rgba(192,57,43,.14); }
  /* Màn hẹp: tên và Gmail xuống hai dòng riêng cho đủ chỗ gõ, chức vụ và nút × ở
     hàng dưới — vẫn kín block, không chừa khoảng trắng. */
  @media (max-width:520px) {
    .mtv-hang input { flex:1 1 100%; }
    .mtv-hang select { flex:1 1 0; }
  }

  /* ⭐ 10/09/2026 — NHÃN CHỨC VỤ CHIẾM HẾT Ô (Boss: *"ko được để hở ra khoảng
     trắng… cho hết block"*). Nhãn "Quản lý" ngắn, "Trợ giảng" dài, nên mép phải cột
     Chức vụ so le trông như xếp ẩu.
     ⛔ Chỉ áp TRONG BẢNG. Cùng mấy tên lớp ấy còn dùng ở dải đầu màn Gán lớp, chỗ
        ấy nhãn phải ôm sát chữ chứ kéo hết bề ngang là xấu. */
  .mtb-bang .mtb-badge.vt-owner,
  .mtb-bang .mtb-badge.vt-admin,
  .mtb-bang .mtb-badge.vt-mem {
    display:flex; width:100%; justify-content:center; }
  .tk-thanh { display:flex; gap:8px; flex-wrap:wrap; align-items:center; margin:14px 0 8px; }
  .tk-thanh input { flex:1 1 220px; min-width:160px; height:44px; border:1px solid var(--vien);
    border-radius:var(--r-o, 8px); padding:0 13px; font-size:16px; }  /* 16px: iPhone khỏi phóng */
  .tk-nhom { margin-top:20px; }
  /* 👔 05/08 (cô Quỳnh: "quản lý tài khoản chuyên nghiệp hơn") — tiêu đề nhóm kiểu
     bảng quản trị: chữ hoa nhỏ, vạch mảnh; thẻ người vuông vắn, viền rõ, bóng nét. */
  /* 05/08 (cô Quỳnh: "lộ rõ AI/khuôn mẫu") — bỏ CHỮ IN HOA GIÃN LY, dùng chữ thường
     cỡ lớn hơn, màu đậm: đọc nhanh hơn và tự nhiên hơn nhiều. */
  .tk-nhom h3 { display:flex; align-items:center; gap:8px; font-size:15px; font-weight:700;
    color:var(--chu); margin:22px 0 9px; padding:0 0 8px;
    border-left:0; border-bottom:1px solid var(--vien); }
  .tk-nhom:first-child h3 { margin-top:2px; }
  .tk-nhom h3 .ico { color:var(--mo); margin-right:0; width:15px; height:15px; }
  .tk-nhom h3 .dem-nhom { font-size:11px; font-weight:700; color:var(--mo);
    background:var(--nen2); border:1px solid var(--vien); border-radius:var(--r-xl); padding:1px 8px; }
  .tk-trong { font-size:12.5px; color:var(--mo); background:var(--nen2); border:1px dashed var(--vien);
              border-radius:var(--r-md); padding:11px 13px; margin-bottom:8px; }
  .hang-tk { background:var(--the); border:1px solid var(--vien); border-radius:var(--r-md);
             padding:11px 13px; margin-bottom:7px; transition:border-color .12s, box-shadow .12s; }
  .hang-tk:hover { border-color:var(--xanh); box-shadow:0 1px 3px rgba(20,50,70,.12); }
  .tk-tomtat { font-size:12.5px; color:var(--mo); padding:2px 0 10px; }
  /* 🔽 Hàng chip LỌC CHỨC VỤ (cô Quỳnh 19/08/2026: "cứ phải kéo tít xuống để tìm
     trợ giảng ở tận cuối cùng rất lâu"). Cuộn ngang trên màn hẹp, không xuống dòng
     lộn xộn. */
  /* 📑 23/08/2026 — hàng chip ĐỔI THÀNH TAB. Cô Quỳnh: *"tôi thấy nó liệt kê xuống
     bên dưới rất dài và thiếu chuyên nghiệp tôi muốn nó có tab rõ ràng ra"*.
     Chip cũ chỉ LỌC, mà mặc định là "Tất cả" — nên mở trang ra vẫn thấy đúng cái
     danh sách dài 73 người xếp dọc như cũ. Tab thì mặc định đứng ở MỘT bộ phận,
     phần còn lại nằm sau tab khác. Cùng một cơ chế lọc, khác cái mặc định và
     khác dáng: viền dưới liền một vạch, tab đang đứng có gạch màu — dáng tab
     quen thuộc, không phải viên thuốc bồng bềnh. */
  .tk-chips { display:flex; gap:2px; margin:0 0 14px; overflow-x:auto; overflow-y:hidden;
    border-bottom:1px solid var(--vien); padding-bottom:0; scrollbar-width:thin; }
  .tk-chip { padding:9px 14px 8px; font-size:13px; font-weight:600; cursor:pointer;
    border:0; border-bottom:2px solid transparent; border-radius:var(--r-sm) var(--r-sm) 0 0;
    background:transparent; color:var(--mo); white-space:nowrap; margin-bottom:-1px; }
  .tk-chip:hover { background:var(--nen2); color:var(--chu); }
  .tk-chip.chon { color:var(--xanh-dam); border-bottom-color:var(--xanh-dam);
    background:transparent; font-weight:700; }
  .tk-chip .dem-nhom { font-weight:600; opacity:.65; font-variant-numeric:tabular-nums; }
  .tk-chip.chon .dem-nhom { opacity:.85; }
  /* Tab đang đứng thì cái tên bộ phận đã nằm ngay trên đầu rồi — lặp lại thành
     một tiêu đề nữa ngay dưới là thừa, mà thừa thì trông vẫn "liệt kê dọc". */
  .tk-mot-tab .tk-nhom > h3 { display:none; }
  .tk-mot-tab .tk-nhom { margin-top:4px; }
  /* 👤 Ảnh đại diện: icon hình người, bỏ chữ cái. Cô Quỳnh: *"logo của các account
     giờ ko được để chữ nữa mà để icon giống facebook"*. */
  .tk-anh.trong { background:var(--nen2); border-color:var(--vien); color:var(--mo); }
  /* ⛔ `margin-right:0` là bắt buộc: luật chung `i[class^="ic-"]` đẩy icon 6px sang
     phải, để nguyên thì hình người lệch hẳn khỏi tâm ô tròn. Mấy thứ mask-* thì
     luật chung lo rồi, khai lại chỉ tổ dài. */
  .tk-anh.trong i { width:19px; height:19px; margin-right:0; vertical-align:0; opacity:.9; }
  .tk-tomtat .cho { color:var(--cam); }
  .tk-hang-the { margin-top:4px; display:flex; gap:5px; flex-wrap:wrap; }
  .tk-the { display:inline-block; font-size:11px; font-weight:700; padding:2px 8px; border-radius:999px;
    background:var(--nen2); color:var(--mo); }
  .tk-the.gv   { background:#e6f4f4; color:#0d7a7a; }
  .tk-the.ok   { background:#e8f6ec; color:#1e7a3c; }
  .tk-the.do   { background:#fdeaea; color:#c0392b; }
  .tk-the.canh { background:#fff3d9; color:#9a6400; }
  .tk-the.toi  { background:var(--xanh); color:#fff; }
  /* Tài khoản do bộ đồng bộ lịch trợ giảng quản (26/07/2026) */
  .tk-the.tudong { background:#EDE9FB; color:#5B3FA8; }
  .hang-tk.luu-tru { opacity:.62; background:#F3F5F7; }

  /* ---- 🚦 TRANG XEM TỐC ĐỘ GHI LÊN SHEET (29/07/2026) ---- */
  .tdg-hang3 { display:flex; gap:12px; flex-wrap:wrap; margin:10px 0 16px; }
  .tdg-o { flex:1 1 160px; background:#fff; border:1px solid var(--vien); border-radius:var(--r-xl);
           padding:14px 16px; text-align:center; }
  .tdg-o b { display:block; font-size:22px; font-weight:700; color:#1F2A33; }
  .tdg-o span { font-size:12px; color:var(--mo); }
  .tdg-ketluan { background:#F7F9FA; border:1px solid var(--vien); border-radius:var(--r-lg);
                 padding:12px 14px; font-size:13.5px; line-height:1.5; }
  /* ============ 🖼 NỀN 4 MÙA HÀ NỘI (31/07/2026) ============
     Cô Quỳnh: nền theo mùa "cho đỡ chán", có lá/hoa/tuyết rơi + mèo đi bộ,
     NHƯNG "không gây khó nhìn khi tìm block lớp, không đau mắt".
     Cách giữ dễ đọc: ảnh nằm DƯỚI một màn phủ trắng mờ (.nen-phu) — cảnh vẫn
     thấy, chữ và thẻ lớp vẫn nét. Ảnh thật (nen-<mùa>.jpg) đứng TRƯỚC trong
     danh sách nền; CHƯA có file thì lớp ảnh trong suốt và MÀU TRỜI dự phòng
     phía sau hiện ra — không vỡ gì, thả ảnh vào thư mục là đẹp ngay. */
  #nenMua { position:fixed; inset:0; z-index:0; pointer-events:none; overflow:hidden; }
  body.co-nen-mua { background:transparent; }
  body.co-nen-mua #app { position:relative; z-index:1; }
  #nenMua .nen-anh { position:absolute; inset:0; background-position:center; background-size:cover; }
  /* Ảnh nằm TRÊN, gradient màu trời DƯỚI cùng làm nền dự phòng. Nhận cả .webp
     lẫn .jpg: đuôi nào 404 thì lớp đó trong suốt, lớp dưới hiện qua — nên có bất
     kỳ đuôi nào (hoặc chưa có ảnh) đều không vỡ. */
  #nenMua[data-mua="xuan"] .nen-anh { background-image:url("/anh/nen-xuan.webp"), url("/anh/nen-xuan.jpg"), linear-gradient(180deg,#CDE9F5 0%,#F8E4EE 55%,#EAF6E7 100%); }
  #nenMua[data-mua="he"]   .nen-anh { background-image:url("/anh/nen-he.webp"),   url("/anh/nen-he.jpg"),   linear-gradient(180deg,#A9DCF2 0%,#D9F0F5 55%,#E9F7EF 100%); }
  #nenMua[data-mua="thu"]  .nen-anh { background-image:url("/anh/nen-thu.webp"),  url("/anh/nen-thu.jpg"),  linear-gradient(180deg,#F5D7A5 0%,#F4E3C9 55%,#F1EADB 100%); }
  #nenMua[data-mua="dong"] .nen-anh { background-image:url("/anh/nen-dong.webp"), url("/anh/nen-dong.jpg"), linear-gradient(180deg,#C7D8EA 0%,#E2EAF4 55%,#F0F4F9 100%); }
  /* 🖼 05/08 — ẢNH NỀN RIÊNG của từng người (chọn trong ⚙ Cài đặt) */
  #nenRieng { position:fixed; inset:0; z-index:0; pointer-events:none; overflow:hidden; }
  #nenRieng .nen-anh { position:absolute; inset:0; background-position:center; background-size:cover; }
  /* 🛡 Đang NHẬP ĐIỂM trong lớp → tắt hẳn ảnh nền (mọi cỡ màn hình) cho khỏi rối mắt */
  body.dang-trong-lop #nenRieng, body.dang-trong-lop #nenMua { display:none !important; }
  body.co-nen-mua.dang-trong-lop { background:var(--nen); }
  /* Lớp phủ ĐỦ MẠNH: ảnh của người dùng có thể rất chói hoặc rất tối — phủ để mọi
     chữ/viền phía trên luôn đọc được (đã đo thử cả ảnh vàng chói lẫn ảnh đen). */
  #nenRieng .nen-phu { position:absolute; inset:0; background:rgba(255,255,255,.58); }
  body.toi #nenRieng .nen-phu { background:rgba(8,14,22,.7); }

  /* ⚙ 05/08 — TRANG CÀI ĐẶT gom một chỗ (hồ sơ · giao diện · tài khoản · thiết bị).
     Kiểu bảng cài đặt của app doanh nghiệp: khối vuông vắn, hàng phân cách rõ. */
  .cd-boc { display:flex; flex-direction:column; gap:14px; max-width:860px; }
  .cd-khoi { background:var(--the); border:1px solid var(--vien); border-radius:var(--r-md); overflow:hidden;
    box-shadow:0 1px 2px rgba(20,50,70,.08); }
  .cd-dau { padding:12px 16px; border-bottom:1px solid var(--vien); background:var(--nen2);
    font-weight:700; font-size:14px; color:var(--chu); }
  .cd-hang { display:flex; align-items:center; gap:14px; padding:14px 16px; border-top:1px solid var(--vien); }
  /* ⛔ Ô ICON CHỈ DÀNH CHO ĐIỆN THOẠI (Boss 10/09/2026 nói riêng về màn điện thoại).
     Máy tính màn rộng đã có khuôn thẻ viền để phân nhóm, thêm một cột icon là thừa.
     ⛔ PHẢI VIẾT `.cd-hang > i.cd-ico`, KHÔNG viết `.cd-ico`. Luật nền
        `i[class^="ic-"]` (dòng ~6871) đặt `display:inline-block`, độ đặc hiệu
        (0,1,1) và nằm SAU chỗ này trong file — `.cd-ico` trơn chỉ (0,1,0) nên thua
        cả hai vế, ẩn không ăn mà chẳng có dấu hiệu gì. Thêm `.cd-hang >` cho lên
        (0,2,1) là thắng thật, khỏi phải chồng `!important`. */
  .cd-hang > i.cd-ico { display:none; }
  .cd-khoi .cd-dau + .cd-hang { border-top:0; }
  .cd-hang-chu { flex:1; min-width:0; }
  .cd-hang-chu b { display:block; font-size:14px; font-weight:600; color:var(--chu); }
  .cd-hang-chu small { display:block; color:var(--mo); font-size:12.5px; margin-top:2px; }
  .cd-nut { flex:none; background:var(--the); border:1px solid var(--vien); border-radius:var(--r-md);
    padding:8px 14px; font-size:13px; font-weight:600; font-family:inherit; color:var(--chu); cursor:pointer; }
  .cd-nut:hover { border-color:var(--xanh); color:var(--muc); }
  .cd-av { width:52px; height:52px; border-radius:50%; overflow:hidden; flex:none;
    display:inline-flex; align-items:center; justify-content:center;
    background:var(--nen2); color:var(--mo); border:1px solid var(--vien); box-sizing:border-box; }
  .cd-av img { width:100%; height:100%; object-fit:cover; display:block; }
  .cd-chon { display:flex; gap:8px; flex-wrap:wrap; flex:none; }
  .cd-chon button { border:1px solid var(--vien); background:var(--the); border-radius:var(--r-md);
    padding:7px 13px; font-size:12.5px; font-weight:600; font-family:inherit; color:var(--chu); cursor:pointer; }
  .cd-chon button.chon { border-color:var(--xanh); background:var(--xanh); color:#fff; }
  /* ══════════════════════════════════════════════════════════════════════════════
     📱 HÀNG CÀI ĐẶT TRÊN MÀN HẸP — vá 22/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     Cô Quỳnh gửi ảnh màn Cài đặt trên iPhone: dòng *"Phóng to / thu nhỏ toàn bộ chữ
     và bảng cho vừa mắt"* bị bóp thành **một cột dọc rộng 90px**, mỗi dòng hai ba
     chữ. Cô: *"nhìn nó xấu quá"*.

     GỐC: `flex-wrap:wrap` MỘT MÌNH KHÔNG ĐỦ. Hàng gồm [cụm chữ][cụm nút]:
        .cd-hang-chu  flex:1  min-width:0   ← co được tới 0
        .cd-chon      flex:none             ← không co
     Cụm nút không chịu co, mà cụm chữ thì co được vô hạn — nên trình duyệt CHỌN
     CÁCH CO CHỮ chứ không bao giờ xuống dòng. Bốn nút "Nhỏ · Vừa · Lớn · Rất lớn"
     ăn gần hết bề ngang, chữ còn lại 90px.
     Đo được ngày 22/08 trên bốn khổ máy (320 · 360 · 393 · 430) — cả bốn đều bóp.

     CÁCH VÁ: cho cụm chữ một SÀN bề ngang. Hết sàn thì cụm nút buộc phải xuống
     dòng — đúng thứ `flex-wrap` sinh ra để làm.
     ⛔ `min(100%, 210px)` chứ KHÔNG phải `210px` trần: máy hẹp 320px sau khi trừ
        đệm chỉ còn 288px, mà hàng có avatar còn trừ thêm 52px nữa. Đặt trần là
        chính cụm chữ tràn ra ngoài — đổi một lỗi lấy một lỗi khác.
     ⛔ ĐỪNG chữa bằng cách thu nhỏ cỡ chữ hay cắt bớt câu mô tả. Câu ấy là thứ
        giải thích nút làm gì; app này người dùng không rành máy tính. */
  @media (max-width:820px) {
    /* ══════════════════════════════════════════════════════════════════════════
       📱 SỬA LẠI 09/09/2026 — Boss: *"setting đang thiết kế kiểu thiếu chuyên
       nghiệp thiếu đi sự đồng bộ trên điện thoại, nó cứ trồng lên nhau trống xấu
       kinh khủng"*.

       Bản vá 22/08 ở trên cho MỌI hàng xuống dòng để cứu lỗi chữ bị bóp thành cột
       90px. Nó chữa đúng lỗi ấy, nhưng vơ cả những hàng chỉ có MỘT nút — "Đổi ảnh
       đại diện", "Đổi mật khẩu", "Liên kết Gmail". Nút đơn rộng 109–127px thừa sức
       nằm cùng hàng, đẩy nó xuống dòng là:
         · mỗi mục ngốn ba dòng thay vì hai → màn phải cuộn thêm 760–1138px;
         · nửa phải mỗi hàng bỏ trống, nút thì nép trái → đúng chữ "trống xấu".

       Chuẩn ngành (Material 3 list item · iOS Settings): MỘT MỤC LÀ MỘT HÀNG NGANG
       — nhãn bên trái, điều khiển bên phải. Chỉ khi điều khiển là một NHÓM nhiều
       nút mới cho xuống dòng rồi trải hết bề ngang.

       Nên tách hai kiểu hàng, đừng gộp:
         · hàng có `.cd-nut` (một nút hành động) → KHÔNG xuống dòng
         · hàng có `.cd-chon` (nhóm nút chọn)   → xuống dòng, trải đều
       ══════════════════════════════════════════════════════════════════════════ */
    /* ① Hàng có NHÓM nút chọn: giữ nguyên cách cũ — sàn bề ngang cho cụm chữ,
       hết sàn thì nhóm nút xuống dòng. Lý do đầy đủ ở khối 22/08 ngay trên. */
    .cd-hang:has(.cd-chon) { flex-wrap:wrap; }
    /* ⛔ SÀN LÀ 100%, KHÔNG PHẢI `min(100%, 210px)` — Boss 09/09/2026 chê "thiếu đi
       sự đồng bộ". Với sàn 210px thì nhóm HAI nút ("Nền sáng · Nền tối", "Thoáng ·
       Gọn") vẫn còn đủ ~140px nên nó Ở LẠI cùng hàng và bị bóp, trong khi nhóm BỐN
       nút ("Nhỏ · Vừa · Lớn · Rất lớn") thì xuống dòng. Cùng một loại điều khiển mà
       hai kiểu bày — mắt đọc thấy lộn xộn ngay.
       Sàn 100% thì MỌI nhóm chọn đều xuống dòng và trải đều bề ngang: một luật, một
       dáng, không phụ thuộc nhóm ấy có mấy nút. */
    .cd-hang:has(.cd-chon) .cd-hang-chu { min-width:100%; }
    .cd-chon { flex:1 1 auto; }

    /* ② Hàng chỉ có MỘT nút: ở lại cùng dòng, nút nép phải.
       `min-width:0` để cụm chữ tự xuống dòng trong lòng nó thay vì đẩy nút đi;
       `flex:none` giữ nút nguyên cỡ, không bị bóp thành hình thước kẻ. */
    .cd-hang:not(:has(.cd-chon)) { flex-wrap:nowrap; }
    .cd-hang:not(:has(.cd-chon)) .cd-hang-chu { min-width:0; flex:1; }
    .cd-hang:not(:has(.cd-chon)) .cd-nut { flex:none; margin-left:auto; }

    /* ③ ĐÍCH BẤM 44px — đo 09/09/2026 thấy CẢ 19 nút của màn này đều cao 32–37px,
       dưới mức tối thiểu của cả hai nhà: Apple 44×44px, Google Material 48×48dp.
       Chỉ nâng chiều cao, KHÔNG phóng cỡ chữ: chữ 13px là số đã chốt trong
       `thiet-ke/BANG-MAU-VA-CHU.md`, phóng lên là lệch khỏi cả app. */
    .cd-nut, .cd-chon button { min-height:44px; padding-top:0; padding-bottom:0; }
    /* Hai tab "Cá nhân · Dữ liệu" cũng là đích bấm — đo 09/09 ra 72×37 và 66×37,
       thiếu 7px so với mức tối thiểu 44px. Đây là hai nút bấm nhiều nhất của màn. */
    .cd-tabs button { min-height:44px; }

    /* ④ Nhóm nút chọn chia đều bề ngang thay vì dồn cục bên trái — bốn nút "Nhỏ ·
       Vừa · Lớn · Rất lớn" thành bốn ô bằng nhau, mắt quét một lượt là thấy hết,
       và không còn khoảng trống lệch bên phải. */
    .cd-chon { display:flex; gap:8px; }
    .cd-chon button { flex:1 1 0; min-width:0; padding-left:6px; padding-right:6px; }

    /* ⑤ Hàng cao tối thiểu 56px (Material: mục hai dòng là 64dp, một dòng 48dp).
       Trước đây chiều cao hàng do nội dung quyết định nên mỗi hàng một kiểu — đó là
       chỗ Boss thấy "thiếu đồng bộ". */
    .cd-hang { min-height:56px; }

    /* ══════════════════════════════════════════════════════════════════════════
       ⚙ KHUÔN TIKTOK CHO MÀN CÀI ĐẶT ĐIỆN THOẠI — Boss 10/09/2026
       ──────────────────────────────────────────────────────────────────────────
       Boss gửi ảnh chụp màn Cài đặt của TikTok: *"bạn hãy nhìn dùng skill mà bạn
       học được phân tích và áp vào app của mình phần setting cho tôi, sửa lại hết
       phần setting trên điện thoại cho tôi."*

       Bản vá 09/09 ngay trên đã dựng lại HÀNG (một mục một hàng ngang, đích bấm
       44px, nhóm nút trải đều). Còn thiếu ba thứ, đo trên ảnh TikTok Boss gửi:

         ① MỖI HÀNG CÓ ICON NÉT MỘT MÀU BÊN TRÁI. Đây là thứ làm mắt quét dọc bắt
            được mục cần tìm mà không phải đọc hết chữ. Boss chốt bằng nút bấm:
            CÓ icon, nét xám đơn sắc — không emoji màu.
         ② TIÊU ĐỀ NHÓM là chữ nhỏ xám trên nền trang, KHÔNG phải một dải nền xám.
            Bản mình đang để `.cd-dau` có `background:var(--nen2)` + viền dưới —
            kiểu thanh tiêu đề của bảng tính. Trên màn hẹp bốn dải xám xếp dọc trông
            như bốn cái bảng chồng lên nhau.
         ③ NHÓM CÁCH NHAU BẰNG KHOẢNG TRỐNG, không phải viền hộp. Bỏ viền quanh
            `.cd-khoi`, thay bằng một tấm nền bo góc ôm lấy đúng phần các hàng.

       ⛔ KHÔNG BÊ NGUYÊN TIKTOK. Ba thứ CỐ Ý không lấy, vì trái mẫu gốc đã chốt ở
          `thiet-ke/BANG-MAU-VA-CHU.md`: emoji màu (Boss đã chê "lộ rõ ui AI" nhiều
          lần), nền tối mặc định, và chữ trắng trên nền đen. Chỉ lấy BỐ CỤC + SỐ ĐO.
       ⛔ KHÔNG PHÓNG CỠ CHỮ theo TikTok — 13–14px là số đã chốt cho cả app.
       ⛔ CHỈ TRONG KHỐI MÀN HẸP NÀY. Máy tính giữ nguyên khuôn thẻ có viền.
       ══════════════════════════════════════════════════════════════════════════ */
    /* ① Ô icon 20px, xám như chữ mô tả.
       ⛔ `.cd-hang > i.cd-ico` chứ đừng `.cd-ico` — luật nền `i[class^="ic-"]`
          (dòng ~6871) là (0,1,1) và nằm SAU trong file, nên `.cd-ico` trơn thua cả
          cỡ lẫn `display`. Lý do đầy đủ ở chỗ ẩn icon cho máy tính, dòng ~2001.
       ⛔ `margin-right:0` bắt buộc: luật chung `i[class^="ic-"]` đẩy icon 6px sang
          phải, cộng với `gap` của hàng thành 18px — icon trôi khỏi cột. */
    .cd-hang > i.cd-ico { display:block; width:20px; height:20px; margin-right:0;
      color:var(--mo); opacity:.85; }

    /* Hàng nào KHÔNG có icon (hàng "Ảnh nền của tôi" dựng thẳng trong JS) thì thụt
       vào đúng bằng ô icon + khe, để chữ vẫn thẳng một cột với các hàng khác.
       Làm bằng CSS chứ không đi thêm icon cho từng hàng lẻ: hàng nào người sau thêm
       vào mà quên icon cũng tự thẳng hàng, không phải nhớ luật này. */
    .cd-hang > .cd-hang-chu:first-child { margin-left:32px; }

    /* ② Tiêu đề nhóm: chữ nhỏ xám, bỏ dải nền và viền dưới. */
    .cd-dau { background:transparent; border-bottom:0; padding:18px 4px 7px;
      font-size:12px; font-weight:600; color:var(--mo); letter-spacing:.02em; }

    /* ③ Khối bỏ viền; nền và bo góc chuyển xuống cho chính các hàng, nên tấm trắng
       ôm đúng phần bấm được. `overflow:visible` vì không còn gì phải cắt. */
    .cd-khoi { border:0; background:transparent; border-radius:0; overflow:visible;
      margin-bottom:4px; }
    .cd-khoi .cd-hang { background:var(--the); }
    .cd-khoi .cd-dau + .cd-hang { border-top:0;
      border-radius:var(--r-md) var(--r-md) 0 0; }
    .cd-khoi .cd-hang:last-child { border-radius:0 0 var(--r-md) var(--r-md); }
    .cd-khoi .cd-dau + .cd-hang:last-child { border-radius:var(--r-md); }

    /* ④ Mô tả kẹp HAI dòng, không phải một.
       ⛔ ĐỪNG cắt còn một dòng bằng `nowrap` + ba chấm. Khối 22/08 ngay trên file
          này đã cấm: *"ĐỪNG chữa bằng cách thu nhỏ cỡ chữ hay cắt bớt câu mô tả.
          Câu ấy là thứ giải thích nút làm gì; app này người dùng không rành máy
          tính."* Câu dài nhất ở đây (hàng Gmail, 66 chữ) vừa đúng hai dòng trên màn
          360px — kẹp 2 dòng chặn được hàng cao vống mà không nuốt chữ nào. */
    .cd-hang-chu small { display:-webkit-box; -webkit-box-orient:vertical;
      -webkit-line-clamp:2; line-clamp:2; overflow:hidden; }

    /* ⑤ Hàng có nhóm nút chọn: sàn của cụm chữ phải TRỪ ĐI ô icon VÀ CÓ DƯ.
       ⛔ Luật 09/09 ở trên đặt `min-width:100%`. Nay hàng có thêm icon 20px + khe
          12px đứng trước, để nguyên 100% là cụm chữ đẩy hàng quá khổ 32px.
       ⛔ TRỪ 40px CHỨ ĐỪNG TRỪ ĐÚNG 32px. Đo 10/09/2026 ở cả bốn khổ máy: trừ khít
          32px thì icon + khe + cụm chữ cộng lại BẰNG ĐÚNG bề ngang còn lại, và mọi
          bề ngang ở đây là số lẻ (`clientWidth` trừ đệm) — chỉ cần dôi nửa pixel là
          trình duyệt hất luôn cụm chữ xuống dòng dưới. Hậu quả không dừng ở một
          hàng xấu: chữ tụt về mép 28px (lệch cột với chín hàng kia), hàng cao vọt
          từ 81px lên 174px, và câu mô tả bị ép vào cột hẹp thành 5–8 dòng — đúng ba
          thứ Boss đang bảo sửa. Dư 8px là chỗ đệm cho phép làm tròn, không hơn.
          (Nhóm nút vẫn xuống dòng như ý: chỗ còn lại 8px không chứa nổi nút nào.) */
    .cd-hang:has(.cd-chon) .cd-hang-chu { min-width:calc(100% - 40px); }
    /* Nhóm nút xuống dòng thì thụt vào thẳng cột với chữ ngay trên nó. */
    .cd-hang:has(.cd-chon) .cd-chon { margin-left:32px; }

    /* ⑥ SÀN CHO CỘT CHỮ — đo 10/09/2026, bốn khổ máy.
       ──────────────────────────────────────────────────────────────────────────
       Luật 09/09 cho cụm chữ `min-width:0` và cho nút `flex:none`: nút giữ nguyên
       bề ngang tự nhiên, còn bao nhiêu thì cụm chữ chịu. Trên màn 320 sau khi trừ
       thêm ô icon 20px, kết quả đo được:
           Mật khẩu 107px · Gmail 102px · Thông báo 136px · PHIÊN BẢN APP 22px
       Hàng "Phiên bản app" tệ nhất vì bên phải nó không phải nút mà là chuỗi số
       phiên bản — chuỗi ấy KHÔNG NGẮT ĐƯỢC, nên bề ngang tối thiểu của nó lớn, và
       cụm chữ bị nén còn 22px: nhãn "Phiên bản app" rơi thành một cột dọc mỗi dòng
       một chữ. Đúng lỗi cô Quỳnh đã chê ngày 22/08, nay tái hiện ở hàng khác.

       Chữa bằng cách đảo thứ tự ai phải nhường: CỘT CHỮ có sàn 52%, phần bên phải
       mới là phần co lại.
       ⛔ `min-width:0` cho nút là BẮT BUỘC đi kèm — không có nó thì nút vẫn lấy bề
          ngang tối thiểu của mình và tổng vượt khổ, đẩy hàng tràn ngang.
       ⛔ Nhãn nút xuống hai dòng ở màn 320 là CHẤP NHẬN ĐƯỢC, vì `min-height:44px`
          đã giữ đích bấm; chữ giải thích bị nén mới là thứ không đọc nổi. */
    /* ⛔ HAI DÒNG NÀY KHÔNG NGANG NHAU — đo bằng thử phá 10/09/2026:
       · Dòng `.cd-nut` là dòng GÁNH VIỆC. Gỡ nó (trả về `flex:none` như luật
         09/09) là cột chữ bị bóp lại ngay, nhãn vỡ dòng — bài kiểm đỏ.
       · Dòng `.cd-hang-chu` là LƯỚI ĐỠ. Gỡ riêng nó thì bài vẫn xanh đủ 108/108,
         vì nút đã chịu co nên chẳng còn ai bóp cột chữ nữa.
       Giữ cả hai là cố ý, và lý do hay hơn tôi tưởng lúc đầu — đo được khi phá:
       SÀN 52% BIẾN LỖI CÂM THÀNH LỖI ỒN.
       · CÓ sàn: cột chữ không chịu co nữa, nên một cái nút không co được sẽ đẩy cả
         hàng TRÀN RA NGOÀI MÀN. Đo thấy ở cả ba khổ 320/360/390 — bài kiểm kêu ngay
         ở phép "KHÔNG tràn ngang".
       · KHÔNG sàn: cột chữ lặng lẽ teo còn 22px. Nhìn vẫn "có chữ", không phép canh
         nào kêu, và người dùng thì chịu trận — đúng lỗi cô Quỳnh chê 22/08/2026.
       ⛔ Nên đừng thấy "gỡ dòng `min-width:52%` mà bài vẫn xanh" rồi kết luận nó vô
          dụng và xoá đi. Nó không gánh bố cục — nó gánh việc LÀM CHO HỎNG NÓ LỘ RA.
          Thà hỏng ồn còn hơn hỏng câm. */
    .cd-hang:not(:has(.cd-chon)) .cd-hang-chu { min-width:52%; flex:1 1 auto; }
    .cd-hang:not(:has(.cd-chon)) .cd-nut { flex:0 1 auto; min-width:0; }
    /* Phần bên phải KHÔNG phải nút (chuỗi số phiên bản) — cho phép ngắt giữa chuỗi.
       `:not(.cd-av)` vì ảnh đại diện cũng là một <span>, mà nó thì không được co. */
    .cd-hang > span:not(.cd-av) { flex:0 1 auto; min-width:0;
      overflow-wrap:anywhere; text-align:right; }

    /* ⑦ CHỪA SẴN ĐÚNG HAI DÒNG CHO MÔ TẢ → mọi hàng một-nút cao BẰNG NHAU.
       ──────────────────────────────────────────────────────────────────────────
       Đây là nửa còn lại của chữ "thiếu đi sự đồng bộ" Boss dùng. Kẹp trần 2 dòng
       (mục ④ trên) mới chỉ chặn hàng cao vống; hàng nào mô tả ngắn thì vẫn thấp
       hơn hàng khác 17px, và mắt đọc dọc thấy ngay các hàng so le. Đặt SÀN bằng
       đúng hai dòng nữa là trần gặp sàn: mọi hàng một-nút cao y hệt nhau.
       ⛔ `2.7em` = 2 × 1.35, và `em` ở đây ăn theo cỡ chữ CỦA CHÍNH <small>, nên
          Boss đổi cỡ chữ toàn app thì hàng vẫn tự đúng. Gõ một số px là hỏng ngay
          lần đầu ai bấm "Cỡ chữ → Lớn".
       ⛔ Phải ghi `line-height:1.35` ngay đây, đừng tin giá trị thừa kế: `normal`
          mỗi phông một khác, mà số nhân trong `2.7em` phải khớp với nó. */
    .cd-hang-chu small { line-height:1.35; min-height:2.7em; }

    /* ⑧ Hàng hồ sơ (ảnh đại diện 52px) CỐ Ý cao hơn và không theo cột icon — chính
       TikTok cũng để hàng tài khoản riêng một khuôn. Ảnh mặt là thứ người ta nhận
       ra mình, bóp bằng 20px là mất nghĩa. */
    .cd-hang:has(.cd-av) { min-height:76px; }
    .cd-hang:has(.cd-av) .cd-hang-chu small { -webkit-line-clamp:1; line-clamp:1; }
  }

  /* ⚙⚙ 11/08/2026 — TRANG CÀI ĐẶT CHIA TAB DỌC.
     Cô Quỳnh: *"tôi ko muốn mở ra kéo xuống như này"*, *"tương lai bàn giao cho
     doanh nghiệp khác"*. Trước đây trang này là MỘT dải cuộn dài 6 khối, mà toàn
     bộ 13 việc hệ thống thì bị nhồi sau MỘT ô xổ xuống — chọn xong bấm "Tiếp"
     mới biết mục đó là gì. Người tiếp nhận app không thể mò ra.
     Nay: dải tab dọc bên trái (kiểu bảng cài đặt của phần mềm doanh nghiệp),
     nội dung bên phải, mỗi việc là một hàng có tiêu đề + một câu giải thích.
     ⛔ Tab nào người này không có mục nào thì KHÔNG DỰNG RA — không phải ẩn đi
        bằng CSS. Ẩn bằng CSS là chữ vẫn nằm trong trang, mở xem nguồn là thấy. */
  /* ⚠️ 11/08/2026 (lần 2) — CÔ QUỲNH: *"thiết kế kiểu này nó trông cứ bị thừa ra
     nhiều khoảng trắng"*. Bản đầu tôi làm dải tab DỌC rộng 200px bên trái. Sai ở
     ba chỗ cộng lại: (1) nhãn tab ngắn nên cột đó gần như trống, (2) mỗi tab chỉ
     2–3 hàng nên khung thấp tè, (3) khung công cụ vốn rộng 1120px căn giữa màn nên
     hai bên hụt sẵn. Nhìn tổng thể là một hộp nhỏ trôi giữa vùng trống mênh mông.
     Nay: tab NẰM NGANG kiểu gạch chân — đúng nếp 7 công cụ khác trong app đang
     dùng — nội dung bắt đầu ngay từ mép trái, không còn cột trống. Và gom 6 tab
     xuống 3 để mỗi tab có đủ hàng, không còn tab hai dòng. */
  .cd-tabs { display:flex; gap:2px; margin:0 0 16px; border-bottom:1px solid var(--vien);
    overflow-x:auto; -webkit-overflow-scrolling:touch; }
  .cd-tabs button { flex:none; border:0; background:transparent; margin-bottom:-1px;
    border-bottom:2px solid transparent; padding:9px 16px; white-space:nowrap;
    font-family:inherit; font-size:13.5px; font-weight:600; color:var(--mo); cursor:pointer; }
  .cd-tabs button:hover { color:var(--chu); }
  .cd-tabs button.chon { color:var(--muc); border-bottom-color:var(--xanh); }
  /* Một câu nói tab này để làm gì — đứng ngay trên nội dung, không phải chú thích mờ. */
  .cd-tab-mt { margin:0 0 12px 2px; font-size:12.5px; color:var(--mo); }
  /* Hàng việc NGUY HIỂM (xoá / hoàn tác): tách hẳn xuống cuối, viền đỏ nhạt bên
     trái. Trước đây "Xoá dữ liệu ĐÃ IMPORT" nằm lọt thỏm giữa danh sách phẳng —
     giáo vụ bấm nhầm là mất dữ liệu thật. */
  .cd-hang.cd-nguy { border-left:3px solid var(--do); }
  .cd-hang.cd-nguy .cd-nut { border-color:var(--do); color:var(--do); }
  .cd-hang.cd-nguy .cd-nut:hover { background:var(--do); color:#fff; }

  /* ══════ BẢNG PHÂN QUYỀN THEO CHỨC VỤ — làm lại 12/08/2026 ══════
     Cô Quỳnh: *"thiết kế thật chuyên nghiệp hơn, bớt trẻ con và để thật giống
     business, tốt, dễ tiếp cận"*.

     Bản cũ sai ở đâu (đếm được, không phải cảm tính):
       1. KHÔNG có một dòng CSS riêng nào — toàn bộ style viết thẳng vào chuỗi HTML
          trong JS. Nên nền tối vỡ (tô cứng #f3f7f7), và không ai sửa nổi.
       2. Emoji 🔐 ở tiêu đề, emoji 🔒 dùng thay icon ô khoá.
       3. Câu chữ NỘI BỘ lọt ra màn hình: "Developer (bạn) luôn có mọi quyền nên
          không có cột riêng" — người dùng doanh nghiệp đọc câu này thấy ngay là
          phần mềm chưa xong.
       4. Ô tick trần, bấm phải trúng đúng 19px; 40 hàng × 4 cột mà không có cách
          nào tick nhanh cả cột, cũng không tìm được hàng nào.

     Bản này: bám đúng nếp trang Cài đặt (.cd-*) — viền mảnh, nền phẳng, tab/nhóm
     phân cách bằng ĐƯỜNG KẺ chứ không bằng màu, mọi màu đi qua var() nên nền tối
     tự đúng. Cả ô <td> là vùng bấm được. */
  /* ══════════════════════════════════════════════════════════════════════════════
     TRANG "QUYỀN THEO CHỨC VỤ" — cô Quỳnh 21/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     *"ấn vào nó sẽ ra 1 tab riêng nhìn cho dễ và chuyên nghiệp hơn"*.
     Cả trang là MỘT CỘT FLEX cao bằng màn hình, và ô cuộn bảng nhận `flex:1` để
     nuốt hết chỗ thừa. Nhờ vậy bảng dài bao nhiêu cũng dùng hết chiều cao có sẵn,
     không bao giờ chừa lại dải trắng dưới đáy — thứ cô Quỳnh chê nhiều nhất.
     ⛔ Đừng đặt `max-height` cố định (kiểu `54vh` của bản hộp thoại cũ) cho
        `.pq-trang .pq-cuon`. Số cứng thì màn to hở đáy, màn nhỏ lại cụt bảng —
        `flex:1` tự đo, không phải đoán. */
  .pq-trang { display:flex; flex-direction:column; gap:0; min-height:calc(100vh - 118px - max(0px, var(--dnc-du, 0px))); }
  .pq-mota { margin:2px 2px 11px; font-size:13px; color:var(--mo); line-height:1.55; max-width:78ch; }
  .pq-trang .pq-cuon { flex:1 1 auto; max-height:none; min-height:220px; }
  /* Thanh nút DÍNH ĐÁY. Bảng 37 hàng: cuộn xuống cuối để tick mấy quyền cuối rồi
     phải cuộn ngược lên tìm nút Lưu là kiểu bỏ quên thay đổi. */
  .pq-day { position:sticky; bottom:0; z-index:4; display:flex; align-items:center;
    gap:10px; flex-wrap:wrap; margin-top:11px; padding:11px 2px;
    background:var(--nen); border-top:1px solid var(--vien); }
  .pq-day .pq-chan { flex:1 1 240px; margin:0; }
  /* Chữ "Có thay đổi chưa lưu" — hổ phách, cùng sắc với "đã tiếp nhận" bên Công
     việc: cả hai đều nghĩa là "đang dở, chưa chốt". */
  .pq-canh { font-size:12.5px; font-weight:700; color:var(--nhan-chu);
    background:var(--nhan-nen); border:1px solid var(--nhan-vien);
    border-radius:var(--r-xl); padding:2px 10px; white-space:nowrap; }
  .pq-thanh { display:flex; gap:10px; align-items:center; flex-wrap:wrap; margin:0 0 10px; }
  .pq-tim { flex:1; min-width:180px; }
  .pq-dem { font-size:12.5px; color:var(--mo); white-space:nowrap; }
  .pq-cuon { overflow:auto; max-height:54vh; border:1px solid var(--vien); border-radius:var(--r-sheet);
    background:var(--the); contain:paint; }
  .pq-bang { width:100%; border-collapse:separate; border-spacing:0; font-size:13px; }
  .pq-bang th, .pq-bang td { padding:8px 10px; }
  /* Hàng tiêu đề DÍNH: cuộn 40 hàng mà không thấy tên cột thì tick nhầm cột ngay. */
  .pq-bang thead th { position:sticky; top:0; z-index:3; background:var(--nen2);
    border-bottom:1px solid var(--vien); text-align:center; font-weight:600;
    font-size:12.5px; color:var(--chu); white-space:nowrap; }
  .pq-bang thead th:first-child { text-align:left; }
  .pq-vaitro { display:block; }
  /* "Chọn cả cột" — chữ nhỏ dưới tên chức vụ, không phải nút to tranh chỗ. */
  /* ⛔ `width:100%` LÀ THỨ GIỮ CON SỐ THẲNG CỘT. `display:block` trên một `<button>`
     KHÔNG kéo nó rộng bằng ô: nút vẫn co lại vừa chữ rồi nằm dính mép trái, nên tên
     chức vụ thì căn giữa mà con số ngay dưới lại lệch sang trái gần 100px — cô Quỳnh
     bắt được đúng chỗ này 21/08/2026. Rộng 100% thì `text-align:center` của ô mới ăn. */
  .pq-tatca { display:block; width:100%; margin-top:2px; font-size:11px; font-weight:500; color:var(--mo);
    background:none; border:0; padding:0; cursor:pointer; font-family:inherit; text-decoration:underline;
    text-underline-offset:2px; }
  .pq-tatca:hover { color:var(--muc); }
  /* Tiêu đề nhóm: CHỮ NHỎ IN HOA giãn nét — nếp bảng doanh nghiệp. Không tô nền
     màu cứng, chỉ một đường kẻ trên. */
  .pq-nhom td { background:var(--nen2); font-size:11px; font-weight:700;
 color:var(--mo); padding:7px 10px;
    border-top:1px solid var(--vien); border-bottom:1px solid var(--vien); }
  .pq-bang tbody tr:not(.pq-nhom) td { border-bottom:1px solid var(--vien); }
  .pq-bang tbody tr:not(.pq-nhom):hover td { background:var(--nen2); }
  /* Ô tên chức năng là <th scope="row"> chứ không phải <td> — trình đọc màn hình
     đọc được "quyền này, cột kia". Trình duyệt tự in đậm + căn giữa <th>, phải gỡ. */
  .pq-bang tbody th.pq-ten { text-align:left; font-weight:500; color:var(--chu); line-height:1.35; }
  .pq-o { text-align:center; width:96px; padding:0; }
  /* ⛔ Trong TRANG (không phải hộp thoại) bề ngang rộng gấp rưỡi, nên nới cột chức
     vụ ra 150px. Để 96px thì ba cột tick dồn hết về mép phải còn cột tên chức năng
     kéo dài 900px trống — mắt phải chạy ngang cả gang tay mới nối được tên với ô
     tick, rất dễ tick nhầm hàng. */
  /* 240px chứ không phải 150px: tên chức năng dài nhất chỉ chiếm ~340px, nên ba
     cột tick rộng 240px kéo ô tick lại gần tên, mắt bớt phải chạy ngang. */
  .pq-trang .pq-o { width:240px; }
  /* Cả ô là vùng bấm — trên điện thoại ngón tay không phải nhắm 19px. */
  .pq-o label { display:flex; align-items:center; justify-content:center; padding:8px 0; cursor:pointer; }
  .pq-o input { width:17px; height:17px; accent-color:var(--xanh); cursor:pointer; }
  /* Ô khoá: icon ổ khoá NÉT MẢNH thay cho emoji 🔒 của bản cũ. `margin-right` phải
     gỡ, không thì icon lệch trái trong ô căn giữa (luật chung `i[class^="ic-"]`
     đặt margin-right:6px cho icon đứng trước chữ). */
  .pq-khoa { display:inline-flex; align-items:center; justify-content:center;
    color:var(--mo); padding:8px 0; }
  .pq-khoa i { width:14px; height:14px; margin-right:0; vertical-align:0; }
  /* Nhãn "chỉ Developer" — viền mảnh, không phải viên kẹo bo tròn 999px. */
  .pq-nhan { display:inline-block; margin-left:7px; font-size:10.5px; font-weight:600;
 color:var(--mo); border:1px solid var(--vien); border-radius:var(--r-sm);
    padding:1px 6px; vertical-align:1px; white-space:nowrap; }
  /* ❓ 12/09/2026 — NÚT "?" CẠNH TÊN TỪNG QUYỀN (Boss giao 12/09).
     > *"có nút bé ? ấn vào đó để nó giải thích công cụ hoạt động như nào"*
     Nút tròn viền mảnh, nằm ngay sau tên hàng, bấm ra hộp giải thích.
     ⛔ `margin-right:0` cho icon bên trong là BẮT BUỘC: luật chung
        `i[class^="ic-"]` đẩy icon 6px sang phải, để nguyên thì dấu hỏi lệch hẳn
        ra khỏi tâm vòng tròn. Đúng cái bẫy đã dính ở `.tk-anh.trong i`.
     ⛔ Cỡ 17px là cỡ NHỎ NHẤT còn bấm trúng trên điện thoại khi tính cả khoảng
        đệm quanh; hạ nữa là người dùng bấm ba lần mới trúng.
     ⛔ Không dùng `:has()` — luật cấm trong CSS mới của app. */
  /* ⛔⛔ 20/09/2026 — NÚT "?" RÕ NÉT HƠN. Boss: *"trong phân quyền chức vụ có
     nút ? làm nó rõ nét hơn"*. Bản cũ: 17px, viền `--vien` nhạt, chữ `--mo` nhạt,
     nền trong suốt — đặt giữa một bảng 52 hàng thì nó chìm hẳn, người phân quyền
     không biết là có chỗ để hỏi.
     ⛔ 19px chứ không to hơn: nó đứng ngay sau tên quyền trong ô bảng, to nữa là
        đẩy cả hàng cao lên và bảng 52 hàng dài thêm cả một màn.
     ⛔ Nền `--nen-o` + viền đậm hơn mới là thứ làm nó nổi lên, không phải cỡ. */
  .pq-bang .pq-hoi { display:inline-flex; align-items:center; justify-content:center;
    width:19px; height:19px; margin-left:7px; padding:0; vertical-align:-4px; flex:none;
    /* 2px chứ không 1,5px — đo thật trong Chrome thấy `getComputedStyle` trả về
       đúng "1px": trình duyệt làm tròn bề rộng viền xuống số nguyên điểm màn,
       nên 1,5px hóa ra không đậm hơn bản cũ một chút nào. */
    border:2px solid var(--mo); border-radius:50%; background:var(--nen-o, #fff);
    color:var(--chu); font-weight:700; cursor:pointer;
    transition:background .14s ease, border-color .14s ease, color .14s ease; }
  .pq-bang .pq-hoi > i { width:12px; height:12px; margin-right:0; vertical-align:0; }
  .pq-bang .pq-hoi:hover { border-color:var(--xanh); color:#fff; background:var(--xanh); }
  .pq-bang .pq-hoi:focus-visible { outline:2px solid var(--xanh); outline-offset:2px; }

  /* Ảnh minh hoạ trong hộp giải thích của nút "?" — Boss 20/09.
     ⛔ Ảnh chụp rộng 1200px, hộp thoại hẹp hơn nhiều — `width:100%` để nó co vừa,
        và `height:auto` để không bị bóp méo. */
  .pq-anh { margin:12px 0 2px; border:1px solid var(--vien); border-radius:var(--r-lg);
    overflow:hidden; background:var(--nen-o, #fff); }
  /* ⛔ MÀN HẸP THÌ CHO CUỘN NGANG, ĐỪNG CO TIẾP. Ảnh rộng 1180px, màn điện thoại
     390px — co vừa màn thì chữ trong ảnh còn chưa tới 5px, chỉ là vết mờ. Người
     phân quyền mở nó ra để NHẬN MẶT công cụ, không đọc được thì bằng không có.
     Vuốt ngang xem từng phần thì vẫn nhận ra được.
     ⛔ `overscroll-behavior-x: contain` để vuốt hết ảnh thì dừng, không kéo luôn cả
        hộp thoại đi theo. */
  .pq-anh img { display:block; width:100%; height:auto; }
  @media (max-width: 760px) {
    .pq-anh { overflow-x:auto; overscroll-behavior-x:contain;
      -webkit-overflow-scrolling:touch; }
    /* ⛔ ĐẶT CỠ CỐ ĐỊNH, ĐỪNG ĐỂ `auto`. Đo thật: `width:auto` cho ra 2360px
       — ảnh chụp ở độ nét gấp đôi nên kích thước tự nhiên cũng gấp đôi, thành ra
       phải vuốt hai quãng mới hết một thanh công cụ. 680px là cỡ đủ để chữ 13px
       trong ảnh còn 7,5px — đọc được, mà chỉ vuốt một quãng ngắn. */
    .pq-anh img { width:680px; max-width:none; }
  }
  .pq-anh-chu { display:block; padding:6px 10px; font-size:11.5px; color:var(--mo);
    border-top:1px solid var(--vien); }
  .pq-chan { margin:9px 2px 0; font-size:12px; color:var(--mo); line-height:1.5; }
  .pq-trong { padding:22px 12px; text-align:center; color:var(--mo); font-size:13px; }
  @media (max-width:760px) {
    .pq-bang { font-size:12.5px; }
    .pq-o { width:64px; }
    .pq-cuon { max-height:46vh; }
  }
  /* ══════════════════════════════════════════════════════════════════════════════
     🌳 22/09/2026 — CÂY PHÂN QUYỀN (Boss chốt câu 1–20)
     ⛔⛔ HÀNG TÊN CHỨC VỤ PHẢI DÍNH KHI CUỘN (Boss nhắn giữa việc 22/09). Đo trên Chrome
        thật 22/09: lăn chuột 2.295px thì hàng tên chức vụ trôi lên tận -2.085px. Lý do:
        `.pq-cuon` là khung cuộn (overflow:auto) mà lại cao theo nội dung, nên TRANG
        cuộn chứ khung không cuộn; hàng tiêu đề dính vào khung, khung trôi thì nó trôi.
        `overflow:clip` vẫn cắt gọn góc bo nhưng KHÔNG tạo khung cuộn → hàng tiêu đề
        dính theo cửa sổ, ngay dưới thanh trên cùng (cố định, cao 48px).
     ══════════════════════════════════════════════════════════════════════════════ */
  .pq-trang .pq-cuon { overflow:clip; contain:none; }
  /* `--pq-tren` = đáy thật của thanh trên, đo lúc mở màn: máy tính 48px, điện thoại 61px.
     Ghim cứng 48px thì trên điện thoại hàng tên chức vụ chui 13px dưới thanh trên. */
  .pq-trang .pq-bang thead th { top:var(--pq-tren, 48px); }
  /* ⛔ Cột tên RỘNG 380px, cột chức vụ tự chia phần còn lại. Bản cũ ghim mỗi cột chức vụ
     240px nên cột tên chỉ còn ~160px — thêm mũi tên + icon của cây vào là tên nhóm, tên
     công cụ và nút "?" gãy ba dòng (chụp Chrome 22/09). */
  .pq-trang .pq-bang tr > :first-child { width:380px; min-width:280px; }
  .pq-trang .pq-o { width:auto; }
  /* Đường kẻ hàng và nền rê chuột phải chạy HẾT hàng, cả ô tên (bản cũ chỉ có ở ô tích
     nên hàng như bị cắt đôi). */
  .pq-trang .pq-bang tbody tr:not(.pq-nhom) th.pq-ten { border-bottom:1px solid var(--vien); }
  .pq-trang .pq-bang tbody tr:not(.pq-nhom):hover th { background:var(--nen2); }
  /* Cây: mũi tên gập/mở · icon công cụ · tên. Nút con thụt vào một nấc. */
  .pq-cay { display:inline-flex; align-items:center; gap:7px; vertical-align:middle; }
  .pq-cay.cap2 { padding-left:29px; }
  .pq-mo-cho { display:inline-block; flex:0 0 22px; width:22px; }
  .pq-mo-con, .pq-mo-nhom { display:inline-flex; align-items:center; gap:7px; background:none; border:0;
    padding:0; color:inherit; font:inherit; cursor:pointer; }
  .pq-mo-con { flex:0 0 22px; justify-content:center; width:22px; height:22px; border-radius:6px; color:var(--mo); }
  .pq-mo-con:hover { background:var(--nen2); color:var(--chu); }
  .pq-mo-con:focus-visible, .pq-mo-nhom:focus-visible { outline:2px solid var(--xanh); outline-offset:2px; }
  .pq-mui { width:14px; height:14px; fill:none; stroke:currentColor; stroke-width:2.2;
    stroke-linecap:round; stroke-linejoin:round; transition:transform .18s ease; }
  [aria-expanded="true"] > .pq-mui { transform:rotate(90deg); }
  .pq-ico { flex:0 0 16px; width:16px; height:16px; fill:none; stroke:currentColor; stroke-width:1.7;
    stroke-linecap:round; stroke-linejoin:round; color:var(--mo); }
  .pq-so-con { margin-left:2px; font-size:11px; font-weight:500; color:var(--mo); letter-spacing:0;
    text-transform:none; font-variant-numeric:tabular-nums; }
  /* Hàng nhóm: bấm cả dải tên để gập/mở; mỗi cột một ô tích cả nhóm. */
  .pq-nhom .pq-mo-nhom { min-height:30px; font-size:11px; font-weight:700; letter-spacing:.05em;
    text-transform:uppercase; color:var(--mo); }
  .pq-nhom .pq-mo-nhom:hover { color:var(--chu); }
  .pq-bang .pq-nhom td.pq-tm-o { padding:0; text-align:center; }
  .ck-tm { display:inline-flex; align-items:center; justify-content:center; width:44px; height:40px;
    padding:0; background:none; border:0; cursor:pointer; }
  .ck-tm:focus-visible { outline:2px solid var(--xanh); outline-offset:-4px; border-radius:8px; }

  /* ── Ô TÍCH (animated check box, đổi màu sang teal thương hiệu — câu 7–10) ────────
     Khung 24px, vùng bấm 44px. <input> thật phủ trong suốt lên cả vùng bấm nên bấm,
     phím cách, trình đọc màn hình vẫn là của ô tích thật. Khung theo nền app: viền
     `--vien`, ruột `--nen-o` — tối/sáng tự đổi theo biến. */
  .pq-trang .pq-o label { position:relative; min-height:44px; padding:0; }
  .pq-trang .pq-o input { position:absolute; left:50%; top:50%; width:44px; height:44px; margin:-22px 0 0 -22px;
    opacity:0; cursor:pointer; }
  .ck { position:relative; display:inline-flex; flex:0 0 24px; width:24px; height:24px; box-sizing:border-box;
    border:1.5px solid var(--vien); border-radius:7px; background:var(--nen-o); pointer-events:none;
    transition:background-color .16s ease, border-color .16s ease, transform .16s ease; }
  .ck svg { position:absolute; inset:0; width:100%; height:100%; fill:none; stroke:#fff; stroke-width:2.6;
    stroke-linecap:round; stroke-linejoin:round; overflow:visible; }
  .ck-net { stroke-dasharray:20; stroke-dashoffset:20; transition:stroke-dashoffset .26s ease .04s; }
  .ck-gach { opacity:0; }
  .pq-o label:hover .ck, .ck-tm:hover .ck { border-color:var(--xanh); }
  .pq-o input:focus-visible + .ck { outline:2px solid var(--xanh); outline-offset:3px; }
  /* ⛔ `.mot-phan` PHẢI đứng trong nhóm này: Chrome coi ô `indeterminate` là KHÔNG
     `:checked` (đo 22/09) — thiếu dòng này thì ô một phần ra nền trắng + gạch trắng,
     nền sáng nhìn như ô trống. */
  .pq-o input:checked + .ck, .pq-o .mot-phan .ck,
  .ck-tm[aria-checked="true"] .ck, .ck-tm[aria-checked="mixed"] .ck { background:var(--xanh); border-color:var(--xanh); }
  .pq-o input:checked + .ck .ck-net, .ck-tm[aria-checked="true"] .ck .ck-net { stroke-dashoffset:0; }
  /* Một phần: dấu — thay cho dấu tích (câu 3). */
  .pq-o .mot-phan .ck .ck-net, .ck-tm[aria-checked="mixed"] .ck .ck-net { opacity:0; }
  .pq-o .mot-phan .ck .ck-gach, .ck-tm[aria-checked="mixed"] .ck .ck-gach { opacity:1; }
  /* Vừa tích: nảy nhẹ + vòng sáng + viền chạy MỘT vòng rồi đứng yên (câu 8) + nổ hạt. */
  .ck.vua-tich { animation:ck-nay .32s ease; }
  .ck.vua-tich::after { content:""; position:absolute; inset:-6px; border-radius:11px;
    border:2px solid var(--xanh); opacity:0; animation:ck-vong .5s ease-out; }
  .ck.vua-tich::before { content:""; position:absolute; inset:-4px; border-radius:10px; padding:2px;
    background:conic-gradient(var(--xanh) 0 25%, transparent 25% 100%);
    -webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite:xor; mask-composite:exclude; animation:ck-chay .6s linear 1 forwards; }
  .ck-no { position:absolute; inset:0; pointer-events:none; }
  .ck-no i { position:absolute; left:50%; top:50%; width:4px; height:4px; margin:-2px 0 0 -2px;
    border-radius:50%; background:var(--xanh); opacity:0;
    transform:rotate(var(--g)) translateX(4px); animation:ck-hat .6s ease-out forwards; }
  .ck-no i:nth-child(odd) { width:3px; height:3px; }
  @keyframes ck-nay { 0% { transform:scale(1); } 45% { transform:scale(.86); } 100% { transform:scale(1); } }
  @keyframes ck-vong { 0% { opacity:.55; transform:scale(.8); } 100% { opacity:0; transform:scale(1.25); } }
  @keyframes ck-chay { 0% { opacity:1; transform:rotate(0deg); } 90% { opacity:1; } 100% { opacity:0; transform:rotate(360deg); } }
  @keyframes ck-hat { 0% { opacity:1; transform:rotate(var(--g)) translateX(5px) scale(1); }
                      100% { opacity:0; transform:rotate(var(--g)) translateX(var(--d)) scale(.4); } }
  @media (prefers-reduced-motion: reduce) {
    .ck, .ck-net, .pq-mui { transition:none; }
    .ck.vua-tich, .ck.vua-tich::after, .ck.vua-tich::before { animation:none; }
  }

  /* 🔘 Nút con bị tắt quyền: ẨN HẲN (câu 14). `!important` vì đây là công tắc quyền —
     nút nào tự khai `display:inline-flex` cũng không được lộ ra. Xem NUT_THEO_QUYEN. */
  .an-theo-quyen { display:none !important; }
  /* ── 📱 ĐIỆN THOẠI (câu 20): chọn MỘT chức vụ ở trên, cây một cột ô tích ─────────── */
  .pq-chon-vt { display:none; }
  @media (max-width:760px) {
    .pq-chon-vt { display:flex; gap:6px; margin:0 0 10px; overflow-x:auto; overscroll-behavior-x:contain;
      scrollbar-width:none; }
    .pq-chon-vt button { flex:0 0 auto; min-height:40px; padding:0 14px; border:1px solid var(--vien);
      border-radius:999px; background:var(--nen-o); color:var(--chu); font:inherit; font-size:13px; cursor:pointer; }
    .pq-chon-vt button[aria-pressed="true"] { border-color:var(--xanh); background:var(--xanh); color:#fff; font-weight:600; }
    /* Nền tối: chữ trắng trên teal chỉ ~3:1 — dùng chữ tối #0F1A1C như mọi nút teal khác (21/09). */
    body.toi .pq-chon-vt button[aria-pressed="true"] { color:#0F1A1C; }
    .pq-trang[data-dt] .pq-bang tr > :nth-child(n+2) { display:none; }
    .pq-trang[data-dt="2"] .pq-bang tr > :nth-child(2),
    .pq-trang[data-dt="3"] .pq-bang tr > :nth-child(3),
    .pq-trang[data-dt="4"] .pq-bang tr > :nth-child(4),
    .pq-trang[data-dt="5"] .pq-bang tr > :nth-child(5),
    .pq-trang[data-dt="6"] .pq-bang tr > :nth-child(6),
    /* 🎯 22/09 — cột Tuyển sinh: chủ tài khoản thấy 6 chức vụ nên cần tới cột 7 */
    .pq-trang[data-dt="7"] .pq-bang tr > :nth-child(7) { display:table-cell; }
    /* ⛔ Cột tên hết ghim 380px/280px: màn 390px thì cột ô tích bị đẩy ra ngoài rồi bị
       `overflow:clip` cắt mất — nhìn thấy cây mà không có ô nào để chạm. */
    .pq-trang .pq-bang { table-layout:fixed; }
    .pq-trang .pq-bang tr > :first-child { width:auto; min-width:0; overflow-wrap:anywhere; }
    .pq-trang .pq-bang thead th { white-space:normal; }
    .pq-nhom .pq-mo-nhom { flex-wrap:wrap; text-align:left; }
    .pq-trang .pq-o { width:64px; }
    .pq-cay { max-width:100%; }
    .pq-ten-chu { min-width:0; overflow-wrap:anywhere; }
    .pq-cay.cap2 { padding-left:20px; }
    .pq-ico { display:none; }
  }
  @media (max-width:760px) { .cd-tabs button { padding:9px 12px; font-size:13px; } }
  /* 📐 05/08 — MẬT ĐỘ "GỌN": bóp khoảng đệm để xem được nhiều dòng hơn mỗi màn */
  body.gon .home-khoi-than { padding:10px 12px; }
  body.gon .home-khoi-dau { padding:9px 12px; }
  body.gon .cd-hang { padding:9px 13px; }
  body.gon .the-lop { padding:11px; }
  body.gon .luoi-lop { gap:8px; }
  body.gon .home-boc { gap:9px; }
  body.gon #thanhCC .cc-muc { padding:4px 9px 4px 12px; }

  #nenMua .nen-phu { position:absolute; inset:0;
    background:linear-gradient(180deg, rgba(248,251,252,.84) 0%, rgba(248,251,252,.62) 30%,
               rgba(248,251,252,.66) 70%, rgba(248,251,252,.82) 100%); }
  /* Hạt rơi (lá / hoa / tuyết): vỏ ngoài RƠI thẳng, ruột LẮC ngang — hai nhịp
     lệch nhau cho tự nhiên. delay ÂM để vừa mở đã kín trời, không phải chờ. */
  .hat-mua { position:absolute; top:-8vh; will-change:transform; animation:hatRoi linear infinite; }
  .hat-mua > span { display:block; animation:hatLac ease-in-out infinite alternate; }
  @keyframes hatRoi { from { transform:translateY(-8vh) rotate(0); } to { transform:translateY(114vh) rotate(330deg); } }
  @keyframes hatLac { from { transform:translateX(-2.6vw) rotate(-22deg); } to { transform:translateX(2.6vw) rotate(22deg); } }
  /* 🐈 Mèo cam đi bộ (mùa xuân, như ảnh mẫu của cô): thân nhún + 4 chân vung so
     le + đuôi ve vẩy, đi hết màn hình ~48 giây rồi vòng lại.
     `transform-box:fill-box` BẮT BUỘC — không có thì transform-origin của SVG
     tính theo cả khung, chân xoay quanh góc màn hình chứ không quanh hông. */
  .nen-meo { position:absolute; bottom:6px; left:-150px; width:92px; height:auto;
             animation:meoDiBo 48s linear infinite; filter:drop-shadow(0 2px 2px rgba(0,0,0,.18)); }
  .nen-meo g, .nen-meo path, .nen-meo rect { transform-box:fill-box; }
  .nen-meo .than { animation:meoNhun .5s ease-in-out infinite alternate; }
  .nen-meo .chan { transform-origin:top center; animation:meoChan .5s ease-in-out infinite alternate; }
  .nen-meo .chan.nhip2 { animation-delay:-.25s; }
  .nen-meo .duoi { transform-origin:bottom right; animation:meoDuoi 1.7s ease-in-out infinite alternate; }
  @keyframes meoDiBo { from { transform:translateX(0); } to { transform:translateX(calc(100vw + 320px)); } }
  @keyframes meoNhun { from { transform:translateY(0); } to { transform:translateY(-2.4px); } }
  @keyframes meoChan { from { transform:rotate(20deg); } to { transform:rotate(-20deg); } }
  @keyframes meoDuoi { from { transform:rotate(-6deg); } to { transform:rotate(12deg); } }
  /* 📵 ĐIỆN THOẠI đang TRONG LỚP → tắt hẳn nền (cô: "dễ gây khó chịu");
     máy tính trong lớp VẪN có nền. */
  @media (max-width:820px) {
    /* 🛡 05/08 — LỖI: luật cũ chỉ ẩn nền 4 mùa, ẢNH NỀN RIÊNG vẫn hiện khi vào lớp
       nhập điểm → rối mắt lúc chấm. Ẩn cả hai. */
    body.dang-trong-lop #nenMua, body.dang-trong-lop #nenRieng { display:none; }
    body.co-nen-mua.dang-trong-lop { background:var(--nen); }
  }
  /* Máy khai "giảm chuyển động" → cảnh đứng yên, không hạt bay, không mèo. */
  @media (prefers-reduced-motion:reduce) {
    .hat-mua, .hat-mua > span, .nen-meo, .nen-meo * { animation:none !important; }
    .hat-mua, .nen-meo { display:none; }
  }

  /* 🔄 Ô người khác vừa điền — nháy vàng nhẹ cho biết "vừa mới lên" (30/07) */
  td.o-vua-doi { animation: oVuaDoi 1.6s ease-out; }
  @keyframes oVuaDoi { 0% { background:#FFE9A8; } 100% { background:transparent; } }

  /* (🔔 Cụm khay thông báo giáo vụ đã BỎ 31/07 — cô Quỳnh: "spam quá". Chỉ còn
     bảng tin đỏ owner bên dưới.) */

  /* 🧰 THANH CÔNG CỤ DỌC (giáo vụ/admin/owner, 31/07) — nút nhỏ mép trái, bấm
     trượt ra panel hẹp; đóng lại chỉ còn nút. Bé để không chiếm màn hình,
     nhất là điện thoại. */
  /* 🧰 04/08 (cô Quỳnh: nút thu gọn "xấu, khó nhìn, vướng") → NÚT TRÒN nổi ở GÓC DƯỚI-TRÁI
     (kiểu app di động): tròn, bóng nổi, KHÔNG nằm giữa mép nên hết vướng trên điện thoại.
     Trên máy tính nở ra thành nút dài có chữ "Công cụ" cho dễ thấy. */
  /* ➡️ 05/08 (cô Quỳnh): BỎ nút tròn 🧰 — thay bằng THANH MŨI TÊN mảnh dính mép trái,
     bấm để mở lại thanh bên. Kín đáo, không che nội dung, kiểu app quản trị. */
  /* ══════════════════════════════════════════════════════════════════════════════
     ⛔ NÚT MỞ LẠI PHẢI MỜ ĐI KHI KHÔNG DÙNG — cô Quỳnh 16/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     Nguyên văn: *"lúc tôi ẩn cái thanh công cụ thì cái nút mở lại đang che khuất
     màn… tôi muốn cái nút đó sẽ mờ đi, khi di chuột vào thì nó mới hiện lên, không
     thì nó mờ đi"*.

     Cô ẩn thanh công cụ CHÍNH LÀ để lấy chỗ. Nút mở lại đậm màu xanh nằm giữa mép
     trái thì lấy lại đúng cái chỗ vừa dọn — ở sổ tuyển sinh nó đè lên cột TVTS.

     NAY: bình thường mờ hẳn và thu mảnh; đưa chuột tới thì hiện đủ.
     ⛔ ĐỪNG dùng `display:none` hay `opacity:0` — mờ hẳn thành vô hình thì người mới
        không biết đường mở lại thanh công cụ, và bàn phím cũng không lần ra. Để .18
        là còn thấy được vệt mờ nếu nhìn kỹ, đủ để biết có cái gì ở đó.
     ⛔ Giữ nguyên bề rộng vùng bấm — mờ là chuyện của MẮT, không được làm khó tay.
        Nút vẫn cao 74px và rộng 24px như cũ, chỉ phần nhìn thấy mới co lại.
     ⛔ `:focus-visible` phải hiện đủ: người đi bằng phím Tab cần thấy mình đang ở đâu.
     ══════════════════════════════════════════════════════════════════════════════ */
  /* ══════════════════════════════════════════════════════════════════════════
     🎨 THANH CÔNG CỤ MANG NỀN XANH THƯƠNG HIỆU — cô Quỳnh 22/08/2026
     ──────────────────────────────────────────────────────────────────────────
     *"cái khung thanh công cụ phải có màu xanh background thương hiệu của MyPAS,
       gợi ý trong ảnh."*  (ảnh: cả thanh nền teal đậm, chữ trắng, logo trắng)

     ⛔⛔ CÁCH LÀM — ĐỌC TRƯỚC KHI SỬA MÀU TRONG THANH:
        Thanh này KHÔNG đi tô lại từng luật một. Nó khai ĐÈ BẢNG MÀU ngay trên
        `#thanhCC`, và mọi luật bên trong vẫn viết `var(--chu)`, `var(--mo)`… như cũ.
        Đổi tông thanh về sau = sửa đúng khối này, không phải lùng 60 luật con.

     ⛔ Vì thế: THÊM luật mới trong thanh thì PHẢI dùng `var(--…)`, đừng gõ thẳng
        mã màu. Gõ thẳng là màu ấy đứng im khi nền đổi, và chữ tối trên nền tối.

     ⛔ Thanh này CỐ Ý xanh ở CẢ hai chế độ sáng và tối — nó là mảng thương hiệu,
        không phải mặt giấy. Ở dưới chỉ có một khối `body.toi` làm nền SẪM thêm.

     ⛔ Mọi màu chữ dưới đây ĐÃ ĐO bằng `r5-thanh-xanh-thuong-hieu.js` (tính thật
        theo WCAG, có phép thử ngược). Đổi một mã màu thì ĐO LẠI, đừng ướm mắt. */
  /* ⭐⭐ 23/08/2026 — CẢ THANH ĐỔI SANG CAM. Cô Quỳnh 22/08:
     *"thiết kế cho cái thanh công cụ có các công cụ của các bộ phận ý — thanh công cụ
     ở bên ngoài ý — sửa nó lại thành màu cam cả thanh công cụ đó, để có màu thứ 2 của
     thương hiệu và nhìn đẹp hơn, cho thanh công cụ ko bị nhìn đúng 1 màu xanh lá đậm"*.

     ⛔ KHÔNG dùng thẳng cam logo #F5821F làm nền: đo ra chữ trắng chỉ được 2,48 lần
        tương phản, cần 4,5. Cam tươi đẹp khi làm CHỮ hoặc VẠCH, không làm NỀN cho chữ
        trắng. Nên hạ xuống cam đất — vẫn đúng sắc cam nhưng đủ tối để đọc.
     ⛔ ĐO LẠI CẢ TÁM MÀU CHỮ như lần đổi teal 22/08, mốc lấy ở ĐỈNH dải (chỗ nhạt
        nhất): chữ chính 6,26 · chữ mờ 4,96 · đỏ 4,71 — đều vượt 4,5, sát mốc teal cũ
        (7,20 · 4,82). Sáng thêm một bậc là chữ mờ tụt dưới chuẩn.
     ⛔ `--xanh` trong bảng dưới GIỮ NGUYÊN teal: nó chỉ làm viền và vạch, và teal sáng
        trên nền cam là cặp bổ túc — giữ được dấu teal thương hiệu ngay trên thanh cam.
     ⛔ KHỐI CHÚ THÍCH NÀY CỐ Ý NẰM NGOÀI `#thanhCC {`. Bài kiểm thu-block-bo-phan
        đòi `--cc-dinh` phải nằm sát đầu khối (trong 900 ký tự) để chắc bảng màu khai
        MỘT chỗ; nhét lời giải thích vào trong là đẩy nó ra xa và bài kiểm đỏ ngay. */
  #thanhCC {
    /* Nền: dải cam dựng từ chính cam logo (#F5821F) hạ sáng xuống cho chữ trắng đọc được. */
    /* ⛔ 22/08/2026 — ĐÃ NÂNG SÁNG một nấc. Bản đầu (#0E4A52 → #082F36) cô Quỳnh
       xem xong nói: *"màu xanh đậm của cả cái thanh công cụ tôi thấy bị đậm quá và
       hơi xấu, chỉnh màu sao cho phù hợp lại và ko bị quá tối"*.
       Nay sáng hơn và teal hơn (bớt ngả đen), vẫn đủ tối cho chữ trắng đạt chuẩn —
       đã đo lại cả tám màu chữ. ⛔ Sáng thêm nữa thì chữ phụ `--mo` tụt dưới 4,5. */
    --cc-dinh:  #125D66;    /* đỉnh dải — chỗ NHẠT NHẤT, mọi phép đo lấy mốc ở đây */
    --cc-giua:  #0F4F57;
    --cc-day:   #0C4249;
    /* ══════════════════════════════════════════════════════════════════════════
       🟠 CAM NAY KHÔNG CÒN LÀ MỘT MẢNG — cô Quỳnh 23/08/2026
       ──────────────────────────────────────────────────────────────────────────
       *"tôi thấy thanh công cụ màu cam và màu xanh nó cứ ko hoà nhập nhau lắm …
         làm màu của nó hoà lẫn nhau được ít cam ít xanh lá"* và
       *"thanh công cụ cố gắng làm sao pha màu chọn màu phù hợp đẹp với cái logo
         MyPAS kia nha"*.

       ĐẾM TỪNG ĐIỂM ẢNH TRONG LOGO APP (anh/icon-512.png) — đây là số, không phải ý kiến:
           teal  #14A0A0  89,2%
           trắng #FFFFFF   8,6%
           cam   #F5821F   1,8%
       Thương hiệu MyPAS dùng cam theo tỉ lệ 1 trên 50. Cột icon cam đặc chiếm
       17,1% chiều ngang thanh — GẤP 9,5 LẦN tỉ lệ ấy. Cam bị dùng thành một MẢNG,
       trong khi logo dùng nó làm một CHẤM NHẤN. Đó là gốc của chữ "không hoà nhập".

       Còn một nguyên nhân thứ hai, cũng đo được: cam #B0540A và teal #125D66 cách
       nhau 157° về SẮC nhưng chỉ chênh 1,48 lần về ĐỘ SÁNG. Mắt không đọc ra
       "lớp dưới / lớp trên", chỉ đọc ra "hai mảng đang cạnh tranh".

       ⛔ CÁCH HIỂN NHIÊN NHẤT ĐÃ THỬ VÀ LOẠI BẰNG SỐ — ĐỪNG LÀM LẠI:
          pha dần cam sang teal (kể cả đi vòng qua OKLCH cho mượt) thì đường pha
          bắt buộc đi qua #6B6000 và #445F1E — vùng OLIU XỈN. Bảy bước đo đủ, không
          bước nào cứu được.

       NAY: cột icon về TEAL SẪM HƠN THÂN. Sắc chỉ lệch 3° nên hai cột hoà vào nhau
       đúng như cô muốn, mà chênh sáng 1,58 lần thì vẫn đọc ra hai lớp.
       Cam dồn hết vào NÚT ĐANG ĐỨNG (xem `--cc-o-day-*` ngay dưới): diện tích còn
       1,6% — khớp tỉ lệ logo — và lúc này cam MANG THÔNG TIN chứ không trang trí. */
    --cc-rail-dinh: #0A3D45;
    --cc-rail-day:  #072F36;
    /* ══════════════════════════════════════════════════════════════════════════
       🟧 DẤU "ĐANG ĐỨNG Ở ĐÂY" — chỗ duy nhất còn cam
       ──────────────────────────────────────────────────────────────────────────
       Đây cũng là lời chữa cho việc thứ hai cô Quỳnh kêu cùng hôm: *"hay chọn nhầm
       trang chủ với giáo vụ và chọn nhầm giáo vụ với tuyển sinh"*. Lỗi ấy là của
       tôi hôm 22/08: dấu "đang đứng" trong app vốn là VẠCH TEAL, thiết kế cho nền
       teal. Đổi nền cột sang cam mà quên đổi vạch theo thì cả ba dấu hiệu cùng yếu đi:
           vạch teal   4,05 → 2,73 lần  (dưới ngưỡng nhìn được 3,0)
           nền nút                1,33 lần
           viền nút               1,84 lần
       Nay tách hẳn HAI NHIỆM VỤ cho hai màu, mỗi màu lo đúng một việc:
           nền cam  → nói "đang ở đây", và icon trắng trên nó đạt 5,10 / 5,75 lần
           viền cam logo → lo việc tách nút khỏi nền sẫm, đạt 4,58 / 5,24 lần
       Gộp hai việc vào một màu thì không màu nào làm nổi cả hai (đã quét 18 mức
       độ sáng: mắt xích yếu nhất chỉ lên tới 3,36 lần).
       ⛔ Viền dùng ĐÚNG cam logo #F5821F. Nó làm được ở đây vì là NÉT VIỀN trên nền
          sẫm; đừng đem nó ra làm NỀN — chữ trắng trên cam logo chỉ 2,48 lần. */
    --cc-o-day-nen:  #B0540A;
    --cc-o-day-vien: #F5821F;
    /* 📋 Nút Công việc — xem khối `.cc-viec` bên dưới. Dùng CHUNG cho cả nền sáng
       lẫn nền tối: đã đo, cả hai chế độ đều trên ngưỡng, nên không khai lại ở
       `body.toi` (khai hai bộ là sớm muộn hai bộ trôi xa nhau). */
    --cc-viec-nen:  #12616B;
    --cc-viec-vien: #14A0A0;
    /* Dưới đây là các biến DÙNG CHUNG toàn app, bị ghi đè TRONG PHẠM VI thanh: */
    --the:      #0F4F57;                 /* "mặt tấm" của thanh giờ là chính nền xanh */
    --nen:      rgba(0,0,0,.18);         /* cột rail — sẫm hơn thân thanh một chút */
    --nen2:     rgba(255,255,255,.08);   /* nền khi rê chuột */
    --nen-o:    rgba(255,255,255,.10);   /* nền ô nhập */
    --chu:      #F4FBFB;
    --mo:       #B7D4D7;                 /* nâng theo nền — đã đo, xem r10 */
    --chu-mo:   var(--mo);
    --muc:      #FFFFFF;
    --vien:     rgba(255,255,255,.20);
    --vien-nhe: rgba(255,255,255,.13);
    --xanh:     #4FD1C5;                 /* chỉ dùng làm VIỀN và VẠCH, không làm chữ */
    --xanh-nhat:rgba(255,255,255,.15);   /* nền mục đang mở */
    --vong:     0 0 0 3px rgba(255,255,255,.26);
    --do:       #FFC0BA;                 /* đỏ nhạt đi cho đọc được trên nền sẫm */
    --do-nen:   rgba(255,179,172,.16);
    --bong-1:   none;
    /* ⛔ HAI DÒNG NÀY LÀ THUỐC CHỮA "CHỮ DÀY QUÁ" — đừng xoá.
       Chữ sáng trên nền sẫm bị trình duyệt vẽ nở ra (loang sáng), nhìn dày hơn
       cùng một nét trên nền trắng. `antialiased` bỏ kiểu vẽ theo điểm ảnh phụ nên
       nét về đúng độ dày thật. Cô Quỳnh 22/08: *"đậm nét quá mức rồi"*. */
    -webkit-font-smoothing:antialiased;
    -moz-osx-font-smoothing:grayscale; }
  /* Nền tối: cùng một tông, sẫm thêm cho khỏi chói giữa màn hình đen.
     ⛔ 23/08/2026 — DÒNG NÀY PHẢI ĐỔI THEO khi đổi dải cam ở trên. Nó chỉ hạ sẫm bốn
        biến nền; quên nó thì chế độ tối giữ nguyên cam sáng và thành mảng chói duy
        nhất giữa màn đen. */
  body.toi #thanhCC { --cc-dinh:#0F535B; --cc-giua:#0C454C; --cc-day:#093840; --the:#0C454C;
                      --cc-rail-dinh:#08333A; --cc-rail-day:#05262C;
                      --cc-o-day-nen:#A34E0C; --cc-o-day-vien:#F5821F; }
  #thanhCC .cc-toggle { position:fixed; left:0; top:50%; transform:translateY(-50%);
    bottom:auto; z-index:11000;
    display:flex; align-items:center; justify-content:center;
    width:24px; height:74px; padding:0; border-radius:0 var(--r-lg) var(--r-lg) 0;
    /* ⛔ Gõ thẳng #14A0A0 chứ KHÔNG `var(--xanh)`: nút này là cái tai thò ra
       NGOÀI thanh, nằm trên nền trang trắng. `--xanh` trong phạm vi thanh đã bị
       đổi thành teal SÁNG (#4FD1C5) để làm viền trên nền sẫm — lấy nó làm nền cho
       chữ trắng ở đây là chữ trắng trên nền sáng, mất hút. */
    background:#14A0A0; color:#fff; border:none; cursor:pointer;
    box-shadow:2px 2px 12px rgba(15,45,50,.26);
    opacity:.18;
    transition:width .15s ease, box-shadow .15s ease, opacity .15s ease; }
  #thanhCC .cc-toggle svg { width:15px; height:15px; fill:none; stroke:currentColor;
    stroke-width:2.2; stroke-linecap:round; stroke-linejoin:round; }
  #thanhCC .cc-toggle:hover, #thanhCC .cc-toggle:focus-visible {
    width:30px; opacity:1; box-shadow:3px 3px 16px rgba(15,45,50,.4); }
  /* Đang kéo nút đi chỗ khác thì phải nhìn rõ mình đang cầm cái gì. */
  #thanhCC .cc-toggle.dang-keo-nut { opacity:1; }
  /* ⛔ Màn cảm ứng KHÔNG có "di chuột vào" — để mờ là ngón tay mò mãi không thấy.
     Nên trên máy chỉ có ngón tay, nút hiện đậm như cũ. */
  @media (hover: none) {
    #thanhCC .cc-toggle { opacity:1; }
  }
  /* 🏢 02/09/2026 — LOGO QUAY VỀ THANH TRÊN, và lần này thanh bên KHÔNG còn logo.
     Luật cũ 05/08 (`.thanh-tren .logo-mypas { display:none }`) đã gỡ. Hồi ấy đúng:
     hai chỗ cùng hiện logo là trùng. Nay thanh trên là dải cố định suốt bề ngang
     kiểu Supabase — góc trái của nó là chỗ mắt tìm logo trước nhất, còn thanh bên
     thì cô Quỳnh muốn *"chỉ còn là thanh công cụ"*.
     ⛔ ĐỪNG chép lại dòng `display:none` cũ. Logo nay CHỈ có một chỗ; ẩn ở đây là
        app mất logo hoàn toàn, không còn chỗ nào đỡ. */

  /* 📱 05/08 (cô Quỳnh: "trên điện thoại có giao diện riêng, thanh công cụ nằm
     NGANG ở dưới cho dễ nhìn") — thanh điều hướng đáy kiểu app di động.
     Máy tính KHÔNG dùng (đã có thanh dọc bên trái). */
  #thanhDuoi { display:none; }
  /* Nút tròn gọi cụm nút điểm danh — chỉ mọc trên điện thoại, chỉ khi đang trong lớp.
     Ẩn bằng CSS chứ không bằng JS: rời lớp là lớp `dang-trong-lop` mất, nút tự biến,
     khỏi phải đi dọn ở bốn chỗ thoát lớp khác nhau. */
  #ddFab, #ddTai { display:none !important; }
  /* 📱 28/08/2026 — thanh cuộn riêng: chỉ có nghĩa trên màn hẹp, trong lớp điểm
     danh. Mọi chỗ khác ẩn hẳn — xem luật hiện ở khối media bên dưới. */
  #ddThanh { display:none; }
  /* 📱 NGĂN KÉO CÔNG CỤ "Tất cả công cụ" cho điện thoại.
     Vùng chạm ≥48px → nhìn rõ, bấm trúng, không cần zoom.

     ⚠️ ĐỔI HƯỚNG 08/09/2026 — TRƯỢT TỪ BÊN TRÁI, KHÔNG CÒN TRƯỢT LÊN TỪ ĐÁY.
     Boss: *"ấn vào cái 3 gạch đó thì nó sẽ mở ra 1 cái thanh giao diện bên trái nó
     sẽ kéo sang… hãy nghiên cứu kỹ giao diện của Facebook"*.

     ⛔ LỜI DẶN CŨ 05/08/2026 ("tấm trượt lên từ đáy — chuẩn app business trên di
        động") NAY HẾT HIỆU LỰC. Nó bàn chuyện mở theo HƯỚNG NÀO, mà Boss đã đổi
        hướng. Đừng dựng lại kiểu trượt lên vì đọc thấy câu ấy ở chú thích khác.

     ⛔ VẪN LÀ MỘT BẢNG DUY NHẤT, dùng chung với nút "Thêm" ở thanh đáy. Chỉ có
        HƯỚNG TRƯỢT đổi. Nội dung, quyền, hàng chọn bộ phận đều giữ nguyên — JS
        không phải biết gì về chuyện này. */
  #ttSheet { display:none; }
  @media (max-width:820px) {
    #ttSheet:not([hidden]) { display:block; position:fixed; inset:0; z-index:11050; }
    /* Nền sau ngăn kéo vừa tối dần vừa NHOÈ DẦN — chỉ tối đi thì trông như bật
       đèn tắt đèn; nhoè thêm mới ra cảm giác lớp trên nổi lên khỏi lớp dưới. */
    #ttSheet .tts-nen { position:absolute; inset:0; background:rgba(12,26,34,.42);
      -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px);
      animation:ttsMo .3s ease both; }
    /* ⛔ CHỪA MỘT DẢI HỞ BÊN PHẢI (14vw) — đó là chỗ bấm để đóng, và cũng là thứ
       cho mắt biết trang cũ vẫn còn nằm sau lưng. Kéo rộng hết màn là mất cả hai.
       ⛔ Bo góc 0: ngăn kéo dán trọn cạnh trái, trên và dưới. Bo góc ở đây lại đẻ
          ra đúng mấy khe hở nho nhỏ mà Boss bảo dọn đi. */
    #ttSheet .tts-hop { position:absolute; left:0; top:0; bottom:0;
      width:min(86vw, 340px); display:flex; flex-direction:column;
      background:var(--the); border-radius:0; border-right:1px solid var(--vien);
      box-shadow:14px 0 46px rgba(12,26,34,.34);
      padding:calc(8px + env(safe-area-inset-top, 0px)) 14px
              calc(14px + env(safe-area-inset-bottom, 0px));
      animation:ttsSang .4s cubic-bezier(.19,1,.3,1) both; }
    /* Trượt SANG PHẢI có đà: đường cong (.19,1,.3,1) chạy nhanh lúc đầu rồi hãm dần
       — mắt đọc thành "có đà", đúng thứ Boss gọi là mượt.
       ⛔ ĐỪNG thêm scale() như bản trượt lên cũ: tấm này cao trọn màn, phóng to thu
          nhỏ theo chiều dọc là mép trên và mép dưới rung, nhìn rất rẻ tiền. */
    @keyframes ttsMo { from { opacity:0; } }
    @keyframes ttsSang {
      from { transform:translateX(-100%); opacity:.55; }
      to   { transform:none; opacity:1; } }
    /* ⛔ 08/09/2026 — ĐÓNG CŨNG PHẢI CÓ CHUYỂN ĐỘNG. Boss: *"ấn mở ra xong ấn đóng
       lại thì phải nhẹ nhàng với animation đóng lại chứ ko phải bụp phất biến mất"*.
       Bản trước chỉ có hiệu ứng lúc MỞ; lúc đóng JS gạt thẳng `hidden = true` nên cả
       tấm biến mất trong một khung hình.
       ⛔ JS PHẢI CHỜ HẾT .26s RỒI MỚI ẨN, nếu không thì luật này vô dụng — thẻ bị ẩn
          ngay khi hiệu ứng vừa bắt đầu. Xem `dongSheetCongCu()` trong js/tinh-nang.js,
          và con số .26s ở hai nơi phải khớp nhau.
       ⛔ Đường cong (.4,0,1,1) là "chậm rồi nhanh dần" — ngược với lúc mở. Mở thì
          cần có đà rồi hãm lại cho mắt bắt kịp; đóng thì cần rời đi dứt khoát, chứ
          hãm lại lúc cuối là trông như tấm bị kẹt. */
    #ttSheet.dang-dong .tts-hop {
      animation:ttsVeTrai .26s cubic-bezier(.4,0,1,1) both; }
    #ttSheet.dang-dong .tts-nen { animation:ttsMoTat .26s ease both; }
    #ttSheet.dang-dong .tts-than { animation:none; }
    @keyframes ttsVeTrai {
      from { transform:none; opacity:1; }
      to   { transform:translateX(-100%); opacity:.55; } }
    @keyframes ttsMoTat { from { opacity:1; } to { opacity:0; } }
    /* Nội dung bên trong hiện SAU tấm một nhịp, cho mắt kịp bắt lấy ngăn kéo trước
       rồi mới tới danh sách — chứ không đổ ập cùng lúc. */
    #ttSheet .tts-than { animation:ttsRuot .34s ease .1s both; }
    @keyframes ttsRuot { from { opacity:0; transform:translateY(9px); } }
    @media (prefers-reduced-motion: reduce) {
      #ttSheet .tts-nen, #ttSheet .tts-hop, #ttSheet .tts-than { animation:none; }
      /* ⛔ Kể cả khi tắt hiệu ứng, luật ĐÓNG vẫn phải giữ `opacity:0` ở đích — JS
         chờ .26s rồi mới ẩn thẻ, mà không có luật này thì trong .26s ấy ngăn kéo
         đứng nguyên như chưa bấm gì, người dùng tưởng nút hỏng nên bấm lại. */
      #ttSheet.dang-dong .tts-hop, #ttSheet.dang-dong .tts-nen {
        animation:none; opacity:0; }
    }
    /* ⛔ Vạch kéo ngang: đó là dấu hiệu của tấm KÉO LÊN TỪ ĐÁY. Ngăn kéo trượt
       ngang thì nó vô nghĩa và gây hiểu nhầm là vuốt xuống được. Ẩn, không xoá —
       markup còn dùng chung với chỗ khác. */
    #ttSheet .tts-keo { display:none; }
    /* 👤 ĐẦU NGĂN KÉO = AVATAR + TÊN NGƯỜI ĐANG DÙNG — Boss chốt 08/09/2026
       *"trong cái thanh công cụ mở ra ở góc trên cùng sẽ có avartar của account đó
       để đỡ bị trắng xóa quá"*. Trước: mỗi dòng chữ "Tất cả công cụ" trên nền trắng.
       ⛔ `justify-content:space-between` cũ đã BỎ — nó có từ thời còn nút ✕ bên phải;
          nút ấy bỏ từ sáng nay nên chữ bị đẩy dính mép trái, còn khoảng phải trống hoác.
       ⛔ Đừng tô nền cho cả hàng: ngăn kéo đã trắng, thêm một dải màu nữa là ra ba
          tầng nền chồng nhau — thứ Boss gọi là "lộ ui AI". Chỉ ảnh tròn là đủ điểm nhìn. */
    #ttSheet .tts-dau { display:flex; align-items:center; gap:10px;
      padding:2px 2px 12px; flex:none; min-width:0; }
    #ttSheet .tts-av { width:38px; height:38px; flex:none; border-radius:50%;
      overflow:hidden; display:flex; align-items:center; justify-content:center;
      background:var(--nen2); color:var(--mo); }
    #ttSheet .tts-av img { width:100%; height:100%; object-fit:cover; display:block; }
    #ttSheet .tts-av svg, #ttSheet .tts-av i { width:22px; height:22px; }
    /* `min-width:0` cho phép tên dài cắt bằng "…" thay vì đẩy phình cả hàng. */
    #ttSheet .tts-toi { display:flex; flex-direction:column; min-width:0; line-height:1.25; }
    #ttSheet .tts-dau b { font-size:15px; font-weight:700;
      overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    #ttSheet .tts-vai { font-size:12px; color:var(--mo);
      overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    #ttSheet .tts-x { width:34px; height:34px; border:0; border-radius:var(--r-lg); cursor:pointer;
      background:var(--nen2); color:var(--chu); font-size:15px; }
    /* 🔎 Ô TÌM NGĂN KÉO — bo tròn và bé lại, Boss chốt 08/09/2026
       *"sửa cái thanh tìm kiếm ở thanh công cụ thành bo tròn cho tôi và để bé đi chứ
       to quá ko cần to như vậy đâu"*. Trước: đệm 12px trên dưới, góc vuông, cao ~46px.
       ⛔ CỠ CHỮ KHAI 15px → 16px, KHÔNG phải hạ. Ô bé đi nhờ bóp ĐỆM và ghim chiều
          cao, không nhờ thu chữ — dưới 16px là Safari trên iPhone tự phóng to cả
          trang lúc bấm vào ô nhập và không tự thu lại.
          ⚠️ Nói cho đúng: 15px cũ **không** phải bẫy đang nổ. Lưới an toàn ở khối
          `@media (hover:none)` phía dưới đã ép `font-size:16px !important` cho mọi
          `input`, nên trên điện thoại ô này vẫn luôn 16px. Tôi đo thử: khai 15px mà
          đo ra vẫn 16px. Sửa ở đây là cho **khai báo khớp với cái chạy thật** — khai
          một đằng chạy một nẻo là cái bẫy cho người đọc mã sau, chứ không phải đang
          vá một lỗi cho người dùng.
       ⛔ Bo tròn ở đây là ngoại lệ CÓ CHỦ Ý so với `--r-lg: 0` của app (app cố ý vuông
          vức kiểu bảng tính). Ô tìm thì mọi app đều bo tròn, và Boss chốt riêng. Đừng
          nhân cái ngoại lệ này ra các ô nhập khác. */
    #ttSheet .tts-tim { width:100%; box-sizing:border-box; flex:none; margin-bottom:10px;
      height:36px; padding:0 14px; border:1px solid var(--vien); border-radius:999px;
      font-size:16px; font-family:inherit; background:var(--nen2); color:var(--chu); }
    #ttSheet .tts-tim:focus { outline:none; border-color:var(--xanh); background:var(--the); }
    /* ⛔ THÂN PHẢI TỰ ÔM LẤY PHẦN LỀ CỦA HỘP (kéo ra -14px rồi đệm lại 14px).
       Lý do: `overflow-y:auto` biến overflow NGANG thành auto luôn, nên con nào thò ra
       khỏi thân đều bị XÉN. Dải xám `.tts-vach` cần chạm hai mép ngăn kéo như Facebook;
       để nguyên thì nó thò phải và bị cắt cụt — trông như vẽ hỏng. Kéo cả thân ra rồi
       đệm vào là dải chạm được mép mà chữ vẫn thẳng hàng như cũ. */
    #ttSheet .tts-than { overflow-y:auto; -webkit-overflow-scrolling:touch; padding-bottom:6px;
      margin-left:-14px; margin-right:-14px; padding-left:14px; padding-right:14px; }
    /* Tiêu đề nhóm: chữ thường, KHÔNG in hoa giãn ly (nhìn tự nhiên, dễ đọc hơn) */
    /* 🎨 22/08/2026 — cùng nếp với nhãn nhóm bên thanh dọc: chữ xám bé, nét 600.
       ⛔ Sửa bên này mà quên bên kia là hai màn của cùng một app trông khác nhau. */
    /* ⛔ 08/09/2026 — TIÊU ĐỀ NHÓM TO LÊN, kiểu "Your shortcuts" của Facebook.
       Chữ 11.5px xám của bản cũ hợp với NHÃN nhóm trên thanh dọc; ở đây nó là tiêu đề
       của cả một khu, nên phải đọc ra ngay chứ không phải ghé mắt. */
    #ttSheet .tts-nhom { font-size:16px; font-weight:700; color:var(--chu);
      margin:18px 2px 10px; }
    #ttSheet .tts-nhom:first-child { margin-top:2px; }

    /* ══════════════════════════════════════════════════════════════════════════
       KHU CÔNG CỤ = LƯỚI HAI CỘT, mỗi ô một THẺ CÓ VIỀN — Boss chốt 08/09/2026
       ──────────────────────────────────────────────────────────────────────────
       Boss gửi ảnh ngăn kéo Facebook: *"nhìn kĩ cho tôi cái thanh công cụ kéo ra của
       facebook nó có thiết kế các block như nào thì tôi muốn bắt trước y hệt"*.

       ⛔⛔ CÓ MỘT LUẬT CŨ NGƯỢC HẲN, VÀ NÓ ĐÃ HẾT HIỆU LỰC — ĐỌC KỸ TRƯỚC KHI ĐỔI LẠI.
          05/08/2026 Boss chê *"lộ chất game/khuôn mẫu"* và bắt bỏ LƯỚI Ô VUÔNG ICON,
          đổi sang danh sách dọc. Luật ấy nói về một hình dáng KHÁC hẳn cái này:

          | | Lưới bị chê 05/08 | Lưới Facebook 08/09 (cái này) |
          |---|---|---|
          | Hình ô | VUÔNG | chữ nhật NGANG, thấp |
          | Icon | TO, giữa ô | nhỏ 22px, nét mảnh, góc trên TRÁI |
          | Chữ | canh GIỮA dưới icon | canh TRÁI, dưới icon |
          | Nền ô | tô màu | trắng, chỉ có viền mảnh |

          Ô vuông + icon to giữa + chữ canh giữa là đúng bố cục của một màn hình game
          hay ngăn ứng dụng — đó mới là thứ Boss chê. Thẻ chữ nhật viền mảnh canh trái
          là bố cục của một thẻ tài liệu. ⛔ Ai đọc sau đừng đổi ô này về vuông/canh
          giữa/tô màu — làm thế là dựng lại đúng thứ Boss đã chê một lần rồi.

       ⛔ MÔ TẢ BỊ ẨN, KHÔNG BỊ XOÁ. Facebook không có dòng mô tả nào trong ô, và ô hai
          cột cũng không đủ chỗ. Nhưng chữ ấy vẫn nằm trong `title` của nút (rê chuột
          trên máy tính là thấy) và vẫn dùng để TÌM ở ô "Tìm nhanh công cụ" — nên bỏ
          `display:none` này đi là mô tả hiện lại ngay, không mất gì.
       ══════════════════════════════════════════════════════════════════════════ */
    #ttSheet .tts-luoi { display:grid; grid-template-columns:1fr 1fr; gap:8px;
      margin-bottom:2px; }
    #ttSheet .tts-muc { display:flex; flex-direction:column; align-items:flex-start;
      gap:9px; width:100%; box-sizing:border-box; min-height:78px;
      background:var(--the); border:1px solid var(--vien); border-radius:12px;
      font-family:inherit; cursor:pointer; padding:13px 12px 12px; text-align:left;
      transition:background .16s ease, border-color .16s ease; }
    #ttSheet .tts-muc-ico { width:22px; height:22px; flex:none; fill:none;
      stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round; color:var(--muc); }
    #ttSheet .tts-muc-chu { width:100%; min-width:0; display:block; }
    /* Tên hai dòng là hết — tên nào dài hơn thì cắt bằng "…", ô vẫn bằng nhau. */
    #ttSheet .tts-muc-chu b { display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
      overflow:hidden; font-size:14.5px; font-weight:600; color:var(--chu); line-height:1.3; }
    #ttSheet .tts-muc-chu small { display:none; }
    #ttSheet .tts-muc:active { background:var(--nen2); border-color:var(--muc); }

    /* Dải xám dày ngăn khu lưới với khu danh sách — Facebook cũng chèn đúng một dải
       như thế giữa "See more" và "Help and support". Kẻ một vạch mảnh thì hai khu vẫn
       dính vào nhau, mà chúng là hai loại việc khác hẳn. */
    #ttSheet .tts-vach { height:8px; margin:16px -14px 2px; background:var(--nen2);
      border-top:1px solid var(--vien); border-bottom:1px solid var(--vien); }

    /* Hàng quản trị / tài khoản = HÀNG CHẠY HẾT BỀ NGANG, có mũi tên bên phải —
       đúng kiểu "Help and support · Settings and privacy" của Facebook. */
    #ttSheet .tts-hang { display:flex; align-items:center; gap:14px; width:100%; min-height:56px;
      background:none; border:0; border-bottom:1px solid var(--vien); font-family:inherit;
      font-size:15px; font-weight:600; color:var(--chu); cursor:pointer;
      padding:12px 2px; text-align:left; }
    #ttSheet .tts-hang:last-of-type { border-bottom:0; }
    #ttSheet .tts-hang svg { width:21px; height:21px; flex:none; fill:none; stroke:currentColor;
      stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round; color:var(--mo); }
    #ttSheet .tts-hang span { flex:1; min-width:0; }
    /* Mũi tên chỉ sang phải: dấu hiệu "bấm vào là đi tiếp", Facebook để ở mọi hàng. */
    #ttSheet .tts-hang .tts-mui { width:17px; height:17px; color:var(--mo); opacity:.75; }
    #ttSheet .tts-hang:active { background:var(--nen2); }
    #ttSheet .tts-hang.do, #ttSheet .tts-hang.do svg { color:var(--do); }
    #ttSheet .tts-trong { padding:18px 2px; color:var(--mo); font-size:14px; text-align:center; }
  }
  @media (max-width:820px) {
    /* ══════════════════════════════════════════════════════════════════════════
       📱 THANH ĐÁY ĐIỆN THOẠI — làm lại 22/08/2026 theo yêu cầu cô Quỳnh
       ──────────────────────────────────────────────────────────────────────────
       *"thanh công cụ ở dưới bị sát với mép dưới điện thoại quá… tôi muốn bạn thiết
       kế lại cho nó cao lên xíu và có mờ ở background có bloom có kiểu dynamic app
       trông premium và thêm animation chuyển cảnh khi ấn nút cho tôi thật mượt"*

       Bản cũ: dải trắng đặc dán sát bốn mép, viền trên một nét, cao 59px.
       Bản này: thanh NỔI, tách khỏi ba mép, nền kính mờ nhìn xuyên thấy nội dung
       trôi bên dưới, bo góc lớn, và mỗi nút có viên nền trượt tới khi được chọn.

       ⛔ BA ĐIỀU KHÔNG ĐƯỢC PHÁ:
       ① Khoảng cách đáy PHẢI cộng env(safe-area-inset-bottom) — đó là vạch thoát
          màn hình iPhone. Và phải có viewport-fit=cover ở thẻ meta, không thì env()
          luôn trả 0 (xem lời cảnh báo ở đầu file).
       ② Nền phải BÁN TRONG SUỐT thì backdrop-filter mới có nghĩa. Đổi sang màu đặc
          là mất sạch hiệu ứng kính mà vẫn trả giá tính toán cho nó.
       ③ backdrop-filter TẠO LỚP VẼ RIÊNG. Thứ gì cần nổi trên thanh này phải có
          z-index cao hơn 60 VÀ không phải con của nó — đúng bẫy đã làm nhãn cột icon
          bị đè hôm nay.
       ══════════════════════════════════════════════════════════════════════════ */
    /* ⚠️ DÁN LIỀN ĐÁY 08/09/2026 — Boss: *"gom hết tất cả lại toàn bộ app trên điện
       thoại, giao diện bạn nhìn Facebook mà xem nó hoàn toàn liền vào nhau"*.
       ⛔ HAI LỜI DẶN CŨ NAY HẾT HIỆU LỰC, đừng dựng lại vì đọc thấy ở chú thích:
          · 22/08/2026 "thanh NỔI, tách khỏi ba mép" (left/right 10px, bottom 9px)
          · 03/09/2026 "bo tròn đẹp hơn" (border-radius 22px)
          Cả hai bàn chuyện thanh này TÁCH khỏi mép bao nhiêu — mà Boss đã đổi hẳn
          sang liền mép. Thứ KHÔNG hết hiệu lực là nền kính mờ và bảng màu đã đo:
          giữ nguyên, xem khối cảnh báo màu ngay dưới.
       ⛔ VÙNG AN TOÀN iPhone nay chừa bằng PADDING-BOTTOM chứ không bằng `bottom:`.
          Thanh dán sát cạnh dưới thật, nền phủ xuống hết vạch thoát màn hình, còn
          chữ và icon thì ngồi phía trên vạch ấy — đúng nếp Facebook. Bỏ chỗ chừa
          này là hàng nút bị vạch thoát của iPhone cắt ngang. */
    #thanhDuoi:not([hidden]) { display:flex; position:fixed; z-index:60;
      /* 🫥 TRƯỢT XUỐNG RỒI TRƯỢT LÊN — kiểu Instagram, Boss chốt 09/09/2026 chiều:
         *"tôi muốn lúc kéo xuống trên điện thoại là cái thanh công cụ nó ẩn đi luôn
         và kéo lên thì nó hiện lên như kiểu của instagram ý"*.
         ⛔ LUẬT "MỜ DẦN, SÀN 0.58" (sáng cùng ngày) ĐÃ HẾT HIỆU LỰC — đừng dựng lại.
            Bản mờ ấy để lộ chữ của trang phía sau lọt lên giữa hàng nút, Boss chụp
            ảnh gửi lại đúng chỗ đó. Ẩn hẳn thì không còn chuyện chồng chữ.
         ⛔ .2s LÀ CHIỀU **HIỆN LẠI**, cố ý ngắn hơn chiều ẩn: kéo lên là muốn bấm
            ngay, chờ lâu thấy ì. Nhưng KHÔNG được 0s — Boss xin *"vẫn phải hơi cảm
            nhận được animation cho nó đỡ trống"*. */
      transform:translateY(0);
      transition:transform .2s cubic-bezier(.2,.9,.3,1), opacity .16s ease-out;
      left:0; right:0; bottom:0; justify-content:center;
      /* ⛔ ĐỆM DƯỚI 10px CHỨ KHÔNG PHẢI 4px — Boss chốt 08/09/2026
         *"thanh công cụ ở dưới cho cao lên tí để tránh cái thanh thoát màn hình của
         iphone"*. `env(safe-area-inset-bottom)` chỉ trả 34px trên iPhone có vạch
         thoát; máy Android và trình duyệt máy tính trả **0**, và lúc ấy hàng nút chỉ
         cách mép đúng 4px — sát đến mức nhìn như bị cắt. 10px là sàn cho mọi máy,
         iPhone vẫn được cộng thêm phần vạch thoát như cũ. */
      gap:2px; padding:7px 6px calc(10px + env(safe-area-inset-bottom, 0px));
      background:var(--td-nen);
      -webkit-backdrop-filter:blur(26px) saturate(1.7);
      backdrop-filter:blur(26px) saturate(1.7);
      border:0; border-radius:22px 22px 0 0;
      /* Chỉ còn MỘT lớp bóng, hắt LÊN TRÊN, rất nhẹ — đủ tách thanh khỏi nội dung
         đang trôi bên dưới. ⛔ Bóng toả xa (bloom) của bản nổi đã bỏ: thanh dán mép
         rồi mà còn quầng sáng thì chỗ giáp ranh hiện một vệt, nhìn lại ra hai mảnh
         rời — đúng thứ Boss bảo dọn. */
      box-shadow:0 -3px 14px -6px var(--td-quang);
      animation:tdHien .42s cubic-bezier(.22,.9,.28,1) both; }
    /* ⛔⛔ KHOI NAY PHAI DUNG SAU `#thanhDuoi:not([hidden])`, DUNG DOI LEN TRUOC.
       Ban dau toi dat no o TREN khoi chinh — CSS van chay dung (dac hieu 1-2-0 hon
       1-1-0), nhung bai `thu-css-dien-thoai.js` cat khoi luat bang cach TIM CHUOI
       `#thanhDuoi:not([hidden])` roi doc toi dau ngoac dong. Chuoi ay la chuoi con
       cua `#thanhDuoi:not([hidden]).td-mo`, nen bai gap luat cua toi TRUOC va cat
       nham mot khoi ba dong — ba phep canh ve vung an toan, kinh mo va bo goc thanh
       day do oan (52/53 -> 49/53). Dat sau la CSS van thang ma bai cat dung khoi. */
    /* 🫥 MỜ ĐI KHI CUỘN XUỐNG — Boss 09/09/2026, phần chạy ở `tdGanMoTheoCuon`.
       ⛔ Tắt luôn `backdrop-filter` lúc mờ. Giảm mỗi độ đục mà giữ lớp làm nhoè thì
          chữ phía sau vẫn bị bôi mờ — Boss xin *"nhìn thấy các block sau thanh công
          cụ rõ hơn"*, tức phải nhìn XUYÊN, không phải nhìn qua kính mờ.
       ⛔ KHÔNG chặn `pointer-events`: thanh mờ vẫn phải bấm được, chạm vào là nó rõ
          lại ngay.
       ⛔ 200ms và chỉ chuyển `opacity` — chuyển `backdrop-filter` là trình duyệt vẽ
          lại cả vùng nhoè mỗi khung hình, giật ngay trên máy yếu. */
    /* Phải viết `:not([hidden])` ở đây nữa cho ĐỦ SỨC ĐÈ. Khối chính dưới kia là
       `#thanhDuoi:not([hidden])` — cùng trọng số với `#thanhDuoi.td-mo`, mà nó
       đứng SAU nên thắng: đo lần đầu thấy độ đục xuống 0,3 đúng ý nhưng lớp làm
       nhoè vẫn nguyên `blur(26px)`, chữ phía sau vẫn bị bôi. */
    /* ⛔⛔ 09/09/2026 — BỎ `opacity:.3` CỨNG. Boss: *"cái thanh công cụ đang bị ẩn
       sâu quá mức ko nhìn đc cx ko ấn được"*, và *"tôi muốn khi kéo xuống nó có hiệu
       ứng mờ dần dần chứ ko phải bụp phát mờ luôn"*.
       Đo bản cũ (scratchpad/do-thanh-day.js, màn 390): cuộn đúng 6px là độ đục nhảy
       thẳng 1 → 0.3 và đứng nguyên ở đó dù cuộn thêm 60, 120, 240 hay 400px. Đó là
       cái "bụp phát mờ luôn", và 0.3 trên nền trắng thì thanh gần như biến mất.
       Nay JS đặt `--td-duc` THEO QUÃNG ĐÃ CUỘN XUỐNG (xem `tdGanMoTheoCuon`), sàn
       dừng ở 0.58 chứ không xuống nữa — vẫn nhìn xuyên thấy block phía sau (yêu cầu
       Boss 09/09 buổi sáng) mà vẫn đọc được nhãn và bấm trúng nút.
       ⛔ ĐỪNG hạ sàn xuống dưới .55: đó đúng là chỗ Boss đã báo hỏng một lần.
       ⛔ Lớp này giờ chỉ còn hai việc: TẮT kính mờ, và cho chiều mờ đi một khoảng
          chuyển DÀI HƠN chiều rõ lại (.34s so với .16s) — mờ thì thong thả, rõ thì
          dứt khoát, đúng lời Boss. */
    /* ⛔⛔ 09/09/2026 CHIỀU — ẨN HẲN, KHÔNG CÒN LÀM MỜ.
       Sáng nay thanh này mờ xuống 0.58 và Boss đã gửi ảnh: chữ của trang phía sau
       lọt lên nằm đè giữa hàng nút ("Chưa đủ số liệu để vẽ đường…" chồng lên chữ
       "Trang chủ"), nhìn rất bẩn. Boss chốt lại: *"kéo xuống là thanh công cụ nó ẩn
       đi luôn, kéo lên thì nó hiện lên như kiểu của instagram"*.
       ⛔ TRƯỢT XUỐNG bằng `translateY`, ĐỪNG chỉ `display:none`: mất hẳn không có
          chuyển động thì thanh nhấp nháy mỗi lần đổi chiều cuộn.
       ⛔ `pointer-events:none` LÀ ĐÚNG Ở BẢN NÀY. Lời dặn cũ "thanh mờ vẫn phải bấm
          được" gắn với bản MỜ — thanh còn nhìn thấy thì phải bấm được. Nay nó nằm
          ngoài màn, để bắt sự kiện là ngón tay chạm mép dưới lại trúng một nút vô
          hình.
       ⛔ Cộng thêm 4px cho chắc chắn khuất hẳn: bóng đổ hắt lên trên, thiếu chỗ này
          thì còn một vệt xám mảnh nằm lại ở mép dưới. */
    #thanhDuoi:not([hidden]).td-mo {
      transform:translateY(calc(100% + 4px));
      opacity:0; pointer-events:none;
      transition:transform .26s cubic-bezier(.4,0,.2,1), opacity .18s ease;
      -webkit-backdrop-filter:none; backdrop-filter:none; }
    @media (prefers-reduced-motion: reduce) {
      #thanhDuoi:not([hidden]) { transition:none; }
    }
    /* ⛔⛔ BỐN MÀU DƯỚI ĐÂY ĐÃ ĐƯỢC ĐO, ĐỪNG ĐỔI BẰNG MẮT.
       Kính mờ để nội dung trang TRÔI QUA bên dưới, nên nền của chữ đổi liên tục:
       lúc là nền trang xám nhạt, lúc là dải chào xanh sẫm, lúc là chữ đỏ cảnh báo.
       Phép đo (scratchpad/r23-do-duc.js) tính màu nền THẬT sau khi trộn kính ở từng
       cảnh xấu nhất, rồi đòi mọi cặp chữ/nền đạt chuẩn đọc được quốc tế 4.5.
       Kết quả bắt được hai màu hỏng mà mắt tôi không thấy:
         · chữ nút thường để `--mo` (#6B6660) chỉ đạt 4.11 khi thanh trôi qua vùng
           tối → đổi sang `--chu`, đạt 12.14
         · chữ mục đang mở để `--muc` (#0D8081) chỉ đạt 3.43 → phải đậm thêm
       ⛔ Đổi độ đục, đổi màu viên nền, hay đổi màu chữ đều phải CHẠY LẠI PHÉP ĐO.
          Hạ độ đục cho "trong hơn" là đúng thứ làm chữ biến mất. */
    /* ⛔ ĐỘ ĐỤC NÂNG .86 → .96 ngày 08/09/2026. Ảnh chụp 390x844 cho thấy chữ của
       trang phía sau LỌT LÊN giữa hàng nút — đọc được cả câu "…lại liên tiếp",
       nhìn rất bẩn. Bản .86 tính cho thanh NỔI cách mép, phía sau nó chỉ có một dải
       hẹp trôi qua; nay thanh dán liền đáy, cả bề ngang trang chạy dưới nó.
       ⛔ NÂNG LÊN LÀ AN TOÀN, KHÔNG PHẢI HẠ. Phép đo tương phản cũ (scratchpad/
          r23-do-duc.js) đòi mọi cặp chữ/nền đạt 4.5 ở nền .86; nền đục hơn thì mọi
          con số ấy chỉ tốt lên. Còn HẠ xuống là phải chạy lại phép đo.
       ⛔ Vẫn giữ dưới 1.0 để backdrop-filter còn có nghĩa — Facebook cũng để thanh
          đáy hơi trong, thấy thấp thoáng nội dung là biết trang còn cuộn tiếp. */
    #thanhDuoi { --td-nen:rgba(255,255,255,.96); --td-vien:rgba(255,255,255,.72);
      --td-quang:rgba(16,110,116,.26); --td-loe:rgba(255,255,255,.85);
      --td-vien-chon:rgba(20,160,160,.14);
      --td-chu:#1f1d1a; --td-chon:#0a6363; }
    body.toi #thanhDuoi { --td-nen:rgba(17,32,38,.96); --td-vien:rgba(255,255,255,.12);
      --td-quang:rgba(0,0,0,.55); --td-loe:rgba(255,255,255,.10);
      --td-vien-chon:rgba(79,209,197,.18);
      --td-chu:#F4F1EC; --td-chon:#8acfc8; }
    @keyframes tdHien { from { transform:translateY(120%); opacity:0; } }

    /* ══════════════════════════════════════════════════════════════════════════
       08/09/2026 — NÚT THEO ĐÚNG NẾP FACEBOOK. Boss: *"nhìn kĩ facebook đi thiết kế
       thật giống vào"*, *"thanh của facebook nó nhỏ gọn xinh xắn bo góc và đẹp,
       mềm mại"*. Soi ảnh Boss gửi, thanh đáy Facebook có ba đặc điểm:
         · VIÊN NỀN BO TRÒN ôm lấy icon đang mở, KHÔNG phải ô vuông kín cả cột
         · icon TO và nét MẢNH, mục đang mở thì icon đậm nét lên
         · chữ nhỏ, nhạt, không đậm — chữ là phần phụ, icon mới là phần chính
       ⛔ CHỮ VẪN GIỮ, cố ý khác Facebook một điểm này. Icon của Facebook là thứ ai
          cũng biết (nhà · bạn bè · chuông). Icon của app này là "Nhắc phụ đạo",
          "Follow up học sinh" — bỏ chữ đi thì trợ giảng phải đoán, mà đoán sai là
          bấm nhầm công cụ. Boss muốn bỏ chữ thì nói một câu, đổi trong một nốt nhạc.
       ══════════════════════════════════════════════════════════════════════════ */
    /* ⛔ 08/09/2026 — CĂN GIỮA THEO SỐ NÚT THẬT. Boss: *"các chức vụ khác sẽ chỉ còn
       lại 3 nút, để ra giữa cho phù hợp với số lượng nút trong thanh công cụ này"*.
       Trước đây mỗi nút `flex:1 1 0` nên luôn chia đều HẾT bề ngang màn: 3 nút thì mỗi
       nút rộng 130px, viên nền phình ra thành một khối chữ nhật to đùng — đúng thứ
       ngược với "nhỏ gọn xinh xắn" Boss dặn.
       Nay nút có bề ngang riêng và cả cụm dồn vào giữa, nên 3 nút hay 4 nút đều cân.
       ⛔ `flex-shrink:1` phải còn: máy hẹp 320px mà 4 nút cứng 96px là tràn ngang. */
    #thanhDuoi .td-nut { position:relative; flex:0 1 96px; max-width:120px; min-width:0;
      display:flex; flex-direction:column; align-items:center; justify-content:center;
      gap:1px; background:none; border:0; font-family:inherit; font-size:10px;
      font-weight:500; color:var(--td-chu); cursor:pointer; padding:4px 2px 3px;
      border-radius:16px; -webkit-tap-highlight-color:transparent;
      transition:color .22s ease, transform .2s cubic-bezier(.34,1.5,.64,1); }
    #thanhDuoi .td-nut span { max-width:100%; overflow:hidden; text-overflow:ellipsis;
      white-space:nowrap; position:relative; z-index:1; opacity:.75;
      transition:opacity .22s ease; }
    /* Viên nền của mục đang mở. Là lớp giả để còn phóng ra từ giữa khi đổi mục —
       đổi thẳng `background` thì màu chỉ hiện đánh bụp, không có chuyển động nào.
       ⛔ `inset:1px 7px` chứ KHÔNG phải `inset:0`: Facebook để viên nền THÓP VÀO,
          hở ra hai bên. Phủ kín cả ô là ra khối chữ nhật, mất hẳn vẻ "xinh xắn". */
    #thanhDuoi .td-nut::before { content:""; position:absolute; inset:1px 7px;
      border-radius:15px; background:var(--td-vien-chon);
      opacity:0; transform:scale(.72);
      transition:opacity .24s ease, transform .3s cubic-bezier(.34,1.5,.64,1); }
    #thanhDuoi .td-nut.chon { color:var(--td-chon); font-weight:600; }
    #thanhDuoi .td-nut.chon span { opacity:1; }
    #thanhDuoi .td-nut.chon::before { opacity:1; transform:none; }
    #thanhDuoi .td-nut:active { transform:scale(.92); }
    #thanhDuoi .td-ico { width:24px; height:24px; flex:none; fill:none; stroke:currentColor;
      stroke-width:1.6; stroke-linecap:round; stroke-linejoin:round;
      position:relative; z-index:1;
      transition:transform .3s cubic-bezier(.34,1.5,.64,1), stroke-width .22s ease; }
    /* Mục đang mở: icon ĐẬM NÉT lên thay vì phóng to vống. Facebook đổi hẳn sang
       icon nền đặc; ở đây bộ icon chỉ có một kiểu nét, nên dày nét là cách gần nhất
       mà không phải vẽ lại cả bộ. */
    #thanhDuoi .td-nut.chon .td-ico { stroke-width:2.2; transform:translateY(-1px); }
    /* ⛔ Ai tắt hiệu ứng chuyển động trong cài đặt máy thì phải im hẳn — luật trợ
       năng, và cũng để máy yếu khỏi giật. Vẫn giữ nguyên MÀU và VIÊN NỀN, chỉ bỏ
       phần chuyển động: người ta cần biết đang ở mục nào, đó không phải trang trí. */
    @media (prefers-reduced-motion: reduce) {
      #thanhDuoi:not([hidden]) { animation:none; }
      #thanhDuoi .td-nut, #thanhDuoi .td-nut::before, #thanhDuoi .td-ico { transition:none; }
      #thanhDuoi .td-nut.chon .td-ico { transform:none; }
    }
    /* Đang nhập điểm trong lớp đã có thanh nút riêng ở đáy → ẩn để khỏi chồng nhau */
    body.dang-trong-lop #thanhDuoi { display:none !important; }
    /* ══════════════════════════════════════════════════════════════════════════
       📅 MÀN LỊCH TRÊN ĐIỆN THOẠI: BỎ HẲN THANH ĐÁY — Boss chốt 09/09/2026
       ──────────────────────────────────────────────────────────────────────────
       *"Phần lịch giáo viên tôi muốn cái bảng lịch nó phải xuống tận cuối màn hình
       bỏ thanh công cụ đi, nói chung ở tất cả màn hình của công cụ nào có giao diện
       lịch ở trên điện thoại đều phải để cái bảng chiếm xuống hết cái app."*

       Thanh đáy `position:fixed` cao 63px + vùng an toàn. Nó không đẩy gì cả, nên
       lưới lịch tính là "vừa màn" mà thực tế bị che mất 63px cuối — đúng dải ô lớp
       người ta cần bấm. Bỏ nó đi là lưới lấy lại trọn phần ấy: `lgvDoTran` đọc
       `getComputedStyle(td).display` nên thấy `none` là tự cộng 63px vào trần, không
       phải sửa thêm dòng JS nào.

       ⛔ CÒN ĐƯỜNG RA CHỨ KHÔNG PHẢI NHỐT NGƯỜI DÙNG: nút ba gạch `#nutBaGach` ở
          thanh trên mở đúng bảng công cụ ấy, và thanh trên KHÔNG bị ẩn ở màn lịch.
          Bỏ nút ba gạch đi thì phải bàn lại luật này.
       ⛔ BA MÀN, KHÔNG PHẢI MỘT. Boss nói "tất cả màn hình công cụ nào có lịch":
          `.lgv-man` Lịch giáo viên · `.lt-man` Lịch test · `.lt-thang-hang` Lịch thi
          định kỳ. Danh sách kê tay là chỗ dễ sót — thêm màn lịch mới thì thêm vào
          đây, `thu-man-lich-full.js` canh đủ cả ba.
       ⛔ LỊCH THI BẮT BẰNG `.lt-thang-hang` (hàng tab tháng) CHỨ KHÔNG PHẢI `.lt-cuon`
          (bảng). Đo thật 09/09: trung tâm chưa khai tháng nào thì màn ấy CHƯA CÓ
          bảng — chỉ có hàng tab và nút "Thêm tháng", nên bắt bằng `.lt-cuon` là
          thanh đáy vẫn hiện nguyên ở đúng cái màn Boss vừa bảo bỏ nó đi. Hàng tab
          thì luôn có, ở cả hai trạng thái.
       ⛔ CHỈ ĐIỆN THOẠI (khối `max-width:820px` này). Trên máy tính thanh đáy vốn
          đã `display:none`, và chỗ trống dưới lưới ở đó do `--lgv-man-cao` lo. */
    body:has(.lgv-man) #thanhDuoi,
    body:has(.lt-man) #thanhDuoi,
    body:has(.lt-thang-hang) #thanhDuoi { display:none !important; }
    /* ⛔⛔ ẨN THANH ĐÁY THÌ PHẢI BỎ LUÔN ĐỆM CỦA NÓ — Boss 09/09/2026 kèm ảnh màn
         Lịch giáo viên: *"có hở ra phần trắng xoá thừa nào ko??? tôi ko thích hở ra
          phần trắng nào cả"*, và *"tránh kéo xuống ở bảng lịch tự nhiên kéo màn hình
          xuống chỗ trắng đó dư ra"*.

       Ba màn trên vừa TẮT thanh đáy ngay phía trên, nhưng luật đệm dưới kia vẫn
       chừa `88px + vùng an toàn` cho một thanh KHÔNG CÒN Ở ĐÓ. Kết quả: một dải
       trắng đúng 88px dính dưới đáy nội dung, và trang cuộn thêm được chừng ấy —
       kéo xuống là màn hình trôi vào chỗ trống.
       ĐO ĐƯỢC 09/09/2026, màn 390×844: Lịch giáo viên trang cao 920 (thừa 76px) ·
       Lịch test 935 (thừa 91px). Bỏ đệm là hết, và phần dôi ra trả về cho lưới lịch.

       ⛔ VẪN CHỪA `env(safe-area-inset-bottom)`: iPhone có vạch thoát ở đáy, không
          chừa thì hàng cuối nằm dưới vạch ấy. Máy Android trả 0 nên không mất gì. */
    body:has(.lgv-man):not(.dang-trong-lop) #noiDung,
    body:has(.lt-man):not(.dang-trong-lop) #noiDung,
    body:has(.lt-thang-hang):not(.dang-trong-lop) #noiDung {
      padding-bottom:calc(6px + env(safe-area-inset-bottom, 0px)); }
    /* Điện thoại dùng thanh đáy nên KHÔNG cần thanh mũi tên mở thanh dọc */
    #thanhCC .cc-toggle { display:none !important; }
    /* Thanh đáy nay cao ~58px + cách đáy 9px + vùng an toàn máy. Đệm phải tính
       ĐÚNG bằng công thức chứ đừng gõ một con số chết: iPhone có vạch thoát thì
       vùng an toàn là 34px, máy Android thường là 0 — một con số không hợp cả hai. */
    body:not(.dang-trong-lop) #noiDung {
      padding-bottom:calc(88px + env(safe-area-inset-bottom, 0px)); }
    /* ⛔ NÚT NỔI "Cài app vào máy" PHẢI ĐỨNG TRÊN THANH ĐÁY, KHÔNG ĐÈ LÊN.
       Chụp màn 22/08 bắt được: nút ấy có bottom:14px và z-index 99999, nên trên
       điện thoại nó nằm chồng đúng giữa thanh và CHE MẤT hai nút "Điểm danh" và
       "Công việc" — người dùng mới cài app xong thì mất luôn hai lối đi chính.
       Nút đọc biến này để tự lùi lên (xem `veNutNoi`); máy tính không khai biến
       nên nó giữ nguyên 14px như cũ. */
    body { --nutnoi-day:calc(80px + env(safe-area-inset-bottom, 0px)); }
  }
  /* 🏢 02/09/2026 — LOGO VÀ DANH THIẾP NGƯỜI DÙNG RỜI KHỎI THANH BÊN.
     Cô Quỳnh: *"thanh công cụ sẽ chỉ còn là thanh công cụ chứ không có hiện
     avatar lên và logo ở thanh nữa"*. Cả hai nay nằm trên thanh trên cùng.

     ⛔ GIỮ NGUYÊN THẺ TRONG HTML, chỉ ẩn bằng CSS — KHÔNG xoá markup. Ba lý do:
        · `veDauThanhCC()` và `avatarVaoO()` vẫn tìm `#ccDauAv` mỗi lần đổi ảnh
          đại diện; xoá thẻ là chúng nhận `null`.
        · `ganSuKienThanhCC()` gọi thẳng `t.querySelector(".cc-dong").onclick`
          không hề kiểm tra null — xoá là app nổ ngay lúc dựng thanh.
        · Trên ĐIỆN THOẠI thanh này là tấm trượt che kín màn, và `.cc-dong` là
          lối ra DUY NHẤT. Bỏ nó ở đó là người dùng kẹt trong tấm trượt.
     Nên: ẩn logo và phần ảnh+tên ở mọi cỡ màn; riêng cái vỏ `.cc-dau` thì chỉ ẩn
     trên MÁY TÍNH (ở đó `.cc-dong` vốn đã ẩn sẵn nên vỏ rỗng, để lại thành một
     vệt trống). Điện thoại giữ vỏ để còn chỗ cho nút đóng. */
  #thanhCC .cc-logo { display:none !important; }
  #thanhCC .cc-dau-av, #thanhCC .cc-dau-chu { display:none !important; }
  /* Luật gốc để nguyên bên dưới cho ai muốn dò lại kiểu cũ — đã bị hai dòng trên đè. */
  #thanhCC .cc-logo-cu { display:flex; flex-direction:column; line-height:1; flex:none;
    padding:14px 14px 12px; border-bottom:1px solid var(--vien); cursor:pointer; background:var(--the); }
  /* ⛔ 22/08/2026 — hạ 800 → 700. Nét 800 là một trong ba thứ lộ giao diện dựng
     bằng AI rõ nhất (cùng với chữ IN HOA ép và giãn chữ). Đây là LOGO nên vẫn phải
     đậm, nhưng 700 đã đủ và nhìn ra chữ hơn hẳn. */
  #thanhCC .cc-logo .ten { font-size:21px; font-weight:700; letter-spacing:-.02em; }
  /* ⛔⛔ LOGO LUÔN LUÔN LÀ CAM + XANH — cô Quỳnh chốt 22/08/2026:
     *"cái logo MyPAS luôn luôn phải đúng màu cam xanh chứ ko được sửa thành cam trắng"*.
     Sáng hôm ấy tôi đã đổi "PAS" sang TRẮNG vì teal thương hiệu (#14A0A0) đặt trên
     nền teal thì chìm. Cô không đồng ý — logo là logo, không phải chỗ để chữa cháy.
     ⛔ Cách làm ĐÚNG: giữ nguyên CẶP MÀU, chỉ nâng độ sáng của vế xanh cho đủ đọc
        trên nền sẫm (#3FCFC2 là chính teal MyPAS kéo sáng lên, không đổi sắc).
        Đã đo: cam 3.56 · xanh 3.92 — chữ logo là chữ TO nên chuẩn là 3,0.
     ⛔ ĐỪNG đổi vế nào sang trắng, xám hay đen nữa. */
  #thanhCC .cc-logo .ten .my { color:#FF9A33; }
  #thanhCC .cc-logo .ten .pas { color:#3FCFC2; }
  #thanhCC .cc-logo .cham { font-size:8px; font-weight:600; letter-spacing:.055em;
    color:#B0D0D4; text-transform:uppercase; margin-top:3px; }
  #thanhCC.mo .cc-toggle { display:none; }               /* mở thì dùng nút ✕ trong panel */
  /* 🖱️ 04/08 (cô Quỳnh): nút công cụ KÉO được đổi vị trí — con trỏ tay nắm; lúc kéo tắt hiệu ứng cho khỏi giật */
  #thanhCC .cc-toggle { cursor:grab; }
  #thanhCC .cc-toggle.dang-keo-nut { transition:none !important; transform:none !important; cursor:grabbing; }
  /* 🧰 ĐANG TRONG LỚP (nhập điểm các DAY) → ẨN HẲN thanh công cụ (cô Quỳnh 03/08: nút
     góc trái vướng nhập điểm). Chỉ hiện ở Trang chủ / danh sách lớp / khi mở công cụ. */
  body.dang-trong-lop #thanhCC { display:none !important; }
  #thanhCC .cc-panel { position:fixed; left:0; top:0; bottom:0; z-index:11001;
    /* ⛔ 22/08/2026 — bóng cũ `rgba(0,0,0,.20)` toả 16px là bóng của một tấm nổi
       lơ lửng. Thanh bên KHÔNG lơ lửng, nó dính vào cạnh màn hình. shadcn dùng đúng
       một đường viền mảnh. Nay: viền + bóng gần như không thấy. */
    width:0; overflow:hidden;
    background:linear-gradient(180deg, var(--cc-dinh) 0%, var(--cc-giua) 52%, var(--cc-day) 100%);
    border-right:1px solid rgba(0,0,0,.18); box-shadow:1px 0 3px rgba(10,40,45,.16);
    transition:width .2s ease; display:flex; flex-direction:column; white-space:nowrap;
    /* ⚡ 06/08/2026 — cô Quỳnh nhận xét: "bật thanh công cụ bên trái lên thì kéo bảng
       lag, ẩn đi lại đỡ hơn." Thanh này `position:fixed` đè lên vùng trang. Nếu nó
       nằm CHUNG lớp vẽ với nội dung thì mỗi nhịp cuộn bảng trình duyệt phải vẽ lại
       cả nó. Hai dòng dưới tách nó ra LỚP VẼ RIÊNG và khoanh vùng vẽ lại trong chính
       nó — cuộn bảng không đụng tới nữa. ⛔ Đừng xoá. */
    will-change:transform; contain:layout paint; }
  /* ⛔ 22/08/2026 — 200 → 248px, cộng thêm đúng bằng cột rail (48px). Không cộng
     thì danh sách công cụ hụt 48px và tên dài như "Điểm danh (danh sách lớp)" vỡ
     làm hai dòng. Đây là màn HẸP; máy tính có luật riêng ở @media min-width:821px. */
  #thanhCC.mo .cc-panel { width:min(252px, 78vw); }
  /* ══════════════════════════════════════════════════════════════════════════
     ⭐⭐ 23/08/2026 — Ở TRANG CHỦ THÌ GẤP CỘT CÔNG CỤ LẠI, CHỈ CHỪA CỘT ICON
     ──────────────────────────────────────────────────────────────────────────
     CÔ QUỲNH 22/08: *"ở thanh công cụ bên trái nút trang chủ khi ấn vào đó thì cái
     thanh công cụ của các bộ phận bên cạnh ko cần hiện lên đâu, chỉ để màn hình
     trang chủ và 1 thanh công cụ trong cùng thôi, cho trang chủ giộng ra nhìn dễ
     hơn"*.
     Trang chủ là màn DUY NHẤT không thuộc bộ phận nào — danh sách công cụ bên cạnh
     lúc ấy đang kể tên của một ngăn mà người ta vừa rời khỏi. Nó chiếm 188px bề
     ngang để nói một điều không còn đúng.
     ⛔ CHỈ GẤP, KHÔNG ĐÓNG HẲN THANH. Đóng hẳn thì mất luôn đường đi sang bộ phận
        khác, người ta phải mở lại thanh mới đi tiếp được — thành ra thêm một cú bấm
        cho mọi việc, đổi lấy một lần rộng màn hình.
     ⛔ Giữ nút ✕ trong danh thiếp: nó là đường đóng thanh, ẩn đi là ở Trang chủ
        không còn cách nào cất thanh. Chỉ giấu phần CHỮ, vì 64px không chở nổi
        một cái tên với một chức vụ.
     ══════════════════════════════════════════════════════════════════════════ */
  #thanhCC.chi-rail.mo .cc-panel { width:56px; }
  /* ⛔⛔ KHI GẤP, NHÃN TỰ VẼ KHÔNG DÙNG ĐƯỢC — bắt được khi mở trình duyệt xem.
     Nhãn tên bộ phận đặt ở `left: calc(100% + 7px)`, tức NẰM NGOÀI thanh. Thanh bung
     rộng 304px thì không sao; gấp còn 64px là nó thò hẳn sang vùng nội dung và bị
     che mất, chỉ còn một mẩu bo tròn ở mép. Đã thử gỡ `overflow:hidden` của panel
     rồi nâng `z-index` lên 11020 — VẪN BỊ CHE, vì thẻ nội dung nằm trong một lớp
     xếp chồng khác.
     Nên khi gấp thì đổi hẳn sang `title` — tooltip gốc của trình duyệt, nó vẽ ngoài
     trang nên không lớp nào che nổi, không overflow nào xén nổi. Xấu hơn một chút,
     nhưng ĐỌC ĐƯỢC, mà lúc gấp thì màn chỉ còn icon nên đọc được mới là điều cần.
     `title` do `ccApGon()` gắn/gỡ theo trạng thái.

     ⛔⛔ VÀ PHẢI GIỮ `overflow:hidden` — đừng nghĩ tới chuyện mở nó ra nữa.
     Bản đầu có thêm `#thanhCC.chi-rail .cc-panel { overflow:visible }` từ hồi còn
     đang thử cho nhãn thò ra. Chuyển sang `title` rồi mà quên gỡ, và nó gây một
     lỗi im lặng hẳn một tầng khác: lúc thanh CỤP (không có `.mo`), panel giấu ruột
     bằng chính `overflow:hidden` — mở ra thì cái ruột 304px tràn nguyên sang vùng
     nội dung. Mắt không thấy gì vì ruột trong suốt, nhưng nó ĂN HẾT CÚ BẤM ở dải
     0–303px. Đo bằng trình duyệt: `elementFromPoint(300, 300)` trả về
     `DIV.cc-hai-cot` chứ không phải nội dung. Bấm tab, bấm nút bên trái màn hình
     đều trơ ra. */
  #thanhCC.chi-rail .cc-rail-ten { display:none; }
  #thanhCC.chi-rail .cc-than { display:none; }
  /* ⛔ ẨN HẲN LOGO khi gấp, đừng chỉ thu nhỏ. Bản đầu chỉ giấu dòng chữ nhỏ bên
     dưới và để lại chữ "MyPAS" — mở trình duyệt ra thì nó cụt thành "MyPA" tràn
     ra ngoài mép thanh, nhìn như app vỡ. 64px không chở nổi năm chữ cái cỡ ấy, mà
     bóp chữ xuống vừa thì đọc không ra. Icon nhà ngay dưới đã đủ nói đây là thanh gì. */
  #thanhCC.chi-rail .cc-logo { display:none; }
  /* ⛔ Xếp DỌC khi thu còn cột ngăn — đây mới là chỗ làm avatar lệch.
     Cột ngăn rộng 64px, trừ đệm hai bên còn 56px; mà avatar 34 + hở 4 + nút 30
     = 68px — thừa 12px nên flex bóp avatar dịch sang trái. Xếp dọc thì cả hai
     cùng nằm giữa, không cái nào lệch. */
  #thanhCC.chi-rail .cc-dau { flex-direction:column; justify-content:center;
    align-items:center; gap:4px; padding:6px 4px; }
  #thanhCC.chi-rail .cc-dau-chu { display:none; }
  /* 🏢 05/08 — ĐẦU THANH = danh thiếp người dùng (ảnh + tên + chức vụ), kiểu app quản trị.
     Không còn chữ "Công cụ": tài khoản chức vụ gì thì hiện đúng chức vụ đó. */
  /* 🎨 22/08/2026 — BỎ MẢNG TEAL ĐẶC Ở ĐẦU THANH.
     Trong cả bốn ảnh cô Quỳnh gửi, khối người dùng là một hàng bình thường trên
     nền thanh: ảnh tròn, tên đậm, dòng phụ xám. Không hề có mảng màu.
     ⛔ Mảng màu đặc ở đầu thanh bên là dấu hiệu số một của giao diện dựng vội —
        nó hút hết mắt về một chỗ chẳng có thông tin gì, mà tên người dùng thì lại
        khó đọc vì chữ trắng trên teal chỉ đạt tương phản ~3,1 lần.
     ⛔ Giữ nguyên `flex:none` — bỏ đi là đầu thanh co lại khi danh sách dài. */
  /* 🎨 Nền teal RẤT NHẠT (`--xanh-nhat`) chứ không phải teal đặc. Đủ để khối
     người dùng tách khỏi danh sách công cụ và mang màu trung tâm, mà chữ vẫn là
     chữ đen bình thường nên đọc rõ — khác hẳn bản cũ chữ trắng trên teal đặc
     (tương phản chỉ ~3,1 lần). */
  #thanhCC .cc-dau { display:flex; align-items:center; gap:10px;
    padding:12px 12px 12px 14px; background:var(--xanh-nhat); color:var(--chu);
    border-bottom:1px solid var(--vien-nhe); font-size:14px; flex:none; }
  /* ⛔ Nền `--the` (trắng) chứ không `--nen2`: ô này nằm TRÊN khối `.cc-dau` vốn
     đã là teal rất nhạt, xám nhạt đặt lên teal nhạt thì nhoè vào nhau. */
  #thanhCC .cc-dau-av { flex:none; width:34px; height:34px; border-radius:50%; overflow:hidden;
    display:inline-flex; align-items:center; justify-content:center;
    background:rgba(255,255,255,.14); border:1px solid rgba(255,255,255,.26); color:#CFE6E8; }
  #thanhCC .cc-dau-av img { width:100%; height:100%; object-fit:cover; display:block; }
  #thanhCC .cc-dau-chu { flex:1; min-width:0; display:flex; flex-direction:column; line-height:1.3; }
  #thanhCC .cc-dau-chu b { font-size:13px; font-weight:600; color:var(--chu);
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  /* ⛔ Dòng chức vụ dùng `--mo`, KHÔNG dùng opacity: opacity làm mờ cả nét chữ nên
     chữ bé thành nhoè, còn màu xám thì vẫn sắc nét. */
  #thanhCC .cc-dau-chu small { font-size:11.5px; font-weight:400; color:var(--mo);
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  /* ☰ Nút ẩn thanh — cô Quỳnh 23/08/2026: *"cái chữ x trong thanh này trông rất
     xấu và làm cho cái avatar bị lệch sang trái nên tôi muốn bạn sửa thanh gạch ngang
     3 gạch app hay có"*.
     ⛔ Ba gạch dựng bằng 3 thẻ <span>, KHÔNG dùng ký tự ☰: ký tự ấy mỗi máy một
        phông, chỗ dày chỗ mảnh, còn <span> thì cao thấp đúng từng pixel — giống
        nút tròn `#ddFab` ở màn điểm danh. */
  #thanhCC .cc-dong { display:flex; flex-direction:column; align-items:center;
    justify-content:center; gap:3px; flex:none;
    background:transparent; border:1px solid transparent; color:var(--mo);
    border-radius:var(--r-md); width:30px; height:30px; padding:0; cursor:pointer; }
  #thanhCC .cc-dong span { display:block; width:15px; height:1.5px; border-radius:var(--r-sm);
    background:currentColor; }
  #thanhCC .cc-dong:hover { background:var(--nen2); color:var(--chu); }
  /* ══════════════════════════════════════════════════════════════════════════
     🎚 CỘT NGĂN (rail) — cô Quỳnh 22/08/2026
     ──────────────────────────────────────────────────────────────────────────
     ⛔ 48px, KHÔNG rộng hơn. Cô Quỳnh: *"nhớ thiết kế cột bên trái mới bé thôi kẻo
        tốn diện tích"*. 48 = nút 36 + đệm hai bên 6. Nút 36px vẫn đạt chuẩn vùng
        bấm tối thiểu cho cảm ứng khi cộng khoảng hở giữa các nút.
     ⛔ Cột này KHÔNG cuộn (`overflow:visible`): nhiều nhất là 4 ngăn, mà cho cuộn
        thì tên hiện khi rê chuột bị chính khung cuộn cắt mất. */
  #thanhCC .cc-hai-cot { flex:1; min-height:0; display:flex; }
  /* ⛔ 52px (nút 40 + đệm 6 mỗi bên) — cô Quỳnh 22/08 lần 2: *"tăng kích thước
     icon và font chữ menu để dễ bấm/quét mắt hơn"*. Vẫn là cột HẸP đúng như lần
     dặn thứ nhất (*"bé thôi kẻo tốn diện tích"*): 52px chỉ bằng một phần sáu thanh. */
  /* ══════════════════════════════════════════════════════════════════════════
     🟠 MÀU CAM CHỈ Ở ĐÚNG CỘT NÀY — VIỆC E, sửa lại 23/08/2026
     ──────────────────────────────────────────────────────────────────────────
     Cô Quỳnh 22/08 xin đổi cam: *"thiết kế cho cái thanh công cụ có các công cụ
     của các bộ phận ý — THANH CÔNG CỤ Ở BÊN NGOÀI ý — sửa nó lại thành màu cam"*.
     Lần đầu tôi hiểu thành cả tấm panel và bôi cam hết. Cô xem xong chụp lại đúng
     phần DANH SÁCH TÊN CÔNG CỤ (ô "Tìm công cụ", nhóm "Giáo vụ", "Điểm danh",
     "Progress test"…) và nói: *"cái thanh này phải màu xanh lá như cũ chỉ riêng
     nhìn kĩ ảnh để biết thanh công cụ nào"*.
     → "Thanh công cụ ở bên ngoài" = ĐÚNG CỘT ICON HẸP NGOÀI CÙNG này (52px), thứ
       nằm sát rìa màn hình. Phần thân bên trong giữ teal như cũ.

     Vì sao cam ĐẤT chứ không phải cam logo #F5821F: cam logo làm nền thì icon
     trắng chỉ đạt 2,48 lần tương phản, dưới xa ngưỡng 3,0 của nét vẽ. Dải
     #B0540A → #96470B cho icon trắng 5,10 và icon mờ 3,01.

     ⛔ PHẢI CÓ VẠCH PHÂN CÁCH RÕ. Cam đất và teal gần nhau về ĐỘ SÁNG (chỉ hơn
        kém 1,48 lần) — chúng khác nhau ở sắc chứ không ở sáng tối. Không vạch thì
        hai cột nhoè vào nhau thành một mảng nâu xỉn, mà người nhìn màu kém lại
        càng không tách nổi. Vạch tối bên phải làm ranh giới ấy hiện ra.
     ══════════════════════════════════════════════════════════════════════════ */
  #thanhCC .cc-rail { flex:none; width:44px; display:flex; flex-direction:column; gap:3px;
    padding:7px 6px;
    background:linear-gradient(180deg, var(--cc-rail-dinh) 0%, var(--cc-rail-day) 100%);
    border-right:1px solid rgba(0,0,0,.32);
    box-shadow:1px 0 4px rgba(0,0,0,.18); }
  /* ══════════════════════════════════════════════════════════════════════════
     ⛔⛔ LÚC CHỈ CÓ CỘT ICON THÌ ĐỪNG LỘ RA HAI THANH — cô Quỳnh 23/08/2026
     ──────────────────────────────────────────────────────────────────────────
     *"Thiết kế cái thanh công cụ sao cho lúc ấn trang chủ không lộ ra 2 thanh, mà
     tôi chỉ muốn 1 thanh bên trong cùng thôi; và cái thanh hẹp bé xíu đó bỏ đi
     hoặc mở rộng cái thanh trong cùng ra, đừng để kiểu chia cắt với 1 thanh hẹp thế."*

     ĐO THẬT 23/08/2026 (màn 1280, body `cc-gon man-cong-cu`):
       `.cc-panel` rộng **64px**, còn `.cc-rail` bên trong chỉ **52px**
       → thừa đúng **12px** của panel lộ ra bên phải cột icon,
       mà panel lại có nền gradient KHÁC và viền phải RIÊNG
         `.cc-rail`  viền phải 1px rgba(0,0,0,.32)
         `.cc-panel` viền phải 1px rgba(255,255,255,.20)
       → hai đường viền cách nhau 12px, nhìn đúng thành "hai thanh".

     CHỮA: lúc chỉ bày cột icon thì cho cột icon rộng ĐẦY panel và nhường việc kẻ
     viền cho panel. Một thanh, một đường viền.
     ⛔ CHỈ áp khi `.chi-rail`. Lúc thanh MỞ hẳn thì panel rộng 252px và danh sách
        công cụ nằm bên phải cột icon — khi ấy cột icon PHẢI giữ 52px và PHẢI có
        viền, không thì icon dính liền vào danh sách.
     ⛔ Đệm ngang lên 12px cho nút 40px nằm đúng giữa 64px (12+40+12=64); giữ 6px
        là icon lệch hẳn sang trái, nhìn còn lỗi hơn cũ.
     ══════════════════════════════════════════════════════════════════════════ */
  #thanhCC.chi-rail .cc-rail { width:100%; padding-left:12px; padding-right:12px;
    border-right:0; box-shadow:none;
    /* Ðệm co cùng nhịp với dải nền (.cc-panel cũng .2s ease) — xem lời dặn ở nút. */
    transition:padding .2s ease; }
  /* ⛔⛔ NÚT PHẢI ĐO THEO CỘT, ĐỪNG TỰ CHẠY MỘT NHỊP RIÊNG — vá 12/09/2026.
     Bản cũ: nút 32px ở trạng thái nghỉ, `width:100%` lúc rê chuột. Nghe thì tương
     đương, nhưng trình duyệt phải NỘI SUY từ `100%` về `32px`, mà `100%` lại tính
     theo `.cc-rail` — cái đang co. Hai đường cong chồng nhau nên nút TỤT NHANH HƠN
     nền, để hở một dải tối không chữ không nút.
     Đo thật (1366×900, rời chuột, ghi từng khung hình): hở tối đa 86,7px (lia ra
     sau 100ms) · 108px (250ms) · 108px (vào-ra-vào).
     ⇒ Cho nút `width:100%` ở CẢ HAI trạng thái: lúc nghỉ `.cc-rail` rộng đúng 32px
       (56 trừ 12+12 đệm) nên số đo không đổi một pixel, mà nút thì bám dính theo
       cột suốt cú co — hết hở.
     ⛔ Chỉ trong `.chi-rail`. Thanh mở hẳn có bố cục khác, `100%` ở đó là nút dài
        hết cột. */
  #thanhCC.chi-rail .cc-rail-nut { width:100%; }
  #thanhCC .cc-rail-nut { position:relative; flex:none; width:32px; height:32px;
    display:flex; align-items:center; justify-content:center; padding:0;
    border:1px solid transparent; border-radius:var(--r-md); background:transparent;
    color:var(--mo); cursor:pointer; font-family:inherit;
    /* ⛔⛔ PHẢI CÓ `width`/`padding`/`gap` TRONG DANH SÁCH — vá 12/09/2026.
       `#thanhCC.chi-rail:hover .cc-rail-nut` đổi `width` 32px ↔ 100%, nhưng nhịp
       cũ không khai `width` nên nút NHẢY MỘT PHÁT trong đúng một khung hình, trong
       khi `.cc-panel` bên ngoài còn co từ từ (`transition: width .2s ease`).
       Khoảng chênh ấy để lại một DẢI TỐI RỖNG — nền còn rộng mà không chữ không nút.
       Đo thật (1366×900, rời chuột): dải còn 142,7px kéo dài 116ms · 164px kéo dài
       149ms · ca vào-ra-vào 164px kéo dài 700ms.
       ⇒ Cho nút đi đúng .2s ease như dải nền thì hai thứ về cùng lúc, hết dải rỗng.
       ⛔ Khối `prefers-reduced-motion` bên dưới vẫn tắt sạch nhịp này — đừng gỡ. */
    transition:background .12s, color .12s, border-color .12s, transform .14s ease,
               width .2s ease, padding .2s ease, gap .2s ease; }
  /* ⛔ Gõ thẳng rgba trắng, KHÔNG `var(--the)`: `--the` trong thanh nay CHÍNH LÀ
     màu nền thanh, nên rê chuột vào sẽ "sáng lên" bằng đúng màu nền — không thấy gì. */
  /* 🪶 nền .12 → .07, và chữ/biểu tượng sáng hẳn lên — đúng gợi ý cô Quỳnh 02/09. */
  #thanhCC .cc-rail-nut:hover { background:rgba(255,255,255,.07); color:#fff;
    border-color:rgba(255,255,255,.24); }
  #thanhCC .cc-rail-nut:focus-visible { outline:none; border-color:var(--xanh); box-shadow:var(--vong); }
  /* ⛔ Ngăn ĐANG MỞ mang BỐN dấu hiệu cùng lúc (nền teal nhạt · viền teal · chữ
     teal đậm · vạch teal mép trái) — cùng lý do với block bộ phận cũ: ở nền tối
     nền nhạt gần như biến mất, còn ai nhìn màu kém thì vẫn còn viền và vạch. */
  /* ⛔⛔ VIẾT LẠI 23/08/2026 — ĐỌC LÝ DO ĐẦY ĐỦ Ở KHỐI `--cc-o-day-*` TRÊN KIA.
     Bản cũ đắp trắng mờ 16% lên nền và kẻ một vạch TEAL. Cả hai đều là cách làm
     đúng CHO NỀN TEAL; từ lúc nền cột đổi sang cam (22/08) thì nền nút chỉ còn hơn
     nền 1,33 lần và vạch teal tụt xuống 2,73 lần — dưới ngưỡng nhìn được. Cô Quỳnh
     báo ngay hôm sau: *"hay chọn nhầm trang chủ với giáo vụ"*.
     Nay nút đang đứng mang MÀU ĐẶC chứ không phải một lớp phủ mờ, nên nó không còn
     phụ thuộc nền cột nữa — đổi nền cột lần sau cũng không làm hỏng dấu này. */
  #thanhCC .cc-rail-nut.chon { background:var(--cc-o-day-nen); color:#fff;
    border-color:var(--cc-o-day-vien); box-shadow:none; }
  /* ══════════════════════════════════════════════════════════════════════════
     MỨC SÁNG THỨ HAI — "danh sách đang bày ngăn này", cô Quỳnh 22/08/2026
     ──────────────────────────────────────────────────────────────────────────
     Cột icon nay chở HAI thứ khác nhau:
         .chon      NƠI ĐANG ĐỨNG   — màn hình trước mắt là cái này
         .dang-bay  NGĂN ĐANG BÀY   — danh sách bên phải là của ngăn này
     Hai thứ ấy TÁCH NHAU RA được: đứng ở Trang chủ mà danh sách bày Tuyển sinh
     là chuyện thường ngày.

     ⛔ VÌ SAO PHẢI CÓ MỨC HAI — đo trên trình duyệt thật 22/08 bắt được: bản vá
        đầu cho nút làm việc "át" ngăn, nên bấm Tuyển sinh thì danh sách đổi mà
        icon không sáng lên. Nút bấm không phản hồi là lỗi nặng hơn hẳn chuyện
        hai nút cùng sáng — người ta bấm lại lần nữa, rồi tưởng app đơ.
     ⛔ NHẸ HƠN HẲN `.chon`, ĐỪNG LÀM ĐẬM LÊN: chỉ vạch teal mờ ở mép trái, không
        nền, không viền. Đậm ngang nhau là lại về đúng cảnh hai nút cùng sáng mà
        không phân biệt được cái nào là nơi mình đứng. */
  /* ⛔ 23/08/2026 — độ đục nâng .45 → .65. Cột icon nay sẫm hơn hẳn, mà vạch này là
     màu MỜ nên nó tự tối theo nền: đo trên nền mới chỉ còn 2,67 lần, dưới ngưỡng
     nét vẽ 3,0. Nâng lên .65 thì đạt 3,91 / 4,31 lần.
     Luật "nhẹ hơn hẳn .chon" ở trên VẪN GIỮ và nay còn dễ giữ hơn: `.chon` là một
     mảng cam ĐẶC, còn đây chỉ là một vạch teal mờ 2px — không cách nào lẫn. */
  #thanhCC .cc-rail-nut.dang-bay { color:rgba(255,255,255,.82);
    box-shadow:inset 2px 0 0 rgba(122,214,209,.65); }
  /* ══════════════════════════════════════════════════════════════════════════
     📋 NÚT CÔNG VIỆC — PHẢI THẤY NGAY, KHÔNG PHẢI DÒ. Cô Quỳnh 23/08/2026
     ──────────────────────────────────────────────────────────────────────────
     *"làm sao để nút công việc trở nên nổi bật hơn nữa vì nó là nút chắc chắn
     nhiều người ấn vào nhưng ko nên phải dò á."*

     ⛔ KHÔNG ĐƯỢC TÔ CAM. Cam trong thanh này đã mang đúng MỘT nghĩa — "nơi cô
        đang đứng" (`--cc-o-day-nen`). Mượn cam cho nút hay dùng là hỏng luôn cái
        dấu vừa dựng hôm nay để chữa chuyện bấm nhầm.
     ⛔ CŨNG KHÔNG mượn vạch teal mờ mép trái — đó là dấu "danh sách đang bày".
     Nên nút này mang dấu hiệu HÌNH THỨC KHÁC HẲN: nó là nút duy nhất trên cột
     LÚC NÀO CŨNG có nền và viền, tức trông ra "một cái nút" giữa những icon trơn.
     Số đo (WCAG, tự tính chứ không ướm):
        nền  #12616B nổi khỏi nền cột 1,67 lần (sáng) · 1,91 lần (tối)
        viền #14A0A0 — đúng teal của file logo — nổi 3,72 / 4,25 lần, trên ngưỡng
             nét vẽ 3,0 ở CẢ HAI chế độ nên dùng chung một bộ màu, khỏi lệch nhau
        chữ  trắng trên nền ấy được 7,12 lần
     ⛔ `:not(.chon)` là bắt buộc: lúc cô đang đứng ở Công việc thì ô cam phải đè
        lên, nếu không thì nút này thành cái duy nhất không cho biết mình đang mở. */
  #thanhCC .cc-rail-nut.cc-viec:not(.chon) {
    background:var(--cc-viec-nen); border-color:var(--cc-viec-vien); color:#fff; }
  #thanhCC .cc-rail-nut.cc-viec:not(.chon):hover {
    background:#17727E; border-color:#3FBFBF; }
  /* Tách khỏi nhóm bộ phận bên trên — mắt neo được vị trí, khỏi đếm từ đầu cột. */
  #thanhCC .cc-rail-nut.cc-viec { margin-top:8px; }
  /* 🔢 Số việc đang chờ, ngay trên nút. Đây mới là thứ khiến cô không phải dò:
     nhìn cột là biết có việc hay không, khỏi bấm vào xem.
     ⛔ Đỏ #C62828 CHỈ khi có việc QUÁ HẠN — cùng quy ước với `.cc-badge.do` trong
        danh sách, đừng đặt màu khác kẻo hai chỗ nói hai kiểu về cùng một việc. */
  #thanhCC .cc-rail-so { position:absolute; top:-4px; right:-4px; min-width:17px;
    height:17px; padding:0 4px; border-radius:var(--r-md); background:#0E7C86; color:#fff;
    border:1.5px solid var(--cc-rail-dinh); font-size:10.5px; font-weight:700;
    line-height:14px; text-align:center; pointer-events:none; }
  #thanhCC .cc-rail-so.do { background:#C62828; }
  #thanhCC .cc-rail-nut svg { width:22px; height:22px; flex:none; fill:none; stroke:currentColor;
    stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round; }
  /* Nút Tài khoản tụt xuống ĐÁY cột — nếp quen của mọi app có cột icon bên trái:
     thứ dùng hằng ngày ở trên, thứ về tài khoản ở dưới cùng. */
  #thanhCC .cc-rail-duoi { margin-top:auto; }
  /* 🏷 TÊN HIỆN KHI RÊ CHUỘT — cô Quỳnh: *"di chuột vào hiện tên nút đó lên để đỡ
     tốn diện tích"*.
     ⛔ Tự vẽ chứ KHÔNG dùng thuộc tính `title` của trình duyệt: `title` đợi gần
        một giây mới hiện, và chữ nó bé xíu theo hệ điều hành, không đổi được.
     ⛔ Nhãn nằm TRONG panel (panel 272 − rail 48 = 224px chỗ trống), vì
        `.cc-panel` có `overflow:hidden` — thò ra ngoài là bị cắt cụt.
     ⛔ `pointer-events:none`: nhãn nổi lên đè sang danh sách công cụ; không chặn
        thì rê chuột trúng nhãn là mất luôn cú bấm vào công cụ nằm dưới nó. */
  #thanhCC .cc-rail-ten { position:absolute; left:calc(100% + 7px); top:50%;
    transform:translateY(-50%); z-index:5; pointer-events:none;
    /* ⛔ Gõ thẳng, KHÔNG `var(--chu)`/`var(--the)`: trong thanh, `--chu` nay là
       trắng và `--the` là teal — cặp cũ hoá ra chữ teal trên nền trắng, chói và
       lạc hẳn tông. Nhãn nổi thì phải SẪM ĐẶC hơn cả nền thanh mới bật lên được. */
    /* ⛔ 23/08/2026 — TRẢ LẠI TEAL SẪM. Có một lượt đổi sang nâu sẫm #3A1B05 hồi
       bôi cam cả tấm thanh; nay chỉ CỘT ICON cam còn thân về teal, mà nhãn này
       bung ra BÊN PHẢI cột icon — tức nó nằm trên nền THÂN. Nền sau lưng nó là
       teal thì nhãn phải teal sẫm, để nâu là một mảng nâu lạc giữa vùng xanh. */
    background:#062A31; color:#FDF6F0; border:1px solid rgba(255,255,255,.20);
    box-shadow:0 2px 8px rgba(0,0,0,.35);
    font-size:12px; font-weight:500;
    padding:4px 9px; border-radius:var(--r-sm); white-space:nowrap;
    /* Tên BỘ PHẬN do người dùng tự đặt, có thể dài. Panel có `overflow:hidden` nên
       tên dài quá sẽ bị cắt cụt KHÔNG có dấu ba chấm — thà cắt có báo còn hơn. */
    max-width:190px; overflow:hidden; text-overflow:ellipsis;
    opacity:0; visibility:hidden; transition:opacity .12s; }
  #thanhCC .cc-rail-nut:hover .cc-rail-ten,
  #thanhCC .cc-rail-nut:focus-visible .cc-rail-ten { opacity:1; visibility:visible; }
  /* ⛔ NÚT ĐANG MỞ THÌ KHÔNG HIỆN NHÃN — cô Quỳnh 22/08 tối: *"nút giáo vụ TÊN BỊ
     TRÙNG"*. Tên ngăn đang mở đã in sẵn ở `.cc-ngan-ten` ngay dưới ô tìm; rê chuột
     vào đúng nút ấy lại hiện thêm một lần nữa, hai chữ y hệt nằm cách nhau vài chục
     điểm ảnh.
     ⛔ CHỈ ẩn nhãn của nút ĐANG MỞ. Các nút chưa mở vẫn phải hiện tên đầy đủ — bịt
        hết là quay lại đúng lỗi cô báo sáng nay (*"khó tìm được cái ô tuyển sinh ý"*),
        và `thu-giao-dien-nen-tang.js` đang canh chính điều đó. */
  #thanhCC .cc-rail-nut.chon:hover .cc-rail-ten,
  #thanhCC .cc-rail-nut.chon:focus-visible .cc-rail-ten { opacity:0; visibility:hidden; }
  /* Tên ngăn đang mở, đặt trên đầu danh sách. Đây KHÔNG phải nút — chỉ để biết
     mình đang đứng ở ngăn nào, vì icon bên rail chỉ nói tên khi rê chuột vào. */
  #thanhCC .cc-ngan-ten { font-size:12px; font-weight:600; color:var(--mo);
    padding:2px 9px 2px; }
  /* ⛔ Lề 10 → 8px (*"thu gọn lề"* — cô Quỳnh 22/08 lần 2). Mỗi bên bớt 2px là
     hàng công cụ được thêm 4px bề ngang, vừa đủ bù cho cỡ chữ tăng lên 14,5px. */
  #thanhCC .cc-than { flex:1; min-width:0; padding:7px; display:flex; flex-direction:column; gap:6px; overflow-y:auto; }
  #thanhCC .cc-tim { width:100%; box-sizing:border-box; padding:8px 10px;
    border:1px solid var(--vien); border-radius:var(--r-md);
    font-size:13px; font-family:inherit; background:var(--nen-o); color:var(--chu); }
  #thanhCC .cc-tim::placeholder { color:var(--mo); }
  /* Vòng sáng khi đang gõ — shadcn có ở mọi ô. Người dùng bàn phím trước đây gần
     như không nhận ra mình đang đứng ở ô nào. */
  #thanhCC .cc-tim:focus { outline:none; border-color:var(--xanh); box-shadow:var(--vong); }
  #thanhCC .cc-tim-boc { position:relative; }
  /* ⛔ `pointer-events:none`: nhắc phím nằm ĐÈ lên ô nhập, không chặn thì bấm trúng
     chữ "Ctrl K" là ô không nhận con trỏ — người dùng bấm mà không gõ được. */
  #thanhCC .cc-tim-phim { position:absolute; right:7px; top:50%; transform:translateY(-50%);
    pointer-events:none; font-family:inherit; font-size:10.5px; color:var(--mo);
    background:var(--nen2); border:1px solid var(--vien-nhe);
    border-radius:var(--r-sm); padding:2px 5px; line-height:1.3; }
  /* Đang gõ thì giấu đi, không thì chữ dài đâm vào nhắc phím. */
  #thanhCC .cc-tim:focus + .cc-tim-phim { display:none; }
  #thanhCC .cc-tim { padding-right:58px; }
  #thanhCC .cc-ds { display:flex; flex-direction:column; gap:2px; }
  /* 🏢 05/08 (cô Quỳnh): mục con là PHỤ → BÉ LẠI (bỏ khung, nền trong, thụt vào)
     để tiêu đề nhóm nổi lên làm block CHÍNH. */
  /* 🎨 22/08/2026 — HÀNG CÔNG CỤ theo nếp shadcn: cao hơn một chút cho dễ bấm,
     bo 8px, chữ 13px, rê chuột mới hiện nền.
     ⛔ Thụt trái chỉ còn 10px (trước 12px): nhãn nhóm nay không có khung nữa nên
        không cần thụt sâu để "chui vào trong hộp". */
  #thanhCC .cc-muc { display:flex; align-items:center; gap:10px; text-align:left;
    background:transparent; border:1px solid transparent; border-radius:var(--r-md);
    /* ⛔⛔ 13,5px/500 — ĐÃ TRẢ VỀ ĐÚNG BẢN CÔ QUỲNH ƯNG, ĐỪNG TĂNG NỮA.
       Đường đi của con số này: 12,5 → 13 → 13,5 (cô ưng) → 14,5 (cô CHÊ) → 13,5.
       Nguyên văn 22/08: *"cho về font chữ của thanh công cụ trước đó mà tôi bảo tôi
       ưng… chứ font chữ của thanh công cụ bây h bạn thiết kế đậm nét quá mức rồi"*.
       ⛔ Thủ phạm thật KHÔNG chỉ là 14,5px. Nền vừa đổi từ TRẮNG sang XANH SẪM, mà
          chữ sáng trên nền sẫm thì trình duyệt vẽ nở ra, nhìn dày hơn hẳn cùng một
          nét — hiện tượng loang sáng. Vì thế ngoài việc hạ cỡ chữ còn phải tắt
          kiểu vẽ dày ở khối `#thanhCC` (xem `-webkit-font-smoothing` trong bảng màu).
          Chỉ hạ cỡ mà quên chỗ kia là vẫn còn dày.
       ⛔ Nét giữ 500, KHÔNG lên 600: hàng ĐANG MỞ cần 600 làm dấu riêng của nó. */
    padding:6px 9px; font-size:13.5px; font-weight:500; color:var(--chu);
    cursor:pointer; white-space:normal; }
  /* 🔍 Nhích to khi lia chuột — cô Quỳnh 22/08: *"Các nút công cụ trong thanh công
     cụ tôi muốn nó có chút zoom ra khi lia chuột vào."*
     ⛔ 1,02 thôi. Hàng công cụ nằm sát nhau trong một cột hẹp; phóng mạnh là chữ
        nhoè và hàng này đè lên hàng kia.
     ⛔ `transform-origin:left center` — nở về BÊN PHẢI, giữ nguyên mép trái. Nở ra
        hai bên thì icon lấn qua mép thanh, nhìn như bị lệch. */
  #thanhCC .cc-muc { transition:background .12s, transform .14s ease, border-color .12s;
    transform-origin:left center; }
  #thanhCC .cc-muc:hover { background:color-mix(in srgb, var(--nen2) 55%, transparent);
                           color:var(--chu); transform:scale(1.02); }
  /* ⛔⛔ `z-index:6` LÀ THUỐC CHỮA, ĐỪNG XOÁ — cô Quỳnh 22/08 tối: *"nút giáo vụ
     tên bị trùng và ĐÈ LÊN thanh tìm kiếm công cụ"*.
     Chuyện xảy ra thế này, và nó tinh vi:
       · `transform` khác `none` TẠO RA MỘT LỚP VẼ RIÊNG trên chính cái nút. Từ lúc
         đó, `z-index:5` của nhãn `.cc-rail-ten` bị NHỐT trong nút, không còn so
         được với thứ gì bên ngoài.
       · Cả cụm nút+nhãn tụt xuống vẽ ở mức của NÚT. Mà `.cc-tim-boc` (ô tìm) cũng
         `position:relative`, lại đứng SAU trong cây HTML → ô tìm vẽ ĐÈ lên nhãn.
       · Nền ô nhập là `rgba(255,255,255,.10)`, gần như trong suốt, nên chữ "Giáo vụ"
         vẫn hiện xuyên qua và chồng lên chữ "Tìm công cụ…". Đúng cảnh trong ảnh cô gửi.
     ⛔ Dấu vân tay để nhận ra loại lỗi này: đi bằng BÀN PHÍM (Tab) thì KHÔNG hỏng,
        vì `:focus-visible` không có `transform`. Rê chuột mới hỏng.
     ⛔ Vì thế: THÊM `transform` cho phần tử nào có con nổi lên trên thì phải cấp
        `z-index` cho nó cùng lúc. Nhớ luật này, đừng nhớ mỗi ca cụ thể. */
  #thanhCC .cc-rail-nut:hover { transform:scale(1.09); z-index:6; }
  /* Máy đặt "ít chuyển động" thì bỏ hẳn phần nhích — vẫn đổi nền nên không mất
     dấu hiệu nào. */
  @media (prefers-reduced-motion: reduce) {
    /* ⛔ Thêm `.cc-rail` 12/09/2026 cùng lượt vá "dải tối rỗng": nay đệm của nó
       cũng chạy nhịp .2s, mà máy đặt ít chuyển động thì không được chạy nhịp nào. */
    #thanhCC .cc-muc, #thanhCC .cc-rail-nut, #thanhCC .cc-rail { transition:none; }
    #thanhCC .cc-muc:hover, #thanhCC .cc-rail-nut:hover { transform:none; }
  }
  /* ⭐ CÔNG CỤ ĐANG MỞ — thứ shadcn nào cũng có mà app mình chưa hề có.
     Không biết mình đang đứng ở đâu là lỗi dùng được, không phải lỗi thẩm mỹ:
     app có hơn 30 công cụ, mở một cái xong quay lại thanh bên thì không dấu vết gì.
     ⛔ Tô bằng NỀN + CHỮ ĐẬM chứ không bằng màu chữ teal: hàng teal giữa danh sách
        xám trông như một đường siêu liên kết, người ta tưởng bấm được sang chỗ khác. */
  /* 🎨 Hàng đang mở mang màu trung tâm: nền teal rất nhạt, chữ teal đậm, và một
     vạch teal mép trái. Ba thứ cùng lúc để ở nền tối cũng thấy (nền tối thì nền
     nhạt gần như biến mất, còn vạch thì vẫn rõ).
     ⛔ Chữ dùng `--muc` (#0D8081 teal ĐẬM) chứ không dùng `--xanh` (#14A0A0):
        #14A0A0 trên nền #E8F5F5 chỉ đạt tương phản ~2,9 lần, đọc không nổi. */
  #thanhCC .cc-muc.dang-o { background:var(--xanh-nhat); color:var(--muc);
    font-weight:600; box-shadow:inset 2px 0 0 var(--xanh); }
  #thanhCC .cc-muc.dang-o .cc-ico { color:var(--muc); }
  body.toi #thanhCC .cc-muc.dang-o { color:var(--muc); }
  /* 🎯 05/08 — icon nét mảnh dùng ở phần NỘI DUNG (tiêu đề khối Trang chủ…) */
  /* 👔 05/08 — icon nhỏ trong NHÃN và trong NÚT (trang Quản lý tài khoản) */
  .ico-the { width:12px; height:12px; fill:none; stroke:currentColor; stroke-width:2;
    stroke-linecap:round; stroke-linejoin:round; vertical-align:-2px; margin-right:4px; }
  .ico-nut { width:15px; height:15px; fill:none; stroke:currentColor; stroke-width:1.8;
    stroke-linecap:round; stroke-linejoin:round; vertical-align:-3px; margin-right:6px; }
  .ico { width:17px; height:17px; flex:none; fill:none; stroke:currentColor;
    stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round;
    vertical-align:-3px; margin-right:7px; color:var(--muc); }
  /* 🎯 05/08 — ICON NÉT MẢNH đơn sắc thay emoji: ăn theo màu chữ, đậm lên khi rê/chọn */
  /* ⛔ 22/08/2026 — nét 1,7 → 1,9 và màu `--mo` → `--chu`. Icon nhạt hơn chữ mà
     lại đứng ĐẦU DÒNG thì mắt đọc cả hàng theo cái nhạt nhất; đây là lý do chính
     khiến cả thanh trông mờ. Nay icon và chữ cùng một tông, cùng một độ đậm.
     ⛔ Rê chuột / hàng đang mở vẫn đổi icon sang teal — hai luật ngay dưới lo việc
        đó, đừng gộp màu vào đây. */
  #thanhCC .cc-ico { flex:none; width:17px; height:17px; fill:none; stroke:currentColor;
    stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round; color:var(--chu); }
  #thanhCC .cc-muc:hover .cc-ico { color:var(--muc); }
  #thanhCC .cc-muc.cc-tk.do .cc-ico { color:var(--do); }
  #thanhCC .cc-muc.keo-qua { border-color:var(--xanh); border-style:dashed;
    background:rgba(255,255,255,.16); }
  #thanhCC .cc-muc.dang-keo { opacity:.45; }
  #thanhCC .cc-keo { flex:none; color:var(--mo); cursor:grab; font-size:15px; line-height:1;
    padding:2px 1px; user-select:none; }
  #thanhCC .cc-keo:active { cursor:grabbing; }
  /* ⭐ 20/09/2026 — NHÃN DÀI XUỐNG HAI DÒNG. Boss chọn bằng nút bấm: thanh hẹp lại
     thì tên dài "cho xuống hai dòng", chứ không cắt bằng dấu ba chấm — cắt thì phải
     rê chuột mới đọc được tên đầy đủ, mà trên điện thoại thì không rê được.
     `min-width:0` để chữ được phép ngắt: thiếu nó thì ô con trong flex giữ nguyên
     bề ngang nội dung và đẩy cả thanh rộng ra, đúng cái ta đang muốn bỏ. */
  #thanhCC .cc-nhan { flex:1; min-width:0; white-space:normal;
    overflow-wrap:anywhere; line-height:1.3; }
  #thanhCC .cc-trong { font-size:12px; color:var(--mo); font-style:italic; padding:6px 2px; }
  #thanhCC .cc-sapco { font-size:11.5px; color:var(--mo); line-height:1.55; padding:8px 4px 4px;
    border-top:1px dashed var(--vien); margin-top:2px; white-space:normal; }
  /* 🗂️ 03/08 — NHÓM thu/mở được (folder) + mục Tài khoản/Quản lý (không có tay kéo). */
  #thanhCC .cc-nhom { display:flex; flex-direction:column; gap:4px; }
  /* 🏢 05/08 (cô Quỳnh): TIÊU ĐỀ NHÓM = BLOCK CHÍNH — to, đậm, có nền + khung,
     bấm để thu/mở; các mục bên dưới là phụ nên bé hơn hẳn. */
  /* 🎨 22/08/2026 — NHÃN NHÓM BỎ KHUNG.
     Đây là điểm khác NHÌN RA NGAY giữa thanh cũ và bốn ảnh cô Quỳnh gửi: bên
     shadcn "Overview · Planning · Account · Documents" đều là chữ xám bé trần
     trụi; bên mình chúng bị bọc trong hộp xám có viền.
     ⛔ Hộp xám ấy nặng hơn chính các công cụ nằm dưới nó — tức là nhãn hút mắt hơn
        nội dung. Ngược hẳn với việc nhãn phải làm.
     ⛔ VẪN LÀ NÚT BẤM ĐƯỢC (thu/mở nhóm) nên vẫn phải có phản hồi khi rê chuột và
        vẫn phải bấm trúng được — vùng bấm giữ nguyên cả chiều ngang. */
  #thanhCC .cc-nhom-ten { display:flex; align-items:center; gap:6px; width:100%; text-align:left;
    background:transparent; border:1px solid transparent; border-radius:var(--r-sm);
    cursor:pointer; font-family:inherit;
    font-size:11.5px; font-weight:600;
    color:var(--mo); padding:6px 10px 4px; margin-top:14px; }
  #thanhCC .cc-nhom:first-child .cc-nhom-ten { margin-top:2px; }
  #thanhCC .cc-nhom-ten:hover { background:transparent; border-color:transparent; color:var(--chu); }
  /* 🏢 13/08/2026 — BLOCK BỘ PHẬN. Chỉ hiện khi người đó dùng công cụ của từ 2 bộ
     phận trở lên; ai một bộ phận thì thanh bên y hệt cũ.
     ⛔ Cố ý KHÔNG vẽ thẻ to có mô tả: thanh bên chỉ rộng 252px, nhét thẻ to là
        dính đúng lời cô chê 11/08 *"trông cứ bị thừa ra nhiều khoảng trắng"*.
        Dùng lại đúng cái đầu nhóm sẵn có, thêm một vạch teal bên trái cho biết
        đang mở cái nào. Mọi màu đi qua var() — tô cứng là nền tối vỡ. */
  /* 🏢 22/08/2026 — BỘ PHẬN KHÔNG PHẢI NHÃN, NÓ LÀ NÚT CHUYỂN.
     Nhãn nhóm bên trên đã bỏ khung, nhưng đầu block BỘ PHẬN thì phải giữ hình hài
     một hàng bấm được — vì bấm vào nó là ĐỔI CẢ DANH SÁCH CÔNG CỤ, không phải chỉ
     thu/mở cho gọn. shadcn cũng phân biệt đúng như vậy: nhãn là chữ trần, còn thứ
     bấm được là một hàng có nền.
     ⛔ Đừng gộp hai cái làm một cho gọn mã. Gộp là mất dấu hiệu "bấm được", mà
        người dùng nhiều bộ phận thì đây là nút họ bấm nhiều nhất. */
  #thanhCC .cc-ban > .cc-nhom-ten { font-size:13.5px; font-weight:600; color:var(--chu);
    padding:9px 11px; margin-top:6px; border-radius:var(--r-md);
    background:var(--the); border:1px solid var(--vien); box-shadow:var(--bong-1); }
  #thanhCC .cc-ban > .cc-nhom-ten:hover { background:var(--nen2); border-color:var(--vien); }
  /* Nhãn "Bộ phận" đứng trên hai nút — không có nó thì hai cái nút đứng trơ ở đầu
     thanh, chẳng cho biết chúng là gì và bấm vào thì đổi cái gì. */
  #thanhCC .cc-ban-nhan { font-size:11.5px; font-weight:600; color:var(--mo);
 padding:2px 10px 4px; }
  /* ⛔ Vạch teal bên trái = "đang mở bộ phận này". Bài kiểm thu-block-bo-phan.js
     canh đúng dòng này, và canh cả việc màu phải đi qua var() — tô cứng là nền
     tối vỡ. Đừng đổi sang màu thẳng. */
  /* ⛔ Bộ phận ĐANG MỞ: nền teal nhạt + viền teal + chữ teal đậm + vạch teal.
     Bốn dấu hiệu cùng lúc là cố ý — ở nền tối thì nền nhạt gần như biến mất, còn
     ai nhìn màu kém thì vẫn còn cái viền và cái vạch. */
  #thanhCC .cc-nhom-ten.chon { background:var(--xanh-nhat); color:var(--muc);
    border-color:var(--xanh);
    box-shadow:inset 2px 0 0 var(--xanh); font-weight:600; }
  #thanhCC .cc-nhom-ten.chon:hover { background:var(--xanh-nhat); border-color:var(--xanh); }
  /* Hàng chọn bộ phận trên tấm trượt điện thoại. */
  .tts-ban { display:flex; gap:6px; padding:0 12px 8px; flex-wrap:wrap; }
  .tts-ban-nut { flex:1; min-width:110px; border:1px solid var(--vien);
    border-radius:var(--r-md);
    background:var(--the); color:var(--chu); font-family:inherit; font-size:13px;
    font-weight:500; padding:9px 12px; cursor:pointer; }
  .tts-ban-nut.chon { border-color:var(--xanh); color:var(--chu); background:var(--nen2);
    font-weight:600; box-shadow:inset 2px 0 0 var(--xanh); }
  #thanhCC .cc-ban-trong { padding:9px 12px; font-size:12.5px; color:var(--mo); line-height:1.5; }
  #thanhCC .cc-nhom-muc { padding-left:2px; }
  #thanhCC .cc-nhom-mui { display:inline-block; transition:transform .15s; font-size:11px; color:var(--mo); }
  #thanhCC .cc-ban > .cc-nhom-ten .cc-nhom-mui { font-size:12px; color:inherit; }
  #thanhCC .cc-nhom.dong .cc-nhom-mui { transform:rotate(-90deg); }
  #thanhCC .cc-nhom-muc { display:flex; flex-direction:column; gap:2px; margin-top:4px; }
  #thanhCC .cc-nhom.dong .cc-nhom-muc { display:none; }
  /* ⛔ 22/08/2026 — BỎ KHUNG ĐỎ quanh "Đăng xuất". Trong thanh bên shadcn, hàng
     nguy hiểm chỉ khác ở MÀU CHỮ; đóng khung nó lại là biến hàng cuối cùng thành
     thứ nặng nhất cả thanh, trong khi nó là hàng người ta bấm ít nhất.
     ⛔ Nền khi rê chuột dùng `--do-nen` (biến sẵn có) chứ không gõ thẳng #FDECEC —
        màu gõ thẳng thì nền tối thành mảng hồng chói. */
  /* Nút Đăng xuất trong bảng Cài đặt — đỏ nhạt, viền đỏ, không phải khối đỏ đặc:
     nó nằm cuối một trang toàn nút xám, đỏ đặc ở đó là quá to tiếng. */
  .cd-nut.cd-nut-do { color:var(--do); border-color:var(--do); }
  .cd-nut.cd-nut-do:hover { background:var(--do-nen); border-color:var(--do); }
  #thanhCC .cc-muc.cc-tk.do { color:var(--do); border-color:transparent; }
  #thanhCC .cc-muc.cc-tk.do:hover { background:var(--do-nen); }
  /* 👤 02/09/2026 — AVATAR GÓC PHẢI BẬT LẠI. Cô Quỳnh: *"cái logo avatar ở góc
     bên phải"*. Luật cũ 03/08 (`#tkBoc { display:none !important }`) đã gỡ.
     ⛔ ĐỪNG dựng lại luật ẩn ấy. Lý do nó tồn tại — *"nhìn tên ở sảnh + thanh là
        đủ"* — đã hết hiệu lực: danh thiếp trong thanh bên vừa bị bỏ cùng lượt này.
        Ẩn ô này bây giờ là app không còn chỗ nào cho biết đang đăng nhập bằng ai,
        và mất luôn menu Đổi mật khẩu / Liên kết Gmail / Đăng xuất nằm trong nó. */
  /* 🖥️ MÁY TÍNH: thanh mở SẴN, ẩn nút mở/đóng; TÁCH rõ khỏi nội dung (bo góc phải +
     bóng) và nội dung NÉ XA hơn cho đỡ sát/rối (cô Quỳnh 03/08). */
  @media (min-width:821px) {
    #thanhCC .cc-toggle { display:none; }

    /* ══════════════════════════════════════════════════════════════════════
       🔝 THANH TRÊN CÙNG KIỂU SUPABASE — cô Quỳnh 02/09/2026
       *"Toàn bộ phần thanh trên cùng gắn vào cái thanh công cụ… nhìn thiết kế
        thanh trên cùng của supabase bạn làm y hệt cho tôi."*
       Ảnh cô gửi: thanh trên chạy SUỐT bề ngang, cao 48px, dính đỉnh; cột công
       cụ bắt đầu BÊN DƯỚI nó. Hàng thứ hai (dải thẻ bảng) thì không chạy suốt —
       nên dải nút công cụ của app giữ nguyên chỗ, đúng như Supabase.
       ⛔ VẠCH TEAL 2px Ở ĐÁY GIỮ NGUYÊN — luật cô Quỳnh 22/08/2026, đó là màu
          nhận diện MyPAS chứ không phải nét trang trí.
       ⛔ 48px GÕ CỨNG, CỐ Ý. Cột công cụ phải biết mình bắt đầu từ đâu ngay từ
          khung hình đầu; đo động bằng biến CSS thì lúc JS chưa kịp đo, cột đè
          lên thanh một nhịp rồi mới nhảy xuống.
       ⛔ z-index 11002 = trên panel (11001) đúng một bậc. Đừng nâng thêm: cao
          hơn nữa là đè cả hộp thoại.
       ⛔ Không áp cho `body.dang-trong-lop` — ở đó thanh công cụ ẩn hẳn và thanh
          trên có bộ luật gọn riêng của màn nhập điểm. */
    body:not(.dang-trong-lop) .thanh-tren {
      position:fixed; top:0; left:0; right:0; z-index:11002;
      height:48px; box-sizing:border-box; padding:0 18px; margin:0;
      /* 🟢 02/09/2026 — 3px, xem lý do ở dòng gốc của .thanh-tren. */
      max-width:none; border:0; border-bottom:5px solid var(--xanh);
      border-radius:0; box-shadow:none; }
    body:not(.dang-trong-lop) #thanhCC .cc-panel { top:48px; }
    /* 🏢 02/09/2026 — LOGO GỌN LẠI CHO VỪA DẢI 48px.
       Bản đầy đủ cao ~42px (chữ 23px + khẩu hiệu 8,5px + đệm), nhét vào dải 48px
       thì chạm cả mép trên lẫn mép dưới, nhìn như bị kẹt. Supabase để đúng một
       dòng chữ hiệu ở góc trái, không kèm khẩu hiệu — làm theo.
       ⛔ KHÔNG đụng màu: "My" cam + "PAS" teal giữ nguyên tuyệt đối. Chỉ đổi cỡ.

       🔄 03/09/2026 — CÔ QUỲNH XIN TRẢ KHẨU HIỆU VỀ (chọn bằng nút bấm, sau khi
       báo *"cái chỗ logo mypas đang bị sai"*). Lý do bỏ đi hôm qua vẫn đúng — bản
       ĐẦY ĐỦ cao 42px thì kẹt thật — nên đây KHÔNG phải bỏ luật cũ mà là thu nhỏ
       cả cụm cho vừa: 17px + 7,5px + 2px đệm = 26,5px, nằm gọn giữa dải 43px (48px
       trừ 5px vạch teal), còn dư 8px mỗi bên.
       ⛔ ĐỪNG trả `.ten` về 23px rồi mới thêm khẩu hiệu — cộng lại là 33px, cụm
          logo chạm sát vạch teal, đúng cái "nhìn như bị kẹt" đã tránh hôm qua.
       ⛔ `white-space:nowrap` của `.cham` (luật gốc) PHẢI giữ: khẩu hiệu xuống dòng
          là cụm cao gấp đôi và thanh vỡ bố cục. */
    body:not(.dang-trong-lop) .thanh-tren .logo-mypas .ten { font-size:17px; }
    body:not(.dang-trong-lop) .thanh-tren .logo-mypas .cham {
      display:block; font-size:7.5px; letter-spacing:.04em; margin-top:2px; }
    body:not(.dang-trong-lop) #app { padding-top:48px; }
    /* ⛔ 02/09/2026 — nút ba gạch "Ẩn thanh" cũng đi luôn trên máy tính. Cô Quỳnh
       bỏ hẳn việc thu thanh; để nút lại thì bấm chẳng ra gì, người dùng tưởng treo.
       Trên điện thoại nó vẫn hiện và vẫn đóng được tấm trượt — đừng gỡ chỗ đó. */
    #thanhCC .cc-dong { display:none; }
    /* 02/09/2026 — nút đóng đã ẩn ở đây từ trước, mà ảnh + tên cũng vừa ẩn nốt,
       nên cái vỏ chỉ còn là một vệt trống có viền. Ẩn luôn. */
    #thanhCC .cc-dau { display:none; }
    /* 🏢 05/08 (cô Quỳnh: "giống app business, thanh trái NỐI LIỀN với các block"):
       thanh điều hướng DÍNH SÁT mép trái, CAO HẾT màn, KHÔNG bo góc, chỉ 1 vạch
       ngăn — nội dung nằm liền kề bên phải như app quản trị chuyên nghiệp. */
    /* ⛔ 22/08/2026 — 252 → 300px, cộng thêm đúng bằng cột rail (48px). Danh sách
       công cụ vẫn rộng 252px như trước, không bị hẹp đi vì cột rail mới.
       ⛔ `padding-left` của #app ngay dưới PHẢI đổi cùng con số, không thì nội
          dung trang nằm đè lên thanh (hoặc chừa một dải trắng).

       ⭐⭐ 20/09/2026 — THÔI GHIM CỨNG, ĐỂ APP TỰ ĐO THEO CHỮ.
       Boss: *"thiết kế lại cho tôi cái thanh công cụ… hẹp lại ngang với chữ đi vì
       nó chiếm diện tích bảng quá"*, và chọn bằng nút bấm: **app tự đo theo chữ
       dài nhất**.
       Đo thật 20/09 (Chrome, 1600px): nhãn dài nhất là "Yêu cầu của giáo viên" =
       132px ở cỡ chữ 13,5px, mà panel đang 276px → THỪA 144px, hơn gấp đôi phần
       chữ thật sự cần. Đó là 144px bề ngang bị lấy mất của bảng, trên mọi màn.
       ⛔⛔ HAI SỐ NÀY PHẢI LUÔN BẰNG NHAU, nên nay CHUNG MỘT BIẾN `--cc-rong`:
          panel rộng bao nhiêu thì `#app` phải chừa đúng bấy nhiêu. Ghi hai con số
          rời như trước là sớm muộn sửa một chỗ quên chỗ kia — chính khối chú thích
          bên trên đã phải dặn điều đó bằng tay.
       `--cc-rong` do `ccDoBeRongThanh()` trong js/tinh-nang.js đặt, sau khi đo nhãn
       thật. Số dưới đây chỉ là bản dự phòng cho lúc JS chưa kịp chạy. */
    #thanhCC .cc-panel, #thanhCC.mo .cc-panel { width:var(--cc-rong, 235px);
      left:0; top:0; bottom:0; max-height:none;
      border-radius:0; border:0; border-right:1px solid var(--vien);
      box-shadow:none; }
    /* ⛔⛔ LUẬT GẤP PHẢI NẰM Ở ĐÂY, TRONG CHÍNH KHỐI NÀY — và không được đòi `.mo`.
       Bản đầu chỉ có một dòng `#thanhCC.chi-rail.mo .cc-panel{width:64px}` đặt tít
       trên, ngoài mọi `@media`. Từ 821px trở lên, thanh là cột dính bên trái và
       KHÔNG mang lớp `.mo` — nên luật ấy chẳng bao giờ khớp, panel cứ 304px, gấp
       chỉ là gấp trên giấy. Nó lại còn nằm trong suốt nên nhìn tưởng gấp thật, mà
       thực ra vẫn ăn hết cú bấm ở dải 0–303px.
       (Phép đo đầu tiên của tôi cũng nói "gấp rồi, 64px" — vì chính đoạn đo tự thêm
       `.mo` vào trước khi đo. Tự dựng điều kiện cho luật của mình rồi đo, thì đo
       cái gì cũng đạt.)
       Đặt SAU dòng 304px ở trên: hai bên cùng độ mạnh (một id + hai lớp), đứng sau
       thì thắng. */
    /* ⭐ 18/09/2026 — Boss xin thu hep cot icon de bang co them cho:
       *"thu hẹp lại thanh công cụ của app 1 chút cho nó hẹp lại sát bó chữ
       vào để có nhiều vị trí chỗ bảng dữ liệu"*. 56 -> 48px.
       ⛔ DUNG HA DUOI 48px. Day dung bang dich bam toi thieu cua Google
          (44px cua Apple con thap hon). Duoi nguong ay la bam truot tay,
          va khong mot bai kiem nao bat duoc — chi nguoi dung that thay.
       ⛔ Chi bop LE hai ben, GIU NGUYEN co icon (Boss chot), nen icon van
          de nhin de bam nhu cu. */
    /* ⛔ 18/09 LUOT SAU — TRA VE 56px. Toi ha xuong 48px theo con so Boss
       chon, nhung DO THAT tren man cho thay nut icon trong cot chi con rong
       23px — hep hon ca cai icon 22px nam trong no. Boss: *"cái thanh công
       cụ này bị bé quá mức bẹp dí"*, va *"các màn hình chỉ có thanh đó thì
       cho rộng hơn nha"*.
       ⛔ DUNG HA LAI XUONG 48px DE "DUOC THEM CHO". Cho cho bang da lay o
          cho khac roi: le ngang cua tam noi dung 20px -> 8px. Ha cot icon
          nua la bop dung cai khong con gi de bop. */
    #thanhCC.chi-rail .cc-panel { width:56px; }
    /* ⛔ Chung biến với `.cc-panel` ngay trên — xem khối chú thích ở đó. Hai con
       số này mà lệch nhau là nội dung đè lên thanh, hoặc chừa một dải trắng. */
    body:not(.dang-trong-lop) #app { padding-left:var(--cc-rong, 235px); }
    /* ⭐⭐ 23/08/2026 — GẤP THANH THÌ NỘI DUNG PHẢI GIÃN THEO.
       Cô Quỳnh xin gấp thanh là để *"cho trang chủ giộng ra nhìn dễ hơn"*. Gấp mà
       quên dòng này thì thanh co lại còn 64px nhưng nội dung vẫn chừa nguyên 304px
       — người ta được đúng một dải trắng rỗng bên trái, không rộng thêm một milimét.
       Đo trên trình duyệt thật: thiếu dòng này, Trang chủ giữ y nguyên bề ngang.
       ⛔ Selector phải mạnh hơn dòng trên (thêm `#thanhCC.chi-rail ~` không dùng được
          vì #app không phải anh em sau nó) — nên dùng `body.cc-gon`. */
    body.cc-gon:not(.dang-trong-lop) #app { padding-left:56px; }
    /* ══════════════════════════════════════════════════════════════════════════
       ⭐⭐ 02/09/2026 — CỘT ICON NỞ RA KHI RÊ CHUỘT, ĐỌC ĐƯỢC TÊN TỪNG NÚT
       ──────────────────────────────────────────────────────────────────────────
       CÔ QUỲNH: *"tôi muốn bạn giúp tôi thiết kế cho cái thanh trong cùng đó lúc
       di chuột vào thì cái thanh đó sẽ mở rộng ra để mọi người đọc được tên của
       icon đó công cụ đó (chứ bây giờ thấy mỗi cái icon tôi cảm thấy rất khó sử
       dụng)"*. Cô lấy mẫu từ thanh bên của Supabase.

       ⛔⛔ ĐÈ LÊN NỘI DUNG, KHÔNG ĐẨY — chính cô chọn khi tôi hỏi. `.cc-panel` là
          `position:fixed` nên nới bề ngang của nó KHÔNG đụng vào dòng chảy trang;
          chỗ nội dung chừa ra do `body.cc-gon #app{padding-left:64px}` ngay trên
          quyết định, và dòng ấy GIỮ NGUYÊN 64px. Bảng đang xem đứng yên tuyệt đối.
          ⛔ ĐỪNG "sửa cho gọn" bằng cách đổi padding ấy theo hover: mỗi lần chuột
             đi ngang cột là cả bảng nhảy 150px, mất luôn chỗ đang đọc.

       ⛔ CHỈ Ở `.chi-rail`. Lúc thanh mở hẳn thì danh sách công cụ đã nằm sẵn bên
          phải cột icon — nở thêm nữa là đè lên chính nó.
       ⛔ `@media (hover:hover)`: máy cảm ứng KHÔNG có trạng thái rê chuột. Thiếu
          dòng này thì trên iPad chạm một cái là cột nở ra rồi nằm nở luôn cho tới
          khi chạm chỗ khác — người dùng tưởng app kẹt.
       ⛔ Độ mạnh: `#thanhCC.chi-rail:hover` (1 id + 2) ăn đứt `#thanhCC.chi-rail`
          (1 id + 1) nên KHÔNG phụ thuộc thứ tự dòng — nhưng vẫn đặt ở đây, ngay
          dưới hai luật nó ghi đè, để người sau đọc một mạch là hiểu.
       ⛔ ĐỪNG đụng `#thanhCC.chi-rail .cc-rail { … }` ở dòng 7459: bài kiểm
          `thu-dien-diem-toan-man.js` ghi ĐÚNG TỪNG CHỮ luật ấy. Ở đây chỉ THÊM.
       ══════════════════════════════════════════════════════════════════════════ */
    @media (hover:hover) {
      #thanhCC.chi-rail:hover .cc-panel { width:164px; }
      /* Nút giãn hết bề ngang và xếp icon-rồi-chữ, thay vì ô vuông 40px giữa cột. */
      #thanhCC.chi-rail:hover .cc-rail { align-items:stretch; padding-left:8px; padding-right:8px; }
      #thanhCC.chi-rail:hover .cc-rail-nut { width:100%; justify-content:flex-start;
        gap:11px; padding:0 9px; }
      /* ⛔ TẮT phóng to 1.09 lần lúc rê chuột. Với ô vuông 40px nó là một hiệu ứng
         nhỏ; với một hàng dài hết cột thì cả hàng phình ra khỏi mép, trông như lỗi. */
      #thanhCC.chi-rail:hover .cc-rail-nut:hover { transform:none; }
      /* Nhãn thôi làm thẻ nổi bên cạnh, trở về nằm THẲNG HÀNG trong nút. Phải gỡ
         hết dáng "thẻ nổi" (nền, viền, bóng, đệm) chứ không chỉ bật hiện lên. */
      #thanhCC.chi-rail:hover .cc-rail-ten { display:block; position:static;
        transform:none; opacity:1; visibility:visible;
        background:none; border:0; box-shadow:none; padding:0;
        max-width:none; font-size:13px; font-weight:500; color:inherit;
        overflow:hidden; text-overflow:ellipsis; }
      /* ⛔ NÚT ĐANG MỞ CŨNG PHẢI HIỆN TÊN. Luật cũ giấu nhãn của nút `.chon` để
         khỏi trùng với tiêu đề ngăn bên phải — nhưng ở `chi-rail` KHÔNG có cột bên
         phải, nên giấu đi là đúng cái nút người ta đang đứng lại thành ô câm. */
      #thanhCC.chi-rail:hover .cc-rail-nut.chon:hover .cc-rail-ten,
      #thanhCC.chi-rail:hover .cc-rail-nut.chon .cc-rail-ten { opacity:1; visibility:visible; }
      /* Số việc: rời góc trên-phải của ô vuông về cuối hàng, kẻo đè lên chữ. */
      /* ⛔⛔ SỐ GHIM LÊN GÓC BIỂU TƯỢNG, KHÔNG dồn về cuối hàng — vá 03/09/2026.
         Boss: *"cái số báo đỏ ở lịch giáo viên đang bị đè lên chữ gây mất thẩm mĩ,
         thiếu đi sự chuyên nghiệp"*.

         ĐO THẬT (Playwright, 25 lớp trống người dạy nên số hiện "40"):
           nút 8→155px (rộng 147) · chữ "Lịch giáo viên" 51→131,8 · số 123,9→146
           → 7,9px chữ nằm DƯỚI con số.

         ⛔ ĐÃ THỬ CÁCH KIA VÀ BỎ: cho số vào dòng chảy (`position:static;
            margin-left:auto`) thì hết đè thật, nhưng nhãn phải co còn 60,9px trong
            khi chữ cần 80,8px → "Lịch giáo v…". Ở bề rộng 147px thì
            8+22+10+80,8+10+22 = 152,8 > 147: biểu tượng, tên đầy đủ và số hai chữ
            KHÔNG cùng nằm một hàng được. Boss đã chê chữ cụt nhiều lần, nên đổi
            cụt lấy hết đè là vá nửa vời.
         ⛔ CŨNG ĐÃ LOẠI cách nới nút rộng ra: 147px là con số đã chốt trong
            `thiet-ke/BANG-MAU-VA-CHU.md`, không tự ý đổi.

         Nên số bám vào GÓC TRÊN-PHẢI CỦA BIỂU TƯỢNG — đúng nếp mọi app có cột icon,
         và nó cũng chính là chỗ số đang đứng khi cột chưa nở ra, nên mắt không phải
         đi tìm lại. Biểu tượng chiếm 8..30px trong nút; số rộng ~22px đặt `left:15px`
         thì mép phải tới 37px, còn nhãn tên bắt đầu ở 43px → cách nhau 6px.
         ⛔ KHÔNG đặt `flex`/`min-width` cho nhãn nữa: số đã ra khỏi dòng chảy thì
            nhãn cứ để tự nhiên, thêm `flex:1` chỉ tổ ép nó co lại vô cớ. */
      #thanhCC.chi-rail:hover .cc-rail-so { top:0; left:15px; right:auto;
        transform:none; }
      /* Cột icon đang là dải cam; nở ra thì chữ phải sáng mới đọc được trên nền ấy. */
      #thanhCC.chi-rail:hover .cc-rail-nut { color:rgba(255,255,255,.92); }
    }

    /* ══════════════════════════════════════════════════════════════════════
       🖱 NỞ RA CẢ KHI THANH ĐANG MỞ — cô Quỳnh 02/09/2026
       Khối ngay trên chỉ lo lúc ĐÃ GẤP (`.chi-rail`). Lúc thanh mở hẳn thì cột
       icon 52px nằm cạnh danh sách công cụ, và rê chuột vào chẳng nở ra gì —
       đúng chỗ cô Quỳnh chỉ.
       ⛔ KHÔNG nới `width` của `.cc-rail`, cũng KHÔNG cho nó `position:absolute`:
          cả hai đều kéo danh sách công cụ bên phải nhảy chỗ rồi nhảy về, giật
          mỗi lần rê chuột. Nền nở ra vẽ bằng `::before` — ngoài dòng chảy, không
          đẩy ai; nút bên trong tràn sang phải ĐÈ LÊN danh sách, đúng lối Supabase.
       ⛔ 212px là cố ý nhỏ hơn panel 304px: panel có `overflow:hidden`, rộng hơn
          304 là bị cắt cụt.
       ⛔ `::before` vẫn nhận chuột (nó là một phần của chính `.cc-rail`), nên rê
          sang vùng chữ không bị tính là rời chuột ra. */
    @media (hover:hover) {
      #thanhCC:not(.chi-rail) .cc-rail { position:relative; }
      /* ⛔ z-index PHẢI đặt ở đây, trên chính `.cc-rail`. Đặt ở `::before` thì vô
         dụng: cột icon không có tầng riêng nên danh sách công cụ (đứng sau trong
         DOM) vẫn vẽ đè lên, chữ chồng chữ — đúng lỗi cô Quỳnh bắt được 02/09. */
      #thanhCC:not(.chi-rail) .cc-rail:hover { z-index:3; box-shadow:none; border-right-color:transparent; }
      /* ⛔ `::before` LUÔN CÓ MẶT, không chỉ lúc rê chuột. Sinh ra ngay lúc hover thì
         nó nhảy thẳng tới 212px, không có mốc "từ" nào để chạy — đúng cái "bụp một
         phát" cô Quỳnh chê. Có sẵn ở bề rộng cột icon rồi mới nở ra được. */
      #thanhCC:not(.chi-rail) .cc-rail::before {
        content:""; position:absolute; left:0; top:0; bottom:0; width:100%; z-index:0;
        background:linear-gradient(180deg, var(--cc-rail-dinh) 0%, var(--cc-rail-day) 100%);
        border-right:1px solid rgba(0,0,0,.32); box-shadow:none;
        transition:width .16s ease, box-shadow .16s ease; }
      #thanhCC:not(.chi-rail) .cc-rail:hover::before {
        width:164px; box-shadow:3px 0 14px rgba(0,0,0,.30); }
      /* 🌫 PHẦN CÒN LẠI CỦA PANEL MỜ ĐI — cô Quỳnh: *"nếu đã đè thì phải đè lên để
         hở mờ đằng sau"*. Không làm mờ thì dải 92px (212 → 304px) lộ ra một mẩu chữ
         bị cắt dở, đúng chỗ cô kêu khó nhìn. `~` được vì `.cc-than` là em kế của
         `.cc-rail` trong `.cc-panel`. */
      #thanhCC:not(.chi-rail) .cc-than {
        transition:opacity .16s ease, filter .16s ease; }
      #thanhCC:not(.chi-rail) .cc-rail:hover ~ .cc-than {
        opacity:.28; filter:blur(2px); pointer-events:none; }
      #thanhCC:not(.chi-rail) .cc-rail-nut { transition:background .12s, color .12s,
        border-color .12s, transform .14s ease, width .16s ease, padding .16s ease; }
      #thanhCC:not(.chi-rail) .cc-rail:hover .cc-rail-nut {
        z-index:1; width:148px; justify-content:flex-start; gap:10px; padding:0 8px;
        transform:none; color:rgba(255,255,255,.92); }
      /* ⛔ Máy nào bật hạn chế chuyển động thì thôi hẳn, đừng ép xem. */
      @media (prefers-reduced-motion: reduce) {
        #thanhCC:not(.chi-rail) .cc-rail::before,
        #thanhCC:not(.chi-rail) .cc-than,
        #thanhCC:not(.chi-rail) .cc-rail-nut { transition:none; }
      }
      #thanhCC:not(.chi-rail) .cc-rail:hover .cc-rail-nut:hover { transform:none; }
      #thanhCC:not(.chi-rail) .cc-rail:hover .cc-rail-ten,
      #thanhCC:not(.chi-rail) .cc-rail:hover .cc-rail-nut.chon .cc-rail-ten {
        display:block; position:static; transform:none; opacity:1; visibility:visible;
        background:none; border:0; box-shadow:none; padding:0;
        max-width:none; font-size:13px; font-weight:500; color:inherit;
        overflow:hidden; text-overflow:ellipsis; }
      /* Cùng bài với khối `.chi-rail:hover` ở trên — đọc chú thích dài ở đó.
         ⛔ ĐỪNG SỬA MỘT KHỐI RỒI THÔI: hai khối này là hai trạng thái khác nhau của
            cùng cột icon (đã gấp / đang mở). Bản 02/09 chép khối trên xuống đây mà
            chỉ đổi `right:8px` thành `right:10px`, nên lỗi đè chữ có ở CẢ HAI. */
      #thanhCC:not(.chi-rail) .cc-rail:hover .cc-rail-so { top:0; left:15px;
        right:auto; transform:none; }
    }
    /* 🖥️ 04/08 (cô Quỳnh): ẨN thanh để RỘNG màn nhìn bảng. Bấm ✕ trong thanh để thu;
       hiện lại tab 🧰 mép trái để mở ra. Thu thì bảng .lt-fullw giãn gần hết màn. */
    body.cc-thu #thanhCC .cc-panel { display:none; }
    body.cc-thu #thanhCC .cc-toggle { display:flex; }
    body.cc-thu:not(.dang-trong-lop) #app { padding-left:0; }
    /* ⛔ Ẩn thanh: NỚI thẻ .noi-dung rộng ra + bảng FILL 100% (bỏ chiêu full-bleed
       margin-left âm — vì thẻ chỉ 1120px, 50% thẻ < 48.5vw nên bảng lòi trái, CẮT cột
       đầu — cô Quỳnh 04/08 "tắt thanh thì giao diện bị lệch"). */
    /* ⛔ 21/08/2026 — trần này nay THẤP HƠN khung mặc định (đã bỏ trần), tức là ẩn
       thanh công cụ đi lại làm màn HẸP LẠI — ngược hẳn ý. Bỏ trần luôn. */
    body.cc-thu.man-cong-cu .noi-dung { max-width:none; }
    body.cc-thu .lt-fullw { width:100%; max-width:100%; margin-left:0; }
  }

  /* ===== Chip CHỌN NHIỀU cho Dự giờ (👀 02/08/2026) — viết ĐẦY ĐỦ câu ===== */
  /* 02/08: cô Quỳnh "chip khó nhìn díu dít" → mỗi nhóm một KHUNG riêng, chip to +
     thoáng hơn, bật/tắt rõ ràng. */
  .dg-nhom { margin:8px 0; padding:9px 11px; border:1px solid var(--vien); border-radius:var(--r-lg); background:var(--the); }
  .dg-nhom > .nv-lb { margin-top:0; }
  .dg-chips { display:flex; flex-wrap:wrap; gap:8px; margin-top:6px; }
  .dg-chip { font-size:13px; background:var(--nen2); border:1px solid var(--vien); border-radius:var(--r-xl);
    padding:7px 14px; cursor:pointer; line-height:1.35; transition:background .1s,border-color .1s; }
  .dg-chip:hover { background:#E8F4F2; border-color:var(--xanh); }
  /* ⛔ 11/09/2026 — KHONG NEN XANH DAC. Boss: *"an vao khong duoc co mau xanh
     dang sau cai khung, chi hien ra cai lua chon thoi."* Dai xanh dam nuot het
     chu va bien hop lua chon thanh mot mang mau.
     ⛔ Van phai con duong NHAN RA muc dang chon (dau ✓ o `::before` + chu xanh
        + vien xanh day hon) — bo sach dau hieu la de ra mot loi khac. */
  .dg-chip.chon { background:transparent; color:#0d6e5f; border-color:#159F8B;
    font-weight:600; box-shadow:none; }
  body.toi .dg-chip.chon { color:#7FD6C4; border-color:#159F8B; }
  .dg-chip.chon::before { content:"✓ "; }
  .dg-them-chon { font-size:12.5px; background:#FFF3D9; border:1px dashed var(--cam); color:var(--cam-dam);
    border-radius:var(--r-xl); padding:7px 13px; cursor:pointer; font-weight:600; }
  .dg-them-chon:hover { background:#FFE9C4; }
  .dg-luutt { font-size:12px; align-self:center; font-weight:600; }
  .dg-luutt.dang { color:var(--mo); } .dg-luutt.xong { color:#2E7D32; } .dg-luutt.loi { color:var(--do); }
  /* 🆕 Bảng Dự giờ "nhìn như Sheet / Lịch thi" (cô Quỳnh 03/08/2026) — hàng = phiếu, ô điền thẳng, cuộn ngang. */
  .dg-cuon { overflow:auto; max-height:calc(100vh - 250px - var(--dnc-du, 0px)); touch-action:none; overscroll-behavior:contain;
    border:1px solid var(--vien); border-radius:var(--r-sheet);
    /* ⚡⚡ 06/08/2026 — NỀN ĐỤC. ĐỪNG BỎ, ĐỪNG ĐỔI SANG `transparent`.
       Cô Quỳnh: "kéo sang 2 bên bằng chuột rất lag và giật."
       Trước đây khung này KHÔNG khai nền → nó trong suốt, và cô đang đặt ẢNH NỀN RIÊNG
       phủ kín màn (`#nenRieng`, position:fixed). Nội dung TRONG SUỐT cuộn trên một tấm
       nền CỐ ĐỊNH là kiểu lag kinh điển: trình duyệt không thể trượt sẵn một lớp ảnh
       đã vẽ, mà phải TRỘN LẠI cả bảng với ảnh nền ở MỖI khung hình.
       Cho nền đục là khung bảng thành một lớp vẽ riêng, trượt đi được — hết trộn. */
    background:var(--the);
    /* 🚀 06/08: gói việc vẽ lại GỌN trong khung bảng. Thiếu dòng này thì mỗi nhịp kéo
       trình duyệt phải xét lại cả trang xem có gì xê dịch → kéo ngang bị khựng. */
    contain:paint; }
  /* Chỉ bật lúc ĐANG kéo: báo trước cho trình duyệt "sắp cuộn nhiều" để nó dựng sẵn
     lớp vẽ. Bật thường trực thì ngốn bộ nhớ vô ích nên gắn theo class .dang-keo. */
  .dg-cuon.dang-keo { will-change:scroll-position; }
  /* ⛔⛔ border-collapse phải là SEPARATE — ĐỪNG đổi về `collapse`.
     Với `collapse`, Chrome vẽ nền ô vào lớp nền của cả BẢNG chứ không gắn theo từng ô,
     nên hàng tiêu đề `position:sticky` bị chữ của các dòng bên dưới ĐÈ XUYÊN QUA lúc
     cuộn — cô Quỳnh báo 06/08/2026: "kéo xuống thì không hiểu cột đó là cột gì nữa".
     Với `separate` thì nền dính liền ô sticky nên che đúng. Viền vẽ bằng border-right
     + border-bottom (không phải `border` cả bốn cạnh) để khỏi thành nét đôi; cạnh
     ngoài cùng đã có viền của .dg-cuon lo. */
  .dg-bang { border-collapse:separate; border-spacing:0; font-size:12.5px; }
  .dg-bang th, .dg-bang td { border-right:1px solid var(--vien); border-bottom:1px solid var(--vien);
    padding:4px 6px; vertical-align:top; }
  .dg-bang thead th { background:var(--dau-bang-nen); color:var(--dau-bang-chu);
    font-weight:700; position:sticky; top:0; z-index:5;
    border-right-color:var(--dau-bang-vien); border-bottom-color:var(--dau-bang-vien);
    white-space:normal; min-width:98px; line-height:1.25; text-align:center; }
  .dg-bang td { min-width:120px; }
  /* 🚀 Bỏ box-shadow, dùng viền thường: bóng đổ trên ô DÍNH phải vẽ lại mỗi khung hình
     lúc kéo ngang, còn viền thì trình duyệt vẽ một lần rồi thôi. */
  .dg-bang .dg-dinh { position:sticky; left:0; z-index:3; background:var(--the); min-width:118px; }
  /* ══════════════════════════════════════════════════════════════════════════════
     ⭐ GOM HỒ SƠ TRÙNG THEO LỚP — nút mở nhóm ở Dự giờ (Boss chốt 16/09/2026)
     ──────────────────────────────────────────────────────────────────────────────
     Boss bấm chọn "giống hệt Sổ tuyển sinh", nên mượn nguyên hình dáng .cts-bung
     bên css/man.css: nút vuông nhỏ mang CON SỐ lượt, nền đặc khi đang mở.
     ⛔ KHÔNG dùng box-shadow để vẽ vạch nhóm ở ô .dg-dinh. Ngay khối trên đã ghi:
        ô này là ô GHIM, bóng đổ trên ô ghim phải vẽ lại mỗi khung hình lúc kéo
        ngang. Dùng viền trái — trình duyệt vẽ một lần rồi thôi.
     ⛔ MỌI DÒNG ĐỀU CÓ VIỀN TRÁI 3px, dòng không thuộc nhóm thì để trong suốt. Chỉ
        tô viền cho dòng trong nhóm là cả bảng xô ngang 3px mỗi lần mở/đóng nhóm.
     ⛔ KHÔNG đặt position:absolute cho nút: ô cột đầu đã là ô ghim (position:sticky),
        chồng thêm một lớp định vị nữa là nút trôi khỏi ô lúc kéo ngang.
     ══════════════════════════════════════════════════════════════════════════════ */
  .dg-bang tbody td.dg-dinh { border-left:3px solid transparent; }
  /* ══════════════════════════════════════════════════════════════════════════
     ⛔ DẢI XANH CHỈ HIỆN KHI CỤM ĐANG MỞ — Boss 16/09/2026.
     ──────────────────────────────────────────────────────────────────────────
     Boss: *"lúc tôi ấn vào mở hiển thị các hàng ẩn thì nhìn khó phân biệt được
     là hàng nào là hàng vừa hiện lên… tôi muốn cái viền xanh ở khung bảng bên
     trái khi mở hàng ẩn của 1 ô nào đó thì cái màu xanh ở khung đó sẽ hiển thị
     ra… và để check được lịch sử nó dài đến đâu"*.

     ĐO THẬT 16/09 (sân 8 phiếu, một lớp 3 phiếu, một lớp 2 phiếu): luật cũ bám
     `tr.dg-nhom` nên MỌI hàng thuộc nhóm đều có dải — kể cả nhóm đang ĐÓNG, lúc
     ấy chỉ một hàng lộ ra. Đo `borderLeftColor` 6 hàng đầu: rgb(13,128,129) ở cả
     hàng nhóm đóng lẫn nhóm mở ⇒ dải KHÔNG nói được cụm nào vừa bung, đúng chỗ
     Boss chê "khó phân biệt".

     Nay dải bám `.cum-mo` — lớp `dgHangHTML` chỉ khoác khi `DG_MO` có khoá nhóm.
     Cụm mở thì cả dãy hàng (đầu + con) cùng mang lớp, nên dải chạy LIỀN từ hàng
     đầu tới hàng cuối: nhìn mép trái là biết lịch sử dài tới đâu.
     ⛔ Nhóm ĐÓNG mất dải là CỐ Ý, không phải sót: dấu hiệu "hàng này có lịch sử"
        đã là NÚT SỐ (`.dg-bung`) — Boss chốt bằng nút "Dải xanh là đủ".
     ══════════════════════════════════════════════════════════════════════════ */
  .dg-bang tbody tr.dg-nhom.cum-mo td.dg-dinh { border-left-color:var(--muc); }
  /* ══════════════════════════════════════════════════════════════════════════
     ⭐ KHUNG XANH ÔM TRỌN CỤM, ĐỦ 4 CẠNH — Boss chốt bằng nút 16/09/2026 (tối).
     ──────────────────────────────────────────────────────────────────────────
     Boss: *"giờ tôi thấy lúc mở ra các hàng ẩn hiện giờ nhận biết được bằng mỗi
     cái màu xanh ở khung bên trái thì giờ tôi thấy bạn thêm cho tôi nó đóng khung
     lại luôn cho tôi từ chỗ mở ra đến hết hàng ẩn đó để nhân biết rõ hơn khi nhìn
     vào ơ giữa cột"*. Hỏi bằng nút, Boss chọn **viền 4 cạnh**, **ôm cả hàng mang
     nút số**, và **đóng cụm lại thì mất hết**.

     ⛔ DÙNG `box-shadow: inset`, KHÔNG DÙNG `border` — lý do kỹ thuật, đừng "sửa
        cho đúng kiểu". Thêm `border` thật vào `td` là **đội chiều cao hàng** và
        đẩy cả bảng — chú thích `O_TEN_CAO_BANG_HANG` (11/09) cấm đổi chiều cao
        hàng, và chính đó là cái Boss gọi là "giật". `inset` vẽ ĐÈ LÊN trong lòng
        ô, không chiếm một pixel nào.
     ⛔ DẢI TRÁI VẪN LÀ `border-left-color` ở luật ngay trên — ô ghim `.dg-dinh` đã
        có sẵn `border-left: 3px solid transparent` nên chỉ cần đổi màu. Đừng
        chuyển nó sang box-shadow: có phép canh riêng trong `thu-dg-gom-ho-so-trung.js`.
     ⛔ CẠNH PHẢI bám `td:last-child` — bảng này kéo được cột nên số cột đổi theo
        màn; ghim theo tên cột là lượt sau mất cạnh phải mà không ai biết.
     ⛔ CẢ BỐN LUẬT ĐỀU ĐÒI `.cum-mo`: cụm đóng lại là không hàng nào còn lớp ấy
        nên khung tự biến — đúng ý Boss, không cần một dòng JS nào để dọn.
     ⛔ `box-shadow` KHÔNG CỘNG DỒN giữa các luật: luật sau đè sạch luật trước. Nên
        hàng vừa-đầu-vừa-cuối và ô cuối của hàng đầu/cuối phải khai ĐỦ các vạch
        trong cùng một câu, không thì mất vạch mà không lỗi nào báo.
     ══════════════════════════════════════════════════════════════════════════ */
  .dg-bang tbody tr.dg-nhom.dau.cum-mo > td  { box-shadow: inset 0  2px 0 0 var(--muc); }
  .dg-bang tbody tr.dg-nhom.cuoi.cum-mo > td { box-shadow: inset 0 -2px 0 0 var(--muc); }
  .dg-bang tbody tr.dg-nhom.dau.cuoi.cum-mo > td {
    box-shadow: inset 0 2px 0 0 var(--muc), inset 0 -2px 0 0 var(--muc);
  }
  .dg-bang tbody tr.dg-nhom.cum-mo > td:last-child {
    box-shadow: inset -2px 0 0 0 var(--muc);
  }
  .dg-bang tbody tr.dg-nhom.dau.cum-mo > td:last-child {
    box-shadow: inset -2px 0 0 0 var(--muc), inset 0 2px 0 0 var(--muc);
  }
  .dg-bang tbody tr.dg-nhom.cuoi.cum-mo > td:last-child {
    box-shadow: inset -2px 0 0 0 var(--muc), inset 0 -2px 0 0 var(--muc);
  }
  .dg-bang tbody tr.dg-nhom.dau.cuoi.cum-mo > td:last-child {
    box-shadow: inset -2px 0 0 0 var(--muc), inset 0 2px 0 0 var(--muc),
                inset 0 -2px 0 0 var(--muc);
  }
  /* ══════════════════════════════════════════════════════════════════════════
     ⛔ Ô TÊN KHÔNG ĐƯỢC NỞ RA KHI BẤM VÀO — nếu không, NÚT SỐ TRÔI 12px.
     ──────────────────────────────────────────────────────────────────────────
     Boss: *"ấn vào số 3… nó lại bị xung đột với ô xem chọn tên hay sao á tôi ko
     rõ nên lúc ấn vào cái nút lại bị nhảy vị trí"*.

     ĐO THẬT 16/09, bấm bằng chuột thật (KHÔNG tự gắn class — xem cảnh báo dưới):
       ô tên đóng  → nút `.dg-bung` ở y=221, `.ont` rộng 68px
       ô tên đang sửa → nút ở y=209, `.ont` rộng 134px      ⇒ LỆCH 12px
     GỐC: `.ont` là `inline-flex` (luật `.sheet-moi tbody tr.sheet-hang td > div`
     thắng, hỏi CSSOM mới thấy) nên bề rộng chạy theo nội dung. Lớp xem hẹp 68px
     nằm CÙNG DÒNG với nút; ô nhập nở ra 134px thì không đủ chỗ ⇒ `.ont` rơi
     xuống dòng dưới ⇒ nội dung ô cao thêm, mà `td` canh `vertical-align:middle`
     nên cả cụm dịch lên 12px. Nút vừa nhắm vào đã trôi khỏi đầu ngón tay.

     ⛔ ĐỪNG ĐO BẰNG CÁCH TỰ GẮN `dang-sua` BẰNG JS: làm thế lệch ra 0px ở CẢ bản
        chưa vá — bốn phương án đều "đạt" hết. Đường thật còn chạy `focus()` +
        `ontMo()`, và chính nó mới làm ô nhập nở.
     ⛔ ĐÃ THỬ VÀ LOẠI: `white-space:nowrap` trên ô (vẫn lệch 12px — nowrap không
        ngăn được flex item nở); ép `.ont-in` co về min-content (hết lệch nhưng ô
        gõ chỉ còn 68px, tên dài không đọc được); cho nút `position:absolute`
        (hết lệch nhưng phải đổi padding của ô ghim — đụng bố cục cột dính).
     ⛔ TRỪ ĐÚNG 24px VÀ CHỈ TRỪ Ở HÀNG THUỘC NHÓM: hàng đầu mang nút
        `.dg-bung` 17px + margin 2+5 = 24px; hàng con mang gạch `.dg-bung-lui`
        đúng 24px. Hàng LẺ không có cả hai nên không được trừ gì — đo lại sau khi
        vá: hàng lẻ vẫn 68px, hàng nhóm 110px cố định ở cả hai trạng thái.
     ══════════════════════════════════════════════════════════════════════════ */
  .dg-bang tbody tr.dg-nhom td.dg-dinh .ont { width: calc(100% - 24px); }
  /* ══════════════════════════════════════════════════════════════════════════
     ⭐ MỞ CỤM: LƯỢT CŨ TRƯỢT NHẸ RA, NỀN XÁM NHẠT — Boss chốt tối 21/09/2026.
     ──────────────────────────────────────────────────────────────────────────
     Boss: *"Y hệt Sổ tuyển sinh hôm nay: lượt cũ trượt nhẹ ra, nền xám nhạt,
     bảng đứng yên, cột trái không đổi màu"* — BỎ kiểu "rèm kéo xuống, so le từng
     hàng" (16/09) và "rèm kéo ngược lên" lúc đóng (18/09). Lịch sử và lý do: khối
     chú thích trên `dgBungNhom` (man-hinh/du-gio.js). Nếp gốc: khối `cts-luot-cu-truot`
     ở css/man.css.
     ⛔ Chỉ `opacity` + `transform`, 0,18 giây, KHÔNG so le, KHÔNG `clip-path`.
     ⛔ Lớp `dg-vua-mo` chỉ có trong ĐÚNG MỘT lượt vẽ ngay sau cú bấm mở; đóng cụm
        thì hàng biến mất ngay, không hiệu ứng.
     ⛔ Tên khung hình RIÊNG — đừng mượn `cts-luot-cu-truot` của Sổ tuyển sinh (bài
        học: keyframe dùng chung kéo về giá trị của nó).
     ══════════════════════════════════════════════════════════════════════════ */
  @keyframes dg-luot-cu-truot {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: none; }
  }
  .dg-bang tbody tr.dg-vua-mo > td { animation: dg-luot-cu-truot .18s ease-out; }
  @media (prefers-reduced-motion: reduce) {
    .dg-bang tbody tr.dg-vua-mo > td { animation: none; }
  }
  /* ⭐ LƯỢT CŨ TÔ XÁM NHẠT — cùng màu `--nen2` với lượt cũ ở Sổ tuyển sinh.
     ⛔ CHỪA HAI CỘT GHIM (`sheet-cot-gham`): dải ghim của Dự giờ vốn đã xám be
        (`--sheet-nen-td2`, Boss chốt "cột cố định phải có màu xám" 18/09). Tô đè
        lên là cột trái đổi màu — đúng điều Boss dặn tránh. Sổ tuyển sinh tô cả dải
        ghim vì dải ấy trắng; ở đây dải đã có màu riêng nên để nguyên.
     ⛔ `background-color`, KHÔNG `background`: ô đầu mang dải số dòng vẽ bằng
        `background-image`, viết tắt là xoá mất.
     ⛔ `:where(...)` không cộng độ nặng: ô đang gõ vẫn trắng như mọi ô đang gõ, ô
        Boss tô màu tay (`sheet-dd-to`) vẫn giữ màu của Boss.
     ⛔ Lượt cũ mang lớp `sheet-nen-rieng` (man-hinh/du-gio.js) để `sheetGhamCot` KHÔNG
        lấy màu này làm màu cả dải ghim — đường lỗi "cả cột cố định xanh hết" Boss
        báo ở Sổ tuyển sinh 21/09. */
  .dg-bang tbody tr.dg-nhom.con > td:where(:not(.sheet-cot-gham, :focus-within, .sheet-dd-to)) {
    background-color: var(--nen2);
  }
  /* Dòng con mờ hơn dòng đầu: nhìn là biết mấy dòng này là lượt cũ của cùng một lớp. */
  .dg-bang tbody tr.dg-nhom.con td { color:var(--mo); }
  /* ⛔⛔ CAO 24px, KHÔNG PHẢI 17px NHƯ NÚT BÊN SỔ TUYỂN SINH — ĐÃ ĐO, KHÔNG ĐOÁN.
     Bảng này chạy ở dạng sheet, và luật của kênh giao diện
       .sheet-moi tbody tr.sheet-hang td button:not(...) { min-height:24px }
     THẮNG luật height:17px ở đây (min-height ăn đứt height). Viết 17 thì file nói
     một đằng, màn hình hiện một nẻo — đo bằng trình duyệt ra đúng 17×24px.
     ⇒ Khai thẳng 24px cho khớp sự thật. Hàng Dự giờ cao theo nội dung chứ không
       ghim 30px như Sổ tuyển sinh, nên 24px không làm dòng phình ra. */
  .dg-bung { display:inline-block; vertical-align:middle; width:17px; height:24px;
      line-height:22px; margin:0 5px 0 2px; padding:0; flex:none;
      font:inherit; font-size:10.5px; font-weight:700; font-variant-numeric:tabular-nums;
      text-align:center; color:var(--muc); background:var(--the);
      border:1px solid var(--muc); border-radius:var(--r-sm); cursor:pointer; }
  .dg-bung:hover { background:var(--xanh-nhat); }
  .dg-bung.mo { background:var(--muc); color:#fff; }
  /* Ô đệm của dòng con: đúng bề ngang cái nút (17 + 5 + 2) để chữ dòng con thẳng
     cột với dòng đầu. Không có nó thì dòng con lệch trái, bảng nhìn như vỡ. */
  .dg-bung-lui { display:inline-block; width:24px; height:1px; vertical-align:middle; }
  /* Ô góc trên-trái dính cả hai chiều: phải cùng màu hàng tiêu đề, không thì nó
     là một ô xám lạc lõng đúng chỗ mắt nhìn vào đầu tiên. */
  .dg-bang thead .dg-dinh { z-index:6; background:var(--dau-bang-nen); }
  /* ⛔⛔ VẠCH ĐẬM CHO TRƯỜNG HỢP APP ĐÃ TỰ GỠ DẢI GHĂM — vá 12/09/2026 (nửa (b) của cụm vạch).
     CHUYỆN ĐÃ XẢY RA: luật vạch 2px chung chỉ bám `.sheet-moi.sheet-gham .sheet-cot-gham-cuoi`
     (css/lop.css, khối "Ranh giới giữa phần đứng yên và phần trôi"). Nhưng `sheetGhamCot`
     TỰ BỎ lớp `sheet-gham` khi dải ghăm nuốt quá 55% bề ngang khung — lúc ấy cột tên vẫn
     ĐỨNG YÊN nhờ `.dg-dinh` ở ngay trên, mà vạch thì biến mất, chỉ còn viền 1px `--vien`.
     Đo pixel thật trên mốc b2d51e6 (sân 18 hàng, cuộn ngang 45%), TÁM phép đo hỏng:
         Chăm sóc 1001 · Dự giờ 390 · Chăm sóc 390 · Follow up 390  — cả thân lẫn hàng tiêu đề
         đều rgb(214,210,203) dày 1px → 1,51:1   (chuẩn nét đồ hoạ WCAG ≥ 3:1)
     Mười lăm cặp còn lại đang ghăm thật thì 4,10–4,75 — tức app đang không nhất quán với
     chính nó ở đúng những khổ máy người ta hay dùng.
     ⛔ ĐỪNG chữa bằng cách hạ ngưỡng 55% trong `sheetGhamCot`: ngưỡng ấy có lý do riêng
        (dải ghăm rộng quá thì còn đâu chỗ mà cuộn), đổi nó là đổi bố cục chứ không phải
        đổi màu một cái vạch.
     ⛔ ĐỪNG nới luật cũ ra bằng cách bỏ `.sheet-gham` khỏi nó: làm thế thì khi CÒN ghăm,
        cả `.dg-dinh` lẫn `.sheet-cot-gham-cuoi` cùng vẽ ⇒ HAI vạch trong một bảng.
     ⇒ Tách luật riêng, và chỉ mở đúng lúc app đã gỡ ghăm: `:not(.sheet-gham)`.
     ⛔ `box-shadow`, KHÔNG phải `border-right`: bảng chạy `table-layout` cố định + JS nhớ
        bề rộng cột, thêm một pixel viền là lệch bề rộng ở MỌI bảng (đã trả giá một lần).
     ⛔ Phải kèm `.sheet-moi`: `.dg-bang` còn được Phụ đạo và mấy bảng khác dùng chung;
        chỉ bảng nào đã khoác áo Sheets mới thuộc bộ luật vạch này. */
  .dg-bang.sheet-moi:not(.sheet-gham) .dg-dinh {
    box-shadow: 2px 0 0 var(--muc, var(--vien-ro, var(--vien)));
  }
  .dg-dinh b { display:block; font-size:12.5px; }
  .dg-dinh .dg-luutt { display:block; font-size:11px; margin:2px 0; }
  .dg-o { width:100%; box-sizing:border-box; border:1px solid var(--vien); border-radius:var(--r-sm); padding:3px 5px;
    font-size:12px; background:var(--nen-o); color:var(--chu); font-family:inherit; }
  /* 10/08/2026 — bỏ `resize:vertical` (kéo tay) vì nay ô TỰ cao theo nội dung.
     Giữ min-height cho ô rỗng vẫn đủ chỗ bấm vào. */
  .dg-ta { min-width:150px; min-height:40px; }
  .dg-chipcell { min-width:180px; max-width:240px; }
  .dg-chipcell .dg-chips { display:flex; flex-wrap:wrap; gap:3px; padding-right:2px; }
  /* ══════════════════════════════════════════════════════════════════════════
     🤝 HAI CỘT TRỢ GIẢNG GỘP LÀM MỘT — Boss giao 16/09/2026 (việc 8).
     "Trợ giảng 1 · NX trợ giảng 1 · Trợ giảng 2 · NX trợ giảng 2" ⇒ còn hai cột
     "Trợ giảng" và "Nhận xét trợ giảng", mỗi cột hai dòng.

     ⛔⛔ HAI CỘT PHẢI DÓNG THẲNG NHAU THEO DÒNG, nếu không thì gộp xong lại tệ hơn
        lúc chưa gộp: người đọc không biết dòng nhận xét thứ hai là của ai.
        Cách giữ cho thẳng là CHO HAI DÒNG CÙNG MỘT CHIỀU CAO TỐI THIỂU ở cả hai
        cột (`--dg-tg-dong`), chứ KHÔNG phải canh bằng mắt rồi gõ số lẻ cho vừa.
     ⛔ ĐỪNG dùng `align-items:center` cho ô: ô trợ giảng và ô nhận xét cao khác
        nhau (một bên là ô gõ, một bên là nút có thể xuống 2–3 dòng thẻ), canh giữa
        là hai cột lệch nhau đúng lúc nhận xét dài ra — tức đúng lúc cần đọc nhất.
     ══════════════════════════════════════════════════════════════════════════ */
  /* ⛔⛔ 40px = ĐÚNG TRẦN CỦA Ô TÊN HAI DÒNG, và phải DÙNG CHUNG cho cả hai cột.
     Đây là thứ giữ cho hai cột dóng thẳng hàng, và nó phải là MỘT con số chứ không
     phải hai. Đo 16/09 lúc chưa dùng chung: ô trợ giảng cao 42px (tên xuống hai
     dòng) còn ô nhận xét 24px ⇒ dòng đầu đã lệch 12px, dòng sau lệch tiếp — người
     đọc lại phải tự đoán nhận xét nào của ai, đúng thứ việc gộp cột sinh ra để bỏ.
     ⛔ ĐỪNG hạ xuống cho hàng thấp lại: hạ là tên dài bị cắt, mà Boss có luật cứng
        11/09 *"tên nhân viên hay học sinh đều phải NHÌN THẤY ĐƯỢC, không được ẩn"*.
     ⚠️ CÁI GIÁ, đã đo và đã báo Boss: hàng cao 32px ⇒ ~94px khi cả hai dòng có tên
        dài. Muốn thấp lại thì KÉO RỘNG cột Trợ giảng — tên nằm gọn một dòng là ô
        tự co về 24px và hàng tự thấp xuống. Bề rộng kéo tay được nhớ lại.
     ⛔ Đã thử ép bề rộng mặc định bằng ba cách (`min-width` ở td · `width` ở th ·
        class `c-ten` của `LOP_TU_VUA`) — cả ba đều KHÔNG ăn: `gaKeoCot` ghi thẳng
        `th.style.width` và style nội tuyến thắng CSS; còn `LOP_TU_VUA` đo
        `td.scrollWidth`, mà ô này cho chữ xuống dòng nên `scrollWidth` không bao
        giờ đòi thêm bề rộng. Đừng đi lại ba đường ấy. */
  .dg-tgcell, .dg-nxtgcell { --dg-tg-dong:40px; vertical-align:top; }
  /* ⛔⛔ ĐỪNG ĐẶT BỀ RỘNG CHO CỘT TRỢ GIẢNG Ở ĐÂY — đã thử và ĐO, cả hai đều trượt:
     `min-width` trên `td.dg-tgcell` ⇒ vẫn 120px · `width` trên `th.dg-th-tg` ⇒ vẫn
     120px. `gaKeoCot` đo rồi ghi thẳng `th.style.width` (đo được 98px), style nội
     tuyến thắng mọi luật CSS. Bề rộng cột ấy nay do `c-ten` + `LOP_TU_VUA` lo —
     xem khối lý do ở `man-hinh/du-gio.js`, chỗ dựng hàng tiêu đề.
     ⛔ ĐỪNG "chữa" bằng `!important`: nó thắng luôn con số người dùng vừa KÉO ra,
        tức giết tính năng kéo rộng cột để đổi lấy một bề rộng mặc định. */
  .dg-nxtgcell { min-width:190px; }
  .dg-tg-dong, .dg-nxtg-dong {
    min-height:var(--dg-tg-dong); display:flex; align-items:flex-start; gap:4px; }
  .dg-tg-dong + .dg-tg-dong, .dg-nxtg-dong + .dg-nxtg-dong {
    margin-top:4px; padding-top:4px; border-top:1px dashed var(--vien); }
  .dg-tg-dong > .ont { flex:1 1 auto; min-width:0; }
  /* Dấu tên chưa khớp tài khoản — Boss chốt "tự gộp, nhưng phải khớp đúng tài
     khoản". Nhỏ, đứng ngoài ô, KHÔNG chặn gõ: đây là lời nhắc, không phải lỗi. */
  .dg-tg-la { flex:0 0 auto; font-size:12px; line-height:1.6; color:#B8860B; cursor:help; }
  /* Nhãn tên ở cột nhận xét: nhỏ và xám, vì tên ĐẦY ĐỦ đã nằm ở cột bên trái —
     đây chỉ là cái mỏ neo cho mắt, in đậm bằng nó là đọc thành hai cột tên. */
  .dg-nxtg-ten { flex:0 0 68px; max-width:68px; font-size:11px; line-height:1.5;
    color:var(--mo); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .dg-nxtg-dong > .dg-o-tich { flex:1 1 auto; min-width:0; }
  /* Chưa có người ở dòng ấy ⇒ mờ đi, để không ai lỡ chấm nhận xét cho ô trống.
     ⛔ Chỉ mờ, KHÔNG `display:none`: ẩn hẳn thì hai cột thôi dóng thẳng hàng, và
        người muốn điền trợ giảng thứ hai không thấy chỗ nào để điền nhận xét. */
  .dg-nxtg-dong.trong { opacity:.45; }
  .dg-nxtg-dong.trong .dg-nxtg-ten { font-style:italic; }
  /* 🆕 04/08 (cô Quỳnh: "để có thanh kéo xuống nhìn rõ hơn") — ô chọn nhiều = KÉO XUỐNG:
     summary hiện mục đã chọn, bấm mở ra list to rõ để tick. Mở inline nên bảng không cắt mất. */
  .dg-chipbox { width:100%; }
  .dg-chipbox > summary { list-style:none; cursor:pointer; display:flex; flex-wrap:wrap; gap:4px; align-items:center;
    padding:5px 7px; border:1px solid var(--vien); border-radius:var(--r-md); background:var(--nen-o); min-height:28px; }
  .dg-chipbox > summary::-webkit-details-marker { display:none; }
  .dg-chipbox[open] > summary { border-color:var(--xanh); border-radius:var(--r-md) var(--r-md) 0 0; }
  .dg-tom-tag { font-size:11px; background:#159F8B; color:#fff; border-radius:var(--r-lg); padding:1px 8px; }
  .dg-tom-trong { font-size:12px; color:var(--mo); }
  .dg-tom-mui { margin-left:auto; color:var(--mo); font-size:10px; transition:transform .15s; }
  .dg-chipbox[open] > summary .dg-tom-mui { transform:rotate(180deg); }
  .dg-chipbox > .dg-chips { max-height:none; overflow:visible; gap:6px; padding:8px;
    border:1px solid var(--xanh); border-top:none; border-radius:0 0 var(--r-md) var(--r-md); background:var(--the); }
  .dg-chipbox .dg-chip { font-size:12px; padding:4px 10px; }
  .dg-chipbox .dg-them-chon { font-size:11.5px; padding:4px 10px; }
  /* ⛔⛔ INFO_KHONG_KEO_COT 11/09/2026 — Boss: *"cot lop... cho no vua voi chu
     luon di, de tranh no mo rong ra nhieu khoang khong dung den."*
     Dong `GV: ... · Tro giang: ...` nam TRONG CUNG O voi o xo chon lop. Do o 2320:
     dong ay DOI 416px trong khi ten lop that chi 30-40px — chinh no keo ca cot rong
     ra, va hang nao khong co no thi o trong hoac.
     ⇒ Dua ra NGOAI DONG CHAY (`position:absolute`). Thuat toan dung bang khong tinh
       phan tu ngoai dong chay vao be rong cot, nen cot thu lai vua o xo.
     ⛔ KHONG dat `display:none`: dong nay CO NGHIA — no cho biet lop vua chon do ai
        day va tro giang la ai. Giau han la lay mat thong tin, khong phai gon.
     ⛔ Phai co nen DUC va `z-index`: ra khoi dong chay la no de len hang duoi;
        trong suot thi chu chong chu.
     ⛔ O cha phai la chan neo. `td` cua bang nay da `position` san hay chua thi
        khong chac, nen neo thang vao chinh o bang `position:relative` o luat duoi. */
  /* ⛔ Lop rieng `.dg-lopcell`, KHONG `:has()` — luat cua kho nay cam `:has()`
     trong CSS moi cua index.html. Lop duoc gan o `man-hinh/du-gio.js`. */
  .dg-bang td.dg-lopcell { position: relative; }
  .dg-bang .dg-lop-info { font-size:11px; margin-top:0; padding:3px 5px;
    position:absolute; left:3px; right:3px; top:100%; z-index:2;
    background:#F1F8F6; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  /* 🆕 Follow up HS "nhìn như Sheet / Lịch thi" (03/08/2026) — dùng chung bảng .dg-*.
     Ô chọn giữ <select>+＋; cột Lịch sử liên hệ xếp dọc gọn trong 1 ô. */
  .dg-bang .fhs-selcell { min-width:230px; max-width:260px; }
  /* ⭐ 12/08/2026 — bốn ô chọn của Follow up nay là CHIP CHỌN NHIỀU (cô Quỳnh:
     "chọn 1 cái xong chọn cái khác thì cái lựa chọn cũ bị mất").
     ⛔ Các câu lựa chọn ở đây DÀI (có câu 130 chữ, cả một câu nhận xét), khác hẳn
        chip ngắn của Dự giờ. Không chặn bề ngang thì một chip kéo cột rộng ra cả
        màn hình. Cho chip XUỐNG DÒNG trong bề rộng của cột. */
  .fhs-chipbox > .dg-chips { max-width:100%; }
  .fhs-chip { max-width:100%; white-space:normal; word-break:break-word; text-align:left; }
  .dg-bang td.cs-ptcell { min-width:190px; }
  /* MỌI ô chọn trong ô (học lực/đánh giá/phụ trách) đủ rộng + chừa chỗ cho dấu ▼ để
     không che chữ (cô Quỳnh 04/08). Giá trị dài: di chuột vào ô thấy đủ (title), hoặc bấm mở. */
  .fhs-o-hang select { flex:1; min-width:0; padding-right:22px; text-overflow:ellipsis; }
  .fhs-ngaycell { white-space:nowrap; }
  .dg-bang td.fhs-lhcell { min-width:340px; }
  /* KHÔNG cap chiều cao → đoạn văn dài hiện ĐỦ (cô Quỳnh 04/08: "ô chữ không to ra"). */
  .fhs-lhcell .fhs-lhs { overflow:visible; }
  .fhs-lhcell .fhs-lh .nv-datevn { width:118px; }
  .fhs-lhcell .fhs-lh-kq { flex:1; min-width:120px; }
  /* ══════════════════════════════════════════════════════════════════════════
     ⭐ NÚT "+ THÊM LẦN" ĐỨNG YÊN MỘT CHỖ — Boss chốt 16/09/2026
     ──────────────────────────────────────────────────────────────────────────
     Boss: *"cái nút thêm lần nó bị đổi vị trí nên tôi muốn bạn cố định lại đúng 1
     vị trí khi mở ô và ko mở ô trong cột lịch sử liên hệ"*. Hỏi bằng nút, Boss
     chọn **góc PHẢI của ô, luôn thế**.

     Gốc: nút là anh em ĐỨNG SAU cụm `.fhs-lhs` trong cùng `<td>`, nên cụm cao lên
     bao nhiêu là nút bị đẩy xuống bấy nhiêu — hàng chưa mở thì nút ở phải trên,
     hàng mở ra thì nút rơi xuống trái dưới. Đúng hai tấm ảnh Boss gửi.
     ⛔ `position:absolute` thì PHẢI chừa chỗ bằng `padding-right` cho cụm bên
        trái, không thì nút nằm đè lên dấu × xoá của lần liên hệ đầu tiên.
     ⛔ `top` chứ không `bottom`: neo đáy thì nút lại đi theo chiều cao ô — đúng
        cái bệnh đang chữa, chỉ đổi chiều.
     ⛔ Ô này KHÔNG phải cột ghim nên `position:relative` ở đây không tháo ghim
        của ai. Đừng bê cách này sang `td.dg-dinh` (xem luật "ngang cơ đứng sau
        thì thắng" — một dòng `position:relative` từng tháo ghim cả đầu bảng).
     ══════════════════════════════════════════════════════════════════════════ */
  /* ══════════════════════════════════════════════════════════════════════════
     NÚT ＋ TRÒN, ĐẶT GIỮA Ô — Boss 17/09/2026 (thay luật ghim góc phải cùng ngày)
     ──────────────────────────────────────────────────────────────────────────
     ⛔⛔ LUẬT `position:absolute` Ở ĐÂY ĐÃ ĐƯỢC GỠ — chính nó đẻ ra cảnh "lẫn hàng".
        Sáng 17/09 tôi ghim nút vào góc phải trên để nó không đổi chỗ khi ô nở ra.
        Nhưng ghim thế là nút rời khỏi mạch nội dung, mà các hàng cao thấp khác nhau
        — nên nút của hàng này nằm ngang tầm chữ của hàng kia. Boss chiều 17/09:
        *"1 hàng mà lại dính 2 hàng cột lịch sử liên hệ làm lẫn lộn và khó nhìn"*.
     ⛔ `padding-right:104px` cũng gỡ theo: nó chỉ tồn tại để chừa chỗ cho nút ghim.
        Giữ lại là mỗi ô mất trắng 104px bề ngang mà chẳng cho ai.
     ⛔ GIỮ `position:relative` trên ô: bảng xem đầy đủ (việc ⒓) không dùng tới nó,
        nhưng dấu ✕ xoá từng lần liên hệ thì có — gỡ là dấu ✕ văng ra góc trang.
     ══════════════════════════════════════════════════════════════════════════ */
  .fhs-lhcell { position:relative; }
  .fhs-them-boc { display:flex; justify-content:center; margin-top:6px; }
  .fhs-lhcell .fhs-them-lh {
    display:flex; align-items:center; justify-content:center;   /* dấu ＋ đúng giữa nút */
    width:28px; height:28px; min-width:28px; min-height:28px;   /* Boss chốt 28×28 */
    padding:0; border-radius:50%;
    font-size:15px; line-height:1;
    color:var(--xanh); background:var(--nen2, #F5F4F1);
    border:1px solid var(--vien); cursor:pointer;
    transition:background .12s, border-color .12s, transform .12s;
  }
  .fhs-lhcell .fhs-them-lh:hover { background:#E8F3EE; border-color:var(--xanh); }
  .fhs-lhcell .fhs-them-lh:active { transform:scale(.92); }
  body.toi .fhs-lhcell .fhs-them-lh { background:rgba(255,255,255,.07); }

  /* Ô TÌM KIẾM đẹp (bo tròn, icon, rộng) — dùng chung các công cụ. */
  .o-tim-dep { width:100%; box-sizing:border-box; padding:11px 15px; border:1.5px solid var(--vien);
    border-radius:var(--r-xl); font-size:14.5px; font-family:inherit; background:var(--nen-o); margin:8px 0 4px;
    transition:border-color .12s, box-shadow .12s; }
  .o-tim-dep:focus { outline:none; border-color:var(--xanh); box-shadow:0 0 0 3px rgba(20,160,160,.15); }
  /* 🚀 Thanh "đang hiện N/M + Hiện thêm" cho bảng lớn (vẽ ít dòng cho nhẹ). */
  .bl-thanh { display:flex; gap:10px; align-items:center; flex-wrap:wrap; margin:2px 0 6px; }
  .bl-dem { font-size:12.5px; color:var(--mo); }
  .bl-them { flex:none; }
  /* Nút "Ít lại" (12/08/2026) — đường VỀ sau khi bấm Hiện thêm. Cố ý nhạt hơn nút
     Hiện thêm: đây là nút phụ, đừng tranh chỗ với việc chính. */
  .bl-bot { flex:none; }

  /* ===== 🧑‍🎓 Follow up học sinh (thẻ GỌN bấm-mở + chia lớp) ===== */
  .fhs-nhom { margin-bottom:16px; }
  .fhs-nhom-dau { display:flex; align-items:center; gap:8px; font-weight:700; font-size:14.5px; color:var(--muc);
    padding:7px 12px; background:var(--nen2); border:1px solid var(--vien); border-radius:var(--r-lg); margin-bottom:8px; }
  .fhs-nhom-so { font-size:12px; font-weight:700; background:var(--xanh); color:#fff; border-radius:var(--r-xl); padding:1px 9px; }
  /* ===== 📇 Thông tin học sinh (tổng hợp) + 📊 Báo cáo điểm danh ===== */
  .tths-thanh { flex-wrap:wrap; gap:8px; align-items:center; }
  .tths-tim { flex:1 1 240px; min-width:180px; }
  .tths-tom { color:var(--mo); font-size:13px; margin:2px 0 12px; }
  .tths-tom b { color:var(--muc); font-size:15px; }
  /* 🏫 05/08: cột "Lớp" ngay cạnh tên học sinh (cô Quỳnh yêu cầu) */
  .tths-lopo { white-space:nowrap; }
  .tths-lop-nhan { display:inline-block; padding:1px 9px; border-radius:999px;
    background:#DCF1F3; color:#0E7C86; font-weight:700; font-size:11.5px; }
  body.toi .tths-lop-nhan { background:rgba(14,124,134,.25); color:#7FD4DC; }
  .tths-lop { margin:0 0 12px 6px; }
  .tths-lop-dau { font-weight:700; font-size:13.5px; color:var(--muc); padding:4px 2px; display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
  .tths-lop-dau small { color:var(--mo); font-weight:600; }
  /* ⛔ 06/08: trước đây chỉ có `overflow-x:auto`. Nghe thì vô hại, nhưng theo luật CSS
     hễ một chiều khác `visible` thì chiều kia cũng thành khung cuộn — mà khung này
     KHÔNG giới hạn chiều cao, nên hàng tiêu đề `position:sticky` chẳng có mép nào để
     bám: kéo xuống là mất tiêu đề hẳn. Nay cho khung một chiều cao tối đa để nó thành
     khung cuộn thật. Nhóm nào ít học sinh, chưa chạm mức này thì hiển thị y như cũ. */
  .tths-cuon { overflow:auto; max-height:calc(100vh - 220px - var(--dnc-du, 0px)); overscroll-behavior:contain;
    border:1px solid var(--vien); border-radius:var(--r-sheet); contain:paint;
    background:var(--the); }   /* nền ĐỤC — cùng lý do đã ghi ở `.dg-cuon`, đừng bỏ */
  .tths-bang { border-collapse:separate; border-spacing:0; width:100%; font-size:13px; min-width:560px; }
  .tths-bang th { background:var(--dau-bang-nen); text-align:left; padding:6px 9px; font-weight:700; color:var(--dau-bang-chu); white-space:nowrap; border-bottom:1px solid var(--dau-bang-vien); position:sticky; top:0; z-index:5; }
  .tths-bang td { padding:5px 9px; border-bottom:1px solid var(--vien); vertical-align:top; }
  .tths-bang tbody tr:nth-child(even) { background:var(--nen2); }
  .tths-ten { font-weight:600; }
  /* 📇 21/09/2026 (việc C) — nối Sổ tuyển sinh theo Mã HS, hai dấu nhỏ trong ô tên:
     · CÙNG MÃ KHÁC TÊN → icon cảnh báo màu dải nhắc vàng, rê chuột thấy cả hai tên.
     · CHƯA CÓ TRONG SỔ → một dòng chữ mờ cỡ nhỏ, không nền không viền (kiểu Sheet).
     ⛔ (0,2,1) để thắng luật nền i[class^="ic-"] (0,1,1), và gỡ lề phải 6px của nó. */
  .tths-ten > i.tths-lech-ten { margin:0 0 0 5px; width:13px; height:13px; vertical-align:-2px;
    color:var(--nhan-chu); cursor:help; }
  .tths-ten > .tths-chua-so { display:block; font-weight:400; font-size:11px; line-height:1.3; color:var(--mo); }
  /* Ô địa chỉ dài hơn ô số điện thoại — hẹp quá thì gõ tới đâu chữ trôi mất tới đó. */
  .tths-bang td.tths-diachi .tths-sua { min-width:180px; }
  /* ⭐ 21/09/2026 — Ô LIÊN HỆ XUỐNG DÒNG, không cắt "…". Boss: *"các ô này khi ghi nhiều
     chữ thì phải xuống dòng cho tôi"*. Ô SỬA ĐƯỢC nay là <textarea> nên tự ăn luật chung
     ㊱ (tối đa 4 dòng rồi "…", bấm vào thấy đủ). Khối này lo ô CHỈ XEM (tài khoản không
     có quyền sửa): chữ nằm thẳng trong <td>, mà cụm bảng-Sheet ép
     `td { white-space:nowrap; text-overflow:ellipsis }` (0,2,3) → phải nặng hơn mới thắng.
     ⛔ Ô chỉ xem hiện ĐỦ chữ, không kẹp 4 dòng: người chỉ xem không có ô để bấm mở ra,
        kẹp lại là giấu mất phần sau. ⛔ Chỉ năm cột liên hệ, không nới luật chung. */
  .tths-bang td.tths-lh-o,
  .sheet-moi tbody tr.sheet-hang td.tths-lh-o { white-space:normal; overflow-wrap:anywhere; text-overflow:clip; }
  /* ══════════════════════════════════════════════════════════════════════════
     ⭐ 23/09/2026 — BẢNG HỌC SINH: Ô CỐ ĐỊNH LUÔN HIỆN ĐỦ (Boss chốt bằng nút)
     ──────────────────────────────────────────────────────────────────────────
     Boss: *"ô tên cố định là cố định"*. Chốt: tên học sinh và MỌI ô chỉ xem (Mã, Lớp,
     Ngày sinh, SĐT, ngày bắt đầu/kết thúc, trạng thái, điểm…) hiện ĐỦ chữ — cột giữ
     bề rộng, chữ dài thì XUỐNG DÒNG, hàng cao lên. Không "…", không phải bấm mới thấy.
     Bấm-để-xem-hết chỉ còn ở ô người ta gõ và hay sửa (Ghi chú · Lớp chuyển · Lớp cũ):
     những ô ấy là <textarea class="o-bang"> nên vẫn ăn luật chung ㊱ như cũ.
     ⛔ Lớp RIÊNG `tths-bang-hs`, đừng viết lên `.tths-bang`: bốn bảng khác (gõ tên lúc
        Tạo lớp, danh sách lớp, hai bảng Báo cáo giáo viên) cũng mở đầu bằng lớp ấy.
     ⛔ (0,3,3) thắng luật ép-một-dòng của cụm Sheet (0,2,3) ở mọi chỗ đặt.
     ⛔ Chỉ gỡ trần 22px cho span/div/b/i — ô nhập (<textarea>/<input>/<button>) có luật
        riêng của chúng, gỡ ở đây là hàng cao vọt theo bài ghi chú dài.
     ⛔ `break-word`, ĐỪNG `anywhere`. Hai cái cùng bẻ chữ dài không vừa ô, nhưng
        `anywhere` còn khai với bảng "ô này hẹp một con chữ cũng được": bảng tự dàn thì
        bóp mọi cột xuống sát đáy, rồi kéo cột (`gaKeoCot`) đo và ĐÓNG ĐINH đúng bề rộng
        teo ấy. Đo 23/09 trên bản anywhere: "24/08/2 026", "Lớp chuyể n", "Trườn g".
        `break-word` giữ đáy cột = từ dài nhất, nên ngày và chữ tiêu đề đứng nguyên. */
  .tths-bang-hs td,
  .sheet-moi.tths-bang-hs tbody tr.sheet-hang td { white-space:normal; overflow-wrap:break-word; text-overflow:clip; }
  .sheet-moi.tths-bang-hs tbody tr.sheet-hang td > span,
  .sheet-moi.tths-bang-hs tbody tr.sheet-hang td > div,
  .sheet-moi.tths-bang-hs tbody tr.sheet-hang td > b,
  .sheet-moi.tths-bang-hs tbody tr.sheet-hang td > i { max-height:none; }
  .tths-bang-hs .tths-tt,
  .tths-bang-hs .tths-diem-ky { white-space:normal; }
  .sheet-moi.tths-bang-hs tbody tr.sheet-hang td > .tths-diem { display:flex; }
  /* Ô "Học sinh" gộp: tên ở trên, hàng khối nhỏ Mã · Lớp (+ nút Chuyển lớp) ở dưới —
     cùng dáng khối `.fhs-phu` của Follow up nhưng lớp riêng, không mượn lớp dùng chung.
     ⛔ CỠ CHỮ CỦA CHÍNH Ô ĐỂ NHỎ (11px), cỡ tên đặt ở `.tths-hs-ten`. Khung xem dùng chung
        của bảng Sheet (js/tinh-nang.js) đo "ô có bị cắt chữ không" bằng CỠ CHỮ CỦA Ô, trên
        cả chuỗi tên + mã + lớp dính liền. Để ô 13px đậm thì chuỗi dính ấy có lúc đo ra
        dài hơn ô thật và khung bật lên đè cái tên — trái đúng luật Boss vừa chốt (tên
        không bao giờ phải bấm mới thấy). 11px thường thì phép đo luôn ra "vừa". */
  .tths-bang-hs td.tths-hs { font-size:11px; line-height:16px; font-weight:400; }
  .tths-hs-ten { font-size:13px; line-height:20px; font-weight:600; color:var(--chu); }
  .tths-hs-phu { display:flex; flex-wrap:wrap; align-items:center; gap:4px; margin-top:3px; }
  .tths-hs-b { font-size:11px; line-height:1.5; font-weight:500; color:var(--mo); background:var(--nen2);
    border:1px solid var(--vien); border-radius:var(--r-sm, 6px); padding:0 6px; max-width:100%; box-sizing:border-box; }
  .tths-hs-b.tths-hs-lop { background:#DCF1F3; border-color:#C4E7EA; color:#0E7C86; font-weight:600; }
  body.toi .tths-hs-b.tths-hs-lop { background:rgba(14,124,134,.25); border-color:transparent; color:#7FD4DC; }
  .tths-hs-phu > .tths-chuyen { display:inline-flex; align-items:center; justify-content:center; min-height:22px; line-height:1; }
  .tths-hs-phu > .tths-chuyen > i { margin:0; }
  .tths-hs-ten > i.tths-lech-ten { margin:0 0 0 5px; width:13px; height:13px; vertical-align:-2px;
    color:var(--nhan-chu); cursor:help; }
  .sheet-moi.tths-bang-hs tbody tr.sheet-hang td.tths-hs > .tths-hs-ten,
  .sheet-moi.tths-bang-hs tbody tr.sheet-hang td.tths-hs > .tths-chua-so { display:block; }
  .sheet-moi.tths-bang-hs tbody tr.sheet-hang td.tths-hs > .tths-hs-phu { display:flex; }
  .tths-hs > .tths-chua-so { margin-top:2px; }
  /* 🎂 Ngày sinh lấy từ Sổ tuyển sinh: chỉ xem, dòng nhỏ nói nguồn ngay dưới. */
  .tths-ns-so { display:block; }
  .tths-ns-goc { display:block; font-size:11px; line-height:1.3; color:var(--mo); }
  .sheet-moi.tths-bang-hs tbody tr.sheet-hang td.tths-ns-o > span { display:block; }
  /* Ô gõ ngày sinh phải chứa trọn khuôn "dd/mm/yyyy". Luật chung của bảng Sheet cho mọi
     ô gõ `width:1px; min-width:100%` (để ô đang sửa không kéo cả cột rộng ra) — nên ô
     gõ không góp chút bề rộng nào, cột chỉ rộng bằng chữ "Ngày sinh" và khuôn cụt còn
     "dd/mm/yy" (đo 23/09: cột 71px, khuôn cần 73px chữ + 4px đệm). `max(100%, 6.2em)`:
     vẫn đầy ô như luật chung, nhưng không hẹp dưới khuôn — và theo cỡ chữ, không ghim px.
     (0,5,4) thắng luật chung (0,2,4) dù luật ấy đứng sau trong file. */
  .tths-bang-hs td.tths-ns-o > textarea.tths-ns,
  .sheet-moi.tths-bang-hs tbody tr.sheet-hang td.tths-ns-o > textarea.tths-ns { min-width:max(100%, 6.2em); }
  /* 📤 Ô tick đầu dòng + thanh "Xuất các em đã chọn". */
  .tths-bang-hs td.tths-chon-o { text-align:center; }
  .tths-chon { width:16px; height:16px; margin:0; cursor:pointer; accent-color:#2E9E5B; vertical-align:middle; }
  /* Luật cụm Sheet cho ô nhập con trực tiếp của ô (`td > input { min-height:24px }`) kéo
     ô tick thành hình chữ nhật — trả về vuông 16px. */
  .sheet-moi.tths-bang-hs tbody tr.sheet-hang td.tths-chon-o > input.tths-chon { min-height:0; }
  .tths-chon-thanh { display:flex; flex-wrap:wrap; align-items:center; gap:8px 12px; margin:0 0 10px; }
  .tths-chon-het { display:inline-flex; align-items:center; gap:6px; font-size:13px; font-weight:600; color:var(--muc); cursor:pointer; }
  .tths-chon-het input { width:16px; height:16px; margin:0; cursor:pointer; accent-color:#2E9E5B; }
  .tths-chon-het input:disabled { cursor:not-allowed; }
  .tths-chon-thanh .nut-nho:disabled { opacity:.5; cursor:not-allowed; }
  .tths-chon-dem { font-size:12.5px; color:var(--mo); }
  .tths-dd-goiy { font-size:12.5px; color:var(--mo); margin:-4px 0 10px; padding:2px 0 2px 9px; border-left:3px solid var(--vien); }
  /* ✏️ Ô sửa tại chỗ (Lớp chuyển · SĐT · Khả năng tiếp thu) trong Thông tin HS */
  /* ══════════════════════════════════════════════════════════════════════════
     📏 Ô NHẬP TRONG BẢNG — RỘNG THEO CỘT, TỰ CAO KHI VIẾT (cô Quỳnh 10/08/2026)
     ──────────────────────────────────────────────────────────────────────────
     Cô: *"sao tôi mở rộng cột ra mà trong vẫn bé xíu thế này sao điền… tôi KHÔNG
     MUỐN Ô NÀO KHI VIẾT DÀI RA PHẢI KÉO XUỐNG cả"*.

     Trước đây mỗi bảng một kiểu: Lịch thi khoá cứng bề rộng 112px (kéo cột rộng
     bao nhiêu ô cũng không biết), mấy bảng khác rộng đúng nhưng chặn chiều cao rồi
     cho cuộn TRONG ô — đọc một ô phải kéo hai lần.

     Nay mọi ô nhập dạng bảng mang class `o-bang`:
       · `width:100%` + `box-sizing:border-box` → bám đúng bề rộng cột, kể cả sau
         khi kéo rộng ra. ⛔ Thiếu box-sizing là viền + padding cộng thêm vào 100%,
         ô tràn ra ngoài ô bảng.
       · `resize:none; overflow:hidden` → bỏ thanh cuộn trong ô. Chiều cao do
         `oBangTuCao()` tính theo nội dung.
       · `field-sizing:content` → trình duyệt đời mới (Chrome 123+) tự lo, không
         cần JS. Trình duyệt cũ chưa hiểu thì bỏ qua dòng này, JS vẫn gánh.
     ⚠️ SỬA LẠI 11/08/2026: chỗ này từng ghi "ĐỪNG đặt `table-layout:fixed`". Nay
        `gaKeoCot` CÓ đặt fixed — nhưng chỉ SAU KHI đã ghim bề rộng cho MỌI cột, nên
        không cột nào bị chia đều, layout giữ nguyên. Không có fixed thì thu cột
        không bao giờ hẹp lại được (lỗi cô Quỳnh báo 11/08). Ô tự cao vẫn chạy bình
        thường: fixed khoá BỀ RỘNG cột, chiều cao hàng vẫn giãn theo nội dung.
     ⛔ Vẫn đừng tự tay đặt fixed cho một bảng nào đó mà chưa ghim đủ bề rộng cột. */
  .o-bang { width:100%; box-sizing:border-box; }
  /* ⛔ CỐ Ý KHÔNG dùng `field-sizing:content` (thứ trình duyệt mới tự lo chiều cao).
     Để cả hai cùng chạy là hai cơ chế đá nhau, mà máy cô Quỳnh với máy nhân viên lại
     khác đời trình duyệt — sinh ra cảnh "máy tôi nhìn thì vừa, máy cô thì lệch".
     Một cơ chế duy nhất: `oBangTuCao()`, chạy giống hệt nhau trên mọi máy. */
  textarea.o-bang { resize:none; overflow:hidden; white-space:pre-wrap; line-height:1.45; }

  /* ⭐⭐ 13/09/2026 — Ô TÍCH NHIỀU MỤC: MỖI MỤC MỘT KHỐI VIỀN RIÊNG.
     Boss: *"phải có viền block riêng chứ ko phải như kiểu Cần cố gắng ôn tập thêm
     bài ở nhà · Đã có tiến bộ trong buổi học này, nó đang phân biệt với nhau qua 1
     dấu chấm là khó nhìn"*. Kiểu Boss chốt bằng nút: viền mảnh · bo góc nhẹ · nền
     xám rất nhạt.
     ⛔ Ô này nay là `<div>`, KHÔNG phải `<textarea>` — xem khối luật ở `oTichHTML`
        trong `js/tinh-nang.js` để biết vì sao phải đổi thẻ và những gì đã phải sửa theo.
     ⛔ Màu lấy từ BIẾN (`--vien`, `--nen2`, `--chu`), đừng chép mã màu: cả ba đều có
        bản nền tối riêng, chép cứng là ô trắng bệch giữa bảng tối.
     ⛔ `align-items:flex-start` — mục ngắn không được kéo cao bằng mục dài; mỗi khối
        cao đúng chữ của nó thì hàng mới gọn. */
  .o-tich {
    display: flex; flex-wrap: wrap; gap: 3px 4px; align-items: flex-start;
    padding: 3px 5px; min-height: 26px; cursor: pointer;
    text-align: left; white-space: normal;
  }
  .o-tich[disabled] { cursor: default; opacity: .72; }
  .o-tich:focus-visible { outline: 2px solid var(--xanh); outline-offset: 1px; }
  /* Ô của buổi ĐÃ KHOÁ dùng chung đúng khối viền này (xem `.o-tich-xem`), không thì
     mở lại buổi cũ là các mục về thành dãy chữ nối bằng dấu chấm. */
  .o-tich-xem { display: flex; flex-wrap: wrap; gap: 3px 4px; text-align: left; }
  .o-tich-muc {
    display: inline-block; max-width: 100%;
    border: 1px solid var(--vien); border-radius: var(--r-sm);
    background: var(--nen2); color: var(--chu);
    padding: 1px 6px; font-size: 12.5px; line-height: 1.5;
    overflow-wrap: anywhere;
  }
  /* ⛔⛔ TRỪ Ô TÍCH RA KHỎI TRẦN 22px CỦA CỤM SHEET — LẦN THỨ HAI CÙNG MỘT Ổ.
     Bảng Điểm danh cũng được khoác lớp `sheet-moi` LÚC CHẠY (đo thật 13/09:
     `class="luoi bang-keo-cot sheet-moi"`), nên nó ăn luôn
         `.sheet-moi tbody tr.sheet-hang td > * { max-height: 22px }`
     Ô tích bốn mục cao thật 52px mà chỗ được cấp chỉ 24px, nên khối cuối nằm NGOÀI
     đáy `<td>` — và `.luoi td` có `overflow:hidden` nên nó bị CẮT MẤT. Tích bốn mục
     chỉ thấy ba, không một dòng báo. Đo thật: ô #2 scrollHeight 52 · clientHeight 24
     · 1 khối nằm ngoài đáy ô.
     ⛔ ĐỪNG chữa bằng cách nới luật của cụm Sheet: nó đang giữ cả chục màn dạng sheet
        ở đúng một dòng. Trừ riêng ô này ra mới là chữa gốc.
     ⛔ CHỈ CẦN GỠ TRẦN, KHÔNG CẦN ĐỘNG `overflow` CỦA Ô BẢNG — bộ thử phá đã chứng
        minh: gỡ luật `overflow:visible` ra thì bài vẫn 42/42. Lý do: `height:32px`
        trên `td` là SÀN chứ không phải trần, nên ô tự giãn theo ruột một khi ruột
        không còn bị kẹp; không có gì tràn ra thì `overflow:hidden` chẳng cắt gì.
        Đã gỡ luật thừa ấy — thêm luật không ai cần là để lại bẫy cho người sau.
     Độ nặng: (0,3,3) so với (0,2,3) của luật cụm Sheet nên thắng ở mọi chỗ đặt. */
  .sheet-moi tbody tr.sheet-hang td > .o-tich { max-height: none; }

  /* Ô chưa tích gì — chữ mờ, thay cho `placeholder` mà <div> không có. */
  .o-tich-goi { color: var(--chu-mo); font-size: 12.5px; line-height: 1.5; }

  .tths-sua { width:100%; min-width:82px; border:1px solid var(--vien); border-radius:var(--r-sm);
    padding:3px 7px; font-size:12.5px; font-family:inherit; background:var(--nen-o); color:var(--chu); }
  textarea.tths-note { min-width:150px; min-height:26px; line-height:1.4; resize:none; overflow:hidden; white-space:pre-wrap; }
  /* 🧑‍🎓 Tóm tắt Follow up tự hiện trong ô Note (chỉ đọc), gạch đầu dòng. */
  .tths-fu { min-width:210px; margin-bottom:6px; padding:5px 8px; background:#F1F7FF; border:1px solid #D3E4F7;
             border-radius:var(--r-md); font-size:12px; line-height:1.5; }
  /* ⛔ ĐẦU KHỐI NAY LÀ <button>. Phải gỡ nếp riêng của trình duyệt (nền xám, viền,
     cỡ chữ mặc định), không thì nó hiện ra như một cái nút lạc lõng giữa ô bảng. */
  .tths-fu-dau { font-weight:700; color:#1F63B8; font-size:11px; margin-bottom:2px;
    display:flex; align-items:center; gap:4px; width:100%;
    background:none; border:0; padding:0; margin-top:0; font-family:inherit;
    text-align:left; }
  /* ⛔ KHÔNG khai `cursor:pointer` ở đây — thừa. `css/nen.css:751` đã đặt
     `button { cursor:pointer }` cho cả app. Bộ thử phá 20/09 chứng minh: gỡ dòng
     ấy ra thì bài vẫn 17/17, tức nó chẳng giữ gì. Luật không ai cần là bẫy để lại
     cho người sau. Con trỏ bàn tay ở đây có được là NHỜ đầu khối là <button> thật. */
  .tths-fu-dau:hover { text-decoration:underline; }
  .tths-fu-dau .tths-fu-ten { flex:1; }
  .tths-fu-mui { transition:transform .15s ease; }
  /* ═══════════════════════════════════════════════════════════════════════════
     THU GỌN 3 DÒNG, BẤM MỚI BUNG — Boss chốt bằng nút 20/09/2026
     ───────────────────────────────────────────────────────────────────────
     Boss chọn "Gọn 3 dòng, bấm mới bung ra" thay vì để hàng cao hết: bảng này
     dùng để RÀ NHIỀU EM, cao hết thì mỗi màn chỉ còn ba em.
     Số 3 dòng tính ra px: đầu khối ~17px + 3 dòng × (12px × 1,5) = 54px
     + đệm trên dưới 10px ≈ 81px. Lấy tròn 82px.
     ⛔ `overflow:hidden` ở đây KHÔNG phải cho đẹp — nó là thứ chặn đúng lỗi Boss
        báo. Trước bản vá, khối này bị ghim `max-height:22px` mà `overflow` là
        `visible`, nên chữ tràn ra vẽ ĐÈ lên ô nhập (đo 20/09: đè 110px).
        Ghim chiều cao mà không ghim tràn thì chữ vẫn chồng — hai thứ phải đi đôi.
     ⛔ Bung ra thì PHẢI `max-height:none`, đừng đặt một số to hơn: nội dung thật
        dài tới đâu không ai biết trước, đặt số là lại chồng chữ đúng kiểu cũ.
     ═══════════════════════════════════════════════════════════════════════════ */
  /* ⛔⛔ HAI BỘ CHỌN DÀI DÒNG DƯỚI ĐÂY LÀ CỐ Ý — ĐỪNG RÚT GỌN VỀ `.tths-fu-gon`.
     Luật gỡ trần ở trên là `.sheet-moi tbody tr.sheet-hang td > .tths-fu` (0,3,3).
     Viết `.tths-fu.tths-fu-gon` (0,2,0) thì NHẸ HƠN, thua bất kể đứng sau — đo
     20/09/2026: khối mang đủ lớp `tths-fu-gon` mà `max-height` vẫn ra `none`,
     cao 146px thay vì 82px, tức thu gọn KHÔNG ăn một tí nào.
     Phải bám đúng cái đường ấy rồi cộng thêm một lớp mới thắng. */
  /* ⛔⛔ CHỖ CẮT ĐẶT LÊN `.tths-fu-ds` (phần gạch đầu dòng), KHÔNG đặt lên cả
     khối — và ghim theo ĐƠN VỊ DÒNG chứ không theo px.
     Bản đầu ghim `max-height:82px` lên cả khối: mức cắt rơi vào GIỮA mặt chữ,
     nửa trên của một dòng còn thò ra (xem scratchpad/anh-ghichu3/1-gon.png).
     Không con số px nào đúng cho mọi ca, vì đầu khối là chữ 11px còn gạch đầu
     dòng là chữ 12px và có dòng cuộn thành hai.
     `4.5em` ở cỡ chữ 12px giãn dòng 1,5 = đúng 3 dòng, nên mức cắt LUÔN rơi
     đúng giữa hai dòng. Đổi cỡ chữ thì nó tự theo — đó là lý do dùng `em`.
     ⛔ Độ nặng phải bám theo đường `.sheet-moi tbody tr.sheet-hang td` như luật
        gỡ trần ở trên, nếu không lại thua y như lần trước (đo ra `max-height:none`
        trong khi khối mang đủ lớp thu gọn). */
  .sheet-moi tbody tr.sheet-hang td > .tths-fu.tths-fu-gon > .tths-fu-ds,
  td > .tths-fu.tths-fu-gon > .tths-fu-ds { max-height:4.5em; overflow:hidden; }
  /* Bấm vào ô để sửa ghi chú thì cũng coi như muốn đọc hết. */
  .sheet-moi tbody tr.sheet-hang td:focus-within > .tths-fu.tths-fu-gon > .tths-fu-ds,
  td:focus-within > .tths-fu.tths-fu-gon > .tths-fu-ds { max-height:none; overflow:visible; }
  .tths-fu:not(.tths-fu-gon) .tths-fu-mui { transform:rotate(180deg); }
  /* Ghi chú tay cũng gọn lại khi KHÔNG gõ — cùng nếp với khối trên, để một hàng
     không tự nhiên cao vọt chỉ vì một em có ghi chú dài.
     `textarea.o-bang` vốn đã `overflow:hidden` nên cắt gọn, không chồng chữ. */
  .sheet-moi tbody tr.sheet-hang td > textarea.tths-note:not(:focus) { max-height:58px; }
  /* ════════════════════════════════════════════════════════════════════════════
     MỞ Ô GHI CHÚ RA THÌ HÀNG PHẢI NỞ ĐỦ — Boss 20/09/2026
     ────────────────────────────────────────────────────────────────────
     Boss: *"Cột ghi chú của thông tin học sinh lúc mở ra vẫn bị đè lên chữ ở dưới mà
     ko có nền, tôi cần lúc nó mở ra thì phải mở rộng cả hàng đó cho tôi để vừa với
     hàng xuống dòng trong ô ghi chú đó."*

     ĐO TẬN TAY 20/09/2026 (Chrome thật, màn Thông tin học sinh):
       ô ghi chú đang gõ → `max-height` tính ra **80px**, `overflow: hidden`
     Thủ phạm là luật DÙNG CHUNG của bảng kiểu Sheet:
         `.sheet-moi tbody tr.sheet-hang td > textarea { max-height: 80px }` (0,3,4)
     Luật ấy cố ý kẹp ô chữ lại **bốn dòng** cho bảng phẳng như Excel — nhưng nó
     KHÔNG trừ lúc đang gõ ra, trong khi chú thích của chính nó hứa *"Bấm vào ô thì
     hiện đủ chữ"*. Nên ghi chú dài hơn bốn dòng thì phần thừa bị CẮT MẤT ngay
     giữa lúc người ta đang sửa nó.

     ⛔⛔ CHỪA RIÊNG Ô GHI CHÚ RA, ĐỪNG NẮN LUẬT CHUNG. Luật chung đang giữ cả chục
        màn dạng sheet ở bốn dòng, KỂ CẢ lưới Điểm danh — mà Boss cấm động vào
        cách chạy của màn Điểm danh. Chỉ ô `.tths-note` đang được gõ mới được nới.

     ⛔ ĐỘ NẶNG PHẢI ĐỦ ĐỂ THẮNG. Luật chung là (0,3,4); viết
        `textarea.tths-note:focus` (0,2,1) thì NHẸ HƠN, thua bất kể đứng sau — đúng
        cái bẫy đã cắn ở khối "thu gọn 3 dòng" ngay trên. Phải bám nguyên đường
        `.sheet-moi tbody tr.sheet-hang td >` rồi cộng thêm lớp và `:focus`.

     ⛔ `height` của ô do JS đặt theo `scrollHeight` (xem `tthsVeBody`), nên gỡ trần
        là ô tự cao đúng bằng nội dung, và `<td>` kéo cả hàng cao theo — `height`
        trên ô bảng là SÀN chứ không phải trần. Đó là lý do không phải động gì tới JS.

     ⛔ CÓ NỀN ĐẮC — Boss nói rõ *"mà ko có nền"*. Ô đang gõ vốn trong suốt
        (đo được `rgba(0,0,0,0)`), nên dù không còn đè nữa thì chữ vẫn dính vào nền
        sọc của bảng và đọc rất rối. Đặt nền theo biến nền thẻ để nền tối cũng đúng.
     ════════════════════════════════════════════════════════════════════════════ */
  /* ⛔ `table.sheet-moi` — chữ `table` KHÔNG PHẢI THỪA. Luật thu gọn ngay trên đạt
        (0,4,4); câu này phải nặng hơn mới thắng. Thêm tên thẻ `table` đưa nó lên
        (0,4,5) — thắng ở mọi thứ tự, khỏi phụ thuộc chỗ đặt trong tệp.
     ⛔ `overflow: hidden` chứ KHÔNG `visible`: ô nay nằm trong dòng chảy và cao đúng
        bằng nội dung (JS đặt `height = scrollHeight`), nên không còn gì để tràn; để
        `visible` là mở đường cho chữ thò ra ngoài ô đúng lúc lỡ đo hụt một dòng.
     ⛔ CÓ NỀN VÀ CÓ MÀU CHỮ. Ô vốn trong suốt (đo được `rgba(0,0,0,0)`), mà hàng chẵn
        của bảng có nền sọc — thiếu nền thì chữ dính vào sọc, đúng câu Boss chê
        *"ko có nền"*. Lấy theo biến nền thẻ để nền tối cũng đúng. */
  table.sheet-moi tbody tr.sheet-hang td.tths-o-mo > textarea.tths-note,
  .sheet-moi tbody tr.sheet-hang td > textarea.tths-note:focus {
    max-height: none;
    overflow: hidden;
    background: var(--the, #fff);
    color: var(--chu, #141F1E);
    /* ⛔⛔ VIỀN VẼ BẰNG BÓNG ĐỔ, KHÔNG DÙNG `border` — trả giá 20/09/2026.
       `border` thật ăn vào chiều cao (ô `box-sizing: border-box`), nên JS đặt
       `height = scrollHeight` là chữ cụt đúng bề dày viền: đo được cần 240px, được
       cấp 238px. Bù ở JS thì vá được MỘT đường, nhưng `oBangHenDo` — lượt gộp
       theo khung hình của `ResizeObserver` — lại ghi đè chiều cao mà không bù, và
       700ms sau ô cụt lại y như cũ (đo tận tay).
       `box-shadow: inset` vẽ y hệt một đường viền mà KHÔNG chiếm một ly bố cục nào,
       nên mọi đường đặt chiều cao đều tự đúng, khỏi ai phải nhớ bù.
       ⛔ Đừng "sửa cho chuẩn" bằng cách đổi lại thành `border`. */
    box-shadow: inset 0 0 0 1px var(--sheet-chon-vien, #00793A);
    border-radius: 3px;
  }
  /* Đang SỬA thì viền đậm hơn — cùng nếp với ô nở kiểu đè (`sheet-o-no-sua`), để
     người ta nhìn là biết đang xem hay đang viết. `box-sizing` của ô đã là
     `border-box` nên đổi bề dày viền không làm ô nhảy một li. */
  table.sheet-moi tbody tr.sheet-hang td.tths-o-mo.sheet-o-no-sua > textarea.tths-note {
    box-shadow: inset 0 0 0 2px var(--sheet-chon-vien, #00793A);
  }
  .tths-fu-m { color:var(--chu); }
  .tths-fu-nhan { font-weight:700; }
  body.toi .tths-fu { background:rgba(31,99,184,.12); border-color:rgba(120,170,230,.35); }
  /* ═══════════════════════════════════════════════════════════════════════════
     TÓM TẮT FOLLOW UP PHẢI XUỐNG DÒNG — Boss 20/09/2026
     ───────────────────────────────────────────────────────────────────────
     Boss: *"cột ghi chú thông tin ko xuống dòng và gạch đầu dòng… xem là rõ ko
     đọc được do câu ko xuống dòng"*.

     ĐO TẬN MẮT (Chrome thật, khối có 4 mục):
       `top` của 4 mục = [265, 265, 265, 265]  → dồn đúng MỘT dòng
       `.tths-fu` computed ra **inline-flex**, rộng **1932px** trong ô **571px**

     ⛔ THỦ PHẠM KHÔNG NẰM Ở LUẬT `.tths-fu` NGAY TRÊN — chỗ ấy khai đúng.
        Luật DÙNG CHUNG của bảng kiểu Sheet đè lên:
            `.sheet-moi tbody tr.sheet-hang td > div { display: inline-flex }` (0,2,4)
        `.tths-fu` là `div` con trực tiếp của `td` nên dính luật ấy.
     ⛔ ĐừNG "SỬA CHO GỌN" BẮNG CÁCH ĐỔI LUẬT CHUNG. Nó phục vụ MỌI bảng kiểu
        Sheet, kể cả lưới Điểm danh — mà Boss cấm sửa cách chạy màn Điểm danh.
        Đây là luật riêng (0,3,4), đủ mạnh để thắng và chỉ thắng ở đúng một chỗ.
     ⛔ PHẢI ĐẶT `white-space` Ở CẢ KHỐI LẪN MỤC CON. `nowrap` trên `td` truyền
        xuống hết cây; đặt mỗi khối cha thì các mục con vẫn nằm nguyên một hàng.
     ═══════════════════════════════════════════════════════════════════════════ */
  .sheet-moi tbody tr.sheet-hang td > .tths-fu,
  td > .tths-fu {
    display:block; white-space:normal; width:100%; box-sizing:border-box;
    /* ⛔⛔ `max-height:none` LÀ PHẦN QUAN TRỌNG NHẤT CỦA LUẬT NÀY — ĐỪNG XOÁ.
       Cụm bảng-Sheet ghim `.sheet-moi tbody tr.sheet-hang td > * {max-height:22px}`
       (0,2,3). Khối này là con trực tiếp của `td` nên dính trần ấy, mà `overflow`
       của nó là `visible` ⇒ chữ KHÔNG bị cắt, nó TRÀN RA NGOÀI HỘP rồi vẽ ĐÈ lên
       ô nhập ghi chú ngay dưới. Đo 20/09/2026 (Chrome thật, 1280px, 14 em có
       Follow up đủ bốn ô):
           cao hộp 22px · nội dung cần 132px · vẽ đè xuống ô nhập 110px
       Đúng cái Boss chê *"ấn vào nó bị lỗi chữ viết trong không nhìn được"*.
       Đây là LẦN THỨ BA cùng một ổ — `.o-tich` cũng đã phải trừ ra y như vậy. */
    max-height:none;
  }
  .tths-fu .tths-fu-dau,
  .tths-fu .tths-fu-m { display:block; white-space:normal; word-break:break-word; }
  /* Gạch đầu dòng thẳng hàng: dấu • đứng riêng một cột, chữ dài xuống dòng
     thì thụt vào cho khớp — không thì dòng thứ hai chạy ra sát lề, đọc rối mắt. */
  .tths-fu .tths-fu-m { padding-left:11px; text-indent:-11px; }
  /* ⛔⛔ CHÚ THÍCH CŨ Ở ĐÂY KẾT LUẬN SAI NGUYÊN NHÂN — ĐÃ THAY, 20/09/2026.
     Bản cũ viết: *"đã thử cho hàng giãn theo nội dung, hàng chỉ cao từ 33px lên
     55px trong khi nội dung cần ~80px… bảng kiểu Sheet ghim chiều cao dòng nên
     hàng không giãn tự do được ⇒ giữ ô cao cố định"*.
     ⛔ SAI Ở CHỖ ĐỔ TỘI CHO CHIỀU CAO HÀNG. `height` trên `td` của cụm Sheet là
        SÀN chứ không phải trần (đã ghi rõ ở khối `.o-tich` bên trên). Hàng không
        giãn được là vì RUỘT bị ghim `max-height:22px`, chứ không phải vì hàng.
     Đo lại 20/09/2026 sau khi gỡ đúng cái trần ấy: hàng tự cao theo nội dung, chữ
     hết chồng. Người sau đọc câu cũ rồi tin là "không sửa được" thì sẽ để nguyên
     một màn Boss đọc không nổi. */
  /* 📝 Điểm Progress test từng kỳ trong Thông tin HS. */
  .tths-diem { display:flex; flex-direction:column; gap:2px; min-width:96px; }
  .tths-diem-ky { font-size:12px; background:#EAF7EF; border:1px solid #BFE6CE; border-radius:var(--r-sm); padding:1px 7px; white-space:nowrap; cursor:default; }
  .tths-diem-nhan { color:var(--mo); }
  .tths-diem-ky b { color:#1E8049; }
  .tths-diem-trong { color:var(--mo); }
  body.toi .tths-diem-ky { background:rgba(46,158,91,.14); border-color:rgba(120,200,150,.35); }
  body.toi .tths-diem-ky b { color:#7FD9A6; }
  .tths-sua:focus { outline:none; border-color:var(--xanh); box-shadow:0 0 0 2px rgba(20,160,160,.14); }
  .tths-sua.dang { border-color:var(--cam); }
  .tths-sua.xong { border-color:#2E9E5B; background:#EAF7EF; }
  .tths-sua.loi { border-color:var(--do); }
  body.toi .tths-sua { background:var(--nen-o); color:var(--chu); }
  .tths-tt { font-size:11.5px; font-weight:700; border-radius:var(--r-xl); padding:1px 8px; white-space:nowrap; display:inline-block; }
  .tths-tt.ong { background:#E4F5EB; color:#1E8049; }
  .tths-tt.min { background:#E4EFFB; color:#1F63B8; }
  .tths-tt.mout { background:#FDECDD; color:#B5610F; }
  .tths-tt.stop { background:#FBE7E7; color:#C23636; }
  .tths-tt.baoluu { background:#EEF0F2; color:#5A6472; }
  .tths-tt.khac { background:#EEF0F2; color:#8A94A2; }
  @media (max-width:820px){ .tths-tim { flex:1 1 100%; } }
  .tths-coso { display:flex; flex-wrap:wrap; gap:7px; margin:0 0 10px; }
  .tths-cs-nut { font-size:12.5px; font-weight:700; padding:5px 13px; border-radius:var(--r-xl); cursor:pointer;
    border:1px solid var(--vien); background:#fff; color:var(--muc); }
  .tths-cs-nut:hover { border-color:var(--xanh); }
  .tths-cs-nut.chon { background:var(--xanh); color:#fff; border-color:var(--xanh); }
  /* Hàng nút lọc KHỐI (cô Quỳnh 08/08/2026): "phụ huynh hỏi lớp này có bao nhiêu
     lớp thì tìm riêng tổng các lớp khối đó". Dùng lại y hệt kiểu nút cơ sở cho
     quen mắt, chỉ thêm chữ "Khối:" đứng trước và số lớp in mờ trong nút. */
  .tths-khoi { align-items:center; }
  .tths-khoi-lb { font-size:12.5px; font-weight:700; color:var(--mo); margin-right:2px; }
  .tths-cs-nut .tths-dem { opacity:.62; font-weight:600; margin-left:4px; }
  .tths-cs-nut.chon .tths-dem { opacity:.85; }
  .tths-khoi-bao { display:inline-block; margin-top:5px; font-size:13px; color:var(--xanh); }
  .tths-khoi-bao a { color:var(--mo); text-decoration:underline; margin-left:4px; }
  /* Bảng LỚP — mỗi lớp một dòng, dùng khi đang lọc khối. Hàng thưa hơn bảng học
     sinh vì ít dòng hẳn, đọc lướt cho nhanh. */
  .tths-bang-lop td { padding:8px 10px; }
  .tths-bang-lop .tths-siso { text-align:center; }
  .tths-bang-lop .tths-siso b { font-size:15px; }
  /* 📅 23/09/2026 — Ô "Lịch học" của Khối & lớp: MỖI THỨ MỘT DÒNG, y như dòng giờ
     của thẻ lớp ở sảnh Điểm danh (`.the-lop .tl-gio`) — Boss chốt. Dựng ở `klOLich`.
     ⛔ Bảng này bị khoác áo Sheets LÚC CHẠY (`sheet-moi`/`sheet-hang` — grep CSS
        không thấy), mà áo ấy ép mọi ô về MỘT dòng: `td > span { display:inline-flex }`
        xếp các dòng NẰM CẠNH NHAU, `td > * { max-height:22px }` xén dòng dưới. Nhả
        ĐÚNG ô này bằng bộ chọn bốn lớp (0,4,3) — thắng chắc cả hai luật ấy dù ai đếm
        chúng là (0,2,4) hay (0,3,4). ⛔ Đừng nhả ở tầng chung: trần 22px là thứ giữ
        mọi bảng khác "phẳng như Excel" (Boss chốt 10/09).
     ⛔ Từng dòng KHÔNG xuống dòng giữa chừng: "T4: 18:00–19:30" đứt đôi là đọc sai
        giờ. Cột hẹp thì ô cắt thẳng như mọi ô Sheets — không đặt `overflow` lên dòng,
        để ô vẫn biết mình đang cắt chữ mà mở khung xem khi bấm.
     `tabular-nums` cho các dòng giờ thẳng cột như trong bảng tính (y như thẻ lớp). */
  .tths-bang-lop td.kl-lich > .kl-lich-dong,
  .sheet-moi tbody tr.sheet-hang td.kl-lich > .kl-lich-dong {
    display:block; max-height:none; white-space:nowrap; font-variant-numeric:tabular-nums; }
  /* Dòng mờ: nguyên văn cột Thứ khi không dòng nào tự nói được thứ — như dòng xám
     `.phu` của thẻ lớp. */
  .tths-bang-lop td.kl-lich > .kl-lich-phu { color:var(--mo); }
  /* Dấu ≠ = lớp này có nhiều ngày khác nhau, con số hiện ra chỉ là ngày đông
     người nhất. Rê chuột vào ô sẽ thấy rõ bao nhiêu em trùng. */
  .tths-lech { color:var(--mo); font-weight:700; cursor:help; }
  /* Hai hàng lọc của màn "Khối & lớp". Mỗi hàng có NHÃN riêng bên trái và một
     đường kẻ ngăn, để không ai lẫn hàng cơ sở với hàng khối nữa (cô Quỳnh
     08/08/2026: *"tôi ấn khối xong chọn cơ sở thì bị trùng"*). */
  .kl-loc { border:1px solid var(--vien); border-radius:var(--r-xl); padding:4px 12px; margin:0 0 12px; }
  .kl-hang { display:flex; align-items:flex-start; gap:12px; padding:9px 0; }
  .kl-hang + .kl-hang { border-top:1px dashed var(--vien); }
  .kl-nhan { flex:0 0 58px; font-size:12.5px; font-weight:700; color:var(--mo);
 padding-top:6px; }
  .kl-nut { display:flex; flex-wrap:wrap; gap:7px; flex:1; }
  /* Huy hiệu SỐ LỚP trên nút — nền riêng, tách hẳn khỏi tên khối. */
  .kl-so { display:inline-flex; align-items:center; justify-content:center; min-width:20px; height:19px;
    padding:0 6px; margin-left:7px; border-radius:var(--r-lg); font-size:11.5px; font-weight:700;
    background:var(--vien); color:var(--mo); }
  .tths-cs-nut.chon .kl-so { background:rgba(255,255,255,.28); color:#fff; }
  #klTom a { color:var(--xanh); text-decoration:underline; margin-left:6px; font-size:12.5px; }

  /* ── 🏫 SET UP KHỐI (Boss 20/09/2026) ──────────────────────────────────────
     Nút mở nằm ngay trong hàng nút Khối, đẩy sang mép phải để không lẫn vào dãy
     nút lọc — bấm nhầm "Set up" khi đang định lọc là mở cả một hộp toàn màn. */
  .kl-nut-setup { flex:0 0 auto; margin-left:auto; align-self:flex-start; }
  /* Hộp setup: đầu · thanh lọc · bảng cuộn · chân. Chỉ BẢNG được co giãn, ba phần
     kia giữ nguyên chiều cao — không thì thanh lọc và hàng nút gán trôi mất khi
     danh sách dài, mà đó là hai thứ phải luôn với tới được. */
  .ks-lay { display:flex; flex-direction:column; gap:10px; min-height:0; height:100%; }
  .ks-dau-hang { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
  .ks-khoi-ds { display:flex; flex-wrap:wrap; gap:6px; margin-top:7px; }
  /* ⛔⛔ 20/09/2026 — HÀNG NÀY NAY LÀ CHỖ GÁN, KHÔNG CÒN LÀ BẢNG TRƯNG BÀY.
     Boss chê: *"nó đang hơi bị rối rắm cho người mới"*, và chỉ đúng ba chỗ. Chỗ
     thứ nhất là hàng này: nó trông y như một hàng nhãn, bấm vào không xảy ra gì.
     Nay nó vừa là bảng đếm, vừa là nút gán, vừa là rổ nhận lớp thả vào — nên
     PHẢI TRÔNG NHƯ BẤM ĐƯỢC. Đây đúng chặng ② của skill `cong-cu-cho-nguoi-that`:
     có trong mã chưa đủ, phải HIỆN RA cho người dùng thấy.
     ⛔ 34px chiều cao tối thiểu: hàng này là đích bấm chính trên điện thoại, mà
        chuẩn ngành là 44px cho ngón tay — khổ nhỏ nới lên 44px ở khối @media
        dưới đáy, khổ máy tính giữ 34px cho đỡ chiếm chỗ. */
  .ks-khoi-the { display:inline-flex; align-items:center; gap:6px; padding:5px 11px;
    min-height:34px; border:1px solid var(--vien); border-radius:var(--r-lg);
    font-size:12.5px; font-weight:600; color:var(--chu); background:var(--nen-o, #fff);
    cursor:pointer; transition:background .14s ease, border-color .14s ease,
                              box-shadow .14s ease, transform .1s ease; }
  .ks-khoi-the:hover { border-color:var(--muc); background:var(--xanh-nhat); }
  .ks-khoi-the:active { transform:translateY(1px); }
  .ks-khoi-the:focus-visible { outline:2px solid var(--muc); outline-offset:2px; }
  .ks-khoi-the b { font-weight:700; color:var(--mo); font-size:11.5px; }
  /* Khối đang lọc: tô hẳn lên, vì lúc ấy bảng dưới chỉ còn lớp của nó — người
     dùng phải thấy ngay vì sao danh sách vừa ngắn lại. */
  .ks-khoi-the.dang-loc { border-color:var(--muc); background:var(--xanh-nhat); color:var(--muc); }
  .ks-khoi-the.dang-loc b { color:var(--muc); }
  .ks-khoi-khac { border-style:dashed; color:var(--mo); }
  /* ⭐ 22/09/2026 — KHỐI ĐANG CHỌN (Boss chốt 21/09: tick = lớp thuộc khối đang chọn).
     Tô ĐẶC, khác hẳn kiểu "đang lọc" ở trên: mọi dấu tick bên dưới đang nói về
     đúng khối này, nhìn lướt phải thấy ngay là khối nào.
     ⛔ Chữ lấy `--the` (màu mặt thẻ), KHÔNG lấy #fff: ở giao diện tối `--muc` là
        teal SÁNG (#4DB6AC), chữ trắng trên đó gần như không đọc được — chữ màu
        mặt thẻ thì sáng/tối đều tương phản đủ. */
  .ks-khoi-the.dang-chon,
  .ks-khoi-the.dang-chon:hover { background:var(--muc); border-color:var(--muc); color:var(--the); }
  .ks-khoi-the.dang-chon b { color:var(--the); }
  /* Thẻ khối vẽ vào một vỏ riêng để ô "＋ Khối mới" đứng ngoài lượt vẽ lại — vỏ
     ấy `display:contents` để thẻ vẫn xếp thẳng hàng như con trực tiếp của hàng. */
  .ks-khoi-the-boc { display:contents; }
  /* ＋ Khối mới — đứng cuối hàng khối (Boss chốt 21/09): gõ tên, Enter. */
  .ks-khoi-moi { display:inline-flex; align-items:center; }
  .ks-khoi-moi-nut { display:inline-flex; align-items:center; gap:5px; min-height:34px; padding:5px 11px;
    border:1px dashed var(--muc); border-radius:var(--r-lg); background:transparent; color:var(--muc);
    font-size:12.5px; font-weight:600; cursor:pointer; }
  .ks-khoi-moi-nut:hover { background:var(--xanh-nhat); }
  .ks-khoi-moi-nut:focus-visible { outline:2px solid var(--muc); outline-offset:2px; }
  .ks-khoi-moi-o { display:inline-flex; align-items:center; gap:6px; }
  .ks-khoi-moi-o input { width:190px; min-height:34px; }

  /* ── Kéo thả: cả hàng sáng lên khi có lớp đang được kéo ──────────────────
     ⛔ Báo hiệu phải nằm ở CHỖ NHẬN, không ở chỗ kéo. Người ta đang nhìn theo
        ngón tay/con trỏ, nên thứ cần nói "thả vào đây được" là mấy cái rổ. */
  .ks-khoi-ds.dang-nhan-tha .ks-khoi-the { border-style:dashed; border-color:var(--muc); }
  .ks-khoi-ds.dang-nhan-tha .ks-khoi-khac { opacity:.45; border-color:var(--vien); }
  .ks-khoi-the.ks-tha-toi { border-style:solid; border-color:var(--muc);
    background:var(--xanh-nhat); box-shadow:0 0 0 3px var(--xanh-nhat); transform:scale(1.04); }

  /* Dòng mách dưới hàng khối — nói TRƯỚC bấm vào sẽ ra gì. Cùng một thẻ khối làm
     hai việc tuỳ lúc, không có dòng này thì đúng là "bày ra mà đoán mới dùng". */
  .ks-mach { margin:8px 0 0; font-size:12.5px; color:var(--mo); line-height:1.5; }
  .ks-mach.co-tick { color:var(--chu); }
  .ks-mach b { color:var(--muc); }
  .ks-mach-phu { display:block; font-size:11.5px; opacity:.85; }
  /* Dòng "đang chỉ hiện…" — KHÔNG ẩn trên điện thoại như `.ks-mach-phu`: bảng
     đang ngắn đi vì bộ lọc, người ta phải biết vì sao và bỏ lọc ở đâu. */
  .ks-mach-loc { display:block; font-size:12px; color:var(--chu); margin-top:2px; }
  .ks-mach-loc a { color:var(--muc); font-weight:600; }
  .ks-thanh { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
  .ks-tim { flex:1 1 220px; min-width:0; }
  .ks-chon { flex:0 0 auto; max-width:200px; }
  .ks-dem { font-size:12.5px; color:var(--mo); margin-left:auto; }
  /* ⭐ 22/09/2026 — "Chọn tất cả lớp đang hiện" TO VÀ RÕ (Boss chốt 21/09).
     Mang `.nut-chinh` cho đúng màu nút chính của app, nhưng ⛔ `.nut-chinh` gốc là
     `width:100%` (di sản ô đăng nhập — xem css/man.css): không kẹp lại ở đây
     là nó thành một dải teal chạy suốt bề ngang hộp. */
  .ks-thanh > .ks-tat-ca { width:auto; flex:none; height:38px; padding:0 16px; font-size:13.5px;
    display:inline-flex; align-items:center; gap:7px; }
  /* Đã tick đủ → nút thành "Bỏ chọn tất cả": hạ xuống nút viền cho khỏi nhầm là
     việc chính, vì bấm vào là GỠ lớp ra. */
  .ks-thanh > .ks-tat-ca.bo-het { background:var(--the); color:var(--chu); border:1px solid var(--vien); }
  .ks-thanh > .ks-tat-ca.bo-het:hover { border-color:var(--muc); background:var(--xanh-nhat); }
  /* Dòng báo trong hộp: "Đang lưu…" · "✓ Đã lưu" · lỗi · nút Hoàn tác.
     ⛔ Báo NGAY TRONG HỘP chứ không dùng toast — `.toast` (z-index 200) nằm dưới
        nền hộp thoại (12000), hiện ra sau lưng hộp toàn màn. */
  .ks-luu { flex:1 1 100%; min-height:18px; font-size:12.5px; color:var(--mo); }
  .ks-luu.ok { color:var(--muc); font-weight:600; }
  .ks-luu.loi { color:var(--do); font-weight:600; }
  .ks-hoantac { display:inline-flex; align-items:center; gap:4px; margin-left:6px; padding:2px 9px;
    border:1px solid var(--vien); border-radius:var(--r-md); background:var(--the); color:var(--chu);
    font-size:12px; font-weight:600; cursor:pointer; }
  .ks-hoantac:hover { border-color:var(--muc); }
  /* Tên khối đang chọn đứng trên cột tick — cho xuống dòng, đừng cắt chữ. */
  .ks-bang th.ks-o-tick { white-space:normal; font-size:11px; line-height:1.25; }
  .ks-bang-boc { flex:1 1 auto; min-height:120px; overflow:auto;
    border:1px solid var(--vien); border-radius:var(--r-lg); }
  .ks-dong { cursor:pointer; }
  .ks-dong.chon { background:var(--xanh-nhat, rgba(0,122,255,.10)); }
  /* Rong 54px: chua vua tay nam keo (⠿) va o vuong dung canh nhau. De 34px
     nhu cu thi hai thu chong len nhau, hoac tay nam bi day xuong dong. */
  .ks-o-tick { width:54px; text-align:center; white-space:nowrap; }
  /* ⛔ Ô vuông KHÔNG tự nhận cú bấm: cả HÀNG đã nghe click rồi, để ô nghe nữa là
     một cú bấm đếm hai lần và tick tự bật rồi tắt ngay. */
  .ks-tick { pointer-events:none; }
  /* ⛔⛔ 20/09/2026 — ĐÁNH DẤU CÁI HIẾM, ĐỪNG ĐÁNH DẤU CÁI PHỔ BIẾN.
     Chỗ rối ② Boss chỉ ra: chữ "tự đoán" đứng cạnh 124 trên 125 dòng (đo ở kho
     Boss), nên nó chẳng phân biệt được gì, chỉ thành một cột chữ xám nhiễu mắt.
     Nay chip của lớp ĐÃ GÁN TAY được tô đậm kèm dấu ✓ — số ấy ít, nên nhìn lướt
     là thấy ngay lớp nào đã chốt, lớp nào còn để app đoán.
     ⛔ `.ks-tudoan` GIỮ LẠI trong tệp này: nó còn được dùng ở chú giải một lần
        dưới hàng khối. Xoá đi là chú giải ấy mất kiểu. */
  .ks-chip { display:inline-block; padding:1px 7px; margin:1px 2px 1px 0;
    border-radius:var(--r-lg); background:var(--vien); font-size:11.5px; color:var(--mo); }
  .ks-chip-tay { background:var(--xanh-nhat); color:var(--muc); font-weight:600; }
  .ks-chip-dau { font-style:normal; margin-right:3px; font-size:10.5px; }
  .ks-tudoan { font-size:11.5px; color:var(--mo); font-style:italic; }

  /* Tay nắm kéo: chỉ bày ra ở máy có CHUỘT. Trên cảm ứng kéo thả bằng ngón rất
     khó trúng, nên ở đó Boss chốt dùng lối bấm thẳng vào tên khối — bày thêm tay
     nắm chỉ tổ mời người ta thử một lối khó dùng.
     ⛔ `pointer: fine` chứ không `max-width`: laptop cảm ứng vừa có chuột vừa
        chạm được, mà bề ngang màn không nói lên điều đó. */
  .ks-nam { display:none; }
  @media (pointer: fine) {
    .ks-nam { display:inline-block; margin-right:7px; color:var(--mo);
      font-size:12px; cursor:grab; user-select:none; }
    .ks-dong:hover .ks-nam { color:var(--muc); }
  }
  .ks-dong.dang-keo { opacity:.45; }
  /* (22/09/2026 — `.ks-chan` / `.ks-datick` đã bỏ cùng nút "Gỡ khỏi khối": bỏ tick
     chính là gỡ.) */
  @media (max-width:640px) {
    /* Điện thoại: thanh lọc và hàng nút gán xếp dọc, mỗi thứ một hàng đủ rộng để
       bấm trúng. Xem lời răn về trục ngay dưới — cùng một bài học. */
    .ks-tim { flex:1 1 100%; max-width:none; }
    /* ⛔ HAI Ô XỔ ĐỨNG CHUNG MỘT HÀNG. Đo ở 390px: mỗi thứ một hàng thì phần
       lọc ăn 3 hàng, bảng lớp chỉ còn 138px — vừa đúng ba dòng học sinh. Mà bảng
       ấy mới là chỗ người ta phải tick. Chia đôi hàng trả lại một hàng cho bảng. */
    .ks-chon { flex:1 1 calc(50% - 4px); max-width:none; min-width:0; }
    .ks-dem { margin-left:0; }
    /* Dòng "Đã lưu" đứng CHUNG HÀNG với "N lớp đang hiện" — màn hẹp, mỗi hàng
       nhường lại được là bảng lớp (chỗ phải tick) cao thêm một hàng. */
    .ks-luu { flex:1 1 0; min-width:0; }
    /* Nút "Chọn tất cả" là việc chính của hộp: cả hàng, cao đủ ngón tay. */
    .ks-thanh > .ks-tat-ca { flex:1 1 100%; height:44px; justify-content:center; }
    .ks-khoi-moi-nut { min-height:44px; flex:0 0 auto; }
    .ks-khoi-moi-o input { width:150px; min-height:44px; }
    /* Câu phụ trong dòng mách là mẹo dùng thêm, không phải bước bắt buộc — trên
       màn hẹp nó ăn hai dòng để nói một điều người ta sẽ tự thấy khi bấm thử. */
    .ks-mach-phu { display:none; }
    /* Hàng khối là ĐÍCH BẤM CHÍNH trên điện thoại (Boss chốt: khổ nhỏ thì bấm
       thẳng vào tên khối để gán). Chuẩn ngành 44px cho ngón tay — Apple 44×44,
       Google Material 48×48dp. Dưới ngưỡng ấy là bấm trượt sang khối bên cạnh,
       mà bấm trượt ở đây nghĩa là gán nhầm cả chục lớp vào sai khối. */
    .ks-khoi-the { min-height:44px; padding:7px 13px; font-size:13px; flex:0 0 auto; }
    /* ⛔⛔ MỘT HÀNG CUỘN NGANG, KHÔNG XUỐNG DÒNG.
       Nhìn tận mắt ở 390px mới thấy: 15 khối × 44px xếp thành sáu hàng, nuốt
       gần hết màn, đẩy cả bảng lớp xuống dưới tầm nhìn — mà bảng ấy mới là chỗ
       phải tick lớp trước. Người dùng mở ra chỉ thấy một rừng nút, không biết
       bắt đầu từ đâu — đúng cái "rối rắm cho người mới" Boss chê.
       Một hàng vuốt ngang giữ đủ 15 khối mà chỉ tốn 44px chiều cao.
       ⛔ `overscroll-behavior-x: contain` — không có nó thì vuốt hết hàng là cả
          hộp thoại trượt theo, hoặc trình duyệt hiểu nhầm thành cử chỉ "lùi lại". */
    .ks-khoi-ds { gap:8px; flex-wrap:nowrap; overflow-x:auto; overscroll-behavior-x:contain;
      padding-bottom:4px; scrollbar-width:thin; }
    /* Hai nút hiếm dùng (sửa danh sách khối · về lại bộ dựng sẵn) đang chiếm mỗi
       nút một hàng to ở ngay đầu hộp, trong khi cả năm mới bấm tới một lần. Thu
       lại cho chúng đứng chung một hàng, nhường chỗ cho việc làm hàng ngày. */
    .ks-dau-hang { gap:6px; }
    .ks-dau-hang > button { font-size:12px; padding:5px 9px; }
  }
  /* ⛔⛔ 09/09/2026 — ĐỔI TRỤC LÀ BIẾN BỀ RỘNG THÀNH CHIỀU CAO.
     Boss: *"dò lại toàn bộ công cụ nào có giao diện nút quá nhiều chiếm nửa màn
     hình ở trên điện thoại"*. Màn Khối & lớp là màn tệ nhất: **383px, tức 45% của
     màn 844px** trôi đi trước khi thấy dòng lớp đầu tiên, mà thẻ lọc chỉ có đúng
     HAI bộ lọc (Cơ sở, Khối).

     Chỗ hỏng đo được: `.kl-nhan { flex:0 0 58px }` là để cột NHÃN rộng 58px. Bản cũ
     ở đây đổi `.kl-hang` sang `flex-direction:column` trên điện thoại — đảo trục
     xong thì 58px ấy thành **CHIỀU CAO** của một dòng chữ 12,5px. Mỗi hàng lọc
     hoá 116px, hai hàng thành 238px.

     Nay giữ nguyên hàng NGANG như máy tính, chỉ thu nhãn còn 46px. Đo lại: chỗ
     trống cho nút là 366 − 46 − 8 − 24 = 288px, mà hàng nút rộng nhất (Khối:
     92 + 7 + 89) chỉ 188px — thừa chán, không hàng nào vỡ.
     ⛔ ĐỪNG hạ chiều cao nút để cho gọn: bề ngang thừa mới là thứ đẩy nút xuống
        dòng, mà mỗi dòng thừa là 44px. Hạ nút là dựng lại đúng lỗi Boss từng kêu. */
  @media (max-width:640px){
    .kl-hang { gap:8px; padding:7px 0; }
    .kl-nhan { flex:0 0 46px; font-size:12px; padding-top:7px; }
    .kl-loc { padding:2px 10px; margin-bottom:8px; }
  }
  .bc-thang-lb { font-size:13px; color:var(--muc); font-weight:700; display:flex; align-items:center; gap:6px; }
  /* Hai ô chọn trong hộp "Xuất báo cáo giờ dạy" — trước là <label>, đổi sang <span>
     ngày 03/09/2026 (xem chú thích ở 25845). <label> vốn là inline nên phải khai
     lại cách xếp, không thì chữ "Năm"/"Tháng" rơi xuống dòng dưới ô chọn. */
  .lgv-xuat-lb { display:inline-flex; align-items:center; gap:6px; }
  .bc-thang-lb select { font-weight:600; }
  .bc-mid-col { text-align:center; white-space:nowrap; }
  .bc-pt { font-weight:700; font-size:12.5px; border-radius:var(--r-xl); padding:1px 8px; display:inline-block; white-space:nowrap; }
  .bc-pt.bc-good { background:#E4F5EB; color:#1E8049; }
  .bc-pt.bc-mid { background:#FDECDD; color:#B5610F; }
  .bc-pt.bc-bad { background:#FBE7E7; color:#C23636; }
  .bc-pt.bc-na { background:#EEF0F2; color:#8A94A2; }
  .bc-tong { display:flex; flex-wrap:wrap; gap:10px; margin:2px 0 12px; }
  .bc-ky { flex:1 1 130px; background:var(--nen2); border:1px solid var(--vien); border-radius:var(--r-xl); padding:10px 12px; text-align:center; }
  .bc-ky-so { display:block; font-size:19px; font-weight:700; color:var(--muc); }
  .bc-ky-lb { display:block; font-size:12px; color:var(--mo); margin-top:2px; }
  .bc-ghichu { font-size:12px; color:var(--mo); line-height:1.6; margin:0 0 14px; }
  /* 👀 Nhắc việc — tổng thể việc của từng GIÁO VIÊN / TRỢ GIẢNG (quản lý xem). */
  .nv-nhom-nguoi { margin-bottom:18px; }
  .nv-nhom-dau { display:flex; align-items:center; gap:8px; font-weight:700; font-size:14.5px; color:var(--muc);
    padding:8px 13px; background:var(--nen2); border:1px solid var(--vien); border-left:4px solid var(--muc); border-radius:var(--r-lg); margin-bottom:9px; }
  .nv-nhom-so { font-size:12px; font-weight:700; background:var(--muc); color:#fff; border-radius:var(--r-xl); padding:1px 9px; margin-left:auto; }
  .fhs-the { padding:0 !important; overflow:hidden; }
  .fhs-tom { display:flex; align-items:center; gap:10px; padding:10px 13px; cursor:pointer; }
  .fhs-tom:hover { background:var(--xanh-nhat); }
  .fhs-tom-l { flex:1; min-width:0; }
  .fhs-tom-l small { color:var(--mo); font-weight:600; }
  .fhs-tags { display:flex; flex-wrap:wrap; gap:5px; margin-top:4px; }
  .fhs-tag { font-size:11.5px; background:#E8F4F2; border:1px solid #CDE8E2; color:#0D6E63; border-radius:var(--r-xl); padding:2px 9px; }
  .fhs-tag.trong { background:transparent; border-style:dashed; color:var(--mo); }
  .fhs-mui { flex:none; color:var(--mo); font-size:15px; transition:transform .15s; }
  .fhs-the.mo .fhs-mui { transform:rotate(180deg); }
  .fhs-than { display:none; padding:2px 13px 12px; border-top:1px solid var(--vien); }
  .fhs-the.mo .fhs-than { display:block; }
  /* 🌱 Gợi ý học sinh mới (Chăm sóc HS) */
  .cs-moi-ds { display:flex; flex-direction:column; gap:6px; }
  .cs-moi-1 { display:flex; align-items:center; gap:10px; padding:7px 10px; border:1px solid #CDE8D5;
    border-radius:var(--r-md); background:#fff; font-size:13px; flex-wrap:wrap; }
  .cs-moi-1 button { margin-left:auto; }
  .cs-moi-tick { flex:none; width:17px; height:17px; cursor:pointer; accent-color:#2E9E5B; }
  .cs-buoi { color:#2E7D32; }
  /* Thanh CHỌN NHIỀU / thêm hàng loạt (cô Quỳnh 02/08). */
  .cs-moi-bar { display:flex; align-items:center; gap:12px; margin:0 0 10px; flex-wrap:wrap; }
  .cs-tickall { display:inline-flex; align-items:center; gap:6px; font-size:13px; font-weight:700; cursor:pointer; color:var(--muc); }
  .cs-tickall input { width:16px; height:16px; cursor:pointer; accent-color:#2E9E5B; }
  .cs-them-chon { padding:7px 15px; font-size:13.5px; }
  .cs-them-chon:disabled { opacity:.5; cursor:default; }
  .fhs-dau { font-size:14.5px; margin-bottom:2px; }
  .fhs-luoi { display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); gap:8px; margin:8px 0; }
  .fhs-o-nhan { display:block; font-size:12px; color:var(--mo); font-weight:700; margin-bottom:3px; }
  .fhs-o-hang { display:flex; gap:5px; align-items:stretch; }
  .fhs-o-hang .fhs-sel { flex:1; min-width:0; }
  .fhs-them-o { flex:none; border:1px solid var(--vien); border-radius:var(--r-md); background:#FFF3D9; color:var(--cam-dam);
    cursor:pointer; font-weight:700; width:34px; font-size:16px; }
  .fhs-them-o:hover { background:#FFE9C4; }
  /* 🏷 16/09/2026 — MÃ HV VÀ LỚP thành hai block bé dưới tên (Boss chốt việc 9/11:
     *"chữ nhỏ, mã HV và lớp là hai block bé"*). Hai cột riêng đã bỏ.
     ⛔ `flex-wrap` chứ đừng để một hàng cứng: cột Học viên là cột GHIM bên trái,
        bề rộng của nó là thứ người dùng tự kéo — hai block không xuống dòng được
        thì kéo hẹp một cái là chữ cụt ngang, đúng lỗi đã trả giá ở cột khác.
     ⛔ Dùng biến màu, đừng gõ mã: app có chế độ tối. */
  .fhs-phu { display:flex; flex-wrap:wrap; gap:4px; margin:3px 0 0 18px; }
  .fhs-phu-b {
    font-size:11px; line-height:1.5; color:var(--mo);
    background:var(--nen2); border:1px solid var(--vien);
    border-radius:var(--r-sm, 6px); padding:0 6px;
    max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .fhs-lhs { display:flex; flex-direction:column; gap:6px; }
  /* ══════════════════════════════════════════════════════════════════════════
     ⭐ MỖI LẦN LIÊN HỆ LÀ MỘT KHỐI RIÊNG — Boss chốt 16/09/2026
     ──────────────────────────────────────────────────────────────────────────
     Boss: *"các ô đang hơi khó nhìn"* → hỏi bằng nút, Boss chọn *"các lần dính
     liền nhau, không biết hết lần nào"* và ghi thêm: *"Nên biến các lần thành các
     block ở trong 1 để nhìn rõ"*. Boss chọn tiếp: **nền nhạt + bo góc nhỏ, cách
     nhau 6px**, và **ngày một bên trái, nội dung bên phải**.
     ⛔ KHÔNG dùng viền 4 cạnh: ô này chứa tới 6–10 lần, viền đủ cạnh là thành
        "bảng trong bảng" — Boss đã chọn nền nhạt chính vì thế.
     ⛔ KHÔNG đụng `.fhs-lhs` gap: 6px ở trên đã là khoảng cách Boss chốt.
     ⛔ `align-items: flex-start` GIỮ NGUYÊN — đổi sang `center` thì ô ngày nhảy
        xuống giữa khi phần kết quả dài mấy dòng, và cột ngày hết thẳng hàng.
     ══════════════════════════════════════════════════════════════════════════ */
  .fhs-lh {
    display:flex; gap:6px; align-items:flex-start;
    background:var(--nen2, #F5F4F1);
    border-radius:6px;
    padding:4px 6px;
  }
  body.toi .fhs-lh { background:rgba(255,255,255,.055); }
  .fhs-lh .nv-datevn { flex:none; width:160px; }
  .fhs-lh-kq { flex:1; }

  /* Dải nhắc giáo vụ chỉ được gán lớp (05/08/2026) */
  .tk-chiganlop { margin:8px 0 4px; padding:9px 14px; border-radius:var(--r-lg); font-size:13px;
    background:#FDF0DC; border:1px solid #F5C99B; color:#8A4B0B; }
  body.toi .tk-chiganlop { background:rgba(217,119,6,.16); border-color:rgba(217,119,6,.4); color:#FBBF77; }

  /* ===== ↔️ KÉO RỘNG / THU HẸP CỘT như Google Sheet (05/08/2026) ===== */
  /* ══════════════════════════════════════════════════════════════════════════════
     ⛔⛔ `:where(...)` LÀ CẢ CÁI VÁ — ĐỪNG BỎ, ĐỪNG VIẾT LẠI THÀNH SELECTOR THƯỜNG.
     ──────────────────────────────────────────────────────────────────────────────
     Tay nắm kéo cột `.cot-nam` là position:absolute, nên ô tiêu đề phải là một ô ĐÃ
     ĐỊNH VỊ thì tay nắm mới bám đúng chỗ. Bản cũ viết thẳng:

         .bang-keo-cot thead th { position:relative; }

     Câu đó có 1 lớp + 2 thẻ, mà lại nằm cuối file. Bảng nào khai `sticky` bằng đúng
     ngần ấy điểm hoặc ít hơn thì bị nó GHI ĐÈ — hàng tiêu đề hết dính, kéo xuống là
     bay mất. Cùng lúc, cột nào khai bằng HAI lớp thì thoát, nên người dùng thấy đúng
     một triệu chứng rất lạ: *chỉ mấy cột ghim bên trái còn tiêu đề, các cột khác mất*.

     Đã cắn HAI lần:
       · 06/08/2026 — bảng Đánh giá (.dg-bang). Vá bằng cách liệt kê tay từng bảng.
       · 15/08/2026 — Sổ tuyển sinh (.cts-bang) và Thống kê tuyển sinh (.tks-bang),
         vì hai bảng này KHÔNG có trong danh sách liệt kê tay đó. Cô Quỳnh:
         *"hàng title đầu tiên không theo xuống để nhìn thấy khi tôi kéo xuống dưới.
         Lỗi này tương tự ở thống kê tuyển sinh."*
         · Sổ tuyển sinh: `.cts-bang thead th` bằng đúng số điểm nhưng đứng TRƯỚC nên
           thua; `.cts-bang .cts-g1..g6` hai lớp nên thắng → đúng sáu cột ghim còn tiêu đề.
         · Thống kê: `.tks-bang th` ít điểm hơn nên thua; `.tks-bang th:first-child`
           hai lớp nên thắng → đúng mỗi cột "Mốc" còn tiêu đề.

     Liệt kê tay là chữa ngọn: bảng thứ sáu ai đó thêm sau này sẽ lại dính y hệt, và
     không ai nhớ ra để thêm vào danh sách.
     `:where(...)` cho câu này ĐIỂM BẰNG KHÔNG. Nghĩa là:
       · bảng nào tự khai `position` cho ô tiêu đề → luật của bảng đó luôn thắng;
       · bảng nào không khai gì → vẫn được `relative` để tay nắm bám đúng.
     Và `sticky` cũng là ô đã định vị y như `relative`, nên tay nắm vẫn bám đúng chỗ.
     ══════════════════════════════════════════════════════════════════════════════ */
  :where(.bang-keo-cot thead th) { position:relative; }
  /* ⛔⛔ BẪY 06/08/2026 — ĐỪNG XOÁ KHỐI DƯỚI ĐÂY.
     Dòng `.bang-keo-cot thead th { position:relative }` ngay trên có ĐỘ ƯU TIÊN BẰNG
     với `.dg-bang thead th` (dòng ~1789) nhưng nằm SAU trong file, nên nó THẮNG và
     xoá mất `position:sticky` của hàng tiêu đề. Hậu quả: kéo xuống là tiêu đề bay mất,
     cô Quỳnh báo 06/08 "không hiểu cột đó là cột gì".
     Vì sao chỉ cột ĐẦU còn chữ: cột đó khai bằng `.dg-bang .dg-dinh` (2 lớp) nên ưu tiên
     cao hơn, không bị xoá — đúng triệu chứng "chỉ mỗi cột đầu hiện tiêu đề".
     Vì sao Lịch thi KHÔNG dính lỗi: `.fss-bang`/`.lt-bang` khai sticky ở dòng ~2123 và
     ~2146, tức là SAU dòng 1973 nên thắng ngược lại. Cùng một bệnh, khác chỗ ngồi.
     Cách chữa: khai lại `sticky` với 2 lớp (ưu tiên cao hơn) — KHÔNG đặt `top` ở đây,
     để mỗi bảng giữ `top` riêng (Lịch thi có hàng tiêu đề thứ hai nằm ở `--lt-h1`). */
  /* Lớp bảo hiểm: khai lại rõ ràng cho từng bảng. Với `:where` ở trên thì khối này
     đã thừa, nhưng giữ để trình duyệt nào chưa hiểu `:where` vẫn chạy đúng.
     ⛔ Không đặt `top` ở đây — mỗi bảng giữ `top` riêng (Lịch thi có hàng tiêu đề
        thứ hai nằm ở `--lt-h1`). */
  .dg-bang.bang-keo-cot thead th,
  .fss-bang.bang-keo-cot thead th,
  .cts-bang.bang-keo-cot thead th,
  .tks-bang.bang-keo-cot thead th,
  .tths-bang.bang-keo-cot thead th { position:sticky; }
  /* Tay nắm ở MÉP PHẢI ô tiêu đề — rộng 7px cho dễ trúng, hiện vạch khi rê vào. */
  /* ══════════════════════════════════════════════════════════════════════════════
     CỘT NGƯỜI DÙNG TỰ ẨN — lớp dùng chung cho MỌI bảng
     ──────────────────────────────────────────────────────────────────────────────
     Gắn lớp này lên ô tiêu đề VÀ mọi ô dữ liệu của cột đó là cột biến mất, mà vị trí
     các cột khác không xê dịch (xem chú thích ở .cts-bang .cot-an).
     ⛔ Ai dùng lớp này thì PHẢI trừ nó ra khỏi tổng bề rộng bảng — xem `tongRong`
        trong gaKeoCot. Quên là bảng `table-layout:fixed` đem phần thừa chia cho các
        cột còn lại, chúng phình ra so với số đã khai, và mốc ghim cột trái tính theo
        số đã khai sẽ lệch. Đo thật lúc chưa vá: lệch tới 98px. */
  .cot-an { display:none; }
  .cot-nam { position:absolute; top:0; right:-3px; width:7px; height:100%;
    cursor:col-resize; z-index:5; user-select:none; touch-action:none; }
  .cot-nam::after { content:""; position:absolute; top:14%; bottom:14%; left:2px; width:2px;
    border-radius:var(--r-sm); background:transparent; transition:background .12s; }
  .cot-nam:hover::after { background:var(--chinh,#159F8B); }
  body.dang-keo-cot { cursor:col-resize !important; user-select:none; }
  body.dang-keo-cot .cot-nam::after { background:var(--chinh,#159F8B); }
  /* ⭐ THU HẸP MÀ CHỮ VẪN ĐỌC ĐƯỢC (cô Quỳnh: "không phải từng chữ rơi lẻ tẻ").
     Ô CHỮ THƯỜNG: cắt bớt kèm "…" thay vì vỡ dòng mỗi từ một hàng.
     Ô NHẬP / textarea: co theo cột (min-width:0) nhưng vẫn gõ được bình thường. */
  .bang-keo-cot td { overflow:hidden; }
  .bang-keo-cot td.ts-note, .bang-keo-cot td.yc-nd { text-overflow:ellipsis; }
  .bang-keo-cot td > input, .bang-keo-cot td > textarea,
  .bang-keo-cot td > select, .bang-keo-cot td > .ont { min-width:0; max-width:100%; box-sizing:border-box; }
  /* ⛔⛔ VÁ 11/08/2026 — CHỮ TRONG CỘT HẸP BỊ CẮT MẤT ĐẦU.
     Cô Quỳnh chụp ảnh: thu cột lại thì tiêu đề "Lớp" chỉ còn "ớp", cột "Mã HV" mất
     hẳn. Nguyên do: thẻ <th> của HTML mặc định CĂN GIỮA. Chữ rộng hơn ô thì nó tràn
     ĐỀU RA HAI BÊN, mà `overflow:hidden` cắt cả hai — nên mất luôn chữ đầu, còn
     đúng khúc giữa. Nhìn như lỗi font chứ không ai đoán ra là do căn giữa.
     → Căn TRÁI + cắt bớt kèm "…" ở BÊN PHẢI: hẹp tới đâu vẫn đọc được từ đầu chữ,
       đúng cách Google Sheet làm.
     ⛔ `white-space:nowrap` là BẮT BUỘC — thiếu nó thì `text-overflow:ellipsis` vô
       hiệu, chữ lại vỡ dòng "lẻ tẻ" đúng thứ cô Quỳnh đã chê. */
  .bang-keo-cot thead th { overflow:hidden; text-overflow:ellipsis;
    white-space:nowrap; text-align:left; padding-right:13px; }
  /* ══════════════════════════════════════════════════════════════════════════════
     ⛔⛔ 21/08/2026 — ĐẦU ĐỀ CỘT PHẢI CĂN CÙNG KIỂU VỚI Ô BÊN DƯỚI NÓ
     ──────────────────────────────────────────────────────────────────────────────
     Cô Quỳnh: *"công cụ quyền theo chức vụ cột lựa chọn bị lệch này cả công cụ báo
     cáo giáo viên thống kê xong cái phần thông tin bên trong bị lệch so với cột"*.

     NGUYÊN NHÂN, đo thật bằng trình duyệt 21/08/2026: luật `.bang-keo-cot thead th`
     NGAY TRÊN ĐÂY căn TRÁI mọi đầu đề. Nó viết SAU `.pq-bang thead th` (căn giữa) và
     hai luật NẶNG BẰNG NHAU (đều một lớp + hai thẻ) → viết sau thì thắng. Kết quả:
     đầu đề căn trái, ô tick căn giữa, lệch đúng nửa bề rộng cột — đo được 85px ở
     màn Quyền, và cả bảng Báo cáo giáo viên cũng cùng bệnh.

     Luật căn trái ấy ĐÚNG cho cột CHỮ (hẹp lại thì còn đọc được từ đầu chữ, xem khối
     giải thích ngay trên). Chỉ SAI ở cột mà ô bên dưới căn giữa. Nên chữa bằng cách
     ĐÁNH DẤU đúng những cột ấy, không đụng luật gốc.

     ⛔ THÊM CỘT SỐ MỚI VÀO BẢNG BÁO CÁO THÌ NHỚ ĐẶT `class="bc-mid-col"` CHO CẢ `<th>`,
        không chỉ cho `<td>`. Quên là cột đó lệch một mình giữa những cột thẳng hàng,
        trông như bảng vỡ.
     ⛔ ĐỪNG chữa bằng `:nth-child(...)`: hai bảng báo cáo có số cột đầu khác nhau
        (bảng theo giáo viên bắt đầu bằng Giáo viên · Cơ sở; bảng theo lớp bắt đầu
        bằng Lớp · Giáo viên), nên một con số thứ tự không thể đúng cho cả hai.
     ══════════════════════════════════════════════════════════════════════════════ */
  .bang-keo-cot thead th.bc-mid-col { text-align:center; }
  .pq-bang thead th:not(:first-child) { text-align:center; }
  /* Chữ trong Ô cũng vậy: cắt gọn ở bên phải, không vỡ dòng lung tung. */
  .bang-keo-cot td { text-overflow:ellipsis; }
  /* ⛔⛔ SỬA LẠI 11/08/2026 — LUẬT NÀY TỪNG ÉP `display:inline-block`, VÀ ĐÓ LÀ LỖI.
     Cô Quỳnh: *"sửa lại cái mã học sinh và lớp bạn sửa trước đó về kiểu cũ đi"*.
     Nhiều bảng cố ý cho TÊN xuống dòng riêng, MÃ nằm dòng dưới — bằng luật
     `.dg-dinh b { display:block }`. Luật tôi thêm có độ ưu tiên cao hơn nên đè mất,
     tên với mã dồn hết vào một dòng, nhìn vỡ hẳn.
     Nay CHỈ giữ phần CẮT BỚT, KHÔNG đụng tới `display` — thẻ nào đang là block thì
     vẫn block, ellipsis vẫn chạy bình thường trên block.
     ⛔ Đừng thêm `display` hay `vertical-align` vào đây nữa. */
  .bang-keo-cot td > span, .bang-keo-cot td > b, .bang-keo-cot td > a {
    max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  /* Tay nắm nằm HẲN trong ô — trước ở `right:-3px` nên bị `overflow:hidden` xén mất. */
  .bang-keo-cot thead th .cot-nam { right:0; }

  /* ══════════════════════════════════════════════════════════════════════════
     ⛔⛔ NGÓN TAY KHÔNG KÉO ĐƯỢC CỘT — cô Quỳnh 23/08/2026
     ──────────────────────────────────────────────────────────────────────────
     *"tôi thấy trên điện thoại rất khó để kéo mở rộng và thu hẹp cột lại bạn tìm
     cách xử lí giúp tôi với."*

     HAI cái sai cùng lúc, đo được cả hai:
       ① Vùng chạm rộng **7px** (luật `.cot-nam` bên trên). Apple đòi tối thiểu 44px,
          Google đòi 48dp — 7px là 16% chuẩn, ngón tay gần như không thể trúng.
       ② Cái vạch chỉ chỗ kéo mặc định `background:transparent`, CHỈ hiện khi
          `:hover`. Màn cảm ứng KHÔNG có "di chuột vào" → vạch **vô hình vĩnh viễn**,
          nên không ai biết phải chạm vào đâu mà kéo.

     Sổ tuyển sinh đã được nới 24px từ 16/08/2026 (xem khối ở ~9458) và chạy tốt,
     nay đem đúng con số ấy cho MỌI bảng, chứ không mỗi màn một kiểu.

     ⛔ DÙNG `@media (hover: none)`, ĐỪNG dùng `(pointer: coarse)`. Cả file đã có sẵn
        khuôn `(hover:none)` ở ~6036 cho nút thanh công cụ, kèm đúng lý do này. Và
        `(pointer:coarse)` chưa từng xuất hiện trong app — đẻ quy ước mới làm gì.
     ⛔ CỘNG THÊM luật cho cảm ứng, ĐỪNG lật ngược mặc định. Nếu đổi `transparent`
        thành có màu rồi giấu lại bằng `(hover:hover)` thì trình duyệt nào không khớp
        truy vấn là **máy tính mọc thêm vạch**. Cách này máy tính không đổi 1 pixel.
     ⛔ Nới bằng `width`, KHÔNG nới bằng `right` dương: `.bang-keo-cot thead th` có
        `overflow:hidden` (ngay trên) nên thò ra ngoài ô là bị xén mất — đúng lỗi mà
        dòng `right:0` phía trên sinh ra để chữa.
     ⛔ Phải viết đủ `.bang-keo-cot thead th .cot-nam` (nặng 0,2,2) và đặt SAU dòng
        `right:0`. Viết ngắn hơn là thua chính dòng ấy — cái bẫy đã cắn ba lần.
     ⛔ Vạch phải neo lại theo mép PHẢI (`left:auto; right:3px`). Luật gốc dùng
        `left:2px`, tay nắm rộng ra thì vạch trôi vào giữa ô, chỉ sai chỗ.
     ⛔ Dùng `opacity` chứ đừng gõ cứng mã màu: `var(--chinh)` tự theo nền tối, và
        lúc đang kéo thì `opacity:1` cho vạch đậm hẳn lên.

     CÂN NHẮC ĐÃ TÍNH: ô tiêu đề `.h-cot` ở lưới điểm danh còn gánh hai việc nữa —
     chạm để ĐỔI TÊN cột, và kéo để ĐỔI CHỖ cột (cả hai tự rút lui khi chạm trúng
     `.cot-nam`). Cột điểm danh đo thật rộng 70–98px nên 24px vẫn chừa 46–74px cho
     hai việc kia; chỉ khi ai đó kéo cột về sàn 56px thì mới còn 32px. Chấp nhận đánh
     đổi đó vì cô Quỳnh đang kêu ĐÚNG màn này, và 32px vẫn chạm được.
     ══════════════════════════════════════════════════════════════════════════ */
  @media (hover: none) {
    .cot-nam::after { background:var(--chinh,#159F8B); opacity:.34; }
    body.dang-keo-cot .cot-nam::after { opacity:1; }
    .bang-keo-cot thead th .cot-nam { width:24px; right:0; }
    .bang-keo-cot thead th .cot-nam::after { left:auto; right:3px; }
  }

/* ===== 🔔 KHUNG BẮT BUỘC BẬT THÔNG BÁO (08/08/2026) =====
     Phủ kín màn hình, KHÔNG bấm xuyên qua được — cô Quỳnh muốn đây là bắt buộc.
     Lối thoát duy nhất là dòng chữ mờ ở đáy hộp, cố ý làm cho khó thấy hơn nút chính. */

  /* ═══ 🔔 HỘP THÔNG BÁO TRONG APP (08/08/2026) ═══
     Cô Quỳnh: *"nếu mà không thông báo ra ngoài máy, đôi khi có số người vẫn bỏ qua,
     thì tôi muốn trong app chắc chắn sẽ nhận thông báo bên phải. Có thể ẩn đi hoặc
     ấn đã đọc."* → bảng TRƯỢT RA TỪ MÉP PHẢI, không phải hộp thoại giữa màn hình. */
  .nut-chuong { position:relative; }
  .nut-chuong i { margin:0; width:19px; height:19px; }   /* nút chỉ có icon, không có chữ */

  .chuong-so { position:absolute; top:-5px; right:-5px; min-width:17px; height:17px;
    padding:0 4px; border-radius:999px; background:var(--do,#D64545); color:#fff;
    font-size:10.5px; font-weight:700; line-height:17px; text-align:center;
    box-shadow:0 0 0 2px var(--the); }
  .tb-nen { position:fixed; inset:0; z-index:2147482900; background:rgba(18,22,28,.42);
    opacity:0; transition:opacity .18s; }
  .tb-nen.hien { opacity:1; }
  .tb-bang { position:fixed; top:0; right:0; bottom:0; width:min(390px,100%);
    z-index:2147482901; background:var(--the); border-left:1px solid var(--vien);
    box-shadow:-8px 0 32px rgba(0,0,0,.16); display:flex; flex-direction:column;
    transform:translateX(100%); transition:transform .22s cubic-bezier(.22,.8,.3,1); }
  .tb-bang.hien { transform:none; }
  .tb-dau { display:flex; align-items:center; gap:10px; padding:14px 16px;
    border-bottom:1px solid var(--vien); background:var(--nen2); }
  .tb-dau h3 { margin:0; font-size:15.5px; font-weight:700; color:var(--chu); }
  .tb-dau .tb-dem { font-size:12px; color:var(--mo); }
  .tb-dong { margin-left:auto; border:none; background:none; color:var(--mo);
    font-size:20px; line-height:1; cursor:pointer; padding:2px 6px; border-radius:var(--r-md); }
  .tb-dong:hover { background:var(--vien); color:var(--chu); }
  .tb-thanh { display:flex; gap:7px; padding:9px 14px; border-bottom:1px solid var(--vien); }
  .tb-thanh button { flex:1; border:1px solid var(--vien); background:var(--the);
    color:var(--mo); border-radius:var(--r-md); padding:6px 8px; font-size:11.5px;
    font-weight:700; cursor:pointer; font-family:inherit; }
  .tb-thanh button:hover { color:var(--chu); border-color:var(--muc); }
  .tb-ds { flex:1; overflow-y:auto; padding:10px 12px 16px; }
  .tb-1 { display:flex; gap:10px; padding:11px 12px; border-radius:var(--r-lg);
    border:1px solid var(--vien); background:var(--the); margin-bottom:8px;
    position:relative; transition:background .12s; }
  /* Tin CHƯA ĐỌC: nền nhạt + vạch màu bên trái, nhìn lướt là biết cái nào mới. */
  .tb-1.moi { background:var(--xanh-nhat); border-color:transparent;
    box-shadow:inset 3px 0 0 var(--muc); }
  .tb-1-ico { flex:none; width:30px; height:30px; border-radius:var(--r-md); display:flex;
    align-items:center; justify-content:center; background:var(--nen2); color:var(--mo); }
  .tb-1-ico .ico { width:16px; height:16px; margin:0; }
  .tb-1.moi .tb-1-ico { background:var(--the); color:var(--muc); }
  .tb-1-than { flex:1; min-width:0; }
  .tb-1-chu { font-size:13px; line-height:1.5; color:var(--chu); overflow-wrap:anywhere; }
  .tb-1.moi .tb-1-chu { font-weight:600; }
  .tb-1-phu { margin-top:4px; font-size:11px; color:var(--mo); }
  .tb-1-nut { flex:none; display:flex; flex-direction:column; gap:4px; }
  .tb-1-nut button { border:none; background:none; color:var(--mo); cursor:pointer;
    font-size:11px; padding:2px 5px; border-radius:var(--r-sm); font-family:inherit; white-space:nowrap; }
  .tb-1-nut button:hover { background:var(--nen2); color:var(--chu); }
  .tb-trong { text-align:center; color:var(--mo); font-size:13px; padding:36px 12px; line-height:1.6; }
  body.toi .tb-bang { box-shadow:-8px 0 32px rgba(0,0,0,.5); }
  body.toi .chuong-so { box-shadow:0 0 0 2px var(--the); }
  @media (max-width:260px) { .tb-bang { width:100%; } }

  /* ===== 📨 Yêu cầu của giáo viên (05/08/2026) ===== */
  /* Thẻ rộng tối thiểu 344px — vừa đủ cho ba nút hành động + nút xoá trên MỘT hàng. */
  .yc-ds { display:grid; grid-template-columns:repeat(auto-fill,minmax(344px,1fr)); gap:12px; }
  /* 21/09/2026 Boss: "block yêu cầu giáo viên đang bị vuông góc, sửa cho bo tròn".
     Boss chọn: CHỈ thẻ này, 8px (bằng ô ghi chú bên trong), giữ sọc màu uốn theo góc.
     ⛔ Gõ số thẳng, KHÔNG nâng --r-xl: biến ấy gánh 88 chỗ, Boss chốt 02/09 là 0px. */
  .yc-the { background:var(--the); border:1px solid var(--vien); border-left:4px solid #94A3B8;
    border-radius:8px; padding:12px 14px; display:flex; flex-direction:column; gap:7px; }
  .yc-the.moi { border-left-color:#C2410C; }
  .yc-the.danglam { border-left-color:#D97706; }
  /* ⛔ 07/08 — BỎ `opacity` cho thẻ đã xong / đã huỷ. Hồi chúng còn nằm CHUNG danh
     sách với việc đang chờ thì làm mờ là đúng (cho việc đang chờ nổi lên). Nay
     chúng nằm riêng trong 🗄 Kho, ở đó chúng LÀ nội dung chính — mờ hết cả kho thì
     đọc rất mệt. Phân biệt bằng màu viền trái + dòng "ai đóng, đóng lúc nào". */
  .yc-the.xong { border-left-color:#1E8E4E; }
  .yc-the.boqua { border-left-color:#94A3B8; }
  .yc-dau { display:flex; align-items:center; gap:8px; flex-wrap:wrap; font-size:14px; }
  .yc-gv { font-size:12px; color:var(--mo); }
  .yc-tt { margin-left:auto; font-size:11px; font-weight:700; padding:1px 9px; border-radius:999px;
    background:#ECEFF3; color:#64748B; }
  .yc-tt.moi { background:#FDECDD; color:#C2410C; }
  .yc-tt.danglam { background:#FDF0DC; color:#D97706; }
  .yc-tt.xong { background:#DFF3E7; color:#1E8E4E; }
  .yc-phu { font-size:11.5px; color:var(--mo); }
  .yc-hs { display:flex; flex-wrap:wrap; gap:5px; }
  .yc-hs1 { font-size:12px; background:var(--nen2); border-radius:999px; padding:2px 9px; }
  .yc-nd { font-size:12.5px; background:var(--nen2); border-radius:var(--r-md); padding:7px 10px; white-space:pre-wrap; }
  /* 🗄 HAI NGĂN: Đang chờ · Kho đã xử lý (07/08/2026).
     Cô Quỳnh: *"đã xử lý thì phải nhảy vào kho đã xử lý, có thể backup lại"*.
     Trước đây việc xong vẫn nằm chung danh sách (chỉ mờ đi + tụt xuống), nên màn
     hình dài dần ra và mắt phải tự lọc — nay tách hẳn. */
  .yc-ngan-hang { display:flex; gap:8px; margin:0 0 10px; flex-wrap:wrap; }
  .yc-ngan { display:inline-flex; align-items:center; gap:8px; font-size:13px; font-weight:700;
    color:var(--mo); background:var(--the); border:1px solid var(--vien); border-radius:var(--r-lg);
    padding:7px 13px; cursor:pointer; font-family:inherit; transition:border-color .12s, color .12s; }
  .yc-ngan:hover { color:var(--chu); border-color:var(--muc); }
  .yc-ngan.chon { color:var(--muc); border-color:var(--muc); background:var(--xanh-nhat); }
  /* 🎞 10/09/2026 — Boss: *"Trong thanh công cụ số 0 bị sát với chữ quá."*
     `gap: 8px` nghe thì thoáng, nhưng huy hiệu này có NỀN chạy sát tới mép chữ
     số, nên khoảng trắng mắt nhìn thấy chỉ còn 8px trừ đi phần đệm — dính vào
     chữ "Đang chờ" bên cạnh. Nới thêm cho hai thứ tách hẳn ra. */
  .yc-ngan-so { min-width:20px; text-align:center; border-radius:999px; padding:1px 7px;
    margin-left:3px; font-size:11.5px; font-weight:700; background:var(--nen2); color:var(--mo); }
  .yc-ngan.chon .yc-ngan-so { background:var(--muc); color:#fff; }
  body.toi .yc-ngan-so { background:rgba(255,255,255,.1); }
  /* Dòng "ai đóng · đóng lúc nào" trên thẻ trong kho. */
  .yc-dong { font-size:11.5px; font-weight:700; color:#1E8E4E; }
  /* Dòng "<tên> đã tiếp nhận" — cùng màu cam với nút Tiếp nhận, để hai giáo vụ
     không cùng ôm một việc mà không biết. */
  .yc-nhan-boi { font-size:11.5px; font-weight:700; color:#9A6400; }
  body.toi .yc-nhan-boi { color:#E4C88A; }
  .yc-the.boqua .yc-dong { color:var(--mo); }
  body.toi .yc-dong { color:#7FD6A0; }
  /* ⛔ 07/08 — ĐỔI TỪ `flex-wrap` SANG LƯỚI 4 CỘT. Thêm nút "Tiếp nhận" là thành ba
     nút hành động; để flex-wrap thì nút thứ ba rớt xuống hàng dưới, nhìn như hai
     nhóm rời rạc. Lưới `1fr 1fr 1fr auto` giữ cả ba luôn cùng một hàng, nút xoá
     nằm cuối đúng bề rộng của nó. */
  .yc-nut { display:grid; grid-template-columns:1fr 1fr 1fr auto; gap:6px;
    align-items:center; margin-top:2px; }
  /* ✔ Hoàn thành · ✕ Huỷ (07/08/2026) — thay ô chọn 4 trạng thái + nút tạo phụ đạo.
     Ở trạng thái thường thì NHẠT (viền mảnh), đang bật thì TÔ ĐẶC — nhìn phát biết
     yêu cầu này đã xử lý chưa mà không phải đọc chữ. */
  .yc-act { min-width:0; border:1px solid var(--vien); background:var(--the);
    color:var(--mo); border-radius:var(--r-md); padding:7px 4px; font-size:11.5px;
    font-weight:700; cursor:pointer; white-space:nowrap; overflow:hidden;
    text-overflow:ellipsis; font-family:inherit;
    transition:background .12s, color .12s, border-color .12s; }
  .yc-act.xong:hover { border-color:#8FCFAC; color:#1E8E4E; background:#F1FAF4; }
  .yc-act.nhan:hover { border-color:#E8B96A; color:#9A6400; background:#FFF8EC; }
  .yc-act.huy:hover  { border-color:#EBB4B4; color:#D64545; background:#FDF4F4; }
  .yc-act.xong.dang { background:#1E8E4E; border-color:#1E8E4E; color:#fff; }
  /* 📥 Tiếp nhận = đang lo dở, chưa xong → màu CAM, khác hẳn xanh (xong) và xám (huỷ). */
  .yc-act.nhan.dang { background:#D9880B; border-color:#D9880B; color:#fff; }
  .yc-act.huy.dang  { background:#8A94A3; border-color:#8A94A3; color:#fff; }
  body.toi .yc-act.xong:hover { background:rgba(46,158,91,.16); }
  body.toi .yc-act.nhan:hover { background:rgba(217,136,11,.16); }
  body.toi .yc-act.huy:hover  { background:rgba(214,69,69,.16); }

  /* ===== 🗑 Xoá một lần liên hệ trong Follow up HS (05/08/2026) ===== */
  .fhs-lh-xoa { flex:none; align-self:flex-start; border:1px solid var(--vien);
    background:var(--the); color:var(--do,#D64545); border-radius:var(--r-md);
    width:24px; height:24px; line-height:1; font-size:12px; font-weight:700; cursor:pointer; }
  .fhs-lh-xoa:hover { background:#FBE7E7; border-color:#EBB4B4; }

  /* ===== ⚠️ Chăm sóc HS: nhóm "dạo này kém" + tìm HS (05/08/2026) ===== */
  .cs-da-co { font-size:11.5px; color:var(--mo); font-style:italic; white-space:nowrap; }
  .cs-moi-1 small { display:block; margin-top:2px; line-height:1.35; }

  /* ===== 📢 Khung TIN HÔM NAY — 4 mục (05/08/2026) ===== */
  /* ⭐ SỬA 05/08/2026 — cô Quỳnh: *"mấy cái ô phân loại trong tin đẹp hơn chứ hơi
     BÉ KHÓ NHÌN và hơi TRẺ CON"*. Bản cũ là chip bo tròn 999px, chữ 12.5px, đếm
     số bé xíu. Nay: thẻ VUÔNG bo nhẹ, chữ 14px, có gạch chân đậm khi chọn (kiểu
     tab công việc), số đếm to rõ. Bỏ kiểu "viên kẹo" cho đỡ trẻ con. */
  /* ============ 🗂 TIN HÔM NAY — BẢNG ĐIỀU KHIỂN (06/08/2026) ============
     Cô Quỳnh: "nhìn được các tin chia sẵn, không bắt buộc cứ phải ấn vào từng ô để
     check thông tin của chức năng đó. Giống doanh nghiệp, cần nhanh và tiện."
     → Bỏ kiểu tab (mỗi lúc chỉ thấy một mục). Nay BÀY HẾT mọi mục ra cùng lúc, mỗi
       mục một thẻ có đầu đề + số đếm + vài dòng tin gần nhất, liếc một cái là nắm.
     → Mục nào KHÔNG có việc thì thẻ tự co lại còn một dòng mờ, nhường chỗ cho mục
       có việc — mắt tự bị kéo về chỗ cần làm.
     → Vị trí các thẻ CỐ ĐỊNH (không nhảy chỗ theo số liệu) để quen tay. */
  /* 📐 VÁ 09/08/2026 — cô Quỳnh: *"khi thông tin không đồng đều về số lượng thì
     trông cái trình bày xấu"*. Bản cũ để `align-items:start`: mỗi thẻ cao đúng bằng
     số dòng nó có, nên Dự giờ 15 dòng cao vống cạnh Yêu cầu GV 1 dòng lùn tịt —
     nhìn như răng cưa. Nay bỏ đi (lưới tự cho thẻ CÙNG HÀNG cao bằng nhau), thân thẻ
     giãn ra cho đầy và dòng "Mở công cụ →" dính đáy. Số lượng lệch bao nhiêu cũng
     vẫn ra một bảng điều khiển vuông vắn. */
  /* 💾 Màn Sao lưu — 09/08/2026 */
  .sl-boc { max-width:760px; }
  /* 🗄 24/08/2026 — dòng tiêu đề cho khối "Bản trên máy chủ". Màn Kho nay có HAI khối
     (trên máy chủ · cất ra ngoài), phải có tên thì mới biết mình đang đọc khối nào. */
  /* Nút "Excel" là nút PHỤ — nhạt hơn và nhỏ hơn nút tải gói, cố ý. Gói .json.gz mới
     là đường khôi phục chính thức; hai nút trông ngang hàng là mời người ta cầm nhầm. */
  .sl-xls { margin-left:6px; font-size:12px; padding:3px 9px; color:var(--mo); }
  .sl-xls:hover { color:var(--muc); }
  .sl-dau-khoi { font-size:13px; font-weight:600; color:var(--mo); margin:16px 0 0;
    text-transform:none; letter-spacing:0; }
  .sl-thanh { display:flex; align-items:center; gap:12px; margin:14px 0 10px; }
  .sl-dem { font-size:13px; color:var(--mo); font-weight:600; }
  .sl-thanh .nut-chinh { margin-left:auto; }
  .sl-ds { border:1px solid var(--vien); border-radius:var(--r-xl); overflow:hidden; background:var(--the); }
  .sl-hang { display:flex; align-items:center; gap:12px; padding:10px 14px;
    border-bottom:1px solid var(--vien); font-size:13.5px; }
  .sl-hang:last-child { border-bottom:none; }
  .sl-ngay { font-weight:600; color:var(--chu); }
  .sl-co { color:var(--mo); font-size:12.5px; }
  .sl-hang .nut-nho { margin-left:auto; }
  .sl-trong { border:1px dashed var(--vien); border-radius:var(--r-xl); padding:18px 14px;
    color:var(--mo); font-size:13px; }
  .sl-luuy { margin-top:14px; padding:11px 13px; border-radius:var(--r-lg); font-size:12.8px;
    line-height:1.55; background:var(--nen2); color:var(--chu); border:1px solid var(--vien); }
  .sl-luuy.phu { background:none; border-style:dashed; color:var(--mo); }
  body.toi .sl-luuy { background:rgba(255,255,255,.05); }
  /* ⛔ Khung báo động MẤT DỮ LIỆU (13/08/2026) — đứng đầu màn Sao lưu, chỉ hiện
     khi có chuyện thật. Cố ý dùng viền đỏ dày bên trái thay vì tô đỏ cả khung:
     đọc được chữ, mà vẫn không thể bỏ qua. */
  .sl-bao-dong { margin:0 0 14px; padding:12px 14px; border:1px solid var(--do);
    border-left:4px solid var(--do); border-radius:var(--r-sm); background:var(--the);
    font-size:13px; line-height:1.55; color:var(--chu); }
  .sl-bao-dong > b { display:block; color:var(--do); font-size:13.5px; margin-bottom:6px; }
  .sl-bao-dong ul { margin:0 0 8px; padding-left:20px; }
  .sl-bao-dong li { margin:3px 0; }
  .sl-bao-dong p { margin:0; color:var(--mo); }
  /* ⛔ VÁ 18/08/2026 — DÒNG BẢN SAO LƯU CÓ LỖ.
     Máy chủ gửi cờ `thieu` từ trưa nay, nhưng màn này nhận về rồi vứt đi: bản
     "-THIEU" hiện ra y hệt bản lành, chỉ khác cái tên. Cô Quỳnh nhìn danh sách
     14 dòng đều nhau thì yên tâm — mà trong đó có dòng thiếu hẳn một kho. */
  /* ══════════════════════════════════════════════════════════════════════════
     NHỚ MỘT THƯ MỤC TRÊN MÁY (21/08/2026)
     ──────────────────────────────────────────────────────────────────────────
     ⛔ TIỀN TỐ `slt-`, KHÔNG dùng `sl-`. Màn này đã xài kín `.sl-ds`, `.sl-hang`,
        `.sl-ngay`, `.sl-co`, `.sl-trong`, `.sl-luuy`. Lần đầu tôi đặt trùng đúng sáu
        tên ấy ở một khối CSS khác trong cùng file — luật khai sau đè luật khai trước,
        im lặng, không báo gì. Cả file này là MỘT bảng kiểu chung.
     ══════════════════════════════════════════════════════════════════════════ */
  .slt-khoi { border:1px solid var(--vien); border-radius:var(--r-xl); background:var(--the);
      padding:12px 14px 13px; margin-top:14px; }
  .slt-khoi > b { font-size:13px; }
  .slt-khoi p { margin:5px 0 0; font-size:12.8px; color:var(--mo); line-height:1.55; }
  .slt-dich { color:var(--chu) !important; font-weight:600; }
  .slt-nut { display:flex; flex-wrap:wrap; gap:8px; margin-top:10px; }
  .slt-tich { display:flex; align-items:flex-start; gap:8px; margin-top:11px;
      font-size:12.8px; cursor:pointer; line-height:1.45; }
  .slt-tich input { margin-top:2px; flex:none; }
  /* ⛔ Câu nói giới hạn phải ĐỌC ĐƯỢC, không phải chữ mờ ở góc — nó là chỗ dễ hiểu
     nhầm nhất của cả chức năng này. */
  .slt-luuy { margin-top:10px !important; padding-top:9px; border-top:1px solid var(--vien);
      color:var(--chu) !important; }
  .sl-hang.co-lo { border-left:4px solid var(--do); }
  /* 💾 21/08/2026 — mỗi dòng nói rõ bản ấy đang nằm ở mấy chỗ (đĩa · database).
     ⛔ Chữ nhạt, không nhãn dán màu: bình thường thì đây chỉ là chữ nền, chỉ khi
        THIẾU một chỗ mới cần bắt mắt (lớp .canh). */
  .sl-cho { font-size:12px; color:var(--mo); white-space:nowrap; }
  .sl-cho.canh { color:var(--do); font-weight:600; white-space:normal; }
  .sl-lo { color:var(--do); font-weight:600; font-size:12px; }

  /* ⛔ 21/08/2026 — NỚI CỘT 286 → 340px. Cô Quỳnh: *"ko được để thừa ra khoảng trắng"*
     và tôi tự đo được (kiem-thu/soi-giao-dien.js): sau khi Trang chủ bỏ dải trắng bên
     phải, khối này rộng 1.278px → chia thành BỐN cột 304px. Trong mỗi thẻ, cái nhãn
     "Quá hạn, chưa nhận xét" ăn mất ~150px, chỉ còn 125px cho chữ — mà dòng ngày cần
     tới 291–366px. Nên bốn thẻ đều cắt cụt "12 ngày trước · 09/08/2…".
     340px → ba cột 426px, chữ có 245px, đủ cả dòng ngày.
     ⛔ Đừng hạ lại xuống 286: rộng thêm 40px mỗi cột là thứ đổi "chữ bị cắt" thành
        "chữ đọc được", không phải chuyện thẩm mỹ. */
  /* ══════════════════════════════════════════════════════════════════════════════
     TRẠNG THÁI RỖNG CỦA KHỐI "THÔNG BÁO CÔNG VIỆC" — cô Quỳnh 21/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     *"nhìn hổng hẳn 1 bảng trắng xóa ô không có gì nhìn xấu như cứt á"*.
     Khối này nằm cùng hàng lưới với ô Ghi chú nên nó CAO BẰNG ô kia (~257px). Ngày
     nào không có việc đến hạn thì ruột chỉ có một dòng chữ dính mép trên, dưới là
     ~110px trắng trơn. Nay dòng ấy căn giữa chỗ trống, kèm một biểu tượng nhạt và
     một dòng chỉ đường — chỗ trống thành một khối có chủ ý.
     ⛔ Biểu tượng để RẤT NHẠT (dùng --vien làm nền, --mo làm màu). Nó là nền, không
        phải thứ cần nhìn; đậm lên là một ô "không có gì" lại đi tranh mắt với ô đang
        có việc thật ngay bên cạnh.
     ⛔ Không animation, không gradient — luật giao diện cô Quỳnh chốt 08/08. */
  /* ⛔ Bo 6px và khung nét LIỀN, không phải nét đứt bo 11px — nét đứt là quy ước
     của "chỗ thả file vào", mà đây chỉ là một dòng thông báo bình thường. */
  .hv-rong2 { flex:1 1 auto; display:flex; flex-direction:column; align-items:center;
    justify-content:center; gap:9px; text-align:center; padding:18px 16px;
    border:1px solid var(--vien); border-radius:var(--r-sm); background:transparent; }
  .hv-rong2:hover { border-color:var(--xanh); background:var(--nen2); }
  .hv-rong2-ico { width:38px; height:38px; border-radius:var(--r-sm); background:var(--nen2);
    display:flex; align-items:center; justify-content:center; }
  .hv-rong2-ico i { width:19px; height:19px; margin:0; background:var(--mo); }
  .hv-rong2-ico.canh { background:var(--tt-dung-nen); }
  .hv-rong2-ico.canh i { background:var(--do); }
  .hv-rong2-chu { font-size:13.5px; font-weight:600; color:var(--chu); }
  .hv-rong2-phu { font-size:12px; color:var(--mo); max-width:380px; line-height:1.45; }

  /* ⛔⛔ `auto-fit` CHỨ KHÔNG PHẢI `auto-fill` — 21/08/2026, đo bằng ảnh chụp.
     ──────────────────────────────────────────────────────────────────────────────
     Hai chữ này khác nhau đúng một chỗ, và chỗ ấy là cả vấn đề cô Quỳnh chê:
       · `auto-fill` → luôn tạo ĐỦ số cột vừa bề ngang (ở đây là 3), thẻ nào không
                       có thì cột ấy VẪN CHIẾM CHỖ và để trắng.
       · `auto-fit`  → cột không có thẻ thì XẸP VỀ 0, thẻ còn lại giãn ra lấp đầy.
     Hôm nay trung tâm chỉ có một mục "Dự giờ" → `auto-fill` để lại 900px trắng
     bên phải nó, giữa trang chủ. Cô Quỳnh: *"nhìn hổng hẳn 1 bảng trắng xóa ô
     không có gì nhìn xấu"*.
     ⛔ ĐỪNG ĐỔI LẠI `auto-fill`. Ngày nào cũng có mục vắng — hôm nào cũng sẽ hở. */
  /* ══════════════════════════════════════════════════════════════════════════════
     ⭐⭐ BĂNG TIN HÔM NAY — một block, vuốt ngang đổi tin, vuốt dọc gập/mở
     ──────────────────────────────────────────────────────────────────────────────
     Boss 08/09/2026: *"Phần Tin hôm nay bạn gom về 1 block thôi. Kéo xuống là để xem
     thông tin của block đó, kéo sang 2 bên để đổi sang block phụ đạo, lịch thi, dự
     giờ, yêu cầu GV… animation thật mượt mà, không bị xung đột nha."*

     Trước đây năm mục bày cùng lúc thành một lưới thẻ; nay mỗi mục là một TRANG nằm
     cạnh nhau trong một hàng ngang, băng trượt để đổi trang.

     ⛔ CHIỀU CAO KHUNG DO JS ĐẶT, ĐỪNG ĐẶT CỨNG Ở ĐÂY. Các trang nằm cạnh nhau nên
        nếu để khung tự cao thì nó luôn cao bằng trang DÀI NHẤT — đang xem trang hai
        dòng mà khối vẫn chừa chỗ cho trang mười dòng, hở ra một mảng trắng.
        `ganHtinVuot()` đo trang đang xem rồi đặt `height`, có chuyển động mượt.
     ⛔ `touch-action` CHIA ĐÔI, CÓ CHỦ Ý — đây là chỗ chống xung đột cử chỉ:
          · `.htin-day`  → `pan-y`: trình duyệt vẫn lo cuộn trang, JS chỉ bắt trục ngang
          · `.htin-o-dau` → `none` : dải DUY NHẤT giành quyền vuốt dọc để gập/mở
        Đặt `none` cho cả băng là ngón chạm trúng băng thì không cuộn nổi trang nữa.
     ══════════════════════════════════════════════════════════════════════════════ */
  .htin-khung { overflow:hidden; border:1px solid var(--vien); border-radius:var(--r-xl);
    background:var(--the); box-shadow:0 1px 3px rgba(20,50,70,.06); }
  /* ⛔ `cursor:grab` KHÔNG PHẢI TRANG TRÍ. Trên máy tính không có gì nói cho người dùng
     biết khối này kéo được — Boss đã báo đúng chuyện đó: *"bạn phải cho chức năng đi
     kéo sang 2 bên chứ, sao tôi ấn cái nút nhỏ ở dưới được"*. Bàn tay mở/nắm là dấu
     hiệu duy nhất mà chuột hiểu.
     `user-select:none` để kéo ngang không bôi đen cả đoạn chữ trong khi kéo. */
  .htin-day { display:flex; align-items:flex-start; touch-action:pan-y;
    will-change:transform; cursor:grab;
    -webkit-user-select:none; user-select:none; }
  .htin-day:active { cursor:grabbing; }
  .htin-trang { flex:0 0 100%; max-width:100%; min-width:0;
    display:flex; flex-direction:column; }
  /* Phần gập: 0fr → 1fr trượt đúng bằng chiều cao thật của nội dung.
     ⛔ ĐỪNG đổi sang `max-height` — phải đoán một con số, đoán thiếu thì cụt đuôi,
        đoán thừa thì lúc đóng lại có một quãng đứng hình không hiểu vì sao. */
  .htin-gap { display:grid; grid-template-rows:0fr;
    transition:grid-template-rows .32s cubic-bezier(.22,.9,.28,1); }
  .htin-gap-ruot { overflow:hidden; min-height:0; }
  .htin-bang.dang-mo .htin-gap { grid-template-rows:1fr; }
  .htin-mui { width:16px; height:16px; flex:none; margin-left:8px; color:var(--mo);
    transition:transform .3s cubic-bezier(.22,.9,.28,1); }
  .htin-bang.dang-mo .htin-mui { transform:rotate(180deg); }
  /* Chấm trang: cho biết đang ở tin nào trong mấy tin, và bấm thẳng tới được.
     ⛔ ĐỪNG BỎ cho gọn — không có nó thì không ai biết là băng vuốt được, mà một cử
        chỉ không ai biết là một tính năng đã chết. Chấm đang xem kéo dài thành gạch
        để phân biệt được cả khi không nhìn kỹ màu. */
  .htin-cham { display:flex; justify-content:center; align-items:center; gap:6px;
    padding:9px 0 1px; }
  .htin-cham-1 { width:7px; height:7px; padding:0; border:0; border-radius:999px;
    background:var(--vien); cursor:pointer;
    transition:width .28s cubic-bezier(.22,.9,.28,1), background .2s ease; }
  /* Tin nào ĐANG CÓ VIỆC thì chấm đậm hơn — liếc một cái biết còn mấy chỗ cần xem,
     khỏi phải vuốt hết một vòng mới biết. */
  .htin-cham-1[data-co] { background:var(--mo); }
  .htin-cham-1.chon { width:22px; background:var(--xanh-dam); }
  @media (prefers-reduced-motion:reduce) {
    .htin-day, .htin-khung, .htin-gap, .htin-mui, .htin-cham-1 { transition:none !important; }
  }
  .htin-o-dau { display:flex; align-items:center; gap:9px; padding:10px 13px; cursor:pointer;
    border-bottom:1px solid var(--vien); background:var(--tint); transition:filter .12s;
    touch-action:none; -webkit-user-select:none; user-select:none; }
  .htin-o-dau:hover { filter:brightness(.96); }
  .htin-o-dau .ico { width:17px; height:17px; margin:0; color:var(--mau); flex:none; }
  .htin-o-ten { font-weight:700; font-size:13.5px; color:var(--chu); }
  .htin-o-so { margin-left:auto; min-width:26px; text-align:center; border-radius:999px;
    padding:2px 9px; font-size:12px; font-weight:700; background:rgba(0,0,0,.06); color:var(--mo); }
  .htin-o-so.co { background:var(--mau); color:#fff; }
  /* 06/08: nới trần từ 236px lên 300px — thẻ nay vẽ ĐỦ mọi dòng (bỏ giới hạn 6 dòng)
     nên cho nhìn thấy nhiều hơn một lượt; dài quá thì cuộn trong chính thẻ.
     📐 09/08: thêm `flex:1` để thân GIÃN RA cho đầy khi thẻ bên cạnh cao hơn, và hạ
     trần 300 → 254px (≈5 dòng). Thẻ 15 dòng không còn kéo cả hàng cao vống lên; con
     số ở đầu thẻ vẫn cho biết tổng nên không giấu mất gì. */
  /* ⛔ 08/09/2026 — BỎ CUỘN TRONG THÂN (`max-height:254px; overflow-y:auto`), và đây
     là việc BẮT BUỘC chứ không phải dọn cho gọn:
       ① Một khung cuộn nằm trong một khối vuốt dọc là hai thứ tranh nhau cùng một cử
          chỉ. Ngón kéo xuống ở giữa thân thì trình duyệt cuộn thân, còn tay người
          tưởng mình đang mở block — đúng "xung đột" Boss dặn phải tránh.
       ② Lý do đặt trần ngày 09/08 đã hết: hồi ấy năm thẻ nằm CẠNH NHAU trong một
          lưới, nên thẻ 15 dòng kéo cả hàng cao vống lên. Nay mỗi lúc chỉ hiện MỘT
          trang, không còn hàng nào để làm lệch.
     Thân dài thì cả trang chủ cuộn như mọi nội dung khác — thứ người dùng vốn quen. */
  /* ══════════════════════════════════════════════════════════════════════════
     ⏰ THÂN THẺ CHỈ CAO BẰNG 5 DÒNG, THỪA THÌ CUỘN TRONG — Boss 10/09/2026
     ──────────────────────────────────────────────────────────────────────────
     Boss: *"cái bảng thông tin ở trang chủ đang bị khi có nhiều lớp thì cái bảng
     thông báo nó dài ra mãi. Tôi muốn giới hạn nó ngắn lại khoảng 5 ô thôi rồi sẽ
     có cái chức năng kéo lên xuống di chuột và di màn hình điện thoại, tránh việc
     block tin hôm nay nó dài quá."*

     ⛔ LUẬT 06/08/2026 ĐÃ HẾT HẠN. Hôm ấy bỏ trần chiều cao vì thân thẻ nằm trong
        LƯỚI: thẻ 15 dòng kéo cả hàng cao vống lên. Nay mỗi lúc chỉ bày MỘT trang
        (xem chú thích ngay trên), không còn hàng nào để làm lệch — nên trần ở đây
        là an toàn, và đúng thứ Boss đang xin.

     ⛔ ĐẶT TRẦN Ở THÂN THẺ, KHÔNG ĐẶT Ở KHUNG NGOÀI `.home-gio-cuon`. Khung ngoài
        vẫn `max-height:none; overflow:visible` — đặt trần cả hai chỗ là hai lớp
        cuộn lồng nhau, ngón tay vuốt không biết lớp nào ăn, và thẻ hàng dưới bị
        cắt cụt. Đó đúng cái bẫy đã ghi ở `.home-gio-cuon` từ 06/08.

     ⛔ TÍNH THEO SỐ DÒNG, ĐỪNG GÕ MỘT SỐ px. Một dòng `.htin-d` = padding 7px×2 +
        chữ ~19px = 33px, cộng `gap:5px`. Năm dòng = 33×5 + 5×4 = 185px, cộng
        padding 7px×2 của thân = 199px. Ai đổi padding hay cỡ chữ thì sửa
        `--htin-cao-dong` một chỗ, khỏi đi dò lại số.
        (Dòng có nhãn dài tự xuống hai hàng nên đôi khi chỉ vừa 4 dòng — Boss nói
         "khoảng 5 ô", và thà hụt một dòng còn hơn cắt cụt một dòng.)

     ⛔ `overscroll-behavior:contain` là vế BẮT BUỘC trên điện thoại: thiếu nó thì
        vuốt hết dòng cuối là cú vuốt "xuyên" ra kéo luôn cả trang chủ — người dùng
        đang đọc trong thẻ bỗng bị nhảy màn.
     ⛔ `-webkit-overflow-scrolling:touch` cho Safari cũ cuộn mượt, không thì nó
        giật từng nấc. */
  .htin-o-than { padding:7px; display:flex; flex-direction:column; gap:5px;
    flex:1 1 auto;
    --htin-cao-dong:33px; --htin-so-dong:5;
    max-height:calc(var(--htin-cao-dong) * var(--htin-so-dong)
                    + 5px * (var(--htin-so-dong) - 1) + 14px);
    overflow-y:auto; overscroll-behavior:contain; -webkit-overflow-scrolling:touch; }
  /* 👤 Việc CỦA CHÍNH NGƯỜI ĐANG XEM — viền trái đậm màu nhấn + nhãn nhỏ trước tên. */
  /* ⛔ 21/08/2026 — DÙNG TEAL THƯƠNG HIỆU, KHÔNG dùng `--mau` của thẻ nữa.
     Từ khi bốn mục kia về xám đá (xem `MUC_MAU`), `var(--mau)` của chúng là xám —
     mà viền xám quanh thẻ xám thì thấy bằng gì? "Có việc của tôi" là tín hiệu
     đáng để mắt nhất trên Trang chủ, không được chìm. */
  .htin-trang.co-toi { box-shadow:0 0 0 1px var(--xanh-dam), 0 1px 3px rgba(20,50,70,.06); }
  .htin-o-toi { margin-left:auto; font-size:11px; font-weight:700; color:var(--xanh-dam);
    background:var(--the); border:1px solid var(--xanh-dam); border-radius:999px; padding:1px 8px; }
  .htin-o-toi + .htin-o-so { margin-left:6px; }
  /* Nét trái của dòng "của tôi" cũng phải là teal, cùng lý do với cái vòng ở trên. */
  .htin-d.cua-toi { border-left-color:var(--xanh-dam); border-left-width:4px; }
  .htin-toi { display:inline-block; font-size:10px; font-weight:700;
 color:#fff; background:var(--mau); border-radius:var(--r-sm);
    padding:1px 6px; margin-right:6px; vertical-align:1px; }
  .htin-o-than::-webkit-scrollbar { width:7px; }
  .htin-o-than::-webkit-scrollbar-thumb { background:#CBD5DD; border-radius:var(--r-md); }
  /* ⛔ `flex-wrap:wrap` + `flex:1 1 190px` cho phần chữ: màn hẹp hoặc nhãn dài thì cái
     nhãn TỰ XUỐNG DÒNG thay vì bóp chữ đến mức cắt cụt. Đây là lớp phòng thứ hai bên
     cạnh việc nới cột ở trên — nới cột lo màn rộng, xuống dòng lo màn hẹp. */
  .htin-d { display:flex; flex-wrap:wrap; align-items:center; gap:8px; padding:7px 9px; border-radius:var(--r-md);
    cursor:pointer; border-left:3px solid var(--vien); background:var(--nen2); transition:background .1s; }
  .htin-d:hover { background:var(--xanh-nhat); }
  .htin-d.gap  { border-left-color:var(--cam); }      /* còn việc phải làm */
  .htin-d.xong { border-left-color:var(--o-tot); }    /* đã ổn */
  .htin-d-chu { flex:1 1 190px; min-width:0; display:flex; flex-direction:column; gap:2px; }
  .htin-d-ten { font-weight:700; font-size:12.8px; line-height:1.3;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  /* ⛔ 21/08/2026 — DÒNG PHỤ NAY XUỐNG DÒNG, KHÔNG CẮT CỤT NỮA.
     Đo được bằng trình duyệt thật: dòng này cần 291–366px mà ô chỉ rộng 233px, nên cả
     bốn thẻ Dự giờ đều hiện "12 ngày trước · 09/08/2…". Nới cột lên 340px vẫn chưa đủ —
     vì dòng này còn kèm tên giáo viên, dài bao nhiêu là tuỳ tên.
     Cắt cụt một dòng NGÀY là giấu mất đúng thứ người ta cần đọc. Cho xuống tối đa hai
     dòng: đủ chỗ cho mọi tên, mà thẻ không phình vô hạn.
     ⛔ Dòng TÊN (.htin-d-ten) thì VẪN cắt cụt một dòng — tên lớp ngắn, và giữ một dòng
        để mọi thẻ thẳng hàng nhau. Chỉ dòng phụ mới được xuống dòng. */
  .htin-d-phu { font-size:11.5px; color:var(--mo); line-height:1.3;
    overflow:hidden; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
    white-space:normal; overflow-wrap:anywhere; }
  .htin-d-nhan { flex:none; font-size:11px; font-weight:700; padding:2px 9px;
    border-radius:var(--r-xl); white-space:nowrap; }
  .htin-d.gap  .htin-d-nhan { background:#FFF3D9; color:#9A6400; }
  .htin-d.xong .htin-d-nhan { background:#E8F6EC; color:#12613A; }
  .htin-trong { font-size:12.5px; color:var(--mo); padding:12px 13px; }
  /* 👁 07/08 — thẻ CHỈ ĐỂ XEM (giáo viên xem yêu cầu lớp mình): không mở được công
     cụ nên bỏ hết dấu hiệu "bấm được", kẻo bấm mãi không thấy gì lại tưởng app hỏng. */
  .htin-trang.chi-xem .htin-o-dau { cursor:default; }
  .htin-trang.chi-xem .htin-o-dau:hover { filter:none; }
  .htin-trang.chi-xem .htin-d { cursor:default; }
  .htin-trang.chi-xem .htin-d:hover { background:var(--nen2); }
  body.toi .htin-trang.chi-xem .htin-d:hover { background:rgba(255,255,255,.04); }
  /* 📐 09/08: `margin-top:auto` — thẻ ngắn bị giãn cao lên thì dòng "Mở công cụ →"
     vẫn nằm sát đáy, thẳng hàng với các thẻ bên cạnh. */
  .htin-chan { margin-top:auto; text-align:center; font-size:12px; font-weight:700; color:var(--muc);
    padding:8px; border-top:1px solid var(--vien); background:var(--nen2); cursor:pointer; }
  .htin-chan:hover { background:var(--xanh-nhat); }
  body.toi .htin-o-so { background:rgba(255,255,255,.12); }
  body.toi .htin-d { background:rgba(255,255,255,.04); }
  /* 🌙 Nền tối: `--tint` là màu pastel SÁNG, để nguyên thì chữ sáng nằm trên nền sáng
     → gần như vô hình. Thay bằng một lớp mờ nhẹ; icon vẫn giữ màu nhấn nên vẫn phân
     biệt được từng mục. */
  body.toi .htin-o-dau { background:rgba(255,255,255,.05); }
  body.toi .htin-d.gap  .htin-d-nhan { background:rgba(242,193,78,.16); color:#F2C14E; }
  body.toi .htin-d.xong .htin-d-nhan { background:rgba(46,158,91,.16); color:#7FD6A0; }

  /* ============ 📊 BẢNG THỐNG KÊ TRANG CHỦ (06/08/2026) ============ */
  .tk-kieu-hang { margin-left:auto; display:flex; gap:3px; background:var(--nen2);
    border:1px solid var(--vien); border-radius:var(--r-md); padding:2px; }
  .tk-kieu { border:none; background:transparent; border-radius:var(--r-md); padding:4px 12px;
    font-size:12px; font-weight:600; color:var(--mo); cursor:pointer; font-family:inherit; }
  .tk-kieu:hover { color:var(--chu); }
  .tk-kieu.chon { background:var(--the); color:var(--muc); box-shadow:0 1px 2px rgba(20,50,70,.12); }
  .tk-phan { margin-bottom:16px; }
  .tk-phan:last-of-type { margin-bottom:6px; }
  /* 🔄 03/09/2026 — HAI BẢNG SỐ XẾP CẠNH NHAU Ở MÀN RỘNG. Cô Quỳnh chọn bằng nút
     bấm: *"thu bé lại để gom nhiều ô bảng đó vào được 1 hàng đỡ bị rối mắt và kéo
     xuống sâu"*. Cùng với khung đồ thị dẹt lại (xem `tkDuong`), cả khối tụt từ
     ~1.300px xuống ~450px — nhìn hết trong một màn.
     ⛔ KHOANH BẰNG `#homeThongKe`, đừng viết trần `.home-khoi-than`. Tên ấy dùng
        chung cho MỌI khối ở Trang chủ (Tin hôm nay, Ghi chú…), mà quanh dòng 4861
        đã có luật biến nó thành cột flex trong hai khối khác — viết trần là hai
        luật đá nhau và hai khối kia vỡ bố cục.
     ⛔ `minmax(0, 1fr)` CHỨ KHÔNG PHẢI `1fr`. Ô lưới mặc định không hẹp hơn nội
        dung của nó; bảng "Chi tiết từng lớp" rộng hơn nửa màn sẽ ĐẨY cột phình ra,
        lưới lệch hẳn. `minmax(0,…)` cho phép ô co lại và để khung cuộn tự lo.
     ⛔ BA THỨ PHẢI CHIẾM CẢ HÀNG: ô chọn nhân viên, bảng từng lớp, và dòng ghi chú
        cuối. Ép chúng vào nửa màn là gọn hơn nhưng dùng khó hơn — đúng thứ skill
        `cong-cu-cho-nguoi-that` dặn tránh. */
  @media (min-width:1080px) {
    #homeThongKe .home-khoi-than {
      display:grid; grid-template-columns:repeat(2, minmax(0, 1fr));
      column-gap:14px; align-items:start; }
    #homeThongKe .home-khoi-than > .tk-chon-nguoi,
    #homeThongKe .home-khoi-than > .tk-phan-rong,
    #homeThongKe .home-khoi-than > .tk-ghichu { grid-column:1 / -1; }
  }
  .tk-phan-dau { display:flex; align-items:center; gap:10px; margin:0 0 11px; font-size:13px; color:var(--mo); }
  .tk-phan-dau b { font-weight:600; color:var(--chu); }
  .tk-vai { font-size:10.5px; font-weight:700;
    color:#fff; background:#0E7C86; border-radius:var(--r-sm); padding:3px 9px; }
  .tk-vai.gv { background:#7C5BD0; }
  /* Ô số liệu — kiểu thẻ chỉ số của bảng điều khiển doanh nghiệp. */
  .tk-luoi { display:grid; grid-template-columns:repeat(auto-fit, minmax(168px,1fr)); gap:11px; }
  .tk-o { padding:14px 16px; border:1px solid var(--vien); border-radius:var(--r-xl); background:var(--the); }
  .tk-o-nhan { display:block; font-size:11px; font-weight:700;
 color:var(--mo); }
  .tk-o-so { display:block; font-size:27px; font-weight:700; line-height:1.15; margin-top:6px;
    letter-spacing:-.5px; color:var(--chu); }
  /* Mũi tên tăng/giảm kiểu bảng chứng khoán. */
  .tk-o-chenh { display:inline-block; margin-top:6px; font-size:12px; font-weight:700;
    padding:2px 8px; border-radius:var(--r-sm); }
  .tk-o-chenh.len   { color:#12613A; background:#E8F6EC; }
  .tk-o-chenh.xuong { color:#A3231B; background:#FDEBEA; }
  /* Giữ nguyên / đi ngang = XANH NƯỚC BIỂN (cô Quỳnh 06/08), không dùng xám nữa. */
  .tk-o-chenh.bang  { color:#1E4FA3; background:#E6EDFA; }
  body.toi .tk-o-chenh.bang { color:#8FB4F0; background:rgba(37,99,201,.18); }
  .tk-o-phu { display:block; margin-top:5px; font-size:11.5px; color:var(--mo); }
  /* Biểu đồ CỘT nằm ngang */
  .tk-cot { display:flex; flex-direction:column; gap:7px; }
  .tk-cot-h { display:grid; grid-template-columns:minmax(0,1fr) 2.4fr auto; gap:10px; align-items:center; }
  .tk-cot-ten { font-size:12.5px; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .tk-cot-thanh { height:18px; border-radius:var(--r-sm); background:var(--nen2); overflow:hidden; }
  .tk-cot-thanh i { display:block; height:100%; border-radius:var(--r-sm);
    background:linear-gradient(90deg, #0E7C86 0%, #17B0A4 100%); }
  .tk-cot-so { font-size:12.5px; font-weight:700; color:var(--muc); min-width:56px; text-align:right; }
  /* 👥 Ô chọn "xem báo cáo của ai" (07/08) — chỉ Quản lý / Developer thấy.
     Cô Quỳnh: *"phải ghi rõ của ai ra chứ, và để có thể chọn được báo cáo của
     từng nhân viên"*. */
  .tk-chon-nguoi { display:flex; align-items:center; gap:9px; flex-wrap:wrap;
    margin:0 0 14px; padding:9px 12px; background:var(--nen2);
    border:1px solid var(--vien); border-radius:var(--r-lg); }
  .tk-chon-nguoi label { font-size:11.5px; font-weight:700;
 color:var(--mo); }
  .tk-chon-nguoi select { flex:1; min-width:220px; max-width:460px; font-size:13px;
    font-weight:600; padding:6px 9px; }
  /* Tên người đang được xem, đặt cạnh nhãn vai — nhắc lại cho khỏi quên đang soi ai. */
  .tk-cua-ai { margin-left:auto; font-size:12px; font-weight:700; color:var(--muc); }

  /* ══ 📈 KHỐI "BẢNG GIÁ" — kiểu sàn chứng khoán (cô Quỳnh 06/08) ══ */
  .tk-gia { border:1px solid var(--vien); border-radius:var(--r-xl); background:var(--the); overflow:hidden; }
  .tk-gia-dau { display:flex; align-items:center; flex-wrap:wrap; gap:10px;
    padding:13px 16px 11px; border-bottom:1px solid var(--vien); background:var(--nen2); }
  .tk-gia-so { font-size:30px; font-weight:700; letter-spacing:-.6px; line-height:1; color:var(--chu);
    font-variant-numeric:tabular-nums; }
  .tk-gia-phu { font-size:11.5px; color:var(--mo); margin-left:auto; text-align:right; }
  /* Chip chọn chỉ số — như chọn mã cổ phiếu trên bảng giá.
     ⛔ 23/08/2026 — BỐN LUẬT DƯỚI PHẢI KÈM `.tk-chip-hang`. Trước viết trần là
     `.tk-chip`, mà tên ấy còn dùng cho hàng tab bên Quản lý tài khoản (khai ở trên,
     quanh dòng 5509). Cùng tên, luật này đứng sau nên đè: hàng tab vẽ ra vẫn mang
     dáng viên thuốc viền hộp, tab đang đứng thì nền xanh đặc — nhìn không ra tab.
     Nó chỉ dùng đúng một chỗ (`tk-gia-dau > .tk-chip-hang`, quanh dòng 15224), nên
     khoanh vào đó là xong, không cần chồng độ mạnh lên nhau. */
  /* ⛔⛔ 09/09/2026 — THIEU `flex-wrap` LA CHIP BIEN MAT HAN, KHONG PHAI CHI XAU.
     Hang chip nay do duoc **382px** trong khi long the chi co 332px (man 390),
     302px (360) va **262px (320)**. Khong khai `flex-wrap` thi mac dinh la `nowrap`,
     chip tran ra ngoai; ma cha `.tk-gia` co `overflow:hidden` VA khong cuon ngang
     duoc — nen chip "So buoi da day" bi XEN CUNG, mat hut. O man 320 mat o CA HAI
     the. Nguoi dung khong he biet co cai chip do de ma di tim.
     ⛔ `overflow:hidden` cua `.tk-gia` phai giu: no lo bo goc cho bieu do ben trong.
        Sua o day, dung go ben ay. */
  .tk-chip-hang { display:flex; flex-wrap:wrap; gap:4px; width:100%; }
  .tk-chip-hang .tk-chip { border:1px solid var(--vien); background:var(--the); color:var(--mo);
    border-radius:var(--r-md); padding:4px 11px; font-size:11.5px; font-weight:600;
    cursor:pointer; font-family:inherit; transition:border-color .12s, color .12s; }
  .tk-chip-hang .tk-chip:hover { color:var(--chu); }
  .tk-chip-hang .tk-chip.chon { background:#0E545C; border-color:#0E545C; color:#fff; }
  .tk-nghia { margin:0; padding:9px 16px 0; font-size:11.5px; line-height:1.55; color:var(--mo); }
  .tk-dothi { padding:4px 6px 0; position:relative; }
  .tk-dothi svg { display:block; width:100%; height:auto; }
  .tk-luoi-ke { stroke:var(--vien); stroke-width:1; stroke-dasharray:3 4; }
  .tk-truc { font-size:10.5px; fill:var(--mo); font-family:inherit; }
  /* 🔢 Số ghi thẳng trên từng mốc — khỏi phải đoán theo chiều cao. */
  .tk-nhanso { font-size:11.5px; font-weight:700; fill:var(--chu); font-family:inherit;
    opacity:0; animation:tkHienSo .45s ease forwards; }
  .tk-cham { fill:var(--the); stroke:var(--mau); stroke-width:1.9;
    opacity:0; animation:tkNoCham .35s cubic-bezier(.3,1.5,.5,1) forwards; }
  .tk-chua { margin:0; padding:26px 16px; font-size:12.5px; color:var(--mo); text-align:center; }
  /* ✨ Hiệu ứng vào: đường TỰ VẼ từ trái sang, vùng tô dâng lên, chấm nảy ra. */
  /* Mỗi ĐOẠN tự vẽ, so le nhau → nhìn như đường chạy dần từ trái sang. */
  .tk-net { stroke-dasharray:300; stroke-dashoffset:300; animation:tkVeNet .38s cubic-bezier(.4,0,.2,1) forwards; }
  .tk-vungto { opacity:0; transform-origin:bottom; animation:tkDangLen .8s .25s ease forwards; }
  .tk-cuoi-quang { opacity:.24; animation:tkNhipTho 2.2s ease-in-out .9s infinite; }
  @keyframes tkVeNet   { to { stroke-dashoffset:0; } }
  @keyframes tkDangLen { from { opacity:0; transform:scaleY(.4); } to { opacity:1; transform:scaleY(1); } }
  @keyframes tkNoCham  { from { opacity:0; r:0; } to { opacity:1; } }
  @keyframes tkHienSo  { from { opacity:0; transform:translateY(5px); } to { opacity:1; transform:none; } }
  @keyframes tkNhipTho { 0%,100% { opacity:.24; } 50% { opacity:.5; } }
  @media (prefers-reduced-motion:reduce) {
    .tk-net, .tk-vungto, .tk-cham, .tk-nhanso, .tk-cuoi-quang { animation:none !important;
      opacity:1 !important; stroke-dashoffset:0 !important; transform:none !important; }
  }
  /* 🖱 Rê chuột: vạch dọc + chấm sáng + ô chú thích ghi rõ tháng nào, số bao nhiêu. */
  .tk-batchuot { position:absolute; inset:4px 6px 30px; display:flex; }
  .tk-vung { height:100%; cursor:crosshair; }
  .tk-vach { position:absolute; top:12px; bottom:30px; width:1px; background:var(--mau);
    opacity:0; transition:opacity .12s, left .12s; pointer-events:none; }
  .tk-vach.hien { opacity:.42; }
  .tk-diem { position:absolute; width:11px; height:11px; margin:-5.5px 0 0 -5.5px; border-radius:50%;
    background:var(--mau); box-shadow:0 0 0 4px color-mix(in srgb, var(--mau) 22%, transparent);
    opacity:0; transition:opacity .12s, left .12s, top .12s; pointer-events:none; }
  .tk-diem.hien { opacity:1; }
  .tk-chuthich { position:absolute; top:2px; z-index:3; pointer-events:none;
    background:#12222A; color:#fff; border-radius:var(--r-lg); padding:9px 13px; min-width:132px;
    box-shadow:0 8px 22px rgba(6,26,32,.34); transition:left .12s; }
  .tk-chuthich b { display:block; font-size:11.5px; font-weight:700; opacity:.72; }
  .tk-ct-ten { display:block; font-size:11px; color:rgba(255,255,255,.6); margin-top:1px; }
  .tk-ct-so { display:block; font-size:19px; font-weight:700; margin-top:4px; letter-spacing:-.3px; }
  .tk-ct-ch { display:block; font-size:11px; font-weight:600; margin-top:3px; }
  .tk-ct-ch.len { color:#6FDCA0; } .tk-ct-ch.xuong { color:#FF9A90; } .tk-ct-ch.bang { color:rgba(255,255,255,.55); }
  /* Đường tí hon trong ô số liệu */
  .tk-nhoxiu { display:block; width:100%; height:22px; margin-top:8px; }
  /* 📋 Bảng CHI TIẾT TỪNG LỚP — dòng TỔNG nổi lên trên, từng lớp ở dưới. */
  .tk-tunglop { margin-top:14px; border:1px solid var(--vien); border-radius:var(--r-xl);
    background:var(--the); overflow:hidden; }
  .tk-tl-dau { padding:10px 14px; font-size:12px; font-weight:600; color:var(--mo);
    background:var(--nen2); border-bottom:1px solid var(--vien); }
  .tk-tl-dau b { color:var(--chu); font-weight:700; }
  .tk-tl-dau i { font-style:normal; color:var(--cam-dam, #9A6400); }
  .tk-tl-cuon { overflow-x:auto; max-height:340px; overflow-y:auto; }
  .tk-tl { width:100%; border-collapse:separate; border-spacing:0; font-size:12.5px; }
  .tk-tl th { position:sticky; top:0; z-index:2; background:var(--the); text-align:right;
    font-size:10.5px; font-weight:700;
    color:var(--mo); padding:8px 12px; border-bottom:1px solid var(--vien); white-space:nowrap; }
  .tk-tl th:first-child { text-align:left; }
  .tk-tl td { padding:9px 12px; text-align:right; border-bottom:1px solid var(--vien);
    font-variant-numeric:tabular-nums; white-space:nowrap; }
  .tk-tl tbody tr:last-child td { border-bottom:none; }
  .tk-tl .tl-ten { text-align:left; font-weight:600; }
  .tk-tl .tl-ten small { display:block; font-size:11px; font-weight:400; color:var(--mo); }
  .tk-tl .tl-mo { color:var(--mo); }
  /* ⛔ 06/08: dòng TỔNG từng DÍNH LẠI khi cuộn (position:sticky; top:33px) — cô Quỳnh
     báo nó "bị kéo theo khi kéo xuống gây vướng", và đúng là nó ĐÈ LÊN dòng lớp phía
     sau, che mất tên cơ sở. Bỏ dính; chỉ hàng TIÊU ĐỀ cột dính là đủ. */
  .tk-tl .tl-tong td { background:var(--nen2); font-weight:700; border-bottom:2px solid var(--vien); }
  .tl-pt { display:inline-block; min-width:52px; padding:2px 8px; border-radius:var(--r-sm); font-weight:700; }
  .tl-pt.tot  { background:#E8F6EC; color:#12613A; }
  .tl-pt.vua  { background:#FFF3D9; color:#9A6400; }
  .tl-pt.kem  { background:#FDEBEA; color:#A3231B; }
  body.toi .tl-pt.tot { background:rgba(91,179,124,.16); color:#7FD6A0; }
  body.toi .tl-pt.vua { background:rgba(217,174,90,.16); color:#E4C88A; }
  body.toi .tl-pt.kem { background:rgba(229,118,108,.16); color:#EFA097; }
  .tk-ghichu { margin:12px 0 0; font-size:11.5px; color:var(--mo); line-height:1.5;
    padding-top:11px; border-top:1px solid var(--vien); }
  body.toi .tk-o, body.toi .tk-tron::after { background:var(--the); }
  body.toi .tk-o-chenh.len   { color:#7FD6A0; background:rgba(46,158,91,.16); }
  body.toi .tk-o-chenh.xuong { color:#F09A93; background:rgba(214,69,69,.16); }
  @media (max-width:640px) {
    .tk-kieu-hang { width:100%; margin:8px 0 0; }
    .tk-kieu { flex:1; }
    .tk-cot-h { grid-template-columns:minmax(0,1fr) 1.4fr auto; }
  }

  /* ===== 📈 BÁO CÁO SỐ TOÀN TRUNG TÂM (07/08/2026) =====
     Nằm NGAY DƯỚI "Thống kê của tôi" ở cột trái Trang chủ. Dùng lại nguyên bộ
     `.tk-tl` của bảng từng lớp cho hai bảng số, chỉ thêm mấy nét riêng dưới đây. */
  .bcs-moc { font-weight:400; font-size:12px; color:var(--mo); }

  /* ===== 📊 THẺ SỐ KIỂU BẢNG ĐIỀU KHIỂN (07/08/2026) =====
     Cô Quỳnh: *"giảm thì số màu ĐỎ chú thích giảm bao nhiêu so với tháng trước,
     tăng thì XANH LÁ, giữ nguyên thì màu thường. Để dạng dashboard cho thật
     chuyên nghiệp. Để animation, chỉ chuột vào đâu thấy rõ thông tin"*.
     ⛔ Hai màu này khai một chỗ rồi dùng lại khắp nơi (thẻ · mũi tên · đường ·
     số nhỏ trong bảng). Rải màu thẳng vào từng chỗ là mỗi chỗ một sắc đỏ khác. */
  :root { --bcs-do:#D64545; --bcs-xanh:#1E8E4E; }
  body.toi { --bcs-do:#F09A93; --bcs-xanh:#7FD6A0; }

  /* ⭐ MỘT KHUNG DUY NHẤT, chọn chỉ số bằng hàng nút (cô Quỳnh 07/08: *"gộp cái
     này vào làm 1 thôi và để nhiều lựa chọn, phải có cả piechart"*). */
  .bcs-bang { border:1px solid var(--vien); border-radius:var(--r-xl); background:var(--the);
    box-shadow:var(--bong-1); padding:10px 12px 12px; }
  /* ══════════════════════════════════════════════════════════════════════════
     📊 HÀNG THẺ SỐ KIỂU SUPABASE — cô Quỳnh 02/09/2026
     *"cái bảng thống kê số liệu của app và trung tâm thì tôi muốn bạn tham khảo
      thiết kế của supabase ấy… tôi muốn nó gọn lại"*

     TRƯỚC: hàng nút chọn + MỘT đồ thị 640×196 + vòng tròn 210px ≈ cao 330px, mà
     chỉ xem được MỘT chỉ số mỗi lúc. NAY: sáu chỉ số hiện cùng lúc trong sáu thẻ,
     cộng thẻ vòng tròn là bảy.

     ⛔ KẺ ĐƯỜNG NGĂN BẰNG `gap:1px` TRÊN NỀN `--vien`, KHÔNG viền từng thẻ. Thẻ
        xuống hàng thì viền hai thẻ cạnh nhau chồng lên nhau thành nét đôi, dày
        mỏng lung tung. Cách này luôn ra nét đơn, xuống bao nhiêu hàng cũng đúng.
     ⛔ KHÔNG CUỘN NGANG. Supabase cuộn ngang được vì họ có nút mũi tên; ở đây
        `auto-fit` cho thẻ tự xuống hàng, cô Quỳnh khỏi phải miết sang phải.
     ⛔ ĐỪNG trả lại hàng nút chọn `.bcs-chip` cũ. Nay chính THẺ là nút chọn —
        bấm thẻ nào thì vòng tròn chia theo cơ sở đổi theo chỉ số ấy. */
  .bcs-dinh { display:flex; align-items:baseline; gap:18px; flex-wrap:wrap;
    margin-bottom:8px; }
  .bcs-dinh-o { display:inline-flex; align-items:baseline; gap:5px; }
  .bcs-dinh-so { font-size:19px; font-weight:600; color:var(--chu);
    font-variant-numeric:tabular-nums; letter-spacing:-.015em; }
  .bcs-dinh-nhan { font-size:12.5px; color:var(--mo); }
  .bcs-the-hang { display:grid; grid-template-columns:repeat(auto-fit, minmax(150px, 1fr));
    gap:1px; background:var(--vien); border:1px solid var(--vien); }
  .bcs-the { display:flex; flex-direction:column; gap:5px; min-width:0;
    padding:9px 11px 8px; background:var(--the); border:0; text-align:left;
    font-family:inherit; color:inherit; cursor:pointer; transition:background .13s; }
  .bcs-the:hover { background:color-mix(in srgb, var(--nen2) 55%, transparent); }
  /* Thẻ đang chọn: vạch màu mảnh ở đỉnh — đúng lối Supabase đánh dấu thẻ đang mở. */
  .bcs-the.chon { background:var(--nen2); box-shadow:inset 0 2px 0 var(--muc); }
  .bcs-the-dau { display:flex; align-items:center; gap:6px; min-width:0; }
  /* ⛔ KHÔNG IN HOA. Supabase in hoa được vì nhãn của họ là tiếng Anh; tiếng Việt
     cỡ 11px mà in hoa thì MẤT DẤU ("CƠ SỞ" đọc thành "CO SO") — đúng bài học đã
     ghi sẵn ở `.bcs-phai-dau` bên dưới. */
  .bcs-the-ten { flex:1; min-width:0; font-size:11px; font-weight:500; color:var(--mo);
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .bcs-the-so { display:block; font-size:20px; font-weight:600; line-height:1.12;
    color:var(--chu); font-variant-numeric:tabular-nums; letter-spacing:-.015em; }
  .bcs-the-chan { display:flex; justify-content:space-between; gap:6px;
    font-size:9.5px; color:var(--mo); font-variant-numeric:tabular-nums; }
  .bcs-the-chan i { font-style:normal; }
  /* Thẻ vòng tròn đứng cuối hàng — chỉ để nhìn, không bấm được. Vòng nhỏ lại còn
     92px cho cao xấp xỉ mấy thẻ kia; lưới kéo mọi ô cao bằng ô cao nhất, để to
     hơn là cả hàng dài thêm chỉ vì một ô. */
  .bcs-the-tron { cursor:default; }
  .bcs-the-tron:hover { background:var(--the); }
  .bcs-the-tron .bcs-tron { max-width:92px; margin:2px auto 0; }
  .bcs-the-tron .bcs-tron-so { font-size:28px; }
  .bcs-the-tron .bcs-tron-nhan { font-size:12px; }
  .bcs-duoi { margin:8px 0 0; font-size:11.5px; line-height:1.5; color:var(--mo); }
  .bcs-duoi b { color:var(--chu); font-weight:600; }
  /* Nút chuyển mốc so sánh (tuần / tháng) — đẩy sang phải, tách khỏi hàng chỉ số. */
  /* Dãy nút chọn mốc — đúng kiểu "Last 3 months · Last 30 days · Last 7 days" trong
     ảnh cô Quỳnh gửi: một rãnh xám, nút đang chọn nổi lên nền trắng. */
  .bcs-moc-hang { margin-left:auto; display:inline-flex; gap:2px; background:var(--nen2);
    border:1px solid var(--vien); border-radius:var(--r-md); padding:2px; }
  .bcs-moc-nut { border:none; background:none; color:var(--mo); border-radius:var(--r-sm);
    padding:4px 10px; font-size:11.5px; font-weight:500; cursor:pointer; font-family:inherit;
    transition:background .13s, color .13s; }
  .bcs-moc-nut:hover { color:var(--chu); }
  .bcs-moc-nut.chon { background:var(--the); color:var(--chu); font-weight:600;
    box-shadow:var(--bong-1); }
  /* (Khối số to + đồ thị 640×196 đã bỏ ngày 02/09/2026 — xem khối lý do ở trên.) */

  /* ===== Biểu đồ cột tí hon trong thẻ (thay đồ thị 640×196 cũ, 02/09/2026) =====
     ⛔ `preserveAspectRatio="none"` Ở ĐÂY THÌ ĐƯỢC — khác hẳn đồ thị to ngày trước.
        Trong này chỉ có hình chữ nhật, không chấm tròn không chữ, nên kéo giãn ngang
        không méo thứ gì. (Đồ thị cũ có chấm và chữ trục nên cấm dùng `none`.)
     ⚠️ ĐÁY KHÔNG PHẢI SỐ 0, CỐ Ý — và đây là một sự đánh đổi, không phải sơ suất.
        Sĩ số trung tâm quanh 1.850 em, mỗi tuần nhích vài em; lấy đáy 0 thì sáu cột
        cao gần bằng nhau như một bức tường, chẳng đọc ra xu hướng gì. Nên đáy đặt
        thấp hơn mốc thấp nhất một quãng. Đổi lại, hình cột CHỈ nói CHIỀU LÊN/XUỐNG
        chứ không nói ĐỘ LỚN — nên con số thật luôn in ngay phía trên, và rê chuột
        vào cột nào cũng ra đúng số của cột đó. Đừng đọc độ cao cột thành tỉ lệ. */
  .bcs-tia { display:block; width:100%; height:30px; margin-top:1px; }
  .bcs-tia-cot { cursor:pointer; transition:opacity .13s; }
  .bcs-tia-cot:hover { opacity:1; }
  .bcs-tia-trong { display:block; font-size:10.5px; color:var(--mo); padding:9px 0; }

  /* ===== Biểu đồ TRÒN chia theo cơ sở ===== */
  .bcs-phai { border:1px solid var(--vien); border-radius:var(--r-lg); background:var(--nen2);
    padding:9px 10px 10px; }
  /* ⛔ BỎ `text-transform:uppercase` VÀ `letter-spacing`. Hai thứ này cộng nét 700
     là đúng ba dấu hiệu lộ giao diện AI. Với tiếng Việt còn tệ thêm một bậc: chữ
     IN HOA cỡ 10,5px thì MẤT DẤU — "CƠ SỞ" đọc thành "CO SO". */
  .bcs-phai-dau { font-size:11.5px; font-weight:600; color:var(--mo); margin-bottom:6px; }
  .bcs-tron { display:block; width:100%; max-width:132px; margin:0 auto; height:auto; }
  .bcs-mieng { transition:opacity .13s, stroke-width .13s; cursor:pointer; transform-origin:70px 70px; }
  .bcs-tron:hover .bcs-mieng { opacity:.45; }
  .bcs-tron .bcs-mieng:hover { opacity:1; stroke-width:30; }
  .bcs-tron-so { fill:var(--chu); font-size:19px; font-weight:700;
    font-family:system-ui, sans-serif; dominant-baseline:middle; }
  .bcs-tron-nhan { fill:var(--mo); font-size:9px; font-weight:400; font-family:system-ui, sans-serif; }
  .bcs-tron-trong { font-size:12px; color:var(--mo); text-align:center; padding:12px 0; }
  .bcs-phai-chan { margin:7px 0 0; font-size:10.5px; color:var(--mo); line-height:1.4; }
  /* Chấm màu trước tên cơ sở trong bảng — cầu nối duy nhất giữa vòng tròn và bảng
     sau khi đã bỏ danh sách chú thích trùng lặp. */
  .bcs-cham-mau { display:inline-block; width:9px; height:9px; border-radius:var(--r-sm);
    margin-right:7px; vertical-align:baseline; flex:none; }

  /* Ô chú thích nổi khi rê chuột vào chấm. Neo `fixed` + tự né mép màn hình. */
  .bcs-chuthich { position:fixed; z-index:2147483000; pointer-events:none;
    background:#20242B; color:#fff; border-radius:var(--r-md); padding:7px 11px;
    font-size:11.5px; line-height:1.45; white-space:nowrap;
    box-shadow:0 6px 20px rgba(0,0,0,.28);
    opacity:0; transform:translateY(4px); transition:opacity .13s, transform .13s; }
  .bcs-chuthich.hien { opacity:1; transform:translateY(0); }
  /* ⛔ 15px/800 LÀ CHO CON SỐ, ĐỪNG HẠ. Bốn chỗ trong Báo cáo số nhét một con
     số ngắn ("287 lớp") vào ô này, và cỡ to là để liếc một cái là thấy — cô Quỳnh
     chốt 07/08. Màn nào cần nhét cả một CÂU thì dùng biến thể `.chu` ngay dưới. */
  .bcs-chuthich b { display:block; font-size:15px; font-weight:700; }
  .bcs-chuthich span { display:block; opacity:.72; }
  /* 📝 BIẾN THỂ CHO CHÚ THÍCH LÀ CÂU — Boss 04/09/2026: *"sao tự nhiên cái chữ
     ở công cụ yêu cầu giáo viên khi di chuột vào ô hoàn thành tiếp nhận và hủy thì
     cái block chữ lại to đùng thế, bé lại đi, đâu phải app cho người già đâu."*
     Đo được: chú thích 15px/800 trong khi nhãn của chính cái nút ấy (`.yc-act`) chỉ
     11,5px — chú thích to hơn nút 1,3 lần, ở nét đậm nhất app. Cộng `nowrap` nên câu
     50 ký tự trải thành một dải đen dài ~450px không xuống dòng.
     ⛔ `max-width` phải đi CÙNG `white-space:normal` — bỏ nowrap mà không chặn bề
        ngang thì câu dài vẫn kéo một dòng dài y như cũ, chỉ khác là không gãy. */
  .bcs-chuthich.chu { white-space:normal; max-width:260px; }
  .bcs-chuthich.chu b { font-size:12px; font-weight:600; }
  .bcs-chuthich .bcs-ct-ngay { opacity:.55; font-size:10.5px; }

  /* ⭐ 11/08/2026 — DẢI "HỌC SINH ĐÃ NGHỈ". Đặt ngay dưới ba ô số to, trước bảng chi
     tiết: cô Quỳnh cần liếc là thấy, không phải mở bảng ra tìm. Nền xám nhạt để tách
     khỏi phần số "đang học" phía trên — hai thứ ngược nghĩa nhau, để lẫn là đọc nhầm. */
  .bcs-nghi { margin:10px 0 2px; padding:9px 11px; background:var(--nen2);
    border:1px solid var(--vien); border-radius:var(--r-md); }
  .bcs-nghi-dau { font-size:11.5px; font-weight:600; color:var(--mo);
    margin-bottom:6px; }
  .bcs-nghi-hang { display:flex; gap:20px; flex-wrap:wrap; }
  .bcs-nghi-o b { display:block; font-size:18px; font-weight:700; color:var(--chu);
    font-variant-numeric:tabular-nums; line-height:1.15; }
  .bcs-nghi-o span { display:block; font-size:12px; color:var(--chu); margin-top:1px; }
  .bcs-nghi-o i { display:block; font-style:normal; font-size:11px; color:var(--mo); margin-top:1px; }
  /* ⛔ Dòng lưu ý KHÔNG được làm mờ quá — nó nói ra chỗ số liệu còn thiếu, đọc sót
     là hiểu sai con số cộng dồn. Giữ màu chữ thường, chỉ nhỏ hơn một bậc. */
  .bcs-nghi-luuy { margin:7px 0 0; font-size:11.5px; line-height:1.45; color:var(--chu); }
  @media (max-width:560px) { .bcs-nghi-hang { gap:16px; } }

  /* ⭐ 11/08/2026 — Ô HAI DÒNG trong bảng "Chia theo khối lớp và loại lớp":
     số LỚP ở trên, số HỌC SINH ở dưới. Cô Quỳnh cần biết khối lớp 2 có mấy lớp VÀ
     mấy em, mà bảng cũ chỉ có số lớp. Để hai dòng thay vì thêm 17 cột nữa — bảng
     đã rộng phải kéo ngang rồi, gấp đôi số cột là không ai đọc nổi. */
  .tk-tl td.bcs-o2 { line-height:1.25; white-space:nowrap; }
  .tk-tl td.bcs-o2 b { display:block; font-weight:700; font-variant-numeric:tabular-nums; }
  .tk-tl td.bcs-o2 i { display:block; font-style:normal; font-size:11.5px; color:var(--mo);
    font-variant-numeric:tabular-nums; }

  /* Số nhỏ có màu nằm cạnh con số trong bảng (mức chênh so với mốc trước). */
  .tk-tl td.bcs-o-ch { white-space:nowrap; }
  .bcs-o-so { font-variant-numeric:tabular-nums; }
  /* ⛔ KHÔNG để `cursor:help` ở đây nữa. Cô Quỳnh 07/08: *"sao tôi di chuột vào lại
     có dấu ? mà không có thông tin"* — con trỏ dấu ? là lời hứa "có chú thích", mà
     `title` của trình duyệt thì chờ cả giây mới hiện, nhiều khi không hiện. Nay
     dùng ô chú thích tự vẽ (`data-ct-*`), hiện ngay, nên con trỏ để thường. */
  .bcs-ch-nho { display:inline-block; margin-left:6px; font-size:10.5px; font-weight:700;
    padding:1px 5px; border-radius:var(--r-sm); cursor:default; }
  .bcs-ch-nho.len  { color:var(--bcs-xanh); background:rgba(46,158,91,.12); }
  .bcs-ch-nho.giam { color:var(--bcs-do);   background:rgba(214,69,69,.12); }
  /* (Bảng "Diễn biến qua các mốc" đã bỏ ngày 07/08 — xem chú thích trong
     `veBaoCaoSoMuc`. Hai luật CSS riêng của nó cũng gỡ theo.) */
  /* Dòng TỔNG của báo cáo này phải NỔI HẲN: nó là con số cả trung tâm, người đọc
     tìm nó đầu tiên. Dày hơn dòng tổng thường một chút (viền trái đậm). */
  .tk-tl .bcs-tong td { background:var(--nen2); font-weight:700;
    border-bottom:2px solid var(--vien); }
  .tk-tl .bcs-tong td:first-child { box-shadow:inset 3px 0 0 var(--muc); }
  /* Ô không có nguồn dữ liệu — cố ý làm mờ để không ai đọc nhầm thành số 0. */
  .tk-tl .bcs-trong { color:var(--mo); opacity:.6; }
  /* Hàng tiêu đề TẦNG TRÊN ("Số lớp" / "Số học sinh") — gom nhóm cho tên cột
     bên dưới ngắn lại. Có kẻ dọc ngăn hai nhóm để mắt không lẫn sang nhóm kia. */
  .tk-tl .bcs-nhom th { text-align:center; background:var(--nen2); }
  .tk-tl .bcs-nhom th[colspan] { border-left:1px solid var(--vien); }
  .tk-tl .bcs-nhom th[rowspan] { text-align:left; vertical-align:bottom; }
  /* ⛔ BẢNG NÀY KHÔNG DÍNH TIÊU ĐỀ — đọc kỹ trước khi "sửa lại cho giống bảng kia".
     `.tk-tl th` mặc định `position:sticky; top:0`, hợp với bảng từng lớp (mấy chục
     dòng, cuộn dọc). Bảng báo cáo số chỉ có ĐÚNG 5 dòng, chẳng bao giờ cần cuộn —
     mà bật dính với tiêu đề HAI TẦNG thì cả hai tầng cùng dán vào `top:0`, tầng
     dưới ĐÈ THẲNG lên dòng TỔNG và nuốt mất toàn bộ con số của cả trung tâm
     (đã dính đúng lỗi đó một lần). Bỏ dính + bỏ trần chiều cao là hết. */
  .bcs-cuon { max-height:none; }
  .bcs-cuon .tk-tl th { position:static; }
  /* Câu mách cách tự kiểm số — một dải riêng ngay dưới tên bảng. `.tk-tunglop`
     không có padding nên dải này phải tự đặt lề, khớp với `.tk-tl-dau` ở trên. */
  .bcs-mach { margin:0; padding:9px 14px 10px; font-size:11.5px; font-weight:400;
    line-height:1.55; color:var(--mo); background:var(--nen2);
    border-bottom:1px solid var(--vien); }
  .bcs-mach b { color:var(--chu); font-weight:700; }
  /* Nút bật/tắt bảng chi tiết theo khối lớp. */
  .bcs-mo { display:inline-flex; align-items:center; gap:6px; margin-top:12px;
    border:1px solid var(--vien); background:var(--the); color:var(--mo);
    border-radius:var(--r-md); padding:6px 12px; font-size:12px; font-weight:600; cursor:pointer; }
  .bcs-mo:hover { color:var(--chu); border-color:var(--muc); }
  /* Câu nói rõ app CHƯA CÓ nguồn nào — ⛔ đừng bỏ đi cho gọn: bỏ là người đọc
     tưởng mấy dấu "—" kia là lỗi app, hoặc tệ hơn, tưởng bằng 0. */
  .bcs-thieu { margin:11px 0 0; padding:9px 12px; border-radius:var(--r-md);
    background:#FFF8E8; border:1px solid #EBD9A8; color:#7A5A00;
    font-size:11.5px; line-height:1.55; }
  body.toi .bcs-thieu { background:rgba(217,174,90,.10); border-color:rgba(217,174,90,.32); color:#E4C88A; }
  .bcs-thieu b { font-weight:700; }


  /* ===== ✅ Cột "Thực hiện?" của Dự giờ (05/08/2026) ===== */
  .dg-th { width:100%; min-width:56px; border:1px solid var(--vien); border-radius:var(--r-md);
    background:var(--nen-o); color:var(--mo); font-size:16px; font-weight:700;
    padding:5px 0; cursor:pointer; line-height:1.1; }
  .dg-th.co { background:#DFF3E7; border-color:#8FCFAC; color:#1E8E4E; }
  .dg-th.khong { background:#FBE7E7; border-color:#EBB4B4; color:#D64545; }
  /* Người ở CƠ SỞ KHÁC trong ô chọn người — vẫn hiện đủ, chỉ ghi chú nhẹ. */
  .ns-cs-khac { font-size:10.5px; color:var(--mo); font-style:normal; opacity:.75; }

  /* ===== 🔽 BỘ LỌC BÊN PHẢI Ô TÌM (cô Quỳnh 19/08/2026) =====
     Ô tìm THU NGẮN lại (không còn chiếm cả bề ngang), nút Bộ lọc nằm bên phải.
     Bảng lọc thả xuống ngay dưới nút, neo theo hàng. */
  .bl-timhang { display:flex; gap:8px; align-items:center; margin:0 0 8px; }
  /* ⛔ Vỏ NEO cho bảng lọc. Neo vào cả hàng (`.bl-timhang`) thì bảng dán ra mép phải
     màn hình, cách nút cả gang tay — cô Quỳnh báo 19/08/2026. Neo vào vỏ này thì
     bảng luôn rơi ĐÚNG NGAY DƯỚI nút. */
  .bl-locvo { position:relative; flex:none; }
  /* Ô tìm co lại nhưng vẫn là phần rộng nhất — “thu bé chiều dài lại CHÚT”,
     không phải bóp còn một mẩu. Trần 620px để trên màn rộng khỏi kéo dài lê thê. */
  .bl-tim-ngan { flex:1 1 auto; min-width:0; max-width:620px; }
  .bl-nutloc { flex:none; white-space:nowrap; }
  .bl-nutloc.dang-loc { border-color:#1565C0; color:#1565C0; background:#E3F2FD; }
  .bl-so { display:inline-block; min-width:17px; margin-left:6px; padding:0 4px;
    border-radius:var(--r-md); background:#1565C0; color:#fff; font-size:11px; font-weight:700;
    line-height:17px; text-align:center; }
  /* `left:0` = mép TRÁI của nút, tức bảng đổ xuống ngay dưới nút. */
  .bl-bang { position:absolute; top:calc(100% + 6px); left:0; z-index:60;
    width:min(340px, calc(100vw - 28px)); max-height:min(70vh, 520px); overflow:auto;
    background:var(--nen-o); border:1px solid var(--vien); border-radius:var(--r-lg);
    box-shadow:0 6px 22px rgba(0,0,0,.14); padding:0 10px 10px; }
  /* Hàng nút DÍNH TRÊN ĐẦU — khỏi phải kéo xuống đáy mới bấm được (cô Quỳnh 19/08). */
  .bl-dau { position:sticky; top:0; z-index:2; display:flex; gap:7px; align-items:center;
    margin:0 -10px 8px; padding:9px 10px; background:var(--nen-o);
    border-bottom:1px solid var(--vien); }
  .bl-dau-chu { flex:1; font-size:12px; font-weight:700; color:var(--mo); }
  .bl-dau button { flex:none; padding:3px 9px; font-size:12px; font-weight:700;
    border:1px solid var(--vien); border-radius:var(--r-md); background:var(--nen2);
    color:var(--chu); cursor:pointer; }
  .bl-dau button:hover { background:var(--nen-o); }
  .bl-dong { min-width:28px; }
  .bl-nhom + .bl-nhom { margin-top:10px; padding-top:10px; border-top:1px solid var(--vien); }
  .bl-nhom-ten { display:flex; align-items:center; gap:6px; font-size:12px; font-weight:700;
    color:var(--mo); margin:0 0 5px; }
  .bl-nhom-ten span { flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  /* Nút bỏ tick riêng từng cột — chỉ hiện khi cột đó đang có tick. */
  .bl-bocot { flex:none; padding:2px 7px; font-size:11px; font-weight:700; text-transform:none;
    letter-spacing:0; border:1px solid #90CAF9; border-radius:var(--r-sm);
    background:#E3F2FD; color:#1565C0; cursor:pointer; }
  .bl-bocot:hover { background:#BBDEFB; }
  .bl-timnhom { width:100%; margin:0 0 5px; padding:5px 8px; font-size:12.5px;
    border:1px solid var(--vien); border-radius:var(--r-md); background:var(--nen2); }
  .bl-muc { max-height:190px; overflow:auto; }
  .bl-mot { display:flex; align-items:center; gap:7px; padding:4px 6px; border-radius:var(--r-sm);
    font-size:13px; cursor:pointer; }
  .bl-mot:hover { background:var(--nen2); }
  .bl-mot input { margin:0; flex:none; }
  .bl-mot span { flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .bl-mot b { flex:none; font-size:11.5px; font-weight:700; color:var(--mo); }
  .bl-ngay { display:flex; gap:8px; flex-wrap:wrap; }
  .bl-ngay label { display:flex; align-items:center; gap:5px; font-size:12.5px; color:var(--mo); }
  .bl-ngay input { padding:4px 6px; font-size:12.5px; border:1px solid var(--vien);
    border-radius:var(--r-o, 8px); background:var(--nen2); }
  .bl-trong { font-size:12.5px; color:var(--mo); font-style:italic; padding:3px 6px; }
  /* Màn hẹp: nút nằm sát mép phải nên đổ bảng sang TRÁI, không thì tràn ra ngoài. */
  @media (max-width:640px) { .bl-tim-ngan { max-width:none; } .bl-bang { left:auto; right:0; } }

  /* ===== 🏫 Hộp tick chọn LỚP cho tháng lịch thi (05/08/2026) ===== */
  .lt-cl-thanh { display:flex; gap:6px; align-items:center; margin:0 0 8px; }
  .lt-cl-thanh .o-tim-dep { flex:1; }
  .lt-cl-ds { max-height:250px; overflow:auto; border:1px solid var(--vien);
    border-radius:var(--r-lg); padding:6px; display:grid; grid-template-columns:repeat(auto-fill,minmax(140px,1fr)); gap:2px; }
  .lt-cl-1 { display:flex; align-items:center; gap:7px; padding:5px 8px; border-radius:var(--r-md);
    font-size:13px; cursor:pointer; }
  .lt-cl-1:hover { background:var(--nen2); }
  .lt-cl-1 input { margin:0; }

  /* ===== 🔎 Ô chọn người CÓ TÌM KIẾM — dùng chung mọi công cụ (05/08/2026) ===== */
  .ont { position:relative; display:flex; align-items:stretch; }
  /* ⛔⛔ ⑤ 11/09/2026 — NUT ▾ DANG NAM DE LEN CHU. Hoi CSSOM (khong grep) thi ra
     thu pham: `.sheet-moi td input[type="text"]` dat `padding:0 2px` va no
     THANG `.ont .ont-in { padding-right:20px }` — cung hang 2 lop nhung ben kia
     co them mot bo chon thuoc tinh. Do that: nut ▾ de len 24px cuoi vung chu,
     6/6 o. ⇒ SIET LUAT CUA MINH LEN (`.sheet-moi td .ont > .ont-in` = 3 lop),
     ⛔ KHONG ha luat kia xuong `:where()` — luat ay dang giu ca bang cho gon.
     ⛔ KHONG `!important`. */
  /* ⛔⛔ TRONG O BANG THI XEP THANH HANG, DUNG DE NUT ▾ NOI DE LEN CHU.
     Hai cach "ne bang hinh hoc" da thu va da do:
       · chua `padding-right` 28px  -> con de len 4px (nut rong 24px + `right:2px`);
       · chua cho bang mot `::before` float 26px + ghim nut vao dong dau 24px
         -> dong MOT sach, nhung dong HAI van bi dam 13px, vi mot dong chu chi cao
            16px ma nut cao 24px nen no thong xuong dong duoi.
     ⇒ Nut thanh MOT COT rieng trong hang: khong con duong nao de dam nhau nua,
       va khong phai canh lai moi lan doi co chu.
     ⛔ Van giu `position:absolute` o moi noi khac — sau cho khac dung chung
        `oNguoiTim` khong co lop xem, doi kieu xep la doi ca sau cho ay. */
  /* ⛔⛔ GO TRAN CAO CHO CHINH `.ont`, khong thi lop xem thua ra ngoai o roi bi
     `td { overflow:hidden }` XEN. Do duoc: hang cao 51px, `.ont` chi 22px, lop
     xem cao 59px va trai tu y=836 den 895 trong khi o chi tu 840 den 891 — mat
     4px dau va 4px duoi, dung kieu "chu bi cat ngang than" da tra gia o cot Giao
     vien. Cung mot o benh, cung mot cach chua (xem khoi ⑨). */
  .sheet-moi tbody tr.sheet-hang td .ont { max-height: none; height: auto; }
  .sheet-moi td .ont { display: flex; align-items: flex-start; }
  .sheet-moi td .ont > .ont-in { flex: 1 1 auto; min-width: 0; padding-right: 4px; }
  .sheet-moi td .ont > .ont-mui { position: static; flex: 0 0 24px; width: 24px;
    height: 24px; align-self: flex-start; }
  /* ⑤b — TEN PHAI XUONG DONG DUOC. `<input>` khong bao gio xuong dong, nen trong
     o bang thi bay LOP XEM hai dong, bam mot cai la doi sang o nhap.
     ⛔ Lop xem CHI hien trong `.sheet-moi td`: sau cho khac dung chung
        `oNguoiTim` (Lo trinh, Cham soc, Lich GV…) van giu nguyen hinh cu. */
  .ont > .ont-xem { display: none; }
  .sheet-moi td .ont { display: block; }
  /* BA dong, khong phai hai: ten that dai toi 36 ky tu ma cot chi con 113px cho
     chu ⇒ hai dong con cut 2/6 o. ⛔ Dung noi cot: cot nay dang ghim, noi la an
     vao cho cua cot khac (luat "lam gon thi bop NGANG"). O ten ngan van cao 24px
     nhu cu — chi hang nao co ten dai moi cao them. */
  /* ⛔⛔ MIN-WIDTH, KHÔNG PHẢI MIN-HEIGHT — vá 12/09/2026, CA MẤT DỮ LIỆU.
     Xoá trắng ô Người dự giờ rồi thì ô xem co còn **12px** (đo được ở cả 1366 lẫn
     390) — đúng bằng 10px padding + 2px viền, tức RUỘT = 0. Ở khổ 390 thì
     `BUTTON.tts-muc` bên cạnh phủ lên: `elementFromPoint` giữa ô trả về nút ấy,
     **bấm lại không mở được ô sửa nữa** ⇒ Boss xoá nhầm một tên là mất luôn ô đó.
     Gốc: `.ont` trong ô sheet computed ra `inline-flex` (co vừa nội dung), nên
     `.ont-xem` là flex item — `min-width: 0` cho phép nó co về đúng 0.
     ⛔ `min-height: 24px` VÔ CAN, cao vẫn đúng 24px. Nới nó là vá nhầm chỗ, xanh giả.
     ⛔ ĐỪNG đặt sàn CỨNG (`min-width: 44px`): số 0 kia đang gánh chiều ngược — tên
        dài 36 ký tự không được phép đẩy cột GHIM nở ra (luật "làm gọn thì bóp
        NGANG"). Sàn 44px là đủ vùng chạm mà vẫn NHỎ HƠN `flex-basis: 78px` của
        `.ont`, nên ô CÓ CHỮ không bao giờ chạm sàn ⇒ cột ghim không bị nới ra.
     ⛔ ĐỪNG viết `min(100%, 44px)`: đã thử, đo ra **36px** chứ không phải 44px —
        `.ont` là inline-flex co theo chính con nó, nên `100%` của con lại phụ thuộc
        bề rộng con, giải ra vòng quanh. Phần trăm ở chỗ này là mốc nói dối.
     ⛔ Chỉ cột Người dự giờ. Cột Giáo viên (`.dg-ten-xem`) không dính, 28/28 sạch. */
  .sheet-moi td .ont > .ont-xem {
    flex: 1 1 auto; min-width: 44px;
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
    overflow: hidden; white-space: normal; overflow-wrap: anywhere;
    min-height: 24px; padding: 3px 5px; line-height: 1.35; font-size: 12.5px;
    cursor: text; border: 1px solid transparent; border-radius: var(--r-o, 8px);
  }
  .sheet-moi td .ont > .ont-xem:hover { border-color: var(--vien); }
  .sheet-moi td .ont > .ont-xem:focus { outline: 2px solid var(--xanh, #0B7A6E); outline-offset: -2px; }
  .sheet-moi td .ont:not(.dang-sua) > .ont-in { display: none; }
  .sheet-moi td .ont.dang-sua > .ont-xem { display: none; }
  .ont .ont-in { flex:1; min-width:0; padding-right:20px; }
  .ont-mui { position:absolute; right:2px; top:0; bottom:0; width:18px; border:none;
    background:transparent; color:var(--mo); cursor:pointer; font-size:11px; padding:0; }
  /* ⛔ position:FIXED — bảng chọn phải THOÁT khỏi khung cuộn ngang `.dg-cuon`
     (overflow:auto), không thì bị cắt mất một nửa. */
/* ⛔ VÁ 09/08/2026 — z-index PHẢI cao hơn nền hộp thoại (.modal-nen = 12000).
   Bảng tên này gắn thẳng vào body nên nó là ANH EM của nền hộp thoại, không phải
   con. Để 9999 thì trong hộp thoại Tạo lớp nó vẽ ra thật nhưng bị nền mờ phủ kín:
   cô Quỳnh bấm vào chỗ đáng lẽ là tên người thì trúng nền, đóng luôn cả hộp thoại.
   Bốn màn dùng trước đó (Lịch thi · Dự giờ · Chăm sóc · Follow up) đều là màn toàn
   trang không có hộp thoại nên 9999 vẫn chạy tốt — Tạo lớp là lần đầu nó nằm trong
   hộp thoại. */
  /* ⛔⛔ NEO_PHAI_ONT 11/09/2026 — HAI TANG: `.ont-than` cuon, `.ont-chan` dung yen.
     Truoc day ca hai nam chung mot vung cuon va chan thi `position:sticky`, nen
     chan VE DE LEN muc dang truot qua duoi no. Anh Boss 11/09: mot dong chu bi
     cat ngang than, dong dem nguoi phu len nua duoi. ⛔ Doi lai `overflow` cua
     `.ont-bang` thanh `hidden` la mot phan cua va: de `auto` thi ca hop cung
     cuon duoc va chan lai troi theo. */
  .ont-bang { position:fixed; z-index:12500; background:var(--the); border:1px solid var(--vien);
    border-radius:var(--r-lg); box-shadow:0 10px 28px rgba(0,0,0,.16); font-size:13px;
    display:flex; flex-direction:column; overflow:hidden; }
  /* ⛔ KHONG_LAN_CUON 11/09/2026 — Boss: *"mo o chon ten ra, keo chuot len ma
     khong giu hay an gi ca, man hinh cu di theo."* Toi CHUA dung lai duoc canh ay
     trong phong do (do that: trang khong nhuc nhich mot pixel o ca ban cu lan ban
     moi), nen day la CHOT PHONG chu khong phai ban va cho mot goc da tim ra.
     Ly do dat no: tu luot nay hop mo ra HET muc nen no thuong khong con phai tu
     cuon; luc ay banh xe lan tren hop se XUYEN xuong trang va keo ca trang di.
     `contain` chan dung cho ay. ⛔ `contain` chu khong `none`: `none` chan ca cu
     cuon TRONG hop, hop dai la ket. */
  .ont-than { flex:1 1 auto; min-height:0; overflow:auto; overscroll-behavior:contain; }
  .ont-muc { padding:7px 12px; cursor:pointer; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .ont-muc:hover { background:var(--nen2); }
  .ont-muc.chon { background:#E8F4F2; color:#0d6e5f; font-weight:700; }
  /* ⭐ 28/08/2026 — NGƯỜI TỪ GOOGLE FORM TÔ TÍM. Cô Quỳnh: *"đánh dấu màu tím ghi
     chú thích bên cạnh là nguông: google form(tháng ...)"*.
     ⛔ Tím là màu MƯỢN, chỉ sống trong bảng chọn nổi này — KHÔNG đụng bộ màu MyPAS
        của bảng và của app.
     ⛔ KHÔNG dùng `:has()` để bắt "mục nào có chú thích" — luật của file này cấm hẳn.
     ⚠️ SỬA 28/08 chiều: TRƯỚC ĐÂY chỉ hai class này mới có chú thích, nên hai dòng
        `white-space:normal` bên dưới là đủ. NAY KHÔNG CÒN ĐÚNG — người khai giờ bằng
        tay mà lệch buổi cũng có chú thích ("không trùng buổi này · Thứ 3 19:00-21:00")
        mà không mang class nào cả. Nên phải cho `.ont-muc` xuống dòng khi có `.ont-chu`
        — làm bằng cách đặt thẳng trên `.ont-chu` (nó đã `display:block`), chứ không
        đi bắt cha bằng `:has()`. */
  .ont-muc.ont-form, .ont-muc.ont-hop { white-space:normal; }
  .ont-muc.ont-form { color:#5E35B1; }
  .ont-muc.ont-hop  { color:#0d6e5f; }
  .ont-muc .ont-chu { display:block; font-size:11px; font-weight:400; color:var(--mo);
    margin-top:1px; white-space:normal; line-height:1.35; }
  /* ⭐ 28/08 chiều — DÒNG NGĂN NHÓM trong bảng chọn: "Rảnh đúng buổi này" ·
     "Không trùng buổi này — vẫn xếp được" · "Chưa điền giờ rảnh".
     78 cái tên trôi liền một mạch thì thứ tự có đúng đến mấy cũng không đọc ra.
     ⛔ KHÔNG phải `.ont-muc` — bấm vào nó không được chọn gì cả. Nên `cursor:default`
        và không có hiệu ứng hover, để không ai tưởng bấm được.
     ⛔ Chữ thường, không IN HOA, không `font-weight:700`, không giãn chữ — đây là
        dòng dẫn mắt. */
  .ont-nhom { padding:6px 12px 3px; font-size:10.5px; color:var(--mo);
    cursor:default; user-select:none; background:var(--nen2);
    border-top:1px solid var(--vien); }
  /* NEO_PHAI_ONT — ruot nay nam trong `.ont-than`, khong con la con truc tiep
     cua `.ont-bang`. Giu ca hai duong de ban cu (neu con) van chay. */
  .ont-bang > .ont-nhom:first-child,
  .ont-than > .ont-nhom:first-child { border-top:0; }
  .ont-muc.ont-form .ont-chu { color:#7E57C2; }
  body.toi .ont-muc.ont-form { color:#C7B6E8; }
  body.toi .ont-muc.ont-form .ont-chu { color:#A98FD8; }
  body.toi .ont-muc.ont-hop { color:#7FD6C4; }
  .ont-trong { padding:9px 12px; color:var(--mo); font-size:12px; white-space:normal; }
  /* NEO_PHAI_ONT — het `sticky`: chan nay nay dung NGOAI vung cuon (`.ont-than`)
     nen tu no da luon o day hop, va khong con de len chu nao nua. */
  .ont-chan { flex:0 0 auto; padding:5px 12px; background:var(--nen2);
    color:var(--mo); font-size:11px; border-top:1px solid var(--vien); }
  /* ⭐ 28/08/2026 (chiều) — nút bung nốt người không đăng ký buổi này.
     Cố ý để NHẠT, không phải nút chính: việc thường ngày là chọn người rảnh đúng
     buổi, còn đây là đường lui khi cần xếp gấp. */
  /* ⛔ Lớp riêng `.co-nut`, KHÔNG `:has(.ont-hien-het)` — luật kho này cấm `:has()`
     trong CSS mới của index.html. */
  .ont-chan.co-nut { padding:0; }
  .ont-hien-het { display:block; width:100%; box-sizing:border-box; text-align:left;
    font:inherit; font-size:11.5px; color:var(--muc); cursor:pointer;
    background:transparent; border:0; padding:7px 12px; }
  .ont-hien-het:hover { background:var(--nen-o); }
  /* 🤝 16/09/2026 — TRỢ GIẢNG CỦA CHÍNH LỚP NÀY đứng đầu danh sách chọn (Boss chốt
     bằng nút bấm: *"trợ giảng trước, người khác ở dưới"*). Thứ tự do mảng `ds`
     quyết định — `ontMo` chỉ lọc chứ không sắp lại — còn luật này chỉ làm cho mắt
     nhận ra ngay đâu là nhóm đầu.
     ⛔ Tô NHẸ thôi. Đây không phải mục "đang chọn" (`.ont-muc.chon` đã có nền xanh
        đậm hơn); tô mạnh ngang nhau là hai ý nghĩa khác nhau trông y hệt. */
  .ont-muc.ont-tg-lop { border-left:3px solid #159F8B; padding-left:9px; }

  /* ===== 📊 Thống kê hẹn phụ đạo (05/08/2026) ===== */
  .pd-lan { display:inline-block; margin-top:3px; padding:1px 7px; border-radius:999px;
    font-size:10.5px; font-weight:700; background:#E4EFFB; color:#2E7BD6; }
  .pd-lan.nhieu { background:#FDECDD; color:#C2410C; }
  .pd-tk-tom { display:flex; gap:10px; flex-wrap:wrap; margin:2px 0 12px; }
  .pd-tk-o { flex:1; min-width:150px; background:var(--the); border:1px solid var(--vien);
    border-radius:var(--r-xl); padding:12px 14px; text-align:center; }
  .pd-tk-o b { display:block; font-size:24px; font-weight:700; color:var(--muc); line-height:1.2; }
  .pd-tk-o span { font-size:12px; color:var(--mo); }
  .pd-tk-lop { background:var(--the); border:1px solid var(--vien); border-radius:var(--r-xl);
    margin:0 0 12px; overflow:hidden; }
  .pd-tk-dau { display:flex; align-items:center; gap:9px; padding:10px 14px;
    background:var(--nen2); font-size:14px; }
  .pd-tk-dem { margin-left:auto; font-size:12px; color:var(--mo); font-weight:700; }
  .pd-tk-loc { font-size:11px; font-weight:700; color:#C2410C; background:#FDECDD;
    border-radius:999px; padding:1px 9px; }
  .pd-tk-bang { width:100%; border-collapse:collapse; font-size:13px; }
  .pd-tk-bang th, .pd-tk-bang td { border-top:1px solid var(--vien); padding:7px 14px; text-align:left; }
  .pd-tk-bang th { font-size:11.5px; color:var(--mo); font-weight:700; }
  .pd-tk-bang td:first-child, .pd-tk-bang th:first-child { width:44px; color:var(--mo); }
  .pd-tk-lan { display:inline-block; padding:1px 9px; border-radius:999px; font-weight:700;
    font-size:12px; background:#E4EFFB; color:#2E7BD6; }
  .pd-tk-lan.nhieu { background:#FDECDD; color:#C2410C; }
  .pd-tk-cho { display:inline-block; padding:1px 9px; border-radius:999px; font-weight:700;
    font-size:12px; background:#FDF0DC; color:#D97706; }

  /* ===== Khung BẢNG NGANG dùng chung =====
     ⚠️ Tên lớp còn chữ "fss" là DẤU VẾT LỊCH SỬ: sinh ra cho công cụ "Follow sĩ
     số" (đã XOÁ HẲN 05/08/2026 theo yêu cầu của cô Quỳnh), nhưng **LỊCH THI ĐỊNH
     KỲ DÙNG CHUNG** mấy lớp này (`fss-cuon` · `fss-bang` · `fss-luu` — xem
     `ltVeMan`). ⛔ ĐỪNG XOÁ theo tên: xoá là bảng Lịch thi mất viền, mất cuộn
     ngang. Giữ nguyên tên để khỏi phải sửa code Lịch thi đang chạy tốt. */
  .fss-cuon { overflow-x:auto; border:1px solid var(--vien); border-radius:var(--r-sheet); background:var(--the); }
  /* ⛔ SEPARATE, đừng đổi về `collapse` — cùng lý do đã ghi ở `.dg-bang`: với `collapse`
     Chrome vẽ nền ô vào lớp nền của cả BẢNG nên hàng tiêu đề dính bị chữ dòng dưới đè
     xuyên qua lúc kéo xuống. Lịch thi dùng chung bộ này (`fss-bang lt-bang`). */
  .fss-bang { border-collapse:separate; border-spacing:0; font-size:12.5px; min-width:100%; }
  .fss-bang th, .fss-bang td { border-right:1px solid var(--vien); border-bottom:1px solid var(--vien);
    padding:4px 6px; text-align:center; white-space:nowrap; }
  .fss-bang thead th { background:var(--dau-bang-nen); color:var(--dau-bang-chu);
    font-weight:700; position:sticky; top:0; z-index:5;
    border-right-color:var(--dau-bang-vien); border-bottom-color:var(--dau-bang-vien); }
  .fss-o.fss-luu { outline:2px solid #2E7D32; }
  /* Nền ĐỤC — cùng lý do đã ghi ở `.dg-cuon`. Đừng bỏ. */
  .lt-cuon { overflow:auto; max-height:calc(100vh - 250px - var(--dnc-du, 0px)); touch-action:none; overscroll-behavior:contain;
    background:var(--the); }
  /* 🔍 06/08/2026 (cô Quỳnh): PHÓNG TO / THU NHỎ BẢNG bằng Ctrl + lăn chuột — thu nhỏ
     để nhìn thấy HẾT các cột cùng lúc. Nhãn nổi ở đáy màn cho biết đang bao nhiêu %,
     bấm vào là về 100%. Tự ẩn sau 2 giây. */
  /* ══════════════════════════════════════════════════════════════════════════════
     ⏳ THANH TIẾN TRÌNH — cô Quỳnh 24/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     Cô Quỳnh: *"nếu cái nào load lâu nên thiết kế cái thanh load như các app hay có
     khi load cái gì đó lâu giúp tôi với cái thanh đó sẽ nằm ngang load đầy thanh là
     load xong"*.

     App vốn CÓ báo đang tải, nhưng chỉ bằng CHỮ ("Đang tải danh sách lớp…") và chỉ ở
     những màn nào có người nhớ viết thêm dòng ấy. Chữ đứng im thì sau vài giây người
     dùng không phân biệt được "đang chạy" với "treo rồi" — nên mới có cảm giác đơ.
     Thanh chạy trả lời đúng câu hỏi đó mà không cần đọc.

     ⛔ Đặt ở ĐỈNH màn hình, cao 3px, KHÔNG che gì. Kiểu thanh của trình duyệt và
        GitHub — người ta đã quen mắt, không phải học.
     ⛔ KHÔNG dùng hộp thoại phủ kín màn hình: nó chặn thao tác, mà phần lớn lượt gọi
        xong trong vài trăm mili giây, chớp một cái hộp là khó chịu hơn cả chờ.
     ⛔ Màu lấy từ --xanh (màu chính của app), không đẻ màu mới.
     ⛔ Tôn trọng máy đã tắt hiệu ứng chuyển động (prefers-reduced-motion): không nhấp
        nháy, chỉ đứng yên một vạch mờ. */
  /* ══════════════════════════════════════════════════════════════════════════════
     ⏳ HỘP TẢI GIỮA MÀN HÌNH — cô Quỳnh 24/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     Cô Quỳnh: *"thanh load phải nằm ở giữa màn hình… phải load xong thì màn hình
     công cụ mới hiện ra chứ ko thì load 1 kiểu màn hình hiện 1 lúc khác trông rất
     ngớ ngẩn và thiếu đồng bộ và chuyên nghiệp"*, rồi ngay sau đó: *"bạn thiết kế
     cái thanh load đẹp vào, ý tôi chỉ đưa cho bạn hình mẫu thôi, giúp tôi thiết kế
     cái đặc trưng cho app tôi"*.

     ⛔ NÊN KHÔNG CHÉP ẢNH MẪU. Ảnh cô gửi là thanh pill viền xanh DƯƠNG của một app
        khác; xanh dương không có trong bộ màu MyPAS, bê nguyên vào là app mượn mặt
        người ta. Lấy BỐ CỤC của mẫu (chữ ở trên, thanh ở dưới, căn giữa), còn chất
        liệu thì lấy của app này:
          · logo thật — chữ "My" cam + "PAS" teal, dùng lại đúng class `.logo-mypas`
            nên chế độ tối và mọi lần đổi logo về sau tự theo, không phải sửa hai chỗ.
          · rãnh `--xanh-nhat`, vạch `--xanh` → `--xanh-sang`: ba sắc teal đã khai ở
            đầu file, không đẻ thêm màu mới.
          · dòng dưới nói rõ ĐANG MỞ CÔNG CỤ NÀO — app có hơn hai chục công cụ; chờ
            mà biết mình chờ cái gì thì thấy ngắn hơn hẳn chờ một cái thanh câm.

     ⛔ CẢ HỘP CHỈ DÙNG BIẾN, KHÔNG GÕ CỨNG MÀU. `body.toi` đã đổi sẵn `--nen` và
        `--xanh-nhat` nên nền tối tự đúng — khỏi đẻ luật `body.toi` thứ hai, cũng là
        khỏi lọt vào danh sách "mảng còn trắng xoá giữa nền tối" của phép soi 22/08.
     ⛔ VẠCH MẢNH 6px, KHÔNG VIỀN DÀY. Viền 2px như ảnh mẫu chọi với đường kẻ 1px
        `--vien` dùng khắp app, nhìn ra ngay là mảnh ghép từ chỗ khác.
     ⛔ CHE VÙNG NỘI DUNG THÔI, KHÔNG CHE CẢ TRANG, và `z-index` phải THẤP HƠN 50 —
        đúng bằng `.thanh-tren`. Lỡ tay mở nhầm công cụ nặng thì còn bấm sang chỗ
        khác được, không phải ngồi đợi hết. */
  /* ⛔⛔ z-index 49, KHÔNG PHẢI 45 — sửa 24/08/2026.
     Cô Quỳnh gửi ảnh bảng điểm danh THÒ RA giữa màn chờ: *"một cột hiện lòi ở đó
     xong load thì cứ load"*. Bảng điểm danh giữ cột trái bằng `position:sticky`,
     và mỗi ô dính như thế mang z-index riêng để đè lên phần cuộn qua dưới nó. Ô nào
     cao hơn 45 thì chui lên trên hộp che, thành một mảng bảng lòi ra.
     49 là mức cao nhất còn AN TOÀN: thanh trên của app ở 50, hộp vẫn phải nằm dưới
     nó (cô Quỳnh đã chốt là trong lúc chờ vẫn bấm được thanh trên).
     ⛔ ĐỪNG NÂNG LÊN 50 TRỞ LÊN. */
  #thanhTai {
    position:fixed; top:0; left:0; width:100%; height:100%; z-index:49;
    display:flex; align-items:center; justify-content:center;
    background:var(--nen);
    opacity:0; visibility:hidden; pointer-events:none;
    transition:opacity .18s ease-out, visibility 0s linear .18s;
  }
  /* ⛔ HIỆN TỨC THÌ (transition:none), CHỈ MỜ DẦN LÚC TẮT. Cô Quỳnh 24/08:
     *"tôi mở công cụ đó ra nó đã hiển thị thì mới thấy thanh load"*. Một phần là do
     hộp mờ DẦN vào trong .18s — mà công cụ chỉ mất chừng 10ms để vẽ xong, nên trong
     lúc hộp còn đang mờ tịt thì màn hình công cụ đã kịp lộ ra sau lưng nó.
     Tắt thì vẫn mờ dần: lúc ấy bảng đã dựng đủ ở phía sau, mờ dần ra nhìn êm hơn
     là biến mất đánh phựt. */
  #thanhTai.chay { opacity:1; visibility:visible; pointer-events:auto;
                   transition:none; }
  /* Nhích lên khỏi tâm hình học một chút: khối căn giữa TUYỆT ĐỐI luôn trông như
     bị tụt xuống dưới. Đây là nhích cho CÂN MẮT, không phải lệch. */
  #thanhTai .tt-giua { display:flex; flex-direction:column; align-items:center;
                       gap:18px; width:min(300px, 58%); margin-top:-5vh; }
  /* 🐸 NHÂN VẬT — cô Quỳnh chọn 24/08/2026, thay chỗ logo:
     *"bỏ chữ MyPAS trong thanh load mà thay vào bằng load animation character này"*.
     Dải `anh/nhan-vat-tai.png` gồm 13 khung ghép ngang, mỗi khung 110×114, chạy bằng
     cách dịch `background-position` — KHÔNG dùng 13 thẻ ảnh, cũng không dùng
     `@keyframes steps()`: đổi khung bằng JS thì lúc tải xong mới nhảy đúng vào
     đoạn kết được, còn keyframes cứ chạy vòng của nó bất kể việc đã xong hay chưa.
     ⛔ `image-rendering:pixelated` — nhân vật vẽ theo lối điểm ảnh, để trình duyệt
        làm mượt thì nét viền nhoè thành một đám mờ. */
  /* 🐸 NHÂN VẬT + LOGO ĐỨNG CẠNH NHAU — cô Quỳnh 24/08/2026:
     *"để cái logo MyPAS ở bên cạnh nhân vật animation loading đi. Cố căn cho mọi thứ
      thật cân đối với các thiết bị và kích cỡ thiết bị khác nhau, điện thoại máy tính"*.

     ⛔⛔ CHIA KHUNG BẰNG PHẦN TRĂM, TUYỆT ĐỐI KHÔNG BẰNG ĐIỂM ẢNH.
        Bản trước khai `background-size:2145px` rồi dịch từng khung `-165px`, và JS
        phải giữ đúng con số 165 cho khớp. Cách ấy trói chết một cỡ: muốn nhân vật
        nhỏ lại trên điện thoại là phải sửa CẢ CSS LẪN JS, lệch một điểm ảnh thì mỗi
        khung xê một tí, chạy vài vòng là nhân vật trôi khỏi khung.
        `background-size:1300%` nghĩa là "dải rộng gấp 13 lần ô", tức mỗi khung vừa
        đúng một ô — bất kể ô to bao nhiêu. Khung thứ i nằm ở `i/12 × 100%`. Nhờ vậy
        cỡ nhân vật muốn đổi thế nào cũng được, JS không phải biết một con số nào.
     ⛔ `aspect-ratio` giữ đúng tỉ lệ khung gốc 110×114 — đặt chiều cao bằng tay thì
        sai một hai điểm ảnh là ảnh bị kéo dẹt, nhìn ra ngay ở lối vẽ điểm ảnh.
     ⛔ `image-rendering:pixelated` — nhân vật vẽ theo lối điểm ảnh; để trình duyệt
        làm mượt thì phóng to lên nét viền nhoè thành một đám mờ. */
  #thanhTai .tt-dau { display:flex; align-items:center; justify-content:center;
                      gap:clamp(10px, 3vw, 20px); }
  /* 🔎 NÉT VÀ NHỎ — hai yêu cầu này KHÔNG chọi nhau, nếu làm đúng chỗ (24/08/2026).
     Cô Quỳnh: *"hình có bị mờ ko, có nhiễu ko, pixel có rõ ràng ko? phải thật rõ
     ràng nét. Và thu bé hình character lại nha tôi thấy nó to quá"*.

     "Thu bé" là việc của CSS lúc hiển thị, KHÔNG phải việc của file ảnh. Thu nhỏ
     ngay lúc xuất file là vứt bỏ điểm ảnh vĩnh viễn: màn hình nào cũng chỉ còn bấy
     nhiêu chi tiết, và trên màn độ nét cao (điện thoại đời mới, laptop retina — mỗi
     điểm ảnh CSS ăn 2–3 điểm ảnh thật) nó phải phóng ngược lên, thành ra mờ.
     Nên file giữ ở 168×178 mỗi khung, còn CSS thu xuống 84px: vừa đúng gấp đôi, nét
     tối đa trên màn retina mà vẫn nhỏ gọn như cô muốn.

     ⛔ BỎ `image-rendering:pixelated`. Nó chỉ hợp khi PHÓNG TO đúng bội số nguyên —
        giữ cạnh ô vuông sắc nét. Ở đây ta THU NHỎ, và pixelated lúc thu nhỏ là bảo
        trình duyệt bỏ bớt điểm ảnh chứ đừng trộn, cho ra viền răng cưa lởm chởm —
        đúng cái cô gọi là "nhiễu". Để `auto` thì trình duyệt lọc mượt, sắc hơn hẳn. */
  #thanhTai .tt-nv {
    /* 68–104px: nhỏ hơn hẳn bản cô chê "to quá" (96–150px) nhưng vẫn đủ để đọc chữ
       "Done" trên quyển vở ở khung cuối. Ảnh gốc 168px mỗi khung, tức vẫn hơn gấp
       rưỡi cỡ hiển thị — thừa điểm ảnh cho màn hình độ nét cao. */
    width:clamp(68px, 17vw, 104px); aspect-ratio:168 / 178; flex:none;
    overflow:hidden;       /* 🐸 22/09 — khung cắt: chỉ lộ đúng một khung của dải bên trong */
    transition:transform .16s cubic-bezier(.34,1.56,.64,1);
  }
  /* 🐸 22/09/2026 — DẢI 13 KHUNG LÀ THẺ CON, TRƯỢT BẰNG `transform`. Boss: *"linh vật bị
     khựng đơ 1 lúc vì đang load"*. Dịch `background-position` bằng JS thì máy bận vẽ là
     đứng hình; `transform` được trình duyệt chạy ở luồng vẽ riêng (xem `nvChay` trong
     js/tinh-nang.js). Hình, cỡ, nét y như cũ: dải rộng đúng 13 ô (1300%), ảnh trải kín dải —
     cùng tỉ lệ thu với `background-size:1300% 100%` của bản trước.
     ⛔ `will-change` cho dải lên lớp vẽ riêng từ đầu, khỏi chờ lúc hoạt ảnh bắt đầu. */
  #thanhTai .tt-nv-dai {
    width:1300%; height:100%;
    background:url("/anh/nhan-vat-tai.png") no-repeat 0 0;
    background-size:100% 100%;
    image-rendering:auto;
    will-change:transform;
  }
  /* 🎉 KHOẢNH KHẮC KHOE SÁCH — cô Quỳnh 24/08: *"đến lúc load xong phải show được
     sách Done trong ảnh tôi gửi"*. Nảy to lên một nhịp ngay lúc ấy: mắt bắt được
     ngay là việc đã xong, và chữ "Done" trên quyển vở cũng to lên theo nên đọc được.
     Đường cong có độ nảy nhẹ (cubic-bezier vọt quá 1 rồi lùi lại) — giống động tác
     giơ lên khoe thật, khác hẳn kiểu phóng to đều đều của máy. */
  #thanhTai.xong .tt-nv { transform:scale(1.16); }
  @media (prefers-reduced-motion: reduce) {
    #thanhTai .tt-nv { transition:none; }
    #thanhTai.xong .tt-nv { transform:none; }
  }
  #thanhTai .logo-mypas { align-items:flex-start; flex:none; }
  /* Nhân vật nhỏ lại thì logo phải nhỏ theo, không thì chữ lấn át hình. Hai cỡ này
     đo bằng chiều cao: chữ "MyPAS" cao xấp xỉ nửa nhân vật, như bản trước. */
  #thanhTai .logo-mypas .ten { font-size:clamp(16px, 4vw, 23px); }
  #thanhTai .logo-mypas .cham { font-size:clamp(6px, 1.4vw, 8px); margin-top:3px; }
  /* Màn hình hẹp: xếp logo lên trên nhân vật, không thì hai thứ chen nhau. */
  @media (max-width: 420px) {
    #thanhTai .tt-dau { flex-direction:column; gap:6px; }
    #thanhTai .logo-mypas { align-items:center; }
  }
  /* ⛔ NHÂN VẬT VÀ THANH CHỈ HIỆN KHI THẬT SỰ PHẢI CHỜ. Cô Quỳnh: *"nếu load nhanh
     thì skip luôn ko cần animation của con này"*. Nên lúc mới bấm, hộp chỉ che nền
     cho màn hình khỏi nhấp nháy; nhân vật và thanh đợi thêm một nhịp mới hiện ra.
     Việc xong trước nhịp ấy thì hộp tắt mà không ai kịp thấy gì. */
  /* ⛔⛔ LOGO PHẢI NẰM TRONG DANH SÁCH NÀY — sửa 24/08/2026.
     Cô Quỳnh: *"ấn công cụ nào thì cái chữ mypas và con nhân vật 2d cũng hiện lên
     trong khi app load siêu nhanh á, ko khớp tí nào"*.
     Bản trước ẩn nhân vật · thanh · dòng chữ cho tới khi vượt ngưỡng, nhưng QUÊN
     cái logo — nên nó hiện ngay từ nhịp bấm. Việc xong sau ba phần trăm giây thì
     người dùng vẫn kịp thấy chữ "MyPAS" loé lên rồi tắt: đúng cảnh cô kêu, và tệ
     hơn cả hiện đủ, vì nó lấp lửng.
     Nay cả bốn thứ cùng nằm sau `co-nv`. Trước ngưỡng thì hộp chỉ là một mảng nền
     TRỐNG cùng màu app — nó vẫn làm đúng việc che màn hình đang dựng dở (yêu cầu cô
     giao hôm trước: *"trước khi nhìn thấy màn hình chức năng thì phải có thanh
     load"*) mà không khoe gì cả. */
  #thanhTai.co-nv .tt-nv, #thanhTai.co-nv .tt-ranh,
  #thanhTai.co-nv .tt-viec, #thanhTai.co-nv .logo-mypas { opacity:1; }
  /* ⛔⛔ `.tt-nv` PHẢI CÓ MẶT TRONG DANH SÁCH NÀY. Thiếu nó là lỗi gốc của cả
     chuyện *"ấn spam công cụ nào thì nhân vật cũng hiện ra"* mà cô Quỳnh báo
     24/08: luật trên chỉ nói khi nào nhân vật ĐƯỢC HIỆN (`co-nv`), không hề nói
     khi nào nó phải ẩn — mà mặc định của `opacity` là 1, nên nó hiện suốt.
     Bốn thứ trong hộp phải cùng một luật: ẩn hết cho tới khi vượt ngưỡng. */
  #thanhTai .tt-nv, #thanhTai .tt-ranh, #thanhTai .tt-viec,
  #thanhTai .logo-mypas { opacity:0; transition:opacity .18s ease-out; }
  /* ⭐⭐ 21/09/2026 — HIỆN BẰNG HOẠT ẢNH CSS, KHÔNG ĐỢI HẸN GIỜ JS. Boss: mở công cụ
     load lâu thì *"cái thanh load và linh vật và logo trung tâm lại mất"* (màn trắng).
     Đo bằng Chrome thật: máy BẬN VẼ bảng lớn liền một mạch hơn 1 giây thì hẹn giờ JS
     `TT_HEN_NV` đứng im, lớp `co-nv` không bao giờ kịp gắn → chỉ còn nền trống.
     Hoạt ảnh `opacity` có hẹn trước chạy ở luồng vẽ riêng của trình duyệt, không cần
     JS rảnh — nên dù máy bận, tới mốc là bốn thứ này tự hiện.
     ⛔ Mốc hẹn lấy từ biến `--tt-cho-nv` do `ttHien` đặt = `TT_CHO_HIEN_NV`. ĐỪNG gõ
        cứng số ở đây: hai chỗ khai một con số là sớm muộn lệch nhau.
     ⛔ CHỈ khi hộp mang `tt-hien-sau` (JS ghi danh — trừ màn Điểm danh, Boss cấm đụng).
     ⛔ Việc xong TRƯỚC mốc thì `chay` bị gỡ trước khi hoạt ảnh kịp chạy → không hiện
        gì, giữ đúng ý *"load nhanh thì skip luôn"* (24/08). */
  @keyframes ttHienSau { from { opacity:0; } to { opacity:1; } }
  #thanhTai.chay.tt-hien-sau .tt-nv, #thanhTai.chay.tt-hien-sau .tt-ranh,
  #thanhTai.chay.tt-hien-sau .tt-viec, #thanhTai.chay.tt-hien-sau .logo-mypas {
    animation:ttHienSau .18s ease-out var(--tt-cho-nv, 440ms) both; }
  @media (prefers-reduced-motion: reduce) {
    #thanhTai.chay.tt-hien-sau .tt-nv, #thanhTai.chay.tt-hien-sau .tt-ranh,
    #thanhTai.chay.tt-hien-sau .tt-viec, #thanhTai.chay.tt-hien-sau .logo-mypas {
      animation-duration:.01s; }
  }
  /* ⛔ RÃNH LẤY MÀU `--vien`, ĐỪNG QUAY LẠI `--xanh-nhat`. Bản đầu dùng
     `--xanh-nhat` cho hợp tông teal — chụp ảnh ra thì rãnh #E8F5F5 nằm trên nền
     #F6F5F3 gần như TÀNG HÌNH, thành ra chỉ thấy một vạch teal lơ lửng giữa màn,
     không ra cái thanh. Nền tối cũng vậy: #1B2C2E trên #14171A chìm nốt.
     `--vien` là đường kẻ dùng khắp app, thấy rõ ở cả hai chế độ, và để vạch teal
     nổi hẳn lên thay vì hoà vào rãnh. */
  #thanhTai .tt-ranh { width:100%; height:8px; border-radius:999px;
                       background:var(--vien); overflow:hidden; }
  #thanhTai .tt-vach { height:100%; width:0; border-radius:999px; position:relative;
                       background:linear-gradient(90deg, var(--xanh), var(--xanh-sang));
                       transition:width .28s ease-out; }
  /* ⛔ ÁNH LƯỚT CÓ LÝ DO, ĐỪNG GỠ CHO "GỌN". Vạch cố ý dừng ở 90% rồi đứng yên cho
     tới lúc máy chủ trả lời — mà đứng yên thì trông y hệt treo, đúng cái bệnh thanh
     này sinh ra để chữa. Ánh lướt nói "vẫn đang chạy" mà không phải nói dối bằng
     cách kéo vạch đi tiếp. */
  #thanhTai .tt-vach::after {
    content:""; position:absolute; inset:0; border-radius:999px;
    background:linear-gradient(90deg, transparent, rgba(255,255,255,.26), transparent);
    animation:ttLuot 1.15s linear infinite;
  }
  @keyframes ttLuot { from { transform:translateX(-100%); } to { transform:translateX(100%); } }
  #thanhTai .tt-viec { font-size:12.5px; color:var(--mo); text-align:center; min-height:16px; }
  @media (prefers-reduced-motion: reduce) {
    #thanhTai, #thanhTai .tt-vach { transition:none; }
    #thanhTai .tt-vach::after { animation:none; }
  }

  #zoomBang { position:fixed; left:50%; transform:translateX(-50%); bottom:18px; z-index:99990;
    background:rgba(18,30,38,.93); color:#fff; border:none; border-radius:999px;
    padding:9px 17px; font-size:13px; font-weight:700; cursor:pointer; font-family:inherit;
    box-shadow:0 6px 22px rgba(0,0,0,.3); transition:opacity .2s; }
  #zoomBang:hover { background:rgba(18,30,38,1); }
  /* 🔍 Cụm nút phóng to / thu nhỏ bảng — cô Quỳnh 23/08/2026 (xem `gaZoomBang`).
     ⛔⛔ NẰM TRÊN BẢNG, KHÔNG NỔI ĐÈ LÊN BẢNG — cô Quỳnh sửa lại chiều 23/08/2026:
        *"cho cái zoom ra zoom vào này ở trên các cột tiêu đề được ko để dễ nhìn
        được nút hơn"*.
        Bản đầu neo góc DƯỚI–PHẢI và nổi đè lên bảng. Lý do khi ấy nghe hợp lý (góc
        trên có tiêu đề dính, góc trái có cột dính), nhưng thực tế dùng thì hỏng ở
        hai chỗ: nút chìm vào giữa đống số nên không ai thấy, và nó che mất đúng
        mấy dòng cuối đang cần đọc.
        Nay là MỘT HÀNG RIÊNG ngay phía trên khung bảng, canh phải. Không đè lên gì,
        mắt bắt được ngay vì nó nằm ở mép trên — chỗ người ta nhìn vào đầu tiên.
     ⛔ ĐỪNG trả về `position:absolute`. Muốn tiết kiệm chiều cao thì thu gọn nút,
        đừng đẩy nó xuống đè lên bảng lần nữa.
     📌 Chiều cao hàng này KHÔNG làm bảng tràn màn: `ddDoCaoBang` đo mép trên thật
        của khung rồi mới tính chiều cao còn lại, nên bảng tự co đúng bằng phần dôi. */
  /* ⟳ Nút tải lại lớp khi đã đứng cạnh cụm phóng to (Boss 10/09) — mặc cùng khuôn
     với nút phóng to để nhìn ra là một cụm, chứ không phải nút lạc.
     ⛔ 21/09/2026: KHÔNG còn `position:fixed` nữa. ⟳ được cắm VÀO TRONG cụm
        `.zoom-nut` rồi đứng lọt ra bên trái cụm 6px bằng `position:absolute` — đi
        liền với cụm, không ai phải đo toạ độ. Lối fixed cũ bị bỏ lại 70px mỗi khi
        thanh MyPAS trên cùng hiện ra (Boss báo "di chuyển ko đứng yên").
        Xem `ddTaiCanhZoom` trong js/tinh-nang.js.
     ⛔ Phải `!important` cả năm thuộc tính vị trí: luật
        `body.dang-trong-lop #ddTai{position:fixed;right:18px;bottom:…}` nặng hơn. */
  .zoom-nut:has(> #ddTai) { position: relative; }
  #ddTai.dd-tai-canh {
    position: absolute !important;
    right: calc(100% + 6px) !important; left: auto !important;
    top: 50% !important; bottom: auto !important;
    /* !important vì `.zoom-nut button:active{transform:translateY(1px)}` sẽ đè — ⟳
       nay là nút TRONG cụm, bấm xuống là nhảy lệch 13px. */
    transform: translateY(-50%) !important;
    width: 29px !important; height: 27px !important;
    min-width: 29px !important; min-height: 27px !important;
    border-radius: var(--r-md) !important;
    background: var(--nen2) !important; border: 1px solid var(--vien) !important;
    box-shadow: none !important;
    /* ⛔ 21/09: KHÔNG ép `display` ở đây. Hiện hay ẩn do luật điện thoại
       `body.dang-trong-lop #ddTai{display:flex!important}` quyết; máy tính thì
       `#ddFab,#ddTai{display:none!important}` giữ ẩn. Ép `inline-flex!important` ở
       đây (id+lớp, nặng hơn luật ẩn chỉ-id) là ⟳ mọc ra cả trên máy tính. */
    align-items: center; justify-content: center;
    z-index: 40;
  }
  #ddTai.dd-tai-canh > i { width: 15px !important; height: 15px !important; margin: 0 !important; }
  #ddTai.dd-tai-canh:hover { background: var(--nen-o) !important; }

  .zoom-nut { display:flex; align-items:center; gap:1px; padding:2px;
    width:fit-content; margin:0 0 6px auto;
    background:var(--the); border:1px solid var(--vien); border-radius:var(--r-md);
    box-shadow:var(--bong-2); user-select:none; }
  .zoom-nut button { min-width:29px; height:27px; padding:0 4px; border:0; border-radius:var(--r-md);
    background:transparent; color:var(--chu); font:600 15px/1 inherit; cursor:pointer; }
  .zoom-nut .zn-so { min-width:46px; font-size:12px; color:var(--mo); font-variant-numeric:tabular-nums; }
  .zoom-nut button:hover { background:var(--nen2); color:var(--chu); }
  .zoom-nut button:active { transform:translateY(1px); }

  /* ⛔ NÚT ĐÃ KỊCH TRẦN/ĐÁY thì xám đi và không nhận chuột. Trước đây bấm − ở mức
     50% chẳng có gì xảy ra và người dùng tưởng nút hỏng — mẫu 21st tắt hẳn nút,
     app mình theo. `pointer-events:none` để cả con trỏ cũng nói "bấm vô ích". */
  .zoom-nut button:disabled {
    opacity: .35;
    cursor: default;
    pointer-events: none;
  }
  /* Con số % nay là nút mở danh sách mức phóng — thêm mũi tên cho người ta biết
     là bấm được, không phải chữ trang trí. */
  .zoom-nut .zn-so::after {
    content: "▾";
    margin-left: 3px;
    font-size: 9px;
    opacity: .7;
  }
  .zoom-nut .zn-so[aria-expanded="true"] { background: var(--nen2); color: var(--chu); }

  /* Danh sách mức phóng. JS đặt vào `body` với `position:fixed` — xem lời dẫn
     trong `gaZoomBang`; để trong khung bảng là bị khung cuộn xén cụt. */
  .zn-ds {
    position: fixed;
    z-index: 9000;
    min-width: 84px;
    padding: 4px;
    border: 1px solid var(--vien);
    border-radius: var(--r-md, 4px);
    background: var(--the);
    box-shadow: 0 6px 20px rgba(0, 0, 0, .16);
    display: flex;
    flex-direction: column;
    gap: 1px;
  }
  .zn-ds > button {
    display: block;
    width: 100%;
    text-align: right;
    padding: 6px 10px;
    border: 0;
    border-radius: var(--r-sm, 4px);
    background: transparent;
    color: var(--chu);
    font-size: 13px;
    /* ⛔ 1.45 chứ không phải 1 — `line-height:1` cắt chân chữ tiếng Việt. */
    line-height: 1.45;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
  }
  .zn-ds > button:hover { background: var(--nen2); }
  .zn-ds > button.dang-chon { font-weight: 600; background: var(--nen2); }
  @media (max-width:820px) {
    /* Trên điện thoại nút phải to hơn để ngón tay bấm trúng — 27px là quá nhỏ.
       ⛔ ĐỪNG hạ xuống dưới 36px để tiết kiệm chiều cao. Đã thử 34px chiều 23/08
          và bài kiểm chặn đúng: 36px là mức chạm đã chốt, hàng này ăn thêm 42px
          chiều cao thì chấp nhận — bảng tự co theo, không tràn màn. */
    .zoom-nut { margin-bottom:5px; }
    .zoom-nut button { min-width:38px; height:36px; font-size:17px; }
    .zoom-nut .zn-so { min-width:52px; font-size:13px; }
  }
  #zoomBang.mo { opacity:0; pointer-events:none; }
  /* 🖱 KÉO CHUỘT ĐỂ CUỘN BẢNG — dùng chung cho MỌI bảng ngang (Lịch thi · Dự giờ ·
     Follow up · Chăm sóc · Phụ đạo), đi kèm `gaKeoBang`. ⛔ ĐỪNG XOÁ. */
  .keo-duoc { cursor:grab; }
  .keo-duoc.dang-keo { cursor:grabbing; user-select:none; }
  .keo-duoc.dang-keo * { user-select:none; }
  /* ⛔ 10/08/2026 — TRONG Ô NHẬP THÌ TRẢ CON TRỎ VỀ BÌNH THƯỜNG.
     `cursor:grab` phủ cả bảng nên rê vào giữa ô nhận xét vẫn thấy hình bàn tay,
     người dùng tưởng chỗ đó chỉ kéo được chứ không bôi chọn chữ được. Nay ô nào
     gõ chữ được thì hiện đúng con trỏ chữ. Đi kèm `laOSoanThao` bên JS. */
  .keo-duoc textarea, .keo-duoc select, .keo-duoc [contenteditable],
  .keo-duoc input:not([type=checkbox]):not([type=radio]):not([type=button]):not([type=submit]) { cursor:auto; }

  /* ===== 📅 Lịch thi định kỳ — bảng theo tháng ===== */
  .lt-thang-hang { display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin:6px 0 10px; }
  /* 🏛 06/08: bỏ "viên kẹo" bo tròn 20px + CAM chói. Góc vuông mềm + teal sâu của
     thương hiệu → giống thanh chọn kỳ của phần mềm quản trị hơn. */
  .lt-thang-tab { background:var(--the); border:1px solid var(--vien); border-radius:var(--r-md); padding:6px 15px;
    font-size:13.5px; font-weight:600; cursor:pointer; color:var(--chu); transition:border-color .12s, color .12s; }
  .lt-thang-tab:hover { border-color:var(--xanh); }
  .lt-thang-tab.chon { background:#0E545C; color:#fff; border-color:#0E545C; font-weight:700; }
  .lt-xoa-thang { margin-left:5px; opacity:.85; }
  .lt-them-thang { padding:7px 14px; font-size:13.5px; }
  .lt-bang th, .lt-bang td { vertical-align:top; }
  /* 03/08 (cô Quỳnh, SỬA LẠI): CẢ 2 hàng tiêu đề (hàng nhóm "Day *8/*9…" + hàng tên
     cột "Phụ trách/Bài thi số…") phải DÍNH LẠI khi kéo xuống để LUÔN nhìn thấy.
     Trước đó làm static (cuộn mất tiêu, cô không thấy tên cột). Cách đúng = xếp TẦNG:
     hàng nhóm dính top:0; hàng tên cột dính top = ĐÚNG chiều cao hàng nhóm (đo bằng JS
     → biến --lt-h1) nên KHÔNG chồng nhau. Cột "Lớp" (rowspan 2) vừa dính trái vừa dính
     trên = góc, z-index cao nhất. */
  .lt-bang thead th { white-space:normal; line-height:1.25; min-width:56px; position:sticky; z-index:5; }   /* tên cột ĐẦY ĐỦ, tự xuống dòng */
  .lt-bang thead tr:first-child th  { top:0; }                       /* hàng NHÓM (Day *8/*9…) */
  .lt-bang thead tr:nth-child(2) th { top:var(--lt-h1, 32px); }      /* hàng TÊN CỘT — nằm ngay dưới hàng nhóm */
  /* Cột "Lớp" DÍNH bên trái khi cuộn ngang — như Sheet, luôn thấy tên lớp, không khuất. */
  .lt-bang .lt-dinh { position:sticky; left:0; z-index:2; background:var(--the); min-width:80px;
    text-align:left; box-shadow:1px 0 0 var(--vien); font-weight:700; }
  .lt-bang thead .lt-dinh { z-index:6; background:var(--dau-bang-nen); white-space:nowrap; top:0; }   /* góc "Lớp": dính cả trên lẫn trái, nổi trên mọi ô */
  .lt-bang .lt-day { background:#EFF3F6 !important; color:#33424F; text-align:center; font-weight:700; white-space:nowrap; }
  .lt-o { box-sizing:border-box; font-family:inherit; }
  input.lt-o, textarea.lt-o, select.lt-o { border:1px solid var(--vien); border-radius:var(--r-o, 8px); padding:3px 5px; font-size:12px; background:var(--nen-o); }
  .lt-datetxt { width:66px; text-align:center; }
  .lt-txt { width:100%; min-width:48px; } .lt-nho { width:44px; text-align:center; }
  /* ⛔ VÁ 10/08/2026 — ĐÂY LÀ Ô TRONG ẢNH CÔ QUỲNH GỬI. Bản cũ:
       width:112px      → khoá cứng, kéo cột rộng ra ô vẫn bé nguyên
       max-height:76px  → viết quá là cuộn TRONG ô, đúng cái cô bảo "phải kéo xuống"
       overflow:auto    → thanh cuộn tí hon trong ô
     Nay bỏ cả ba, để `.o-bang` lo. */
  .lt-ta { min-width:94px; }
  select.lt-pt { min-width:106px; max-width:150px; }
  /* 🧱 Nút sửa cột trên đầu mỗi cột (cô Quỳnh 02/08). */
  .lt-bang th.lt-cot { padding:5px 5px; }
  .lt-cot-ten { font-weight:700; margin-bottom:4px; }
  .lt-cot-nut { display:flex; gap:2px; justify-content:center; }
  /* 🏛 06/08/2026 (cô Quỳnh: "một số công cụ trông rất trẻ con, không có sự business"):
     Cụm nút sửa cột (◀ ✏ ⏸ ▶) trước đây HIỆN THƯỜNG TRỰC dưới MỌI tên cột — nhìn vào
     bảng là thấy một rừng nút tí hon, rối và nghiệp dư. Nay chỉ hiện khi RÊ CHUỘT vào
     đúng cột đó. Vẫn chừa chỗ sẵn (visibility chứ không phải display) nên bảng không
     giật khi hiện ra.
     ⚠️ Chỉ áp cho máy CÓ chuột. Điện thoại không rê được, nên vẫn hiện thường trực —
     nếu không thì trên điện thoại sẽ mất hẳn đường sửa cột. */
  @media (hover:hover) and (pointer:fine) {
    .lt-cot-nut { visibility:hidden; opacity:0; transition:opacity .12s; }
    .lt-bang th.lt-cot:hover .lt-cot-nut,
    .lt-bang th.lt-cot:focus-within .lt-cot-nut { visibility:visible; opacity:1; }
  }
  .lt-cn { border:1px solid var(--vien); background:var(--nen-o); border-radius:var(--r-sm); cursor:pointer;
    font-size:11px; line-height:1; padding:2px 4px; color:var(--muc); }
  .lt-cn:hover:not(:disabled) { background:#E8F4F2; border-color:var(--xanh); }
  .lt-cn:disabled { opacity:.28; cursor:default; }
  .lt-bang .lt-cot-them { min-width:62px; background:var(--nen2); }
  /* ⛔ Ô "＋ Cột" NẰM TRONG hàng tiêu đề, nên phải mang màu tiêu đề.
     Lớp `.lt-cot-them` dùng chung cho cả `<th>` ở thead lẫn `<td>` ở tbody (xem chỗ
     dựng bảng), mà luật trên đặt nền xám cho cả hai. Độ nặng (0,2,0) của nó THẮNG
     `.fss-bang thead th` (0,1,2), nên suốt thời gian qua ô này là một mảng xám đứng
     chình ình ở cuối hàng tiêu đề xanh — nhìn ra ngay trong ảnh cô Quỳnh gửi 23/08.
     Đổi mỗi biến màu thôi thì KHÔNG chữa được chỗ này; phải có đúng luật dưới đây. */
  .lt-bang thead .lt-cot-them { background:var(--dau-bang-nen); }
  .lt-them-cot { white-space:nowrap; }
  /* Hàng NHÓM cột (Day *8/*9/*0/*1) như Sheet — nhãn nhóm SỬA ĐƯỢC (cô Quỳnh 02/08). */
  /* 🏛 06/08: đổi HỒNG PHẤN (#FCE4E1) sang XÁM XANH trung tính. Màu hồng làm bảng
     trông như sổ tay học trò; xám xanh mới ra dáng bảng quản trị. */
  /* Hàng NHÓM (Day *8, Day *9…) nằm TRÊN hàng tên cột, nên nó phải SẪM HƠN một
     bậc — tầng trên nhạt hơn tầng dưới là đọc ngược thứ bậc.
     ⛔ Dùng `--dau-bang-vien` (#176939) chứ không pha màu mới: nó vốn sinh ra làm
        "sẫm hơn nền tiêu đề một bậc", đúng việc cần ở đây. */
  .lt-bang thead .lt-nhom { background:var(--dau-bang-vien) !important; color:var(--dau-bang-chu);
    font-weight:700; white-space:nowrap; }
  .lt-nhom-sua { border:1px solid #C3CED8; background:#fff; border-radius:var(--r-sm); cursor:pointer;
    font-size:11px; padding:1px 5px; margin-left:5px; color:#4A5866; }
  .lt-nhom-sua:hover { background:#F2F6F8; border-color:var(--xanh); }
  .lt-bang thead .lt-nhom-trong { background:var(--dau-bang-vien) !important; border-bottom:none; }
  .lt-o.fss-luu { outline:2px solid #2E7D32; }
  /* Ô Done GỌN + HIGHLIGHT (cô Quỳnh 02/08): bấm để đổi Chưa → Đang làm (cam) → Xong (xanh). */
  button.lt-done { width:30px; height:26px; border:1px solid var(--vien); border-radius:var(--r-sm); cursor:pointer;
    font-size:14px; font-weight:700; line-height:1; background:var(--nen-o); color:var(--mo); padding:0; }
  button.lt-done.xong { background:#2E7D32; border-color:#2E7D32; color:#fff; }
  button.lt-done.cho { background:#F5A623; border-color:#F5A623; color:#fff; }
  button.lt-done:hover { filter:brightness(1.06); }
  /* ⭐ BOSS CHOT 13/09/2026 — O TICH PHAI NAM GIUA O CUA NO.
     Boss: *"lich thi dinh ky o tick lech khong o giua"*, thay o ca dien thoai
     lan may tinh.
     DO THAT (co so NT, thang 9/2026, 4 lop, 24 o tich):
       may tinh 1280 — nut 30px trong o rong 84 / 117 / 163 / 164 / 169 / 176px,
                       lech trai 23 · 39 · 62 · 63 · 65 · 69px. 24/24 o lech.
       dien thoai 390 — o hep deu 56px, lech trai 9px. 24/24 o lech.
     GOC: `.lt-bang td` khong dat `text-align`, nen thua ke `left` cua bang. Nut
     la phan tu inline-block nen no nam sat mep trai; cot cang rong thi lech cang
     nhieu — dung canh Boss nhin thay.
     ⛔ CANH GIUA BANG `margin: auto` TREN CHINH NUT, khong sua `text-align` cua td:
        o Note/Ngay/Nguoi trong cung bang la chu va o nhap, chung PHAI giu le trai.
        Doi `text-align` cua td la keo theo ca nhung o ay.
     ⛔ Phai co `display: block` thi `margin: auto` moi an — nut mac dinh la
        `inline-block`, ma `margin: auto` khong canh giua duoc phan tu inline.
     ⛔ Chi nham `td > button.lt-done` (con TRUC TIEP cua o). Nut `lt-done` con
        xuat hien o chu giai thich dau bang (`.lt-cg-o`) — cho ay phai nam theo
        dong chu, khong duoc keo ra giua. */
  .lt-bang td > button.lt-done { display:block; margin-left:auto; margin-right:auto; }
  /* Zebra + hover cho đỡ "toàn màu trắng rối mắt" (cô Quỳnh 02/08). */
  .lt-bang tbody tr:nth-child(even) td { background:#F6FAFB; }
  .lt-bang tbody tr:nth-child(even) .lt-dinh { background:#EAF3F4; }
  .lt-bang tbody tr:hover td { background:#FFF7E6; }
  .lt-bang tbody tr:hover .lt-dinh { background:#FBEACC; }
  /* 🌙 Dark: zebra/hover/dải nhóm đang dùng màu SÁNG cứng → đổi sang tông tối; dải nhóm
     salmon (Day *8…) GIỮ nền nhưng chữ đổi nâu đậm cho đọc rõ (chữ --chu sáng bị chìm). */
  body.toi .lt-bang tbody tr:nth-child(even) td { background:rgba(255,255,255,.03); }
  body.toi .lt-bang tbody tr:nth-child(even) .lt-dinh { background:#2B3137; }
  body.toi .lt-bang tbody tr:hover td { background:rgba(242,193,78,.09); }
  body.toi .lt-bang tbody tr:hover .lt-dinh { background:rgba(242,193,78,.16); }
  /* ⛔⛔ HAI HÀNG NÀY KHÔNG CÙNG MỘT NỀN — TÁCH RA, sửa 22/08/2026.
     Chúng từng dùng chung một luật với ghi chú "nền hai hàng này bị ép sáng bằng
     !important nên trong nền tối vẫn phải để chữ ĐẬM". Câu ấy ĐÃ SAI từ lúc hàng
     nhóm đổi nền: `.lt-nhom` nay lấy `var(--dau-bang-vien)`, mà biến đó ở nền tối
     là #0E3320 — xanh lá gần đen. Chữ #2B3742 trên nó chỉ hơn nhau 1,14 lần, tức
     là gần như vô hình. Cô Quỳnh 22/08:
        *"Nền đen ở công cụ lịch thi định kì của giáo vụ cái dòng Day bị tối quá
          màu đen che khuất mất ko nhìn thấy được."*

       · `.lt-nhom` (hàng "Day *8 · Day *9…") — nền THEO chế độ, tối thì tối theo.
         Chữ phải lấy `--dau-bang-chu` như chế độ sáng → 10,9 lần.
       · `.lt-day`  — nền vẫn ép sáng #EFF3F6 bằng !important thật, nên chữ ở đây
         VẪN phải đậm. Đừng gộp nó vào luật trên, gộp là chữ sáng trên nền sáng.

     ⛔ Bài `thu-nen-toi-luoi-va-vien.js` đo lại cả hai con số này mỗi lần chạy. */
  body.toi .lt-bang thead .lt-nhom { color:var(--dau-bang-chu); }
  body.toi .lt-bang .lt-day { color:#2B3742; }
  body.toi .lt-chugiai { background:var(--nen2); border-color:var(--vien); }
  /* 🖥️ 04/08 (cô Quỳnh: "các công cụ lỗi hiển thị ở độ phân giải khác nhau"): BỎ chiêu
     full-bleed `margin-left:calc(50%-48vw)` — nó tính theo VIEWPORT nhưng thẻ .noi-dung bị
     cap 1120px nên ở màn RỘNG bảng lòi lệch/che. Thay bằng: bảng FILL 100% khung + NỚI khung
     rộng ra khi có bảng (dưới, qua :has). An toàn ở mọi độ phân giải + mọi trạng thái thanh. */
  .lt-fullw { width:100%; max-width:100%; margin-left:0; }
  /* ⛔ 21/08/2026 — BỎ TRẦN 1680px. Luật này viết sau luật gốc nên nó THẮNG, và đó
     chính là chỗ để hở mảng trắng bên phải trên màn rộng. Xem khối giải thích dài ở
     luật `:has(.home-boc)` phía trên (khoảng dòng 660). Nay để `none` cho khớp luật
     gốc; dòng này giữ lại chỉ để nói rõ là ĐÃ CÂN NHẮC, đừng đặt trần lại.
     ⛔ Mấy màn này là màn CÓ BẢNG NHIỀU CỘT — chúng cần bề ngang NHẤT. Đặt trần ở đây
        là vừa hở mép phải vừa ép bảng phải cuộn ngang sớm hơn cần thiết. */
  body.man-cong-cu .noi-dung:has(.lt-fullw),
  body.man-cong-cu .noi-dung:has(.fss-cuon) { max-width:none; }
  .lt-datevn-o { display:flex; gap:3px; min-width:94px; }
  .lt-datevn-o .lt-datetxt { flex:1; }
  .lt-datevn-o .nv-lich { padding:0 5px; font-size:12px; }
  /* Chú giải ký hiệu — cô Quỳnh: "không có hướng dẫn, tích là gì ai hiểu được". */
  /* 🏛 06/08: dải chú giải trước đây nền BẠC HÀ + chữ teal đậm, hút mắt ngang với dữ
     liệu thật. Đây chỉ là ghi chú phụ nên cho lùi lại: nền xám nhạt, chữ mờ, cỡ nhỏ. */
  .lt-chugiai { display:flex; flex-wrap:wrap; gap:6px 18px; margin:2px 0 10px; padding:8px 13px;
    background:var(--nen2); border:1px solid var(--vien); border-radius:var(--r-md);
    font-size:12px; color:var(--mo); align-items:center; }
  .lt-cg-o { display:inline-flex; align-items:center; justify-content:center; width:24px; height:20px; border-radius:var(--r-sm);
    border:1px solid var(--vien); background:var(--nen-o); color:var(--mo); font-weight:700; vertical-align:middle; }
  .lt-cg-o.cho { background:#F5A623; border-color:#F5A623; color:#fff; }
  .lt-cg-o.xong { background:#2E7D32; border-color:#2E7D32; color:#fff; }
  /* Segmented "Chăm sóc": 2 mục Đang chăm sóc / Thêm HS mới (cô Quỳnh 02/08 — khỏi cuộn). */
  .cs-muc-bar { display:flex; gap:8px; margin:4px 0 10px; flex-wrap:wrap; }
  .cs-muc-b { background:var(--nen2); border:1px solid var(--vien); border-radius:var(--r-xl); padding:7px 16px;
    font-size:13.5px; font-weight:700; cursor:pointer; color:var(--muc); }
  .cs-muc-b.chon { background:#16A0A0; color:#fff; border-color:#16A0A0; }
  /* ⛔ 09/09/2026 — HỤT ĐÚNG 4px NÊN VỠ HÀNG. Trên màn 390px, hai chip đo được
     188px ("Đang chăm sóc ( 0 )") và 174px ("HS mới 1-2 buổi ( 0 )"): 188 + 8 + 174
     = 370px, mà chỗ trống chỉ có 366px. Thiếu 4px thôi mà chip thứ hai rơi xuống
     dòng riêng, ăn thêm 42px đầu màn.
     Đệm ngang 16 → 11px là mỗi chip hụt 10px, tổng còn 350px — vừa một hàng, và
     chữ vẫn nguyên vẹn (chỉ đệm đổi, không đụng cỡ chữ).
     ⛔ Đệm DỌC giữ nguyên 7px: đây là nút bấm bằng ngón tay. */
  @media (max-width:640px){
    .cs-muc-b { padding:7px 11px; }
    .cs-muc-bar { gap:6px; margin:4px 0 8px; }
  }
  .dg-lop-info { font-size:12.5px; color:var(--mo); background:#F1F8F6; border:1px solid #CDE8E2;
    border-radius:var(--r-md); padding:6px 10px; margin:4px 0; }
  .dg-the-nx { margin:3px 0; font-size:13px; }
  .dg-the-nx b { color:var(--muc); }
  .dg-tag { display:inline-block; background:#E8F4F2; border:1px solid #B2DFDB; border-radius:var(--r-xl);
    padding:1px 8px; font-size:11.5px; margin:2px 3px 0 0; }

  /* ===== Màn CHỌN HỌC SINH cần phụ đạo (sau caption) ===== */
  .pdc-ds { margin-top:8px; }
  .pdc-tim { width:100%; box-sizing:border-box; padding:8px 10px; border:1px solid var(--vien);
    border-radius:var(--r-md); font-size:14px; font-family:inherit; margin-bottom:8px; }
  .pdc-list { max-height:44vh; overflow-y:auto; border:1px solid var(--vien); border-radius:var(--r-md); }
  .pdc-item { display:flex; align-items:center; gap:9px; padding:8px 11px; font-size:14px;
    border-bottom:1px solid var(--vien); cursor:pointer; }
  .pdc-item:last-child { border-bottom:none; }
  .pdc-item:hover { background:#F1F8F6; }
  .pdc-item input { width:18px; height:18px; flex:none; }
  .pdc-dem { font-size:12.5px; color:var(--mo); margin-top:6px; }

  /* ===== 🔎 THANH TÌM GẮN THÊM CHO Ô CHỌN LỚP / HỌC SINH — 20/08/2026 =====
     Cô Quỳnh: *"các nút chọn lớp và chọn học sinh, chọn người phụ trách phải luôn có
     thanh tìm kiếm chứ sao kéo xuống hết được"*. Ô chọn NGƯỜI đã có sẵn (`.ns-tim`);
     thiếu là ô chọn LỚP và HỌC SINH — chúng là ô xổ gốc của trình duyệt, không nhét
     ô tìm vào trong được. Nên gắn một ô tìm NGAY TRÊN nó, gõ tới đâu lọc tới đó.
     ⛔ Nét mảnh, không nền màu: đây là ô phụ, đừng tranh chỗ với ô chọn chính. */
  .oc-tim { position:relative; }
  .oc-tim > input.oc-o { width:100%; box-sizing:border-box; margin-bottom:4px;
    padding:5px 26px 5px 9px; border:1px solid var(--vien); border-radius:var(--r-o, 8px);
    font:inherit; font-size:12.5px; background:var(--the); color:var(--chu); }
  /* ⛔ VÁ 20/08/2026 — ba dòng dưới trước ghi `var(--mo2)`, mà app KHÔNG có biến
     `--mo2` nào cả (chỉ có `--mo`). Biến không tồn tại thì cả câu color hỏng, chữ
     rơi về màu thừa kế — chữ mời và ô đếm đậm ngang chữ chính, đúng cái "trông khó
     dùng" cô Quỳnh chê. Không báo lỗi ở đâu hết, nên phải nhớ: gõ tên biến màu thì
     soi lại xem nó có thật không. */
  .oc-tim > input.oc-o::placeholder { color:var(--mo); }
  .oc-tim > input.oc-o:focus { outline:2px solid var(--xanh); outline-offset:-2px; }
  .oc-tim > .oc-xoa { position:absolute; top:3px; right:4px; width:20px; height:20px;
    border:none; background:none; color:var(--mo); cursor:pointer; font-size:15px;
    line-height:1; padding:0; display:none; }
  .oc-tim.co-chu > .oc-xoa { display:block; }
  .oc-tim > .oc-dem { font-size:11px; color:var(--mo); margin:2px 0 0 2px; display:none; }
  .oc-tim.co-chu > .oc-dem { display:block; }
  .oc-tim.khong-ai > input.oc-o { border-color:var(--do); }
  /* 🗺 Dòng mách "lớp ấy nằm ở cơ sở kia" — cô Quỳnh 20/08/2026, xem `ocGoiYCoSo`.
     Chỉ hiện khi ô tìm KHÔNG ra gì, nên không bao giờ chen vào lúc đang dùng bình
     thường. Nét mảnh, không nền màu — đây là câu mách, không phải cảnh báo lỗi. */
  .oc-tim > .oc-goiy { margin:4px 0 0; font-size:11.5px; color:var(--mo); }
  .oc-tim > .oc-goiy > .oc-goiy-d { display:flex; flex-wrap:wrap; align-items:center;
    gap:6px; padding:5px 8px; margin-top:3px;
    border:1px solid var(--vien); border-radius:var(--r-md); background:var(--nen2); }
  .oc-tim > .oc-goiy b { color:var(--chu); font-weight:600; }
  .oc-tim > .oc-goiy .oc-sang { flex:none; padding:3px 9px; font:inherit; font-size:11.5px;
    border:1px solid var(--xanh); border-radius:var(--r-sm); background:none;
    color:var(--xanh); cursor:pointer; }
  .oc-tim > .oc-goiy .oc-sang:hover { background:var(--xanh); color:#fff; }

  /* Hàng dự giờ vừa được thêm — nháy nhẹ để mắt bắt được ngay trong bảng 184 dòng. */
  @keyframes dgNhay { from { background:var(--xanh-nhat); } to { background:transparent; } }
  .dg-vua-them > td { animation:dgNhay 2s ease-out; }
  @media (prefers-reduced-motion:reduce) { .dg-vua-them > td { animation:none; } }

  /* ===== 👥 BỘ CHỌN NGƯỜI theo cơ sở (tìm kiếm + thêm nhân viên) — 02/08/2026 ===== */
  .ns-boc { border:1px solid var(--vien); border-radius:var(--r-lg); background:var(--the); padding:8px; }
  .ns-tim { margin-bottom:6px; }
  .ns-list { max-height:190px; overflow-y:auto; display:flex; flex-direction:column; gap:2px; }
  .ns-item { display:flex; align-items:center; gap:8px; padding:6px 8px; border-radius:var(--r-md); cursor:pointer; font-size:13.5px; }
  .ns-item:hover { background:var(--xanh-nhat); }
  .ns-item input { width:16px; height:16px; flex:none; }
  .ns-item .ns-vai { margin-left:auto; font-size:11.5px; color:var(--mo); }
  .ns-trong { color:var(--mo); font-size:12.5px; padding:6px 4px; }
  .ns-them { margin-top:7px; }
  .ns-dau { display:flex; align-items:center; justify-content:space-between; gap:8px; margin-bottom:4px; }
  .ns-dem { font-size:12px; color:var(--mo); }
  .cc-badge { display:inline-block; min-width:18px; padding:0 5px; border-radius:var(--r-md); background:var(--mo);
    color:#fff; font-size:11px; font-weight:700; text-align:center; }
  .cc-badge.do { background:#C62828; }
  /* ⛔ Trong thanh, `--mo` nay là xanh xám NHẠT — chữ trắng đặt lên là mất hút.
     Số nhắc việc phải đọc được, nó chính là thứ người ta liếc vào đầu tiên. */
  #thanhCC .cc-badge { background:rgba(255,255,255,.26); color:#fff; }

  /* ===== 📋 NHẮC VIỆC (01/08/2026) ===== */
  .nv-tabs { display:flex; gap:6px; flex-wrap:wrap; margin:10px 0; }
  .nv-tab { background:var(--nen2); border:1px solid var(--vien); border-radius:var(--r-xl); padding:6px 15px;
    font-size:13px; cursor:pointer; }
  .nv-tab.chon { background:var(--chinh,#159F8B); color:#fff; border-color:var(--chinh,#159F8B); font-weight:700; }
  /* tab LỌC: Tất cả · Việc của tôi · Việc tôi giao */
  .nv-loctabs { display:flex; gap:6px; flex-wrap:wrap; margin:0 0 10px; }
  .nv-loc { background:#fff; border:1px solid var(--vien); border-radius:var(--r-md); padding:5px 12px; font-size:12.5px; cursor:pointer; }
  .nv-loc.chon { background:#E8F4F2; border-color:var(--chinh,#159F8B); color:#0d6e5f; font-weight:700; }
  /* ⛔ 21/08/2026 — dải nhắc này trước đây nền vàng viền vàng, chiếm nguyên bề ngang
     ngay đầu màn. Cô Quỳnh: giao diện phải trắng đen kiểu doanh nghiệp. Nay là một
     dòng chữ nhạt có nét gạch trái, đọc được mà không cướp mắt. */
  .nv-bangchung { background:none; border:0; border-left:2px solid var(--vien);
    border-radius:0; padding:2px 0 2px 11px; font-size:12.5px; color:var(--mo); margin:0 0 12px; }
  .nv-bangchung b { color:var(--chu); font-weight:600; }
  .nv-giaoluc { color:var(--mo); font-weight:400; font-size:11px; }
  /* Ô ghi chú của một việc — nền chìm trung tính, không phải giấy nhớ vàng. */
  .nv-note { display:block; font-size:12.5px; color:var(--mo); background:var(--nen2);
    border-left:2px solid var(--vien); padding:5px 9px; border-radius:0 var(--r-md) var(--r-md) 0;
    margin-top:5px; white-space:pre-line; line-height:1.5; }
  .nv-thanh { display:flex; gap:8px; align-items:center; margin-bottom:8px; flex-wrap:wrap; }

  /* ═══ BLOCK THU GỌN NÚT PHỤ (Boss giao 10/09/2026) ═══════════════════════════
     Mẫu: `expandable-action-bar` của 21st.dev. Bản gốc là React + framer-motion;
     đây là bản dịch sang CSS thuần — phần mở/đóng ở `gonNutPhu` trong js/tinh-nang.js.

     Ý: mấy nút phụ (Làm mới, Tải về Excel, Sửa công cụ…) co lại thành dấu hiệu
     trong một viên thuốc; rê chuột vào thì chữ nở ra. Nút CHÍNH đứng ngoài, giữ
     nguyên chữ — Boss chốt.

     ⛔ NỞ BẰNG `max-width`, ĐỪNG NỞ BẰNG `width:auto`. Trình duyệt không chuyển
        tiếp được từ `0` sang `auto`, nên chữ sẽ nảy đánh bụp một cái thay vì trượt
        ra. `max-width` có số hai đầu nên chạy mượt; để dư (200px) cho nhãn dài
        nhất, phần thừa không chiếm chỗ vì `width` vẫn tự co theo chữ. */
  /* ⛔⛔ MỌI NÚT TRONG BLOCK PHẢI CÙNG MỘT KHUÔN. Boss chê bản đầu 10/09:
     *"thiết kế sao cho gom vào 1 ô mà nó hợp chứ ko xấu như này phải giống nhau"*.
     Lý do bản đầu chắp vá: ba nút vào chung một viên mà mỗi nút mang khuôn riêng —
     Làm mới bị luật icon-only 08/09 ép 36×36 không viền không nền · Bộ lọc giữ
     khuôn `.nut-nho` (có viền, có nền, bo góc vuông hơn) · nút chính tô đặc màu
     thương hiệu. Cạnh nhau thành ba cỡ, ba màu, hai kiểu bo góc.

     ⛔ `!important` ở đây là bắt buộc: khối icon-only phía dưới đặt
        `width/height/padding/font-size` đều `!important` để phủ cả app. Muốn ba
        nút bằng nhau thì chỉ có cách đè lại. Hai khối chia nhau theo NGỮ CẢNH:
        ngoài block thì khối kia thắng, trong block thì khối này. */
  .nv-gon { display:inline-flex; align-items:center; gap:2px; flex:none;
    padding:3px; border-radius:999px;
    background:var(--nen2); border:1px solid var(--vien);
    /* ⛔⛔ KÉO NGANG ĐƯỢC KHI QUÁ DÀI — Boss chê 10/09, kèm ảnh màn Quản lý lớp:
       *"tôi di chuột vào thanh mở ra nó bị lỗi nặng"*. Đo thật: màn ấy có 11 nút,
       rê vào là viên nở ra 1.408px trên màn 1.280px — hai nút cuối bị cắt cụt,
       không tài nào bấm được. Ở 390px thì 9/11 nút nằm ngoài màn.
       Boss chốt: *"phải có chức năng kéo sang 2 bên"*.
       ⛔ `overscroll-behavior-x: contain` để lúc kéo hết viên thì KHÔNG kéo tiếp
          cả trang — thiếu nó là điện thoại vuốt một cái trôi luôn màn hình.
       ⛔ Và `overflow-y` PHẢI là `visible`... nhưng CSS không cho: một trục cuộn
          thì trục kia tự thành `auto`. Đó là lý do có khối JS `gonBangLocNoi`
          trong js/tinh-nang.js — nó bê bảng lọc ra ngoài viên. Đừng gỡ khối ấy. */
    max-width: 100%;
    overflow-x: auto; overflow-y: hidden;
    overscroll-behavior-x: contain;
    scrollbar-width: none; -webkit-overflow-scrolling: touch; }
  .nv-gon::-webkit-scrollbar { height: 0; width: 0; }
  /* Vệt mờ hai mép để người dùng biết còn nút bên ngoài — không có dấu hiệu này
     thì viên trông như đã hết, chẳng ai nghĩ tới chuyện kéo.
     ⛔⛔ VỆT PHẢI BÁM THEO CHỖ ĐANG CUỘN — vá 12/09/2026.
     Bản cũ chỉ hỏi "có tràn không" rồi mờ LUÔN CẢ HAI MÉP, bất kể đang ở đâu.
     Hai cái sai cụ thể:
       · đứng ở đầu dải mà mép trái vẫn mờ ⇒ báo có nội dung bên trái, trong khi
         không có gì cả — dấu hiệu nói dối;
       · cuộn tới cuối rồi mà mép phải vẫn mờ ⇒ tưởng còn nữa, vỡt mãi không ra.
     Nay JS (`gonSoatTran`) bật riêng từng bên theo `scrollLeft`, và nghe cả `scroll`.
     ⛔ Mép phải mờ 22px chứ không 14px: để LỘ HẲN MỘT MẢNH nút kế tiếp chứ không cắt
        đúng mép — cắt đúng mép thì nhìn như dải đã hết. */
  .nv-gon.co-tim, .nv-gon { -webkit-mask-image: none; }
  .nv-gon.nvg-con-trai.nvg-con-phai {
    -webkit-mask-image: linear-gradient(to right, transparent 0, #000 14px,
                        #000 calc(100% - 22px), transparent 100%);
            mask-image: linear-gradient(to right, transparent 0, #000 14px,
                        #000 calc(100% - 22px), transparent 100%); }
  .nv-gon.nvg-con-phai:not(.nvg-con-trai) {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 22px), transparent 100%);
            mask-image: linear-gradient(to right, #000 calc(100% - 22px), transparent 100%); }
  .nv-gon.nvg-con-trai:not(.nvg-con-phai) {
    -webkit-mask-image: linear-gradient(to right, transparent 0, #000 14px);
            mask-image: linear-gradient(to right, transparent 0, #000 14px); }
  /* ⛔⛔ ĐANG MỞ HỘP THẢ THÌ PHẢI TẮT MẶT NẠ — vá 12/09/2026, LỖI HỒI QUY của `2aad561`.
     `mask-image` LẬP MỘT TẦNG XẾP CHỒNG MỚI trên viên, nên hộp thả `<details>` bung ra
     bị NHỐT trong tầng ấy và nội dung trang vẽ đè lên. Phần tử còn nguyên trong DOM,
     `display:flex` · `visibility:visible` · `pointer-events:auto`, nằm trong màn
     (x=141–375, y=199–231) — mà `elementsFromPoint` tại đúng tâm nó trả về
     `DIV.noi-dung.nd-co-cuon` nằm TRÊN, còn chính nó không có mặt trong chồng vẽ.
     Bấm thật ở khổ 390: 9/9 mục ăn trước vá → 5/9 sau vá. Bốn mục chết đều nằm TRONG
     hộp thả: Mỗi tháng một lần · Mỗi tuần một lần · Tự mở khi cần · Cập nhật quyền
     vào lớp — trong đó "Gửi Form · Mỗi tháng một lần" đúng là mục Boss chỉ đích danh.
     Nhân quả đã chứng minh: cùng một mục, bấm hai lượt, chỉ khác `mask-image` —
     4/4 cặp đảo chiều.
     ⛔ ĐỪNG BỎ VỆT MỜ để chữa: đo được 19–23/255, trên ngưỡng mắt thấy rõ (~8/255) và
        mạnh hơn nhiễu nền hơn 700 lần. Chỉ tắt ĐÚNG LÚC có hộp đang mở — lúc ấy người
        ta đang chọn trong menu, không cần ai nhắc "còn nút bên phải".
     ⛔ CÙNG HỌ VỚI BẪY `backdrop-filter` đã có trong sổ: một thuộc tính TRANG TRÍ lặng
        lẽ đổi mốc neo / tầng vẽ của con. Thêm bất cứ thứ gì trong họ ấy (`mask-*` ·
        `filter` · `backdrop-filter` · `opacity` < 1 · `transform` · `will-change`) lên
        một hộp CÓ CON BUNG RA thì phải ĐO LẠI CHỒNG VẼ bằng `elementsFromPoint`,
        đừng chỉ nhìn ảnh — ảnh không nói cho biết ai nằm trên ai.
     ⛔ ĐO LẠI THÌ PHẢI DỰNG ĐÚNG CẢNH, không thì thước xanh oan. Lượt đo đầu của tôi
        xanh 8/8 ngay trên chính bản hỏng, vì hai chỗ sai: ① `scrollIntoView` để
        `inline:"center"` — nó tự cuộn mục vào GIỮA khung, mà mặt nạ chỉ cắn ở HAI MÉP,
        tức thước tự tay chữa lỗi giúp app; ② mở hộp bằng `d.open = true` trong lúc
        `<summary>` còn ngoài màn (x=447 > 390) — hộp thả khi ấy thò khỏi hộp cuộn của
        dải nên bị CẮT, và bị cắt Y HỆT NHAU ở cả hai mốc nên che mất câu hỏi thật.
        Cảnh đúng: cuộn dải hết sang phải → BẤM THẬT vào `<summary>` → hỏi chồng vẽ.
        Số đo cảnh ấy: `dfeac73` 4/4 bấm được · `2aad561` 0/4 · bản vá này 4/4, và
        5 khổ (390 · 1001 · 1280 · 1366 · 2320) 20/20. Ca thử phá — ép mặt nạ bật lại
        ngay cả khi hộp đang mở — ĐỎ lại đúng 4/4. Vệt mờ không suy suyển: lệch pixel
        thật 25,53 mép phải lúc đầu dải · 32,22 mép trái lúc cuối dải. */
  .nv-gon:has(details[open]), .nv-gon:focus-within {
    -webkit-mask-image: none !important;
            mask-image: none !important; }

  /* Một khuôn duy nhất cho MỌI nút bên trong — kể cả nút nằm lồng trong vỏ
     `.bl-locvo` (nút Bộ lọc). Cỡ 32px: vừa gọn, vừa còn đủ để ngón tay bấm
     trúng khi block mở sẵn ở màn hẹp. */
  .nv-gon button {
    display:inline-flex !important; align-items:center; justify-content:center;
    width:auto !important; min-width:32px !important; max-width:none !important;
    height:32px !important; min-height:32px !important;
    /* ⛔⛔ CHỪA SẴN CHỖ — Boss chốt 12/09/2026, thay hẳn lối "nở ra khi rê chuột".
       LÝ DO: cụm nở 377,4 → 487px trong ~400ms kể từ lúc con trỏ tới, nên nút người
       ta định bấm chạy khỏi ngón tay: đo ở Giờ trợ giảng, điểm (403,177) đang là
       "Việc khác" thì 300ms sau đã là "Gửi Form"; lề trái "Việc khác" 355,2 → 454,8.
       Boss BIẾT VÀ CHẤP NHẬN cái giá: cụm nay luôn rộng bằng lúc mở.
       ⇒ Mọi số đo HÌNH HỌC ở đây phải TRÙNG với luật mở bên dưới; thứ duy nhất
         được đổi khi rê chuột là ĐỘ MỜ của chữ.
       ⛔ Đổi `padding` hay `font-size` ở đây thì PHẢI đổi y hệt ở luật mở, không
          thì nút lại nhúc nhích — mà một pixel cũng là trượt tay. */
    /* ⛔⛔ VỀ LẠI ĐỆM GỌN 7px — Boss chốt lần thứ ba, 12/09/2026: *"Để lại như
       trước ý, tôi ưng cái đó. Trước khi bạn sửa vừa rồi tôi vẫn ưng mà."*
       Ba dáng Boss đã đi qua: `ef0d2dd` (gọn, rê vào nở ra) → `2aad561` "chừa sẵn
       chỗ" (luôn 487px) → nhãn nổi. Boss nhìn tận mắt và chọn lại cái ĐẦU TIÊN.
       ⛔ ĐỪNG trả `0 10px` về đây nữa: 3px mỗi bên × 2 bên × 9 nút chính là chỗ
          chênh 377 ↔ 487px, tức chính cái "gọn" Boss ưng.
       ⇒ Lỗi "nút trượt khỏi ngón tay" của dáng này KHÔNG chữa bằng cách đổi dáng
         nữa, mà bằng cách NỞ TỨC THÌ — xem khối "LỐI ①" ở luật mở bên dưới. */
    padding:0 7px !important; margin:0 !important;
    border:0 !important; border-radius:999px !important;
    background:transparent !important; box-shadow:none !important;
    color:var(--mo) !important;
    /* ⛔⛔ `font-size:0` MỚI LÀ CÁI THU CỤM LẠI — trả về 12/09/2026.
       Đây là đường thu DUY NHẤT ăn được vào các cụm NÚT VIẾT TAY (màn Giờ trợ giảng
       tự viết thẳng `<div class="nv-gon">` và KHÔNG bọc chữ trong `.nvg-chu`) — nên luật
       `max-width:0` của `.nvg-chu` không với tới. Đo thật: để 12,5px thì cụm nghỉ rộng
       481px, trả về 0 thì còn 377,4px — đúng 103,6px, chính là cái "gọn" Boss ưng.
       ⛔ Đừng tưởng `font-size:0` là ẩn chữ bằng mẹo bẩn: số đếm vẫn đọc được vì
          `.nv-gon .so-dem` khai lại 12,5px, và icon `<i>` có kích thước riêng.
       ⛔ Sửa số này thì PHẢI sửa y hệt ở luật mở (`:hover` · `.mo` · `.giu-mo` ·
          `:has(:focus-visible)`), không thì cụm mở ra mà chữ vẫn câm. */
    font-size:0 !important;
    /* ⛔⛔ `line-height:1` LÀ THỦ PHẠM CẮT CHÂN CHỮ. Boss chê 10/09: *"chữ số
       trong các block đang bị khuất che mất khiến nó cụt ở chân chữ và chân số"*.
       Đo thật 16 màn cùng ngày: 137 chỗ có `scrollHeight 14 > clientHeight 13` —
       ô chữ cao đúng bằng cỡ chữ, mà chữ Việt còn dấu đội lên trên và chân g/y/p
       thò xuống dưới, nên bị `overflow:hidden` xén cả hai đầu.
       ⛔ 1.45 là số ĐO RA, không phải áng chừng: 12,5px × 1,45 = 18px, thừa 4px so
          với 14px chữ thật cần. Hạ xuống 1.2 là 15px — sát quá, cỡ chữ nhích một
          nấc là cụt lại. */
    font-weight:500; line-height:1.45; gap:0 !important; flex:0 0 auto !important;
    transition:background-color .15s ease, color .15s ease,
               font-size .45s cubic-bezier(.4,0,.2,1),
               padding .45s cubic-bezier(.4,0,.2,1),
               gap .45s cubic-bezier(.4,0,.2,1); }
  /* Icon bằng nhau tuốt — đây là thứ mắt nhìn thấy đầu tiên khi block đang thu. */
  .nv-gon button > i { width:18px !important; height:18px !important;
    margin:0 !important; flex:none; }
  /* ── Ô TÌM CŨNG THU LẠI (Boss chốt 10/09 lượt 3, bằng nút bấm) ──────────
     *"thu hết, kể cả ô tìm"*. Đóng thì còn dấu kính lúp; rê vào thì ô nhập nở.

     ⛔ ĐANG GÕ THÌ KHÔNG ĐƯỢC THU. `:focus-within` ở khối mở phía dưới lo việc
        ấy — thiếu nó thì người dùng gõ được nửa chữ, chuột rời khỏi viên một cái
        là ô co lại nuốt mất chỗ gõ. Đây là lý do ô tìm KHÔNG dùng `display:none`:
        phần tử ẩn hẳn thì mất luôn tiêu điểm bàn phím.

     ⛔ Và ô có chữ rồi thì cũng không thu — lọc đang bật mà chỗ gõ biến mất thì
        người dùng không hiểu vì sao bảng chỉ còn mấy dòng. Lối `.dang-loc` ở dưới. */
  /* Viên có ô tìm: ĐÓNG thì vẫn nhỏ như viên chỉ có nút, MỞ mới chiếm cả hàng.
     Đặt width:100% cho lúc đóng là hỏng hết ý nghĩa "thu gọn". */
  .nv-gon.co-tim { flex:0 1 auto; max-width:100%; }
  @media (hover:hover) { .nv-gon.co-tim:hover { flex:0 1 auto; } }
  /* Cùng lý do như trên: chỉ đổi khi đang gõ trong ô tìm, không phải mỗi lần
     tiêu điểm rơi vào một cái nút nào đó trong viên. */
  .nv-gon.co-tim.mo, .nv-gon.co-tim:has(.nvg-tim :focus) { flex:0 1 auto; }
  /* ⛔ Ô TÌM ĐỪNG NUỐT CẢ HÀNG. Boss chê 10/09: *"cái thanh tìm kiếm bị dài
     quá"* — ô nở tới 520px đẩy hết nút sang mép phải, nhìn như hai cụm rời
     chứ không còn là một viên. 260px đủ đọc "Tìm (tên HS · lớp · người phụ
     đạo)…" mà vẫn để nút nằm ngay cạnh. */
  .nv-gon .nvg-tim { display:inline-flex; align-items:center; flex:0 1 auto;
    min-width:32px; height:32px; padding:0 7px; border-radius:999px;
    color:var(--mo); overflow:hidden;
    transition:flex-basis .45s cubic-bezier(.4,0,.2,1); }
  .nv-gon .nvg-tim > i { width:18px; height:18px; flex:none; }
  .nv-gon .nvg-tim > input {
    flex:1 1 auto; width:0; min-width:0; max-width:0; opacity:0;
    height:32px !important; min-height:32px !important;
    margin:0 !important; padding:0 !important;
    border:0 !important; border-radius:0 !important;
    background:transparent !important; box-shadow:none !important;
    outline:none !important; font-size:13px; line-height:1.45; color:var(--chu);
    transition:max-width .45s cubic-bezier(.4,0,.2,1),
               opacity .3s ease,
               padding .45s cubic-bezier(.4,0,.2,1); }
  .nv-gon .nvg-tim > input::placeholder { color:var(--mo); }

  /* Mở ra: ô nhập chiếm phần lớn viên, có vạch mảnh ngăn với đám nút. */
  @media (hover:hover) {
    /* ⛔⛔ RÊ CHUỘT KHÔNG ĐƯỢC LÀM Ô TÌM NỞ RA. Boss chê 10/09:
       *"cứ kéo vào thanh lại dài ra xíu lệch vị trí ấn"*.
       Ô tìm nở thêm 260px thì MỌI nút bên phải nó dịch chỗ ngay dưới con trỏ —
       người ta đang nhắm nút "Làm mới" thì nút ấy trượt đi và bấm trúng nút khác.
       Chữ trong nút nở ra là chuyện nhỏ, còn 260px là cả một quãng.
       ⇒ Ô tìm chỉ nở khi người dùng THẬT SỰ BẤM vào nó (`:focus-within` ở dưới),
         hoặc khi trong ô đã có chữ. Rê chuột qua thì nó đứng yên.
       ⛔ Đừng "sửa lại cho đồng bộ" bằng cách thêm `:hover` vào đây — đó đúng là
          cái vừa gỡ đi. */
  }
  /* ⛔ DẤU ĐÓNG NGAY TRÊN LÀ CỦA `@media (hover:hover)`. Media ấy nay rỗng, chỉ
     còn lời dẫn — nhưng PHẢI giữ dấu đóng. Lúc gỡ hai luật hover tôi đã cắt mất
     nó, và hậu quả là toàn bộ luật `:focus-within` dưới đây rơi vào trong media:
     trên điện thoại (`hover: none`) chúng không áp dụng, ô tìm nằm im 0px, người
     dùng gõ được mà không thấy chữ mình gõ. Đếm ngoặc mới lòi ra: file lệch 5 dấu
     trong khi bản gốc lệch 4.
     ⇒ Ai xoá nốt lời dẫn này thì nhớ xoá cả dòng `@media (hover:hover) {` ở trên. */
  /* ⛔⛔ `flex:0 1 auto` KHÔNG ĐỦ — nó cho phép ô co lại tới 0. Viên trên điện
     thoại chứa cả chục nút, nên khi bung ra ô tìm chỉ giành được 14px: người dùng
     gõ được mà chữ không có chỗ hiện. Đo 10/09 ở màn Phụ đạo và Chăm sóc đúng
     14px, trong khi Sổ tuyển sinh (ít nút hơn) được 195px.
     ⇒ Lúc ĐANG GÕ thì ô tìm là thứ quan trọng nhất trong viên: cho nó một sàn
       `min-width` và quyền nở, đám nút chịu khó cuộn sang phải. Viên vốn đã cuộn
       ngang được nên không nút nào mất đi, chỉ là phải kéo mới thấy. */
  /* ⛔⛔ BỎ `.nv-gon:focus-within` KHỎI CHỖ NÀY — vá 10/09/2026.
     Boss: *"tôi ấn vào 1 nút trong thanh công cụ… tự nhiên thanh tìm kiếm lại dài
     ra trong khi tôi không ấn, làm tôi ấn trượt nút tôi cần ấn."*
     `:focus-within` đặt trên CẢ VIÊN nên nó khớp khi tiêu điểm rơi vào BẤT CỨ
     `<button>` nào bên trong. Bấm một nút bất kỳ ⇒ ô tìm nở 32→168px ⇒ nút vừa
     bấm nhảy đi 130px, cả viên phình 918→1182px, ngón tay bấm hụt cái tiếp theo.
     ⇒ Chỉ nở khi tiêu điểm ở CHÍNH Ô NHẬP: `.nvg-tim:focus-within` (bên trong ô
       tìm) — luật ấy vốn đã có sẵn ngay dưới, chỉ cần bỏ cái quá rộng đi.
     ⛔ Đừng "chữa" bằng cách bỏ luôn `.mo`: đó là lúc người dùng CHỦ ĐỘNG bấm mở
        viên ra, nở là đúng ý họ.
     ⛔ Lượt sau muốn thêm điều kiện nở thì nhớ: mọi bộ chọn đặt trên `.nv-gon` mà
        dùng `:focus-within` đều bao gồm cả đám nút. Muốn "đang gõ" thì phải neo
        vào `.nvg-tim`, không neo vào viên. */
  .nv-gon.mo .nvg-tim,
  .nv-gon .nvg-tim:focus-within {
    flex: 1 1 auto;
    /* Đủ cho chừng 20 chữ cái — gõ tên học sinh vẫn thấy trọn. */
    min-width: 168px;
  }
  .nv-gon.mo .nvg-tim > input,
  .nv-gon .nvg-tim > input:focus {
    max-width:260px; width:auto; opacity:1; padding:0 8px 0 6px !important; }
  /* Đang có chữ trong ô thì giữ mở, đừng nuốt mất chỗ gõ. */
  .nv-gon .nvg-tim > input:not(:placeholder-shown) {
    max-width:260px; width:auto; opacity:1; padding:0 8px 0 6px !important; }
  .nv-gon .nvg-tim:has(> input:not(:placeholder-shown)) { flex:0 1 auto; }
  .nv-gon:has(.nvg-tim > input:not(:placeholder-shown)) { flex:0 1 auto; }
  .nv-gon > input:focus { box-shadow:none !important; }

  /* Vỏ neo bảng lọc không được vẽ gì thêm, kẻo thành một cái hộp trong hộp. */
  .nv-gon .bl-locvo { display:inline-flex; padding:0; margin:0; border:0;
    background:none; }

  /* Chữ: thu về 0 khi đóng, nở ra khi mở.
     ⛔ `flex:none` KHÔNG THỪA — nút là hộp flex, thiếu nó thì chữ bị bóp về 0
        dù `max-width` đã nở. Và `font-size` mới là thứ quyết định: đo thật
        10/09 lúc đang rê, `mw=200px` mà `w=0px` vì cỡ chữ đang là 0. */
  /* ⛔⛔ NHỊP MỞ/ĐÓNG — Boss chê 10/09: *"nó nhanh quá như kiểu bụp phát hiện
     luôn ý"*, và dặn *"mở ra nhẹ nhàng và từ từ thôi đóng lại cũng từ từ"*.
     Hai chỗ đã sửa, đừng trả về:
       · `cubic-bezier(.34,1.56,.64,1)` là đường NẢY — số 1.56 cho nó vọt quá
         đích rồi giật về. Đúng thứ tạo cảm giác "bụp". Nay dùng đường mượt
         `(.4,0,.2,1)` của Material: ra nhanh, vào chậm, không nảy.
       · `font-size` TRƯỚC ĐÂY KHÔNG CÓ TRONG TRANSITION. Mà chính nó mới là
         thứ làm chữ hiện ra (xem ghi chú ở khối dưới). Cỡ chữ nhảy thẳng từ 0
         lên 12.5px trong khi bề rộng bò từ từ ⇒ chữ đập vào mắt trước rồi hộp
         mới đuổi theo. Nay cả hai đi cùng nhịp.
     Thời gian: .45s cho hộp, .3s cho độ mờ. Đóng cũng đúng nhịp ấy vì
     transition đặt ở trạng thái NGHỈ, không đặt trong `:hover`. */
  /* ⛔ `overflow:hidden` PHẢI GIỮ (nó làm nên cú thu chữ), nên chiều cao dòng
     phải đủ rộng cho dấu tiếng Việt — xem ghi chú ở khối nút phía trên. */
  .nv-gon .nvg-chu { display:inline-block; flex:none; overflow:hidden;
    line-height:1.45;
    /* ⛔ `max-width` GIỮ NGUYÊN 200px Ở CẢ HAI TRẠNG THÁI — xem "CHỪA SẴN CHỖ" trên. */
    /* Lúc nghỉ chữ thu về 0 — đó chính là cái "gom lại cho gọn" Boss ưng. */
    white-space:nowrap; font-size:12.5px; max-width:0; opacity:0; margin-left:0;
    transition:max-width .45s cubic-bezier(.4,0,.2,1),
               opacity .3s ease,
               margin-left .45s cubic-bezier(.4,0,.2,1),
               font-size .45s cubic-bezier(.4,0,.2,1); }

  /* ⛔⛔ NÚT KHÔNG CÓ ICON THÌ ĐỪNG THU CHỮ. Đo thật 10/09/2026 ở màn Chăm sóc:
     hai nút "HS mới 1-2 buổi (0)" và "HS dạo này kém (23)" không mang thẻ <i>
     nào, nên thu lại xong chúng thành hai Ô TRỐNG rộng 32px — không dấu hiệu,
     không số, không gì cả. Người dùng nhìn thấy một khoảng trắng giữa viên và
     không đời nào đoán được đó là "còn 23 em dạo này kém".

     ⇒ Có icon thì thu được (icon thay lời). Không icon thì giữ nguyên chữ.
     ⛔ Đừng "chữa" bằng cách gán đại một icon cho chúng: icon sai nghĩa còn tệ
        hơn chữ dài, và con số đếm là thứ Boss cần liếc một cái là thấy. */
  .nv-gon button:not(:has(> i)) {
    font-size:12.5px !important; padding:0 10px !important; gap:0 !important; }
  .nv-gon button:not(:has(> i)) .nvg-chu {
    max-width:260px; opacity:1; margin-left:0; }
  /* Con số đếm luôn phải đọc được, kể cả trong nút đã thu. */
  .nv-gon .so-dem { font-size:12.5px !important; font-weight:600; }

  /* Hàng phụ đã bị bóc hết ruột: ẩn đi chứ KHÔNG xoá — mã màn còn gọi tới nó
     theo `id`. Xem ghi chú dài ở `gonNutPhu` trong js/tinh-nang.js. */
  .nvg-hang-trong { display: none !important; }

  /* ⛔⛔ SỐ ĐẾM PHẢI CÁCH CHỮ MỘT NHỊP. Boss chê 10/09: chữ và số dính vào nhau,
     đọc ra "còn104em". Thủ phạm là lượt bỏ `gap` sáng nay: bỏ gap thì dấu ngoặc
     hết bị văng khỏi số, nhưng chữ đứng ngay trước số cũng mất luôn khoảng thở.
     ⇒ Trả lại khoảng hở bằng margin của CHÍNH con số, không dùng `gap` — gap
       chen đều vào mọi khe nên nó mới đẩy dấu ngoặc đi. */
  .nv-gon .so-dem { margin: 0 2px 0 4px; line-height: 1.45; }
  .nv-gon .nvg-chu + .so-dem { margin-left: 4px; }

  /* ── MỞ RA ─────────────────────────────────────────────────────────────── */
  /* ⛔ `@media (hover:hover)` KHÔNG PHẢI THỪA — cùng bẫy đã trả giá ở dải avatar
     sáng nay. Thiếu nó thì trên điện thoại cú chạm đầu bị dịch thành "rê chuột
     giả" và block kẹt ở trạng thái mở. Điện thoại đi lối class `.mo`. */
  /* ⛔⛔ RỜI CHUỘT RA THÌ GIỮ MỞ 4 GIÂY RỒI MỚI THU — Boss chốt 10/09:
     *"kéo chuột ra khỏi thanh thì phải 4s nó mới kéo về như cũ để tránh việc mọi
     người lỡ kéo chuột ra khỏi thanh đo gây ra khó chịu"*.
     Cách làm: đặt `transition-delay` ở trạng thái NGHỈ (lúc đóng) chứ không đặt
     trong `:hover`. CSS chạy hoạt ảnh theo luật của trạng thái ĐÍCH, nên:
       · rê vào  → luật `:hover` có delay 0  → mở ngay lập tức;
       · rời ra  → về luật nghỉ có delay 4s → đứng yên 4 giây rồi mới thu.
     ⛔ Đừng đảo hai chỗ này: đặt delay trong `:hover` là rê vào phải chờ 4 giây
        mới thấy chữ, đúng ngược ý Boss.

     ⛔⛔ CÁCH LÀM TRÊN ĐÃ BỊ GỠ — vá 12/09/2026. Ý ĐỊNH CỦA BOSS GIỮ NGUYÊN, chỉ
        đổi CÁCH thực hiện. Vì sao phải đổi:
        `transition-delay` hoãn CHUYỂN ĐỘNG, không hoãn QUYẾT ĐỊNH ĐÓNG. Rời chuột
        lúc cụm mới nở được nửa chừng thì trình duyệt chốt ngay đích là "đóng", rồi
        ngồi im 4 giây — nên trong 4 giây ấy cụm ĐỨNG NGUYÊN Ở GIÁ TRỊ DỞ DANG.
        Đo thật (1366×900, lia vào rồi lia ra giữa chừng), bề ngang cụm gốc 377,4px:
            lia ra sau  30ms → 379,4px, đứng im   32ms  (vô hại)
            lia ra sau  60ms → 379,0px, đứng im 4 000ms
            lia ra sau 100ms → 385,9px, đứng im 3 999ms
            lia ra sau 150ms → 419,8px, đứng im 4 033ms
            lia ra sau 250ms → 466,8px, đứng im 4 033ms
            vào-ra-vào       → 486,8px, đứng im 4 217ms
        Đúng câu Boss chê: *"mở ra nửa vời rồi dừng luôn, trông dở dang"*.
     ⇒ Nay hoãn VIỆC BẮT ĐẦU ĐÓNG chứ không hoãn chuyển động: JS khoác lớp
       `.giu-mo` ngay lúc con trỏ rời cụm (xem `nvgNoiGiuMo` trong js/tinh-nang.js),
       giữ 4 giây rồi mới bỏ. Lớp ấy mang đúng bộ luật "mở" như `:hover`, nên:
         · rời chuột giữa chừng → cụm CHẠY NỐT cho mở hết, không đông cứng;
         · đủ 4 giây → bỏ lớp, cụm thu về trọn vẹn một nhịp .45s.
     ⛔ ĐỪNG trả `transition-delay: 4s` về đây "cho gọn": nó là chính cái bệnh.
     ⛔ Con số 4 giây nằm ở `NVG_GIU_MO_MS` trong js/tinh-nang.js — sửa một chỗ. */
  .nv-gon:hover button, .nv-gon:hover .nvg-chu,
  .nv-gon:hover .nvg-tim, .nv-gon:hover .nvg-tim > input,
  .nv-gon.mo button, .nv-gon.mo .nvg-chu,
  .nv-gon.giu-mo button, .nv-gon.giu-mo .nvg-chu,
  /* ⛔ `:focus-visible` chứ không phải `:focus-within`: đi bằng phím Tab thì bung
     nhãn chữ ra cho đọc được (không bung là người dùng bàn phím mù chữ hoàn
     toàn), còn BẤM CHUỘT thì tuyệt đối không xô bố cục dưới ngón tay. Trình duyệt
     tự phân biệt hai đường ấy — mình không phải đoán. */
  .nv-gon:has(:focus-visible) button, .nv-gon:has(:focus-visible) .nvg-chu,
  .nv-gon:has(.nvg-tim :focus) .nvg-tim,
  .nv-gon:has(.nvg-tim :focus) .nvg-tim > input { transition-delay: 0s; }

  @media (hover:hover) {
    .nv-gon:hover button { font-size:12.5px !important; padding:0 10px !important;
      gap:0 !important; }
    .nv-gon:hover .nvg-chu { max-width:200px; opacity:1; margin-left:0; }
    .nv-gon button:hover { background:var(--nen-o) !important; color:var(--chu) !important; }
  }
  /* ⛔ `.giu-mo` phải đi CÙNG `.mo` ở MỌI luật mở, không riêng luật delay.
     Thiếu một chỗ là cụm "giữ mở" mà chữ vẫn thu — tức vẫn dở dang, chỉ đổi kiểu. */
  .nv-gon.mo button, .nv-gon.giu-mo button, .nv-gon:has(:focus-visible) button {
    font-size:12.5px !important; padding:0 10px !important; gap:0 !important; }
  .nv-gon.mo .nvg-chu, .nv-gon.giu-mo .nvg-chu, .nv-gon:has(:focus-visible) .nvg-chu {
    max-width:200px; opacity:1; margin-left:0; }
  /* ══════════════════════════════════════════════════════════════════════════
     ⛔⛔ "NÚT CHẠY KHỎI NGÓN TAY" — ĐÃ ĐO HẾT, VÀ ĐÂY LÀ SỰ THẬT ĐẦY ĐỦ.
     ✅ BOSS ĐÃ CHỐT 12/09/2026 — VIỆC NÀY ĐÓNG, ⛔ ĐỪNG MỞ LẠI.
        Boss nghe đủ ba đáp án kèm số thật rồi chọn: *"Giữ dáng đang ưng — chịu 12/20
        khi đi dọc thanh."* Nên **12/20 là CÁI GIÁ ĐÃ ĐƯỢC CHẤP NHẬN**, không phải một
        việc còn dở. Phép canh `do-nvgon.js` ca ② sẽ còn ĐỎR MÃI MÃI — đó là ĐÚNG;
        đừng thấy nó đỏ mà tưởng ai đó quên làm, và ⛔ đừng đi "chữa" nó.
     ──────────────────────────────────────────────────────────────────────────
     Đo 12/09/2026 bằng CÚ BẤM THẬT (`do-bam-truot.js`): 20 cú mỗi cột, 4 khổ desktop,
     toạ độ bấm chốt từ lúc chuột CÒN Ở XA (đúng chỗ người ta nhìn thấy nút), rồi
     chuột đi 25 bước tới đó và bấm. ⛔ Không dùng `locator.click()` — nó tự chờ phần
     tử đứng yên rồi mới bấm, tức tự chữa đúng cái lỗi đang đi tìm.

                                      đi từ TRÊN xuống | đi DỌC THANH từ trái
       dáng này (Boss ưng, đang dùng)          20/20      |      12/20
       + Lối ① "nở tức thì" (transition 0s)       —         |      12/20
       + Lối ② "vùng đệm 120px quanh cụm"          —         |      12/20
       bản "chừa sẵn chỗ" (`2aad561`, Boss bác)   20/20      |      20/20

     Đọc bảng này cho đúng:
       · Đưa tay từ BẢNG LÊN thanh công cụ — đường đi thường gặp nhất — thì KHÔNG
         BAO GIỜ trượt. Con trỏ chỉ chạm cụm ở bước cuối, cú bấm nổ gần như cùng lúc.
       · Chỉ khi đi DỌC THEO THANH (băng ngang qua cả cụm rồi mới tới nút) mới trượt,
         vì cụm nở ra ngay từ mép trái và đẩy hàng xóm đi 109,6px.
       · HAI LỐI CHỮA ĐỀU KHÔNG ĐỔI ĐƯỢC GÌ: vẫn 12/20. Nở nhanh hay nở sớm cũng
         thế, vì cái làm trượt không phải NHỊP nở mà là VIỆC nở trong dòng chảy.
     ⛔ ĐỪNG THỬ LẠI HAI LỐI ẤY.
     ⛔ Và đừng đọc phép canh `do-nvgon.js` ca ② ("điểm (403,177) sau 300ms vẫn là
        Việc khác") như một bài có thể đạt: đo được rằng cấu hình DUY NHẤT làm nó xanh
        là cụm MỞ SẴN VĨNH VIỄN (thử với bán kính đệm 5000px ⇒ xanh 3/3). Hễ cụm còn
        nở TRONG DÒNG CHẢY thì hàng xóm còn bị đẩy. Đây là CÁI GIÁ của dáng Boss chọn,
        không phải một lỗi đang chờ vá. Muốn hết hẳn thì phải ĐỔI DÁNG — việc của Boss.
     ⚠️ TẬT CỦA THƯỚC, ghi để lượt sau khỏi mắc lại: bản đầu cho chuột xuất phát ở
        `cụm.left - 60` ⇒ x≈17px ở desktop, tức NẰM TRONG vùng nở của cột công cụ
        trái. Cột ấy nở ra phủ lên nút "Làm mới" nên 4/20 cú trượt ở MỌI dáng, kể cả
        dáng không nở — và vì nó trừ oan không đều nhau, có lúc đọc ra "Lối ① làm tệ
        hơn", điều không hề có. Nay đường đi từ trái bị chặn không cho bắt đầu trong
        `#ccRail`.
     ══════════════════════════════════════════════════════════════════════════ */

  .nv-gon button:focus-visible { background:var(--nen-o) !important;
    color:var(--chu) !important; outline:2px solid var(--xanh); outline-offset:1px; }

  /* Việc CHÍNH của màn vẫn phải nhận ra được giữa đám nút giống hệt nhau — nhưng
     chỉ bằng MÀU CHỮ, không đổi khuôn. Boss dặn các nút phải giống nhau. */
  .nv-gon button.nut-chinh { color:var(--xanh) !important; }
  .nv-gon button.nut-chinh:hover { background:var(--xanh-nhat) !important;
    color:var(--xanh-dam) !important; }
  /* Nút Bộ lọc đang bật thì vẫn phải thấy là đang bật. */
  .nv-gon button.dang-loc { color:var(--xanh) !important; }

  @media (prefers-reduced-motion: reduce) {
    .nv-gon .nvg-chu, .nv-gon button { transition:none; }
  }


  /* ⛔ KHOẢNG HỞ ĐẶT BẰNG MARGIN CỦA CHỮ, KHÔNG BẰNG `gap` CỦA NÚT.
     `gap` chen đều vào MỌI khe trong nút — mà nút đếm số có tới bốn mảnh:
     <i> · "Đang chăm sóc (" · <span class=so-dem>0</span> · ")". Đặt gap 6px là
     dấu ngoặc văng khỏi con số, đọc ra "(  0  )" rời rạc. Đo thật 10/09/2026.
     ⇒ Chỉ chèn hở ở ĐÚNG MỘT KHE: giữa icon và chữ đầu tiên. */
  /* ⛔ 6px ở CẢ HAI trạng thái — chừa sẵn chỗ, đừng để khe này nở lúc rê chuột. */
  /* Nghỉ thì không có khe (chữ rộng 0); mở ra mới chèn 6px. */
  .nv-gon button > i + .nvg-chu { margin-left:0; }
  @media (hover:hover) {
    .nv-gon:hover button > i + .nvg-chu { margin-left:6px; }
  }
  .nv-gon.mo button > i + .nvg-chu, .nv-gon.giu-mo button > i + .nvg-chu,
  .nv-gon:has(:focus-visible) button > i + .nvg-chu { margin-left:6px; }
  .nv-gon button:not(:has(> i)) .nvg-chu { margin-left:0; }

  /* ⛔ MÀN HẸP: MỞ SẴN, ĐỪNG THU. Điện thoại không có chuột để rê, mà thanh ở đó
     lại thừa chiều ngang — thu lại chỉ tổ bắt chạm hai lần cho mỗi việc.
     📱 22/09/2026 — thêm `(hover:none)`: MÁY KHÔNG RÊ CHUỘT ĐƯỢC cũng mở sẵn, dù màn
     rộng. Boss chốt: *"iPad / điện thoại xoay ngang: chạm một lần là chạy, tên nút
     hiện sẵn như điện thoại dọc"*. Trước đó iPad (1024) và điện thoại xoay ngang
     (844) lọt khỏi mốc 820px nên chữ thu: chạm lần 1 chỉ mở cho đọc, lần 2 mới chạy.
     ⛔ Hỏi `hover`, đừng hỏi bề ngang hay `pointer`: máy tính màn cảm ứng mà có chuột
        vẫn là `hover:hover` → giữ nguyên nếp máy tính (rê vào mới nở).
     ⛔ Luật anh em cho nút Làm mới ở khối "Màn hẹp hoặc máy không rê chuột" (~12980)
        phải đổi CÙNG lúc. Bài canh: kiem-thu/thu-cham-nut-gon-dien-thoai-22-09.js */
  @media (max-width:820px), (hover:none) {
    /* ⛔⛔ CHỈ CÒN `opacity` — vá 12/09/2026 cùng lượt "chừa sẵn chỗ".
       Khối này trước đây khai lại cả `font-size` · `padding` · `gap` · `margin-left`.
       Ba cái đầu nay đã trùng với luật nền nên thừa, riêng `gap:6px` thì KHÁC luật
       nền (`gap:0`) — mà luật `.nv-gon:hover button` lại ép về 0. Kết quả: ở 390
       rê chuột vào là nút "Mở đợt" tụt 86,4 → 80,4px, kéo hai nút sau dịch trái 6px.
       Đo được sau khi đã vá xong bốn khổ desktop (lệch 0px) mà 390 vẫn lệch 6px.
       ⛔ Khoảng hở icon–chữ đã do `margin-left` của chữ lo (xem lời dặn ở khối trên),
          đừng dùng `gap` — `gap` chen đều vào MỌI khe nên nó làm dấu ngoặc văng khỏi số. */
    /* ⛔⛔ PHẢI KHAI LẠI `max-width` — luật nền nay thu chữ về 0 (Boss đòi gọn).
       Bản "chừa sẵn chỗ" để nền là 200px nên khối này chỉ cần `opacity`; trả dáng
       cũ mà quên dòng này là điện thoại nhìn thấy một hàng icon câm, không chữ nào.
       ⛔ VẪN KHÔNG khai `gap`: `gap:6px` ở đây từng làm 390 lệch 6px lúc rê chuột
          (luật `.nv-gon:hover button` ép `gap:0`). Khe icon–chữ do `margin-left` lo. */
    .nv-gon .nvg-chu { max-width:200px; opacity:1; margin-left:0; transition:none; }
    .nv-gon button > i + .nvg-chu { margin-left:6px; }
  }
  .nv-h { margin:16px 0 8px; font-size:14px; color:#2b2b2b; }

  /* ══════════════════════════════════════════════════════════════════════════════
     🧱 BLOCK TỪNG NHÂN VIÊN — cô Quỳnh 21/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     *"khi mọi người tạo việc nhiều xong nhìn nó rất là rối và khó chịu"*.
     Đóng lại thì mỗi người chỉ chiếm MỘT dòng: tên · chức vụ · mấy con số. Cả bộ
     phận 12 người vừa một màn hình, nhìn phát biết ai đang gánh nặng.
     ⛔ Nét mảnh, không nền màu, không đổ bóng — đây là danh sách làm việc, không
        phải bảng quảng cáo. Màu chỉ dùng để BÁO ĐỘNG (quá hạn), không để trang trí.
     ══════════════════════════════════════════════════════════════════════════════ */
  /* ⛔⛔ LUẬT MÀU CỦA CẢ MÀN CÔNG VIỆC — cô Quỳnh chốt 21/08/2026
     *"thiết kế phải chuyên nghiệp business trắng đen ko được màu mè gây hiểu nhầm
     thành UI của AI"*.
     Nghĩa là ở màn này CHỈ ĐƯỢC DÙNG bốn biến trung tính: --the (nền thẻ),
     --nen2 (nền chìm), --vien (nét), --chu / --mo (chữ đậm / chữ nhạt).
     ⛔ CẤM: nền teal, nền cam, chip đổ màu, viền teal, bo góc to, đổ bóng.
     ⛔ NGOẠI LỆ DUY NHẤT: chữ "quá hạn" được dùng --do, và CHỈ Ở DẠNG CHỮ — không
        nền đỏ, không viền đỏ. Đó là báo động thật, không phải trang trí. Bỏ nốt
        chỗ này thì việc trễ chìm nghỉm giữa mấy chục dòng xám.
     Muốn nhấn mạnh thì dùng ĐỘ ĐẬM và KHOẢNG TRỐNG, không dùng màu. */
  /* ══════════════════════════════════════════════════════════════════════════════
     ⭐ MỖI NGƯỜI MỘT THẺ RIÊNG, CÓ KHOẢNG HỞ — cô Quỳnh 21/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     *"Công cụ công việc bạn tách các block tên nhân viên ra chứ ko để liền thì nhìn
     vẫn rất là rối mắt tách ra nha"*.

     Bản cũ: một cái hộp dài, mọi người dính liền nhau, ngăn bằng một đường kẻ mảnh.
     Mắt phải tự cắt xem dòng nào là của ai — mà mỗi dòng lại có tới bốn con số bên
     phải, nên nhìn thành một bảng số dày đặc.
     Nay mỗi người là MỘT THẺ đứng riêng, cách nhau 8px. Cùng lượng thông tin, nhưng
     mắt không phải làm việc cắt dòng nữa.

     ⛔ GIỮ NGUYÊN LUẬT MÀU Ở TRÊN: thẻ chỉ có nét xám và nền trắng. Tách thẻ KHÔNG
        phải cái cớ để thêm đổ bóng, bo góc to hay viền màu.
     ⛔ Khoảng hở 8px là vừa: hở ít hơn thì vẫn dính, hở nhiều hơn thì danh sách 20
        người phải cuộn thêm cả màn hình.
     ══════════════════════════════════════════════════════════════════════════════ */
  .nv-bl-ds { display:flex; flex-direction:column; gap:8px; margin-top:10px;
    border:0; background:none; }
  /* Cả thẻ LÀ một cái nút — bấm chỗ nào cũng sang trang riêng của người đó. */
  /* ⛔ `flex-wrap:wrap` ở ĐÂY chứ không chỉ trong `@media`: xem khối đo đạc ở trên.
     Cột số tự tụt xuống hàng dưới khi cột tên chạm đáy 240px — không cần biết cửa sổ
     rộng bao nhiêu, không cần đoán thêm một mốc màn hình nào. */
  .nv-bl { width:100%; display:flex; align-items:center; flex-wrap:wrap; gap:10px 14px;
    padding:13px 16px;
    border:1px solid var(--vien); border-radius:var(--r-lg); background:var(--the); cursor:pointer;
    text-align:left; font:inherit; color:var(--chu); }
  /* ⛔ VIỀN RÕ + NỀN HỞ RA MỘT BẬC — 22/08/2026.
     Khối này là thứ BẤM ĐƯỢC và xếp chồng lên nhau thành danh sách dài, nên ranh
     giới giữa hai khối phải tự thấy mà không cần rê chuột. Hai thứ cùng lo việc đó:
     viền `--vien-ro` (3 lần, đúng chuẩn cho đường viền) và nền `--the` sáng hơn nền
     trang một bậc. Thiếu một trong hai là khối lại chìm vào nền như trước. */
  .nv-bl { border-color:var(--vien-ro); }
  .nv-bl:hover { background:var(--nen2); border-color:var(--chu); }
  .nv-bl:focus-visible { outline:2px solid var(--chu); outline-offset:-2px; }
  /* ⛔⛔ 22/08/2026 — Ô NÀY NAY LÀ ẢNH ĐẠI DIỆN THẬT, không còn là "dấu nhận mặt
     bằng chữ cái". Cô Quỳnh: *"các block tên nhân viên để avatar của account nhân
     viên nha, để cho có sắc màu đẹp hơn, khuyến khích mọi người đổi avatar"*.
     Chưa có ảnh thì hiện hình người xám (xem `AV_NGUOI`), giống Facebook.
     ⛔ Vẫn VUÔNG bo góc, KHÔNG tròn — cô Quỳnh chốt 21/08, và lý do vẫn đúng: bo
        tròn hẳn là lập tức trông như mọi bảng điều khiển AI dựng sẵn.
     ⛔ 40px giữ nguyên (cô Quỳnh 21/08: *"block tên nhân viên phải to hơn rõ hơn"*).
     ⛔ `overflow:hidden` là BẮT BUỘC từ nay: có ảnh thật rồi, thiếu dòng này thì
        ảnh vuông thò ra ngoài bốn góc bo. */
  .nv-bl-chu, .nv-ng-chu { flex:none; width:40px; height:40px; border-radius:var(--r-lg); display:flex;
    align-items:center; justify-content:center; overflow:hidden;
    background:var(--nen2); color:var(--mo); border:1px solid var(--vien); }
  .nv-bl-chu img, .nv-ng-chu img { width:100%; height:100%; object-fit:cover; display:block; }
  /* ⛔ Block CỦA CHÍNH MÌNH và trang riêng: chỉ đổi VIỀN cho đậm hơn, KHÔNG bôi đen
     cả ô nữa — bôi đen thì ảnh thật đặt vào sẽ bị viền đen ôm quanh trông rất nặng. */
  .nv-bl.toi > .nv-bl-chu, .nv-ng-chu { border-color:var(--chu); }
  /* ⛔⛔ SÀN 240px LÀ THỨ CHỮA ĐÚNG LỖI CÔ QUỲNH KÊU. Đo được: cột tên tụt tới 190px
     ở cửa sổ 900px và tên dài vỡ hai dòng. Có sàn thì `flex-wrap` ở `.nv-bl` đẩy cột
     số xuống hàng dưới trước khi tên bị bóp.
     ⛔ Phải khai CẢ `flex-basis` 240px LẪN `min-width` 240px: `flex-basis` là chỗ bắt
        đầu co, `min-width` mới là chỗ KHÔNG CO NỮA. Thiếu `min-width` thì flex vẫn co
        xuống tới `min-content` và sàn thành vô nghĩa. */
  .nv-bl-ten { flex:1 1 240px; min-width:240px; display:flex; flex-direction:column; gap:2px; }
  /* ⛔ `break-word` chứ KHÔNG `anywhere`. Hai giá trị này cắt chữ như nhau, nhưng
     `anywhere` còn cho phép flex bóp ô xuống dưới bề ngang của TỪ DÀI NHẤT — tức là
     nó tự tay mở đường cho đúng cái "dồn chữ" đang phải chữa. */
  .nv-bl-ten b { font-size:15px; font-weight:600; overflow-wrap:break-word; }
  /* ⛔⛔ KHÔNG IN HOA, KHÔNG GIÃN CHỮ. Bản cũ là `text-transform:uppercase` +
     `` — đúng hai trong ba thủ phạm làm giao diện "lộ rõ UI của AI"
     mà cô Quỳnh đã chê NĂM lần. Bảng của Google Sheets (mẫu gốc cô Quỳnh muốn) viết
     tiêu đề bằng chữ thường. Và tiếng Việt IN HOA mất sạch dấu phụ trên đầu chữ nên
     đọc chậm hơn hẳn. */
  .nv-bl-ten small { font-size:11.5px; color:var(--mo); }
  /* Đuôi phân biệt hai người trùng tên. Không viết hoa (tên đăng nhập phân biệt
     hoa thường), và đậm hơn chữ chức vụ vì đây mới là thứ để phân biệt. */
  .nv-bl-ma { text-transform:none; letter-spacing:0; font-weight:600; color:var(--chu); }
  .nv-bl-toi { display:inline-block; margin-left:7px; font-size:11px; font-weight:600;
    color:var(--mo);
    border:1px solid var(--vien); border-radius:var(--r-xl); padding:0 8px; vertical-align:1px; }
  /* Bốn con số xếp thành cột đều nhau — đọc như một bảng, không như mấy cái nhãn dán. */
  /* `margin-left:auto` để cột số luôn nằm sát mép phải — cả khi nó ở cùng hàng với
     tên lẫn khi đã tụt xuống hàng dưới. */
  .nv-bl-so { flex:none; display:flex; align-items:center; gap:0; margin-left:auto; }
  .nv-bl-o { display:flex; flex-direction:column; align-items:flex-end; min-width:72px;
    padding:0 11px; border-left:1px solid var(--vien); line-height:1.3; }
  .nv-bl-o b { font-size:16px; font-weight:600; color:var(--chu); font-variant-numeric:tabular-nums; }
  /* ⛔ KHÔNG IN HOA, KHÔNG GIÃN CHỮ — xem lý do đầy đủ ở `.nv-bl-ten small` ngay trên. */
  .nv-bl-o i { font-size:11px; font-style:normal; color:var(--mo); }
  .nv-bl-o.khong b { color:var(--mo); font-weight:400; }
  .nv-bl-o.qh:not(.khong) b { color:var(--do); }
  /* Mũi tên "sang trang" — vẽ bằng hai nét, không dùng ký tự thay hình. */
  .nv-bl-mt { flex:none; width:9px; height:9px; margin-left:2px;
    border-right:1.5px solid var(--mo); border-top:1.5px solid var(--mo);
    transform:rotate(45deg); }

  /* ══════════════════════════════════════════════════════════════════════════
     📦 16/09/2026 — BLOCK NHÂN VIÊN BÉ LẠI, BO GÓC, TỰ XẾP VỪA MÀN
     ──────────────────────────────────────────────────────────────────────────
     Boss giao (việc 11/11): *"block tên nhân viên bo tròn, bé hơn"*, và chốt hai
     điểm bằng nút bấm: **"bo góc vừa (8px)"** · **"tự xếp vừa màn, block co theo
     tên"**.

     ⛔⛔ GÕ 8px THẲNG VÀO ĐÂY, ĐỪNG ĐỘNG VÀO `--r-lg`. Biến ấy đang là **0px** và
        đó là quyết định của CẢ APP: giao diện mẫu là Google Sheets, mọi thứ vuông.
        Đổi biến để bo một chỗ là bo luôn hàng trăm chỗ khác — đúng kiểu "sửa một
        dòng, hỏng cả app" mà không ai phát hiện ngay.

     ⛔ VÌ SAO DÁM GỠ SÀN 240px CỦA `.nv-bl-ten`. Sàn ấy sinh ra để chữa đúng một
        cảnh: block rộng 100%, cột SỐ nằm cùng hàng và bóp cột tên xuống 190px làm
        tên dài vỡ hai dòng. Nay block KHÔNG rộng 100% nữa mà co theo nội dung —
        không còn khoảng nào để cột số giành, nên cảnh ấy không dựng lại được.
        ⛔ Nhưng `overflow-wrap:break-word` ở `.nv-bl-ten b` thì GIỮ NGUYÊN: tên
           siêu dài vẫn phải xuống dòng trong lòng block chứ đừng đẩy block phình
           ra khỏi màn. Và `max-width:100%` dưới đây là cái chặn ấy.

     ⛔ `align-items:stretch` ở dải: các block cùng hàng phải cao BẰNG NHAU, không
        thì mỗi cái một chiều cao theo số dòng tên — nhìn như hàng răng khấp khểnh.
     ══════════════════════════════════════════════════════════════════════════ */
  .nv-bl-ds { flex-direction:row; flex-wrap:wrap; align-items:stretch; }
  .nv-bl {
    width:auto; flex:0 1 auto; max-width:100%;
    border-radius:8px;                 /* Boss chốt: bo góc vừa */
    padding:9px 12px; gap:8px 10px;    /* bé hơn: 13px 16px → 9px 12px */
  }
  /* Ảnh đại diện nhỏ lại theo block. ⛔ Vẫn VUÔNG bo góc chứ không tròn hẳn —
     lý do cũ còn nguyên (bo tròn hẳn là lộ ngay ra giao diện máy dựng sẵn). */
  .nv-bl > .nv-bl-chu { width:32px; height:32px; border-radius:7px; }
  /* Co theo tên: bỏ sàn 240px, cho phép co tới nội dung. */
  .nv-bl > .nv-bl-ten { flex:0 1 auto; min-width:0; }
  .nv-bl > .nv-bl-ten b { font-size:14px; }
  /* Cột số gọn lại và thôi bị đẩy sát mép phải — block nay không còn mép phải nào
     để mà sát, `margin-left:auto` chỉ khiến nó nhảy lung tung khi block hẹp. */
  .nv-bl > .nv-bl-so { margin-left:6px; }
  .nv-bl .nv-bl-o { min-width:56px; padding:0 8px; }
  .nv-bl .nv-bl-o b { font-size:14px; }
  /* ── Dòng "đã điền sẵn, khỏi chọn" (người bàn giao · người tiếp nhận) ──
     `.nv-bangiao-co` có từ 10/08/2026 nhưng CHƯA TỪNG có luật CSS — nó rơi về kiểu
     mặc định của trình duyệt suốt từ đó. Nay hai dòng dùng chung một bộ áo. */
  .nv-bangiao-co, .nv-nguoi-san { display:flex; align-items:center; gap:8px;
    flex-wrap:wrap; margin:2px 0 4px; padding:8px 11px; font-size:13.5px;
    border:1px solid var(--vien); border-radius:var(--r-md); background:var(--nen2); }
  .nv-bangiao-co i.ic-nguoi, .nv-nguoi-san i.ic-nguoi { flex:none; width:15px; height:15px; opacity:.75; }
  .nv-bangiao-co b, .nv-nguoi-san b { font-weight:600; }
  .nv-bangiao-co > i:not(.ic-nguoi), .nv-nguoi-san span { color:var(--mo); font-size:12px; font-style:normal; }
  /* Nút đẩy hẳn về mép phải — nó là lối RẼ hiếm dùng, không nên đứng cạnh cái tên
     như thể hai thứ ngang hàng. */
  .nv-nguoi-san button { margin-left:auto; }
  /* ══ Ô chọn người bị giấu khi block đã định sẵn người nhận ══
     ⛔ `display:none` chứ KHÔNG `visibility`/`opacity`: ô này có danh sách 40 người
        kèm ô tìm; để nó chiếm chỗ mà trong suốt thì form dài ngoằng một khoảng trắng
        không ai hiểu. Dấu tích bên trong vẫn nguyên, và `nsLayChon` đọc bằng
        `:checked` nên KHÔNG phụ thuộc thẻ có hiện ra hay không.
     ⛔⛔ LỚP PHẢI BÁM VÀO THẺ BỌC `#nvNhanBoc`, TUYỆT ĐỐI KHÔNG bám vào
        `#nvNhanPicker`. `nsGanPicker` (dòng ~29756) mở đầu bằng
              box.className = "ns-boc";
        — GÁN ĐÈ chứ không `classList.add` — nên mọi lớp gắn thẳng vào `#nvNhanPicker`
        đều bị thổi bay ngay sau đó, LẶNG LẼ. Đã mắc đúng lỗi này ngày 21/08/2026 và
        chỉ bắt được khi mở trình duyệt thật đọc `getComputedStyle(...).display`. */
  #nvNhanBoc.an { display:none; }

  .nv-bl-rong { color:var(--mo); font-size:12.5px; margin:8px 0; }
  .nv-bl-trong { color:var(--mo); font-size:13px; border:1px solid var(--vien);
    border-radius:var(--r-xl); padding:18px; text-align:center; background:var(--the); }
  /* ══════════════════════════════════════════════════════════════════════════════
     📑 DẠNG SHEET trong công cụ Công việc — cô Quỳnh 28/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     Bốn màu hàng cô nêu: *"nếu nhân viên đã tiếp nhận thì cả hàng có màu vàng, nếu
     chưa tiếp nhận sẽ có màu của loại công việc (quan trọng = màu đỏ, bình thường =
     màu trắng), nếu nhân viên ấn done thì bôi cả hàng màu xanh."*

     ⛔ MÀU NHẠT, KHÔNG PHẢI MÀU ĐẶC. Đây là bảng đọc cả ngày, mà chữ nằm ngay trên
        nền ấy. Đỏ đặc thì chữ đen không đọc nổi và màn hình như đang báo cháy —
        đúng thứ cô Quỳnh gọi là "lộ rõ ui AI". Nền nhạt + một vạch màu ở cột đầu
        là cách bảng tính thật vẫn làm.
     ⛔ MỖI LUẬT NỀN SÁNG PHẢI CÓ BẢN `body.toi`. `thu-nen-toi-luoi-va-vien.js` canh
        việc này, và quan trọng hơn: nền trắng ở chế độ tối là chữ trắng trên nền
        trắng — mất hẳn một hàng chứ không phải xấu một chút.
     ⛔ ĐỪNG tô nền lên `tr`. Ô `.dg-dinh` (cột đầu dính trái) có nền riêng đè lên,
        nên tô ở `tr` là cột đầu trơ ra trắng giữa một hàng có màu. Tô vào `td`.
     ══════════════════════════════════════════════════════════════════════════════ */
  .nv-sh-mach { font-size:13px; color:var(--mo); margin:10px 0 6px; }
  .nv-sh-chugiai { display:flex; flex-wrap:wrap; gap:6px 16px; margin:0 0 10px;
    font-size:12px; color:var(--mo); }
  .nv-sh-chugiai span { display:inline-flex; align-items:center; gap:6px; }
  .nv-sh-o { width:13px; height:13px; border-radius:var(--r-sm); border:1px solid var(--vien-ro);
    display:inline-block; }
  /* Bảng ăn hết bề ngang khung — `.dg-bang` không tự khai `width` (bảng dự giờ có
     17 cột nên luôn tràn), còn bảng này chỉ 7 cột, để mặc thì thừa một khoảng trắng
     bên phải trông như bảng bị cụt. */
  .nv-sh-bang { width:100%; }
  /* ⭐ GỌN HƠN (cô Quỳnh 28/08 trưa): hàng thấp lại, chữ nhỏ một nấc, cột ngày và
     cột chip không xuống dòng. Trước đó mỗi hàng cao ~36px nên 13 dòng việc đã
     tràn hết màn — phải cuộn mới thấy hết một cơ sở. */
  .nv-sh-bang td { font-size:12.5px; vertical-align:middle; padding-top:4px; padding-bottom:4px; }
  .nv-sh-bang th { font-size:12.5px; }
  /* ⛔ CHỈ SỐ CỘT ĐÃ TRƯỢT, VÀ LẦN TRƯỢT TRƯỚC HỎNG IM LẶNG. Bỏ cột "Thời gian
     giao" (08/09) làm nth-child(3) trỏ nhầm sang cột Công việc, nên cột ấy bị
     nowrap và chữ dài TRÀN ĐÈ cột bên cạnh — đo được 313px ngày 09/09.
     Nay hàng có 5 ô: 1 Nhân viên · 2 ô-gộp(giờ+việc) · 3 Hạn · 4 Mức độ · 5 Tình
     trạng. Ô gộp KHÔNG được nowrap (chữ việc phải xuống dòng, Boss cấm cắt cụt).
     ⛔ Thêm hay bớt cột thì phải sửa luôn mấy số này, không thì lại hỏng kiểu cũ. */
  .nv-sh-bang td:nth-child(3), .nv-sh-bang td:nth-child(4),
  .nv-sh-bang td:nth-child(5) { white-space:nowrap; }

  /* Ô Nhân viên: ảnh đại diện bên trái, tên bên phải. */
  .nv-sh-ai { display:flex; align-items:center; gap:7px; min-width:0; }
  .nv-sh-avt { flex:none; width:24px; height:24px; border-radius:var(--r-sm); overflow:hidden;
    display:flex; align-items:center; justify-content:center; background:var(--nen2);
    border:1px solid var(--vien); color:var(--mo); }
  .nv-sh-avt img { width:100%; height:100%; object-fit:cover; display:block; }
  .nv-sh-avt svg { width:15px; height:15px; }
  .nv-sh-ai b { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

  /* ══════════════════════════════════════════════════════════════════════════
     📊 16/09/2026 — DẠNG SHEET THEO MẪU `21st.dev/@originui/.../table-with-images`
     ──────────────────────────────────────────────────────────────────────────
     Boss giao (việc 10/11) kèm thẳng link mẫu, và chốt hai điểm bằng nút bấm:
       · *"các account hiện giờ logo đều có icon rồi mà"* ⇒ dùng đúng avatar app
         đã có (`avatarHtml`/`AV_NGUOI`), không dựng thêm bộ ảnh nào
       · **"giữ kiểu mẫu, hàng vừa phải"** ⇒ lấy dáng của mẫu, KHÔNG lấy hàng
         cao 90px của nó

     ĐO TỪ MÃ GỐC CỦA MẪU (demo "Table with images"): header `h-12 px-3` chữ xám
     `text-muted-foreground` · cell `p-3 align-middle` · row `border-b
     hover:bg-muted/50` · bảng `text-sm` · ô đầu = ảnh + tên đậm vừa + dòng phụ
     `text-xs` xám · **KHÔNG có đường kẻ dọc** · cột cuối `text-right`.

     BA CHỖ CỐ Ý KHÔNG LÀM GIỐNG MẪU — nói rõ ra đây để lượt sau khỏi tưởng bỏ sót:

     ① ẢNH VẪN VUÔNG BO GÓC, KHÔNG TRÒN. Mẫu dùng ảnh tròn, nhưng Boss đã chốt
        thẳng 21/08/2026 cho block nhân viên: *"vẫn vuông bo góc, không tròn"* —
        lý do là bo tròn hẳn trông ngay ra giao diện máy dựng sẵn, thứ Boss đã chê
        NĂM lần. Hai lệnh này đá nhau, nên tôi giữ lệnh Boss chốt trực tiếp và
        BÁO LẠI để Boss quyết; đổi sang tròn chỉ cần một dòng ở đây.
     ② KHÔNG CÓ HOVER ĐỔI NỀN. Mẫu có `hover:bg-muted/50`. Nhưng bảng này dùng
        NỀN HÀNG để mang thông tin: đỏ nhạt = gấp · vàng = đã tiếp nhận · xanh =
        đã xong (Boss chốt 28/08). Luật ấy nặng (0,2,1); mọi cách viết hover tự
        nhiên đều nặng hơn và sẽ NUỐT MẤT màu trạng thái đúng lúc người ta rê
        chuột vào để đọc. Hiệu ứng đẹp không đáng đổi lấy một thông tin biến mất.
     ③ CỘT CUỐI KHÔNG CĂN PHẢI. Mẫu căn phải vì cột cuối của nó là số/hành động;
        cột cuối ở đây là CHIP trạng thái, căn phải thì chip rời khỏi cụm chữ và
        mắt phải nhảy ngang cả bảng để đọc.

     ⛔ BỎ KẺ DỌC PHẢI BỎ ĐÚNG CHỖ: `.dg-bang th, .dg-bang td` (css:4182) khai
        `border-right` cho MỌI bảng dạng Sheet trong app. Gỡ ở đó là gỡ cho cả
        chín bảng khác — nên chỉ gỡ trong phạm vi `.nv-sh-bang`.
     ══════════════════════════════════════════════════════════════════════════
     ⛔⛔ VÀ PHẢI VIẾT ĐỦ NẶNG. Lượt đầu tôi viết `.nv-sh-bang tbody td` (0,1,2) —
        đúng bằng `.sheet-moi tbody td` của khối Sheet, mà khối ấy đứng SAU trong
        file nên nó thắng. Đo được: đặt `padding:9px 12px` mà trình duyệt trả
        `4px 4px 4px 48px`, đặt `border-right:0` mà vẫn ra `1px`, đặt `height:44px`
        mà đầu bảng vẫn 25px. Không một lỗi nào báo — chỉ là luật không ăn.
        ⇒ Thêm `.sheet-moi` vào chính bộ chọn cho nặng hơn một bậc, và giữ luôn
          bản không có nó cho những bảng chưa khoác lớp ấy.
     ⛔ ĐỪNG ÉP `padding` GỘP: ô đầu mỗi hàng đang có `padding-left:48px` để chừa
        chỗ cho DẢI SỐ DÒNG. Ép gộp là dải số đè lên chữ. Chỉ đặt padding dọc và
        padding phải. */
  .nv-sh-bang { font-size:13px; }
  .nv-sh-bang.sheet-moi thead th, .nv-sh-bang thead th,
  .nv-sh-bang.sheet-moi tbody td, .nv-sh-bang tbody td { border-right:0; }
  /* ĐẦU BẢNG: ĐỤNG ĐÚNG MỘT THỨ — ĐỆM DỌC. Đo 16/09 mới vỡ ra, và hoá
     ra ba dòng tôi định đè đều là đè THỪA hay đè SAI:
       · `font-size:12px` + `font-weight:400` — luật chung đã đặt sẵn đúng thế, và
         mẫu originui cũng muốn thế. Viết lại 12,5px/500 là đẩy đầu bảng này LỆCH
         khỏi chín bảng còn lại mà chẳng gần mẫu hơn chút nào.
       · `color` — màu đầu bảng cố ý nằm trong `:where(.sheet-moi) :where(thead th)`
         độ nặng 0 (css:14721) để bảng nào có màu riêng thì màu riêng thắng. Ghi đè
         là cướp đúng cái quyền ấy — chính là vụ chữ trắng hoá xám nhạt trên nền
         navy đã phải vá hôm 11/09.
       · `padding-right:12px` — `.bang-keo-cot thead th` chừa 13px ấy để làm CHỖ CẦM
         KÉO CỘT. Bóp lại là bóp tay kéo: mất một thứ dùng được để đổi một thứ
         nhìn được.
     Còn đúng một việc thật: đầu bảng đang 25px (chữ 12px + đệm 4+4), chật hơn hẳn
     thân bảng 32px nên đầu và thân dính lại làm một mảng. Mẫu tách hai phần ấy ra.

     ⛔ PHẢI VIẾT NẶNG HƠN (0,2,2), KHÔNG PHẢI (0,2,1) — mốc đo 16/09.
        Luật chung `.sheet-moi[class] thead th` (css:14726) CỐ Ý tự nâng một bậc bằng
        `[class]` để thắng luật riêng của từng bảng. Tôi viết
        `.nv-sh-bang.sheet-moi thead th` (0,2,1) thì thua nó đúng một bậc — mà CSSOM
        VẪN NẠP luật đầy đủ nên không có lỗi nào báo: đặt 10px, trình duyệt trả 4px.
        Cách bắt: hỏi CSSOM `th.matches(r.selectorText)` cho MỌI luật có đặt
        padding/font, rồi đọc cả danh sách — grep không bao giờ thấy `[class]`.
        ⇒ Dùng lại đúng mẹo ấy, hai lần, để không phụ thuộc vào việc `sheetGan`
          còn khoác `sheet-moi` lúc chạy hay không.
     ⛔ Vẫn giữ `sticky` + nền của `.dg-bang thead th`, đừng gỡ: cuộn bảng mà mất
        hàng tiêu đề là lỗi nặng hơn hẳn phần thẩm mỹ này. */
  .nv-sh-bang[class][class] thead th { padding-block: 9px; }
  /* ⛔⛔ CHIỀU CAO VÀ ĐỆM CỦA Ô THÌ KHÔNG ĐỤNG — đo 16/09 mới biết, và đây là
     chỗ suýt làm hỏng một tính năng đang chạy.
     Thanh chức năng của bảng có ba mức cỡ ô (Thoáng 32 · Vừa 28 · Chật 24, Boss
     chốt 10/09). Mức ấy đi vào `--sheet-o-cao` / `--sheet-o-dem`, rồi luật
     `.sheet-moi ... tr.sheet-hang td { height: var(--sheet-o-cao) }` (0,3,3) áp
     xuống. Tôi đặt `padding-block:8px` thì trình duyệt vẫn trả `4px` — không phải
     luật yếu, mà vì chiều cao ô là THỨ NGƯỜI DÙNG ĐANG CHỈNH.
     ⇒ Ép cho giống mẫu là cướp mất ba cái nút ấy. Mẫu originui không có khái niệm
       "cỡ ô"; app thì có, và cái có thật thắng.
     Boss chốt "giữ kiểu mẫu, HÀNG VỪA PHẢI" — mức Thoáng 32px vốn đã là vừa phải,
     và ai muốn khác thì đã có nút. */
  .nv-sh-bang.sheet-moi tbody td, .nv-sh-bang tbody td {
    vertical-align:middle; font-size:13px;
  }
  /* Ô đầu theo mẫu: ảnh lớn hơn, tên đậm vừa, dòng phụ nhỏ và xám. */
  .nv-sh-bang .nv-sh-avt { width:32px; height:32px; }
  .nv-sh-bang .nv-sh-avt svg { width:19px; height:19px; }
  .nv-sh-bang .nv-sh-ai { gap:10px; }
  .nv-sh-bang .nv-sh-ai b { font-weight:500; font-size:13px; }
  /* (.nv-sh-viec cũ bỏ 09/09: ô ấy nay là .nv-sh-doi trải hai cột.) */
  /* ⭐ 28/08 chiều — MỖI VIỆC CON MỘT DÒNG. Cô Quỳnh chê kiểu nối "…; …; …" khó nhìn.
     ⛔ Ô này phải `vertical-align:top`: hàng nào có bốn việc con thì tên nhân viên
        canh giữa sẽ trôi xuống giữa cột, đọc ngang không thẳng hàng nữa. */
  /* (luật .nv-sh-viec cũ bỏ 09/09 — xem .nv-sh-doi bên dưới.) */
  /* ⏱️ MỘT LƯỚI HAI CỘT cho "Hoàn thành lúc" + "Công việc" — thay hai <ul> rời.
     Boss 08/09/2026: *"dòng nào của cột công việc nhân viên đã done và nó gạch thì
     dóng đúng thẳng ở cột thời gian"*.
     ⛔ ĐỪNG tách lại thành hai ô bảng: hai <td> khác nhau thì trình duyệt không dóng
        được từng dòng con của chúng, nên chữ vừa xuống dòng là lệch cả cột. Đây là
        lỗi đã đo thật ngày 09/09 (trượt ~1px mỗi dòng, và chữ dài đè cột bên cạnh).
     ⛔ `--nvsh-gio` phải DÙNG CHUNG cho tiêu đề cột 2 và cột đầu của lưới. Sửa một
        chỗ mà quên chỗ kia là tiêu đề lệch khỏi nội dung, nhìn như bảng vỡ. */
  .nv-sh-bang { --nvsh-gio:132px; }
  .nv-sh-bang th:nth-child(2) { width:var(--nvsh-gio); }
  .nv-sh-bang td.nv-sh-doi { vertical-align:top; padding-left:0; padding-right:0;
    padding-top:6px; white-space:normal; }
  .nv-sh-luoi { display:grid; grid-template-columns:var(--nvsh-gio) 1fr; align-items:start; }
  /* ⛔⛔ TRỪ RIÊNG Ô GỘP NÀY RA KHỎI LUẬT "mọi thứ trong ô về một dòng" CỦA CỤM SHEET.
     Boss 13/09: *"chuyển sang xem dạng sheet thì cột hoàn thành lúc và công việc đang
     bị lỗi xung đột trèn nhau"*.
     GỐC: bảng Công việc được khoác lớp `sheet-moi` LÚC CHẠY, nên nó ăn luôn hai luật
     của cụm Sheet:
       `.sheet-moi tbody tr.sheet-hang td > div  { display:inline-flex }`  (0,2,4)
       `.sheet-moi tbody tr.sheet-hang td > *    { max-height:22px }`
     `.nv-sh-luoi` chỉ có (0,1,0) nên THUA — lưới hoá `inline-flex`, ba cặp (giờ, việc)
     xếp NGANG thay vì hai cột dọc, và chữ của cột Công việc tràn đè lên vùng cột Hoàn
     thành lúc. Đo thật 13/09: ô giờ trong lưới chỉ còn 16px trong khi cột rộng 134px,
     lệch 114px — đúng cảnh Boss thấy.
     ⛔ ĐỪNG chữa bằng cách nới luật của cụm Sheet (bỏ `> div` hay hạ xuống `:where`):
        luật ấy đang giữ MỌI màn dạng sheet ở đúng một dòng, nới ra là hàng cao gấp đôi
        ở cả chục màn khác. Trừ đúng một ô ra mới là chữa gốc.
     ⛔ `max-height:none` phải đi kèm: gỡ mỗi `display` mà quên trần thì lưới bị xén
        còn 22px — lại đúng kiểu lỗi "gỡ một chiều, lỗi rơi sang chiều kia".
     Độ nặng: `.sheet-moi`+`tr.sheet-hang`+`td.nv-sh-doi`+`.nv-sh-luoi` = (0,4,3), hơn
     (0,2,4) của luật cụm Sheet nên thắng ở mọi chỗ đặt. */
  .sheet-moi tbody tr.sheet-hang td.nv-sh-doi > .nv-sh-luoi {
    display: grid;
    max-height: none;
    /* ⛔⛔ `align-items: start` KHÔNG PHẢI THỪA — bỏ nó là giờ hết dóng thẳng hàng.
       Luật cụm Sheet ở ~12845 đặt MỘT THỂ `display:inline-flex` VÀ `align-items:center`;
       ghi đè mỗi `display` thì `center` ở lại và đi theo lưới. Ô giờ của ý CHƯA XONG
       rỗng ruột (cao đúng 2px đệm) nên bị dồn xuống giữa hàng — đo thật 13/09: lệch
       9,4px. Và khi ý việc dài xuống nhiều dòng thì giờ rơi xuống GIỮA khối chữ thay
       vì dóng dòng đầu — đúng thứ Boss dặn giữ: *"dòng nào nhân viên đã done thì
       dóng đúng thẳng ở cột thời gian"*.
       ⛔ LỖI NÀY KHÔNG NHÌN RA ĐƯỢC Ở Ô RỖNG (không chữ thì không ai thấy nó nằm
          đâu) — chỉ lộ ra khi ép ý việc xuống nhiều dòng. Bài kiểm phải có cả hai ca. */
    align-items: start;
  }
  /* line-height dùng chung MỘT SỐ cho cả hai ô — hai số khác nhau chính là nguồn
     gốc lỗi trượt 1px mỗi dòng trước đây. Đổi một bên thì phải đổi cả hai. */
  .nv-sh-ogio { padding:1px 8px; line-height:1.45; white-space:nowrap; }
  .nv-sh-oviec { padding:1px 8px 1px 23px; line-height:1.45; position:relative;
    white-space:normal; overflow-wrap:anywhere; }
  /* Chấm đầu dòng vẽ tay chứ không dùng list-style: dấu chấm mặc định của trình
     duyệt to và đậm quá cho cỡ chữ 12.5px, nhìn rối hơn là dẫn mắt. */
  .nv-sh-oviec::before { content:"·"; position:absolute; left:12px; top:1px;
    color:var(--mo); font-weight:700; }
  .nv-sh-oviec.xong { color:var(--mo); text-decoration:line-through; }
  .nv-sh-chip { display:inline-block; padding:1px 8px; border-radius:999px; font-size:11.5px;
    line-height:1.75; white-space:nowrap; border:1px solid var(--vien-ro); color:var(--chu-mo); }
  .nv-sh-chip.gap { border-color:rgba(198,40,40,.4); color:#C62828; background:rgba(198,40,40,.08); }
  body.toi .nv-sh-chip.gap { border-color:rgba(239,154,154,.4); color:#EF9A9A; background:rgba(239,154,154,.1); }
  /* Chip tình trạng — chỉ đổi MÀU CHỮ, để nền của hàng nói phần còn lại.
     ⛔ Tên lớp là `tt-tiepnhan` (KHÔNG gạch dưới), khác mã dữ liệu `tiep_nhan`.
        Lấy qua `nvLopTT()`, đừng ghép `"tt-" + v.tinhTrang` — đã gây lỗi im lặng 21/08. */
  .nv-sh-chip.tt-done     { color:#2E7D32; border-color:rgba(46,125,50,.35); }
  .nv-sh-chip.tt-tiepnhan { color:#9A6B00; border-color:rgba(154,107,0,.35); }
  .nv-sh-chip.tt-cancelled{ color:var(--mo); }
  body.toi .nv-sh-chip.tt-done     { color:#A5D6A7; border-color:rgba(165,214,167,.35); }
  body.toi .nv-sh-chip.tt-tiepnhan { color:#E8C468; border-color:rgba(232,196,104,.35); }

  /* ⛔⛔ 20/09/2026 — ĐÃ BỎ NỀN MÀU CẢ HÀNG. Boss: *"trong công việc dạng sheet
     bạn bỏ màu đi được ko"*, và chốt bằng nút bấm là *"chỉ bỏ nền hàng"* —
     giữ nguyên chip "Quan trọng" / "Đã tiếp nhận" ở hai cột cuối.

     Vì sao bốn mảng màu ấy sai chỗ: bảng này là công cụ làm việc, mẫu gốc là
     Google Sheets (thiet-ke/BANG-MAU-VA-CHU.md). Tô nền cả hàng thì mọi dòng
     đều hét lên cùng lúc, mắt không còn chỗ nghỉ để đọc chữ — đúng thứ Boss đã
     chê nhiều lần là *"lộ ra là máy làm"*. Nay một hàng nói trạng thái bằng
     BA đường vẫn đủ rõ: vạch màu mảnh ở cột đầu · chip ở cột Tình trạng · chữ
     gạch ngang nếu đã huỷ.

     ⛔ GIỮ `var(--the)` cho MỌI hàng, đừng bỏ trắng luật này: bảng có cột ghim
        (`td.dg-dinh` dính bên trái khi cuộn ngang). Ô ghim mà trong suốt thì
        chữ của cột bên dưới chạy xuyên qua nó lúc cuộn.
     ⛔ VẠCH MÀU Ở CỘT ĐẦU (`box-shadow` ngay dưới) THÌ GIỮ — Boss bỏ NỀN, không
        bỏ màu. Vạch 3px là cách các công cụ cùng loại (Linear, Notion) đánh dấu
        hàng cần chú ý mà không làm ồn cả bảng.
     ⛔ Ô chú giải `.nv-sh-o` nay giải thích VẠCH ấy, nên đổi sang vẽ vạch bên
        trái thay vì tô đặc — không thì chú giải nói một đằng, bảng một nẻo.
     ⛔ CẢ MÁY TÍNH LẪN ĐIỆN THOẠI (Boss chốt). Khối `@media (max-width:640px)`
        bên dưới không khai lại nền hàng, nên bỏ ở đây là bỏ cho cả hai. */
  .nv-sh-hang > td { background:var(--the); }
  .nv-sh-huy > td { color:var(--mo); text-decoration:line-through; }
  /* Ô chú giải: vạch màu bên trái, khớp đúng vạch ở cột đầu của bảng.
     `.nv-sh-thuong` không có vạch nào nên để trống — đúng sự thật. */
  i.nv-sh-o.nv-sh-gap    { box-shadow:inset 3px 0 0 #C62828; }
  i.nv-sh-o.nv-sh-nhan   { box-shadow:inset 3px 0 0 #E8A800; }
  i.nv-sh-o.nv-sh-xong   { box-shadow:inset 3px 0 0 #00793A; }
  i.nv-sh-o.nv-sh-huy    { box-shadow:inset 3px 0 0 #9AA3AB; }
  /* Vạch màu ở cột đầu — chỗ mắt chạm trước khi đọc chữ. */
  .nv-sh-gap    > td.dg-dinh { box-shadow:inset 3px 0 0 #C62828; }
  .nv-sh-nhan   > td.dg-dinh { box-shadow:inset 3px 0 0 #E8A800; }
  .nv-sh-xong   > td.dg-dinh { box-shadow:inset 3px 0 0 #00793A; }
  .nv-sh-huy    > td.dg-dinh { box-shadow:inset 3px 0 0 #9AA3AB; }
  @media (max-width:640px) {
    /* `flex-wrap` nay đã khai ở luật chính nên không lặp lại nữa. Phần còn giữ ở đây
       là thứ CHỈ đúng cho điện thoại: bốn con số trải đều hết bề ngang, căn trái, bỏ
       nét ngăn — ở 390px mà giữ nét ngăn dọc thì bốn ô chật cứng dính vào nhau.
       ⛔ Sàn 240px của cột tên phải HẠ XUỐNG ở đây: màn 390px trừ lề chỉ còn ~330px,
          giữ sàn 240 thì avatar + tên vẫn vừa nhưng không còn chỗ thở. */
    .nv-bl { gap:9px 12px; padding:12px 13px; }
    .nv-bl-ten { flex:1 1 60%; min-width:0; }
    .nv-bl-so { flex:1 1 100%; order:3; margin-left:0; }
    .nv-bl-o { flex:1; min-width:0; align-items:flex-start; padding:0 8px 0 0; border-left:0; }
  }
  /* ── TRANG RIÊNG CỦA MỘT NGƯỜI ─────────────────────────────────────────── */
  .nv-ng { border:1px solid var(--vien); border-radius:var(--r-xl); background:var(--the); margin:10px 0 14px; }
  .nv-ng-dau { display:flex; align-items:center; gap:12px; padding:14px 16px; }
  .nv-ng-ten { display:flex; flex-direction:column; gap:2px; min-width:0; }
  .nv-ng-ten b { font-size:16px; font-weight:600; overflow-wrap:anywhere; }
  /* ⛔ Cùng luật với `.nv-bl-ten small`: không in hoa, không giãn chữ. Hai chỗ này
     hiện CÙNG MỘT dòng chức vụ của CÙNG MỘT người — lệch nhau là lộ ngay. */
  .nv-ng-ten small { font-size:11.5px; color:var(--mo); }
  /* Dải số kiểu bảng điều khiển: mỗi ô một con số, ngăn bằng một nét mảnh. */
  .nv-ng-so { display:flex; flex-wrap:wrap; border-top:1px solid var(--vien); }
  .nv-ng-o { flex:1 1 0; min-width:96px; padding:11px 16px; border-left:1px solid var(--vien); }
  .nv-ng-so > .nv-ng-o:first-child { border-left:0; }
  .nv-ng-o b { display:block; font-size:22px; font-weight:600; line-height:1.1;
    color:var(--chu); font-variant-numeric:tabular-nums; }
  .nv-ng-o i { font-size:11.5px; font-style:normal; color:var(--mo); }
  .nv-ng-o.khong b { color:var(--mo); font-weight:400; }
  .nv-ng-thanh { display:flex; flex-wrap:wrap; gap:8px; padding:12px 16px; border-top:1px solid var(--vien); }
  /* ⛔ 21/08 — nút KHÔNG được kéo dài hết hàng. Cô Quỳnh gửi ảnh: nút "Giao việc cho
     …" trải nguyên bề ngang màn hình như một dải màu, nhìn rất thô. `.nut-chinh` ở
     nơi khác có luật nở hết hàng, nên phải chặn TẠI ĐÂY. */
  .nv-ng-thanh > button { flex:0 0 auto; width:auto; align-self:flex-start; }
  /* Chip "Mới" trên thẻ việc — việc vừa giao trong 24 giờ và chưa ai đụng tới.
     ⛔ Chữ, không phải nhãn dán màu. */
  .nv-moi { font-size:9.5px; font-weight:600;
    color:var(--chu); background:none; border:1px solid var(--chu); border-radius:var(--r-xl); padding:0 8px; }

  /* 📊 Báo cáo công việc một người. */
  .nv-bc-luoi { display:grid; gap:10px; grid-template-columns:repeat(auto-fit, minmax(150px, 1fr)); }
  .nv-bc-o { border:1px solid var(--vien); border-radius:var(--r-lg); padding:10px 12px; }
  .nv-bc-n { font-size:11.5px; color:var(--mo); }
  .nv-bc-v { font-size:22px; font-weight:700; color:var(--muc); font-variant-numeric:tabular-nums; margin-top:2px; }
  .nv-bc-p { font-size:11.5px; color:var(--mo); margin-top:2px; }
  .nv-bc-nhac { font-size:12px; color:var(--mo); line-height:1.6; margin:12px 0 0; }

  /* ✍ Bộ soạn chi tiết công việc — mỗi việc một ô. */
  .nv-an-hoan-toan { position:absolute; width:1px; height:1px; padding:0; margin:-1px;
    overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
  .nv-ct-soan { border:1px solid var(--vien); border-radius:var(--r-lg); padding:8px; background:var(--the); }
  .nv-ct-ds { display:flex; flex-direction:column; gap:5px; }
  .nv-ct-d { display:flex; align-items:center; gap:7px; }
  .nv-ct-stt { flex:none; width:20px; text-align:center; font-size:11.5px; color:var(--mo);
    font-variant-numeric:tabular-nums; }
  .nv-ct-o { flex:1 1 auto; min-width:0; border:1px solid var(--vien); border-radius:var(--r-md);
    padding:7px 9px; font:inherit; font-size:13.5px; background:var(--the); color:var(--chu); }
  .nv-ct-o:focus { outline:2px solid var(--xanh); outline-offset:-2px; }
  .nv-ct-bo { flex:none; width:26px; height:26px; border:1px solid var(--vien); border-radius:var(--r-md);
    background:var(--the); color:var(--mo); cursor:pointer; font:inherit; font-size:14px; line-height:1; }
  .nv-ct-bo:hover { border-color:var(--do); color:var(--do); }
  .nv-ct-thanh { display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin-top:9px;
    padding-top:9px; border-top:1px solid var(--vien); }
  .nv-ct-them { border:1px solid var(--xanh); background:none; color:var(--xanh); border-radius:var(--r-md);
    padding:4px 11px; font:inherit; font-size:12.5px; font-weight:700; cursor:pointer; }
  .nv-ct-them:hover { background:var(--xanh); color:#fff; }
  .nv-ct-them:hover i { background:#fff; }
  .nv-ct-dem { font-size:12px; color:var(--mo); }
  .nv-ct-mau { margin-left:auto; display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
  .nv-ct-chonmau { width:auto; min-width:150px; max-width:230px; padding:4px 8px; font-size:12.5px; }
  .nv-ct-luumau, .nv-ct-bomau { border:1px solid var(--vien); background:var(--the); color:var(--muc);
    border-radius:var(--r-md); padding:4px 10px; font:inherit; font-size:12.5px; font-weight:700; cursor:pointer; }
  .nv-ct-luumau:hover { border-color:var(--xanh); color:var(--xanh); }
  .nv-ct-bomau:hover { border-color:var(--do); color:var(--do); }
  @media (max-width:640px) { .nv-ct-mau { margin-left:0; flex:1 1 100%; } }

  /* THU GỌN (cô Quỳnh 01/08: "block bé hơn để chứa nhiều việc trong màn hình"). */
  .nv-ds { display:flex; flex-direction:column; gap:6px; }
  /* ⛔ 21/08/2026 — BỎ HẾT NỀN MÀU TRÊN THẺ VIỆC (cô Quỳnh: giao diện phải trắng
     đen kiểu doanh nghiệp). Bản cũ tô nền cam nhạt cho việc quá hạn và việc quan
     trọng: mở màn ra là một mảng cam, đúng thứ cô gọi là "màu mè, lộ ra UI của AI".
     Nay phân biệt bằng ĐỘ ĐẬM CỦA NÉT VIỀN TRÁI, không bằng nền:
       · thường     → nét trái xám nhạt
       · quan trọng → nét trái đen đậm
       · quá hạn    → nét trái đen đậm + chữ "Quá hạn" màu đỏ trong dòng hạn
       · đã xong    → cả thẻ mờ đi
     Đừng đổi lại thành nền màu. */
  .nv-the { border:1px solid var(--vien); border-left:3px solid var(--vien); border-radius:var(--r-lg);
    padding:8px 12px; background:var(--the); font-size:13px; }
  /* ══════════════════════════════════════════════════════════════════════════════
     ⭐⭐ VIỆC QUAN TRỌNG / KHẨN CẤP PHẢI ĐẬP VÀO MẮT — cô Quỳnh 21/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     *"các công việc nào mà khẩn cấp/quan trọng thì phải có màu nổi bật như đỏ lên
     nhưng ko được màu quá mức gây khó nhìn chỉ làm cho nó nổi bật dễ nhìn và dễ để
     ý vì nó là việc quan trọng."*

     Ba nấc, cố ý DÙNG CHUNG MỘT SẮC ĐỎ chứ không mỗi nấc một màu — mắt chỉ cần
     nhớ "đỏ = phải lo", đậm dần là gấp dần:
       · thường     → nét trái xám nhạt, nền trắng          (không đổi)
       · quan trọng → nét trái ĐỎ 4px + nền đỏ ~3% + chip đỏ
       · quá hạn    → như trên, nền đậm hơn một nấc + chữ "QUÁ HẠN" đỏ đậm

     ⛔ NỀN CHỈ ĐƯỢC NHẠT NHƯ THẾ. Bản trước 21/08 đổ nền cam #FFF6EC cho thẻ quá
        hạn và vàng #FFFCF6 cho việc quan trọng — mở màn ra là một rổ màu, đúng thứ
        cô Quỳnh gọi là "màu mè, lộ ra UI của AI", và đã gỡ. Lần này khác ở chỗ:
        MỘT sắc duy nhất, nhạt hơn hẳn, và chỉ đắp cho việc THẬT SỰ gấp — trên sổ
        thật phần lớn việc là "Bình thường" nên màn hình vẫn trắng là chính.
     ⛔ Đừng bỏ nét viền trái mà chỉ để nền: người mù màu đỏ-lục nhìn nền 3% gần
        như không thấy gì. Nét dày 4px thì thấy được kể cả khi không phân biệt màu.
     ══════════════════════════════════════════════════════════════════════════════ */
  /* ⭐ 21/08/2026 — NÉT TRÁI HỔ PHÁCH = ĐÃ CÓ NGƯỜI NHẬN.
     Cô Quỳnh phải liếc một cái là biết việc nào có người ôm, không phải soi lại
     chữ trong ô chọn. Đặt TRƯỚC hai luật đỏ bên dưới là CỐ Ý: cùng độ ưu tiên thì
     luật viết sau thắng, nên việc quan trọng / quá hạn vẫn giữ nét ĐỎ.
     ⛔ Đừng đảo thứ tự. Gấp quan trọng hơn "đã có người nhận" — nhận rồi mà quá
        hạn thì vẫn phải đỏ, không thì tín hiệu gấp bị màu hổ phách nuốt mất. */
  .nv-the.danhan { border-left-color:var(--nhan-vien); border-left-width:4px; }
  .nv-the.ghim { border-left-color:var(--do); border-left-width:4px; background:var(--do-nen); }
  .nv-the.quahan { border-left-color:var(--do); border-left-width:4px; background:var(--do-nen2); }
  .nv-ghim { font-size:9.5px; font-weight:700;
    color:var(--do); background:none; border:1px solid var(--do); border-radius:var(--r-xl); padding:1px 8px; }
  /* ⛔ Thẻ đã xong thì THÔI đỏ, dù mức độ vẫn là quan trọng — việc xong rồi không
     còn gì để gấp, để đỏ là làm loãng đúng cái tín hiệu vừa dựng lên. */
  .nv-the.xong.ghim, .nv-the.xong.quahan { background:var(--the); border-left-color:var(--vien); }
  .nv-the.xong { opacity:.55; border-left-color:var(--vien); }
  /* 🗑 Thẻ trong thùng rác — nền chìm hẳn, để không lẫn với việc đang chạy (11/08/2026). */
  .nv-the.rac { border-left-color:var(--vien); background:var(--nen2); }
  /* ☑ Tick chọn + xoá hàng loạt trong Kho đã xử lý (11/08/2026). */
  .yc-tick { width:16px; height:16px; margin-right:6px; flex:none; cursor:pointer; }
  .yc-chon-het { display:inline-flex; align-items:center; gap:6px; font-size:13px; cursor:pointer; }
  .yc-chon-het input { width:16px; height:16px; cursor:pointer; }
  .yc-xoa-lo[disabled] { opacity:.45; cursor:not-allowed; }
  .yc-xoa-lo:not([disabled]) { color:#C62828; border-color:#E8A5A5; }
  .nv-rac-con { margin-left:auto; font-size:12px; color:var(--mo); }
  #nvMoRac.dang-mo { background:var(--nen2); border-color:var(--vien2); }
  .nv-the-dau { display:flex; gap:7px; align-items:center; flex-wrap:wrap; }
  .nv-ngay { font-size:12.5px; font-weight:600; color:var(--chu); }
  .nv-dau-phai { margin-left:auto; display:flex; gap:5px; }
  /* ⛔ 21/08/2026 — HAI Ô SỔ XUỐNG NÀY TRƯỚC ĐÂY ĐỔ NỀN PASTEL (cam · lam · lục ·
     hồng). Trên một màn 30 thẻ việc thì thành một rổ màu. Nay trắng viền mảnh; thứ
     phân biệt là CHỮ trong ô, vốn đã nói rõ "Quan trọng / Khẩn cấp", "Pending",
     "Đã xong"… Mức cao thì nét viền đậm lên, không đổi nền. */
  .nv-sel { font-size:11.5px; font-weight:500; padding:2px 8px; border-radius:var(--r-md);
    border:1px solid var(--vien); background:var(--the); color:var(--chu); cursor:pointer; }
  .nv-md-sel, .nv-tt-sel { background:var(--the); color:var(--chu); border-color:var(--vien); }
  .nv-md-sel.qt, .nv-md-sel.gap { border-color:var(--chu); font-weight:600; }
  /* ⭐⭐ 21/08/2026 — "ĐÃ TIẾP NHẬN" NAY LÀ HỔ PHÁCH, KHÔNG CÒN XÁM.
     ──────────────────────────────────────────────────────────────────────────────
     Cô Quỳnh: *"cái đã tiếp nhận phải rõ màu khác để đỡ phải nhìn đọc lại ô đó đã
     chọn tiếp nhận chưa chữ bé khó đọc"*.
     Bản cũ phân biệt bằng nền xám `--nen2` + viền đậm — cùng họ xám với hai trạng
     thái kia, nên muốn biết việc đã có người nhận chưa thì BẮT BUỘC phải đọc chữ
     11,5px trong ô. Đúng thứ cô Quỳnh than.
     Nay: chữ hổ phách đậm, nền hổ phách nhạt, viền hổ phách, cỡ chữ nhích lên
     12,5px và in đậm 700. Liếc là thấy, khỏi đọc.
     ⛔ CHỈ TRẠNG THÁI NÀY ĐƯỢC ĂN MÀU. Pending và Done vẫn xám: tô cả ba là hết
        cái nào nổi, quay lại đúng chỗ cũ. */
  .nv-tt-sel.tt-tiepnhan { background:var(--nhan-nen); border-color:var(--nhan-vien);
    color:var(--nhan-chu); font-weight:700; font-size:12.5px; }
  .nv-tt-sel.tt-done, .nv-tt-sel.tt-cancelled { color:var(--mo); }
  /* Dòng "ai đã tiếp nhận, lúc nào" trên thẻ việc.
     ⛔ 21/08/2026 — ĐỔI TỪ XÁM SANG HỔ PHÁCH cho khớp ô chọn tình trạng ở trên.
        Hai chỗ này luôn nói cùng một chuyện; để hai màu khác nhau là bắt người đọc
        tự nối lại. Cỡ chữ 11,5 → 12,5px vì cô Quỳnh chê *"chữ bé khó đọc"*. */
  .nv-danhan { font-size:12.5px; font-weight:700; color:var(--nhan-chu);
               background:var(--nhan-nen); border:1px solid var(--nhan-vien);
               border-radius:var(--r-xl); padding:1px 9px; white-space:nowrap; }
  .nv-ct { list-style:none; margin:3px 0; padding:0; }
  .nv-ct li { display:flex; gap:6px; align-items:flex-start; font-size:13px; line-height:1.35; padding:1px 0; }
  .nv-ct li input { margin:2px 0 0; flex:none; }
  .nv-ct li.xong span { text-decoration:line-through; color:var(--mo); }
  .nv-ct-rong { color:var(--mo); font-size:12px; }
  .nv-chan { display:flex; gap:12px; flex-wrap:wrap; margin-top:3px; }
  .nv-han { font-size:11.5px; color:var(--mo); }
  /* Chỗ màu DUY NHẤT còn lại của thẻ việc: chữ báo quá hạn. */
  .nv-han.do { color:var(--do); font-weight:700; }
  .nv-cuatoi { font-size:11px; color:var(--chu); font-weight:600; }
  /* thẻ phụ đạo */
  .pd-hs { font-size:13.5px; margin:2px 0; }
  .pd-dong { font-size:12.5px; color:#455A64; margin:2px 0; line-height:1.5; }
  .pd-nhan { display:block; color:var(--mo); font-weight:600; }   /* nhãn 1 dòng, nội dung xuống dòng dưới */
  .pd-cols { display:flex; gap:8px; flex-wrap:wrap; margin-top:5px; }
  .pd-cot { display:flex; flex-direction:column; gap:2px; font-size:11px; color:var(--mo); }
  .pd-cot select { font-size:11.5px; padding:2px 5px; }
  .pd-goi { background:#E3F2FD; border:1px solid #90CAF9; border-radius:var(--r-md); padding:8px 12px; font-size:12.5px; color:#1565C0; margin:0 0 10px; }
  .pd-chua { font-size:12px; color:var(--mo); font-style:italic; margin:3px 0; }
  .pd-dabiet { font-size:12px; color:#2E7D32; font-weight:700; align-self:center; }
  /* mẫu câu (chèn nhanh vào ô Kết quả) */
  .pd-maubar { display:flex; flex-wrap:wrap; gap:6px; align-items:center; margin:6px 0 2px; }
  .pd-mau-nhan { font-size:12px; color:var(--mo); }
  .pd-mau-chip { font-size:12.5px; background:#E8F4F2; border:1px solid #B2DFDB; border-radius:var(--r-xl); padding:3px 10px; cursor:pointer; }
  .pd-mau-chip:hover { background:#D0EBE7; }
  .pd-mau-xoa { color:#C62828; cursor:pointer; margin-left:3px; font-size:11px; }
  /* 🆕 Nhắc phụ đạo "nhìn như Sheet / Lịch thi" (03/08/2026) — dùng chung bảng .dg-*. */
  .pd-dinh-lop { display:block; font-size:11px; color:var(--mo); }
  /* ⛔⛔ 16/09/2026 — MỜ TỪNG Ô, KHÔNG MỜ CẢ HÀNG. Boss giao (việc 4/11):
     *"chữ mờ hàng đã phụ đạo đè lên dòng dưới khi mở ô"*, và chốt bằng nút bấm:
     **"nền đục hẳn, chữ đậm lại như bình thường"**.
     ──────────────────────────────────────────────────────────────────────────
     GỐC LÀ MỘT CHỮ `opacity` ĐẶT SAI CHỖ. Bản cũ là `.pd-hang-xong{opacity:.6}`
     — đặt trên `<tr>`. Mà `opacity` của CHA thì con KHÔNG GỠ LẠI ĐƯỢC: nó không
     phải thứ kế thừa để ghi đè, nó là một lớp vẽ đã pha sẵn rồi mới đặt xuống
     trang. Viết `td.sheet-o-dang{opacity:1}` là vô nghĩa — ô con có đục đến mấy
     thì cả lớp vẽ vẫn bị nhân với 0,6 một lần nữa.
     ⇒ Hạ `opacity` xuống từng `<td>`. Nhìn y hệt bản cũ (mọi ô trong hàng đều
       mờ 0,6), nhưng nay gỡ lại được cho ĐÚNG ô đang mở.

     ĐO THẬT 16/09 (Nhắc phụ đạo, 14 buổi, 7 buổi "Đã phụ đạo", ô Kết quả chữ dài):
        hàng opacity 0,6 · ô opacity 1 (vô dụng, vì cha đã pha)
        nền ô  : rgba(0,0,0,0)   ← TRONG SUỐT, nên nhìn xuyên xuống dòng dưới
        nền ruột: rgba(0,0,0,0)  ← ô nở cao 40px → 80px mà vẫn trong suốt
     Hai chữ "đè lên dòng dưới" của Boss chính là chỗ này: ô nở ĐÚNG là nằm trên
     (đo `elementFromPoint` ở nửa dưới ô trả về chính nó), nhưng vì không có nền
     nên chữ dòng dưới hiện xuyên qua, hai lớp chữ chồng nhau.

     ⛔ PHẢI TÔ NỀN CẢ Ô LẪN RUỘT. Ruột (`textarea`) mới là thứ nở ra và phủ lên
        dòng dưới; tô mỗi `<td>` thì phần ruột tràn khỏi ô vẫn trong suốt.
     ⛔ `--the` chứ đừng `#fff`: app có chế độ tối, gõ trắng cứng là ô nở loè
        một mảng sáng giữa bảng tối. */
  .pd-hang-xong { opacity:1; }
  .pd-hang-xong > td { opacity:.6; }
  /* ⛔⛔ 20/09/2026 — CỘT GHIM TÊN HỌC SINH PHẢI ĐỤC. Boss báo:
     *"cột cố định tên học sinh ở đầu tiên… khi tôi kéo bảng sang bên phải thì những
     cái chữ mờ nó đang bị xung đột với cả tên cột vốn dĩ phải không được mờ và để
     hở chữ đằng sau"*.
     ──────────────────────────────────────────────────────────────────────────
     CÙNG MỘT CĂN BỆNH với khối ⛔⛔ ngay trên, chỉ khác chỗ phát: `opacity:.6`
     ở dòng `> td` hạ luôn cả NỀN của ô ghim xuống 60%. Ô ghim thì `position:sticky`
     nên nó đứng yên trong lúc các cột khác trượt QUA BÊN DƯỚI nó — nền trong suốt
     là chữ của cột đang trượt hiện xuyên lên, hai lớp chữ chồng nhau.
     Hàng tiêu đề KHÔNG bị: nó không mang `.pd-hang-xong`.
     ĐO THẬT 20/09 ở màn 390px (Chrome thật, 1 buổi "Đã phụ đạo"):
        td.dg-dinh  opacity 0,6 · nền rgb(240,238,234) → pha còn 60% = nhìn xuyên
        th đầu bảng opacity 1   · nền rgb(255,255,255) → đục, không sao
     ⛔ CHỈ GỠ `opacity`, ĐỪNG GỠ VẺ MỜ. Boss chốt bằng nút: **"giữ mờ, chỉ làm nền
        đặc lại"** và **"giữ độ đậm như cũ"**. Nên nền về đục, còn chữ chuyển sang
        màu `--mo` để mắt vẫn đọc ra "buổi này xong rồi".
     ⛔ `--the` chứ đừng `#fff`: app có chế độ tối.
     ⛔ Đặt SAU dòng `> td { opacity:.6 }` và có thêm một lớp nữa nên chắc chắn
        thắng; đừng đảo lên trên. */
  .pd-hang-xong > td.dg-dinh { opacity:1; background:var(--the); color:var(--mo); }
  .pd-hang-xong > td.sheet-o-dang,
  .pd-hang-xong > td.sheet-o-bung,
  .pd-hang-xong > td:focus-within { opacity:1; background:var(--the); }
  .pd-hang-xong > td.sheet-o-dang textarea,
  .pd-hang-xong > td.sheet-o-bung textarea,
  .pd-hang-xong > td:focus-within textarea,
  .pd-hang-xong > td.sheet-o-dang input,
  .pd-hang-xong > td.sheet-o-bung input,
  .pd-hang-xong > td:focus-within input { background:var(--the); }
  /* ══ 👋 TIỄN HÀNG ĐI — Boss chốt 16/09/2026 (việc 6a, 6b) ══════════════════════
     Boss: bấm Huỷ thì *"hàng thu bé lại rồi biến mất"*; Đã phụ đạo + đủ ba ô Done
     thì *"highlight xanh phủ kín hàng rồi biến mất"*. Tốc độ Boss chốt bằng nút:
     **vừa phải, khoảng 0,6 giây** — nên 0,6s, đừng tự chỉnh cho "mượt hơn".

     ⛔⛔ ĐỌC KHỐI `.pd-hang-xong` NGAY TRÊN TRƯỚC KHI SỬA CHỖ NÀY. Ở đó `opacity`
        đã được hạ xuống TỪNG `<td>` có chủ đích (opacity của cha thì con không gỡ
        lại được). Nếu ở đây ta đặt `opacity` lên `<tr>` thì lập tức dựng lại đúng
        cái bẫy ấy: ô đang mở không sáng lên được nữa.
        ⇒ Hiệu ứng này cũng chạy TRÊN TỪNG `<td>`, không chạm `<tr>`.

     ⛔ KHÔNG hoạt hoạ `height` của `<td>`: chiều cao ô trong bảng do cả hàng quyết
        định, đặt height lên ô là trình duyệt làm ngơ. Thu nhỏ bằng `padding` +
        `font-size` + `transform: scaleY()` — cái nhìn được là "hàng xẹp xuống".
     ⛔ `overflow:hidden` là BẮT BUỘC: ruột ô (textarea) cao hơn ô, không cắt thì
        lúc ô xẹp chữ vẫn thò ra, trông như hàng vỡ chứ không phải hàng biến.

     ⛔ MÁY TẮT HIỆU ỨNG thì phải hết sạch thời gian, không phải rút ngắn. Hàm
        `pdTienHang` ĐỌC `animation-duration` của chính hàng ấy để biết chờ bao
        lâu — để 0s ở đây là nó vẽ lại ngay, đúng ý "không có hiệu ứng". */
  /* ══ 🎞 VIẾT LẠI 18/09/2026 — Boss: *"hơi xấu, làm cho nó mượt và không khựng
     và nét smooth, và lúc nó biến mất là có cả thêm hiệu ứng blur nữa để tránh
     nhìn thấy nét gấp"*. Boss chốt bằng nút: **mờ + nhoè tại chỗ TRƯỚC, rồi mới
     xẹp** · nhoè vừa · giữ 0,6 giây · vệt xanh giữ nhưng dịu hơn · nhịp chậm dần
     về cuối · hàng dưới trượt lên có đà.

     ⛔⛔ ĐO THẬT 18/09 mới ra thủ phạm, KHÁC hẳn thứ tôi đoán ban đầu. Quay từng
        khung hình (requestAnimationFrame) bản cũ:
            2ms cao 49px → 596ms cao 41px → rồi ĐỨNG IM 41px
        Hàng chỉ co được **8px** rồi nằm im suốt 300ms cuối, sau đó `veLaiGiuUI`
        vẽ lại và nó biến TỪ 41px XUỐNG 0 trong một khung hình. **Cú tụt 41px ấy
        chính là "nét gấp" Boss nhìn thấy** — không phải do nhịp hay do thiếu blur.
     ⛔ VÌ SAO chỉ co 8px: chiều cao ô đến từ `height: var(--sheet-o-cao)` — con số
        NGƯỜI DÙNG TỰ KÉO CHỈNH. Bản cũ animate `padding` + `font-size`, hai thứ
        ấy chỉ ăn được phần đệm; `height` giữ nguyên phần còn lại. Chú thích cũ đã
        ngờ điều này nhưng chưa ai quay khung hình ra để thấy.
     ⇒ Cho `height` về 0 là CẦN nhưng CHƯA ĐỦ. Đo lại sau khi sửa: hàng chỉ xuống
        tới 40px rồi đứng im. **`height` trên một ô bảng hành xử như chiều cao TỐI
        THIỂU**, không phải chiều cao thật — ruột ô còn cao bao nhiêu thì ô còn cao
        bấy nhiêu, dù đã `height:0`. Mỗi hàng phụ đạo có `<select>`, `<textarea>`,
        `<button>`; ba thứ ấy có chiều cao riêng nên `font-size:0` không đụng tới.
     ⇒ Nên phải có THÊM animation `pdRuot` co chính ruột ô (`> td > *`), chạy đồng
        nhịp với `pdXep`. `max-height` mới là thứ thắng được chiều cao riêng của ô
        nhập liệu. ⛔ Đừng bỏ bước này rồi tin vào bài đo chỉ canh độ giật giữa hai
        khung hình: lúc ấy hiệu ứng mượt thật, nhưng cú tụt 40px→0 khi vẽ lại
        vẫn còn nguyên — bài đo phải canh **chiều cao cuối ≤ 2px**.
     ⛔ Giá trị trong @keyframes thắng luật thường nên không cần `!important`. Chỉ
        khai ở khung cuối để nội suy từ chiều cao thật — ⛔ đừng gõ cứng số px,
        người dùng đã tự kéo chỉnh.

     ⛔ HAI ANIMATION CHỒNG NHAU, KHÔNG PHẢI MỘT. Boss muốn "mờ+nhoè TRƯỚC, rồi
        xẹp". Gộp vào một @keyframes thì `height` nội suy đều suốt cả 0,6 giây,
        tức xẹp ngay từ đầu — sai ý. Tách hai chặng nối đuôi bằng `animation-delay`
        mới đúng: 0,25s mờ nhoè tại chỗ → 0,35s xẹp xuống.
     ⛔ Bỏ `transform: scaleY` của bản cũ: nay `height` co thật nên scaleY là lớp
        biến dạng thừa, chồng lên nhau làm chữ méo lúc đang mờ.
     ══════════════════════════════════════════════════════════════════════════ */
  @keyframes pdNhoe {
    0%   { opacity:1; filter:blur(0);     }
    100% { opacity:.42; filter:blur(2.4px); }
  }
  @keyframes pdXep {
    0%   { opacity:.42; filter:blur(2.4px); }
    /* Nhoè đậm dần trong lúc xẹp — mép hàng mờ đi nên mắt không bắt được nét gấp. */
    100% { opacity:0; filter:blur(5px);
           height:0; padding-top:0; padding-bottom:0; font-size:0; border-width:0;
           /* Thẻ inline (`<b>`, `<span>`) không nhận `max-height`; chỉ `line-height`
              mới hạ được chiều cao dòng của chúng về 0. */
           /* ⛔ `min-height` cũng phải về 0. Đo 18/09: sau khi pad/viền/line-height
              đều đã 0 mà mọi ô vẫn đứng ở 6px — đúng bằng sàn `min-height`. */
           line-height:0; min-height:0; }
  }
  /* Vệt xanh báo "đã xong". Dịu hơn bản cũ: bản cũ nhảy thẳng sang #C8E6C9 ở 30%
     rồi #A5D6A7 ở 55% — hai bậc màu thấy rõ. Nay một dải liền và nhạt hơn. */
  /* Co chính ruột ô — xem khối chú thích trên. Dùng `max-height` chứ không `height`,
     vì `<select>`/`<textarea>`/`<button>` đều có chiều cao riêng mà `max-height` thắng.
     ⛔ Khung đầu phải là một con số đủ lớn, không phải `none` — `none → 0` không nội
     suy được, nó nhảy một phát, đúng cái nét gấp đang đi chữa. */
  @keyframes pdRuot {
    0%   { max-height:120px; }
    100% { max-height:0; padding-top:0; padding-bottom:0;
           margin-top:0; margin-bottom:0; min-height:0; border-width:0; }
  }
  /* ⛔ `> td > *` (con TRỰC TIẾP) KHÔNG ĐỦ — đo ra còn 20px. Icon `<i class=ic-nguoi>`
     nằm trong `<b>`, tức con CẤP HAI, và nó là inline-block có `height` cứng nên
     `font-size:0` của ô không co nó lại. Phải với tới MỌI con cháu. */
  .pd-hang.pd-tien-huy > td *,
  .pd-hang.pd-tien-xong > td * {
    overflow:hidden;
    animation:pdRuot .35s .25s cubic-bezier(.22,.61,.36,1) forwards;
  }
  @keyframes pdXanh {
    0%   { background:rgba(200,230,201,0);   }
    100% { background:rgba(200,230,201,.85); }
  }
  /* ⛔ 6px CUỐI CÙNG NẰM Ở CHÍNH `<tr>`, KHÔNG PHẢI Ở Ô — đo 18/09/2026: mọi ô đã
     về pad 0 · viền 0 · line-height 0 · font 0 · min-height 0 mà vẫn đứng ở 6px,
     và CSSOM cho thấy KHÔNG luật nào khác đặt chiều cao cho ô. Tức 6px là sàn của
     hàng, do thuật toán bảng cấp. Hạ nốt trên `<tr>`. */
  @keyframes pdHangXep {
    100% { height:0; line-height:0; font-size:0; }
  }
  .pd-hang.pd-tien-huy,
  .pd-hang.pd-tien-xong {
    animation:pdHangXep .35s .25s cubic-bezier(.22,.61,.36,1) forwards;
  }
  .pd-hang.pd-tien-huy > td,
  .pd-hang.pd-tien-xong > td {
    overflow:hidden;
    /* Chỉ khai `will-change` cho thứ ĐANG animate. Khai `transform` như bản cũ là
       bảo trình duyệt dựng lớp riêng cho một thuộc tính không còn dùng nữa. */
    will-change:opacity, filter, height;
    /* Nhịp chậm dần về cuối (Boss chốt) — chạy nhanh lúc đầu rồi dừng êm, giống
       vật thật. `ease-in` của bản cũ thì ngược: kết thúc đúng lúc nhanh nhất. */
    animation-timing-function:cubic-bezier(.22,.61,.36,1);
    animation-fill-mode:forwards;
    animation-name:pdNhoe, pdXep;
    animation-duration:.25s, .35s;
    animation-delay:0s, .25s;
  }
  /* Vệt xanh chạy song song suốt cả hai chặng, chỉ thêm cho nút Xong. */
  .pd-hang.pd-tien-xong > td {
    animation-name:pdNhoe, pdXep, pdXanh;
    animation-duration:.25s, .35s, .3s;
    animation-delay:0s, .25s, 0s;
  }
  /* ⛔ Ô đang mở được `.pd-hang-xong > td` tô nền `var(--the)` — nền ấy đè mất màu
     xanh của hiệu ứng. Lúc đang tiễn thì hiệu ứng phải thắng. */
  .pd-hang.pd-tien-xong > td.sheet-o-dang,
  .pd-hang.pd-tien-xong > td.sheet-o-bung,
  .pd-hang.pd-tien-xong > td:focus-within { background:transparent; }
  @media (prefers-reduced-motion: reduce) {
    /* Không có hiệu ứng, và `pdTienHang` đọc ra 0s nên vẽ lại ngay. */
    .pd-hang.pd-tien-huy > td, .pd-hang.pd-tien-xong > td { animation:none; opacity:0; }
    .pd-hang.pd-tien-huy, .pd-hang.pd-tien-xong { animation:none; }
    .pd-hang.pd-tien-huy > td *,
    .pd-hang.pd-tien-xong > td * { animation:none; }
  }

  /* ══ 🧱 CỘT "LỊCH SỬ PHỤ ĐẠO" — Boss chốt 16/09/2026 (việc 6d) ═════════════════
     Boss chốt bằng nút: mỗi lần MỘT block · hiện NGÀY NGẮN · MỚI NHẤT ĐỨNG ĐẦU ·
     nhiều block thì MỘT DÒNG, CUỘN NGANG trong ô.
     ⛔ `flex-wrap:nowrap` + `overflow-x:auto` là đúng ý "một dòng, cuộn ngang".
        Đổi sang `wrap` là hàng của em học nhiều buổi cao vống lên — Boss đã chọn
        KHÔNG muốn thế.
     ⛔ `max-width` phải có, không thì ô tự nong theo số block và bảng tràn ngang. */
  .pd-ls-cot { max-width:230px; }
  .pd-ls-day { display:flex; flex-wrap:nowrap; gap:4px; overflow-x:auto; padding-bottom:2px;
    scrollbar-width:thin; }
  .pd-ls-trong { color:var(--mo); }
  .pd-ls-block { flex:0 0 auto; display:inline-block; padding:2px 8px; border-radius:6px;
    font-size:11.5px; font-weight:700; line-height:1.5; white-space:nowrap;
    border:1px solid transparent; font-family:inherit; }
  .pd-ls-block.xong { background:#E8F5E9; color:#2E7D32; border-color:#A5D6A7; }
  .pd-ls-block.huy  { background:#FFEBEE; color:#C62828; border-color:#EF9A9A; }
  /* Buổi CHỜ vẫn phải có mặt, không thì dãy block lệch với cột "Số lần hẹn" ngay
     bên cạnh và người đọc tưởng app đếm sai. Trung tính, và không bấm được. */
  .pd-ls-block.cho  { background:var(--nen2,#F1F3F5); color:var(--mo); border-color:var(--vien); }
  .pd-ls-block.bam  { cursor:pointer; }
  .pd-ls-block.bam:hover  { filter:brightness(.94); }
  .pd-ls-block.bam:active { transform:translateY(1px); }
  .pd-ls-block.bam:focus-visible { outline:2px solid var(--chinh,#2E7D32); outline-offset:1px; }
  .pd-ls-block[disabled] { opacity:.5; cursor:default; }

  .dg-bang .pd-tt-sel, .dg-bang .pd-done-sel { min-width:94px; font-weight:700; }
  .pd-tt-sel.tt-pending { background:#FFF3E0; color:#E65100; border-color:#FFCC80; }
  .pd-tt-sel.tt-done { background:#E8F5E9; color:#2E7D32; border-color:#A5D6A7; }
  .pd-tt-sel.tt-cancelled { background:#FFEBEE; color:#C62828; border-color:#EF9A9A; }
  .pd-done-sel.tt-done { background:#E8F5E9; color:#2E7D32; border-color:#A5D6A7; }
  .pd-thaocot { min-width:150px; }
  .pd-thaocot .nv-b { margin:0 2px 3px 0; }
  .pd-thaocot .pd-dabiet { display:inline-block; margin:0 2px; }
  /* 🆕 Chăm sóc HS mới "nhìn như Sheet / Lịch thi" (03/08/2026) — dùng chung bảng .dg-*. */
  .dg-bang td.cs-datecell { min-width:146px; }
  /* ☑ Hai cột tick "Đã liên hệ" / "Đã trao đổi" (11/08/2026) — hẹp, canh giữa,
     vì trong ô chỉ có đúng một dấu ✓ hoặc ✕. */
  .dg-bang td.cs-tickcell { min-width:92px; text-align:center; }
  .cs-tick { min-width:44px; font-size:15px; font-weight:700; }
  .cs-tick:not(.xong) { color:var(--mo); }
  /* 📊 23/08/2026 — thanh "còn thiếu bao nhiêu em". Cô Quỳnh: *"thiếu ai rất khó
     để ý"*. Bấm vào là lọc ra đúng mấy em còn thiếu. Để dáng nút phẳng, chỉ một
     vạch màu bên trái — chỗ này là con số để liếc, không phải nút hành động lớn. */
  /* ⛔ Con số KHÔNG dùng `var(--cam)`. Cam logo #F5821F đặt lên nền thẻ trắng chỉ
     được 2,59 lần tương phản — dưới xa ngưỡng đọc được 4,5, số nhoè hẳn vào nền.
     Đo rồi mới chọn: #B0540A = 5,10 trên trắng. Vạch bên trái thì chỉ cần 3,0 nên
     #DC7014 (3,30) là đủ, giữ được đúng sắc cam thương hiệu ở chỗ dễ thấy nhất.
     Chế độ tối phải đảo hẳn sang cam nhạt — #B0540A trên nền #1B1F23 tối thui. */
  .cs-thieu-thanh { display:flex; gap:8px; flex-wrap:wrap; margin:0 0 10px;
    --cs-so:#B0540A; --cs-vach:#DC7014; --cs-du:#2E7D52; }
  body.toi .cs-thieu-thanh { --cs-so:#F0A868; --cs-vach:#E8A55C; --cs-du:#5FBF8C; }
  .cs-con-thieu, .cs-du-roi { font-size:12.5px; padding:5px 11px; border-radius:var(--r-sm);
    border:1px solid var(--vien); background:var(--the); color:var(--chu);
    font-family:inherit; line-height:1.35; }
  .cs-con-thieu { cursor:pointer; border-left:3px solid var(--cs-vach); }
  .cs-con-thieu:hover { background:var(--nen2); border-color:var(--cs-vach); }
  .cs-con-thieu b { font-variant-numeric:tabular-nums; color:var(--cs-so); }
  .cs-du-roi { border-left:3px solid var(--cs-du); color:var(--mo); }
  .nv-meta { font-size:12px; color:#455A64; margin:1px 0; }
  .nv-nut { display:flex; gap:5px; flex-wrap:wrap; margin-top:5px; }
  .nv-b { font-size:12px !important; padding:3px 9px !important; }
  /* 🔗 link dùng chung */
  .nv-link { margin:6px 0 4px; border:1px solid var(--vien); border-radius:var(--r-lg); padding:6px 12px; background:#fff; }
  .nv-link summary { cursor:pointer; font-size:13px; font-weight:600; }
  .nv-link-ds { display:flex; flex-direction:column; gap:5px; margin-top:8px; }
  .nv-link-1 { font-size:13px; color:#1565C0; text-decoration:none; }
  .nv-link-1:hover { text-decoration:underline; }
  .nv-b { font-size:12.5px; padding:5px 11px; border:1px solid var(--vien); border-radius:var(--r-md); background:var(--nen2); cursor:pointer; }
  /* 21/08/2026 — nút "Đã xong" bỏ nền xanh lá. Nay là nút viền đậm chữ đậm: vẫn là
     nút nổi nhất trên thẻ, mà không kéo thêm một màu nữa vào màn hình. */
  .nv-b.xong { background:var(--the); border-color:var(--chu); color:var(--chu); font-weight:600; }
  .nv-b.xong:hover { background:var(--chu); color:var(--the); }
  .nv-b.hoan { background:#FFF8E1; border-color:#FFE082; }
  .nv-b.xoa { color:#C62828; }
  /* form giao việc */
  .nv-form { border:1px solid var(--vien); border-radius:var(--r-xl); padding:14px; background:var(--nen2); margin-bottom:12px; }
  .nv-form h3 { margin:0 0 10px; font-size:15px; }
  .nv-lb { display:block; font-size:12.5px; font-weight:600; margin:9px 0 4px; } .nv-lb i { font-weight:400; color:var(--mo); }
  .nv-in { width:100%; box-sizing:border-box; padding:8px 10px; border:1px solid var(--vien); border-radius:var(--r-md); font-size:14px; font-family:inherit; background:var(--nen-o); color:var(--chu); }
  textarea.nv-in { resize:vertical; }
  /* ô NGÀY kiểu VN dd/mm/yyyy + nút lịch */
  .nv-datevn { display:flex; gap:6px; align-items:stretch; position:relative; }
  .nv-datevn .nv-datetxt { flex:1; }
  /* Ô ngày ẩn PHỦ đúng khung → lịch bung NGAY tại field, không nhảy ra xa (cô Quỳnh 04/08). */
  .nv-date-an { position:absolute; inset:0; width:100%; height:100%; opacity:0; pointer-events:none; border:0; padding:0; margin:0; }
  .nv-lich { border:1px solid var(--vien); border-radius:var(--r-md); background:var(--nen2); cursor:pointer; padding:0 10px; font-size:16px; }
  /* Ô NGÀY trong hộp thoại chung (kieu:"ngay"). */
  .ht-ngay { display:flex; gap:6px; }
  .ht-ngay .ht-ngaytxt { flex:1; min-width:0; }
  .ht-ngay .ht-ngay-an { position:absolute; width:0; height:0; opacity:0; pointer-events:none; }
  .ht-ngay-nut { flex:none; border:1px solid var(--vien); border-radius:var(--r-md);
      background:var(--nen2); color:var(--chu); cursor:pointer; padding:0 11px;
      font-family:inherit; }
  .ht-ngay-nut:hover { border-color:var(--xanh); color:var(--xanh); }
  /* Nút phụ trong hộp thoại — việc phá bỏ, nên viền đỏ nhạt chứ không nền đỏ đặc:
     nền đỏ đặc cạnh nút Lưu là mắt tự nhảy vào nó trước. */
  .ht-nut-phu { border:1px solid var(--do); background:transparent; color:var(--do);
      border-radius:var(--r-md); padding:6px 13px; font-family:inherit; font-size:13px;
      font-weight:600; cursor:pointer; margin-bottom:4px; }
  .ht-nut-phu:hover { background:var(--do); color:#fff; }
  .ht-ghichu-phu { font-size:11.5px; color:var(--mo); margin-bottom:12px; }
  .nv-nguoi { display:flex; flex-wrap:wrap; gap:6px 14px; padding:8px; border:1px solid var(--vien); border-radius:var(--r-md); background:#fff; max-height:170px; overflow:auto; }
  .nv-ck { font-size:13.5px; display:flex; align-items:center; gap:5px; cursor:pointer; }
  .nv-ck .nv-vai { color:var(--mo); font-size:11px; }
  .nv-hang { display:flex; gap:10px; flex-wrap:wrap; } .nv-hang > div { flex:1; min-width:120px; }
  .nv-form-nut { display:flex; gap:8px; margin-top:14px; }
  /* ⛔ Nút không nở hết hàng — xem lời cô Quỳnh ở `.nv-ng-thanh` phía trên. */
  .nv-form-nut > button { flex:0 0 auto; width:auto; }
  /* ⛔ Trên điện thoại thì NGƯỢC LẠI: hai nút chia đôi hết bề ngang cho ngón tay bấm
     trúng. Ở 390px mà nút chỉ rộng bằng chữ thì bấm trượt suốt. */
  @media (max-width:640px) { .nv-form-nut > button { flex:1 1 0; } }
  /* ô nhắc ĐỎ dính góc phải (việc quá hạn của tôi) */
  #nhacViecODo { position:fixed; right:14px; bottom:14px; z-index:12000; max-width:min(360px,92vw); }
  .nvo-hop { background:#fff; border:2px solid #C62828; border-radius:var(--r-xl); box-shadow:0 6px 22px rgba(0,0,0,.22); overflow:hidden; }
  .nvo-dau { background:#C62828; color:#fff; font-weight:700; font-size:13.5px; padding:9px 12px; display:flex; align-items:center; gap:8px; }
  .nvo-x { margin-left:auto; background:rgba(255,255,255,.25); border:0; color:#fff; border-radius:var(--r-sm); width:26px; height:24px; cursor:pointer; font-size:14px; }
  .nvo-ds { max-height:46vh; overflow:auto; } #nhacViecODo.thu .nvo-ds { display:none; }
  .nvo-mot { padding:9px 12px; border-bottom:1px solid #f0dede; }
  .nvo-ct { font-size:13.5px; line-height:1.45; } .nvo-phu { font-size:11.5px; color:var(--mo); margin:3px 0 6px; }
  .nvo-xong { background:var(--the); border:1px solid var(--chu); color:var(--chu); font-weight:600;
    font-size:12.5px; padding:5px 12px; border-radius:var(--r-md); cursor:pointer; }
  .nvo-xong:hover { background:var(--chu); color:var(--the); }
  body.dang-trong-lop #nhacViecODo { display:none; }   /* đang nhập điểm thì không che (như khay TB cũ) */

  /* 📢 04/08 (cô Quỳnh "đỡ che màn hình, vẫn thao tác + đọc được"): dải mảnh,
     clamp 2 dòng (1 dòng khi đang chấm điểm) + "Xem thêm" bung/thu, đóng được. */
  #bangCoSo { position:relative; background:#C62828; color:#fff; padding:8px 46px 8px 16px;
              font-size:13.5px; line-height:1.5; box-shadow:0 2px 8px rgba(0,0,0,.22); }
  #bangCoSo .bcs-nhan { display:inline-block; font-weight:700; font-size:11px;
                        opacity:.92; margin-right:8px; }
  #bangCoSo .bcs-chu { white-space:pre-line; }
  #bangCoSo:not(.mo) .bcs-chu { display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
  #bangCoSo .bcs-them { background:rgba(255,255,255,.92); color:#C62828; border:0; border-radius:var(--r-sm);
                        font-size:11px; font-weight:700; padding:1px 8px; margin-left:6px; cursor:pointer; }
  #bangCoSo .bcs-x { position:absolute; top:7px; right:10px; width:26px; height:26px; border:none;
                     border-radius:var(--r-md); background:rgba(255,255,255,.22); color:#fff; cursor:pointer;
                     font-size:15px; line-height:1; }
  #bangCoSo .bcs-x:hover { background:rgba(255,255,255,.38); }
  body.dang-trong-lop #bangCoSo:not(.mo) .bcs-chu { -webkit-line-clamp:1; }


  /* ══════════════════════════════════════════════════════════════════════════
     📢 HỘP CẬP NHẬT — GIỮA MÀN HÌNH, cô Quỳnh chốt 19/08/2026
     ──────────────────────────────────────────────────────────────────────────
     Thay cho dải đếm ngược 5 giây ở góc phải trên. Cô Quỳnh:
       *"tôi muốn thay đổi kiểu khi update vps xong thì app sẽ bị freeze để cập
       nhật thứ mới và ở giữa màn hình sẽ xuất hiện thông báo update liệt kê các
       thứ update ra… đến khi nào app đã cập nhật xong thì sẽ hiện nút x để tắt"*
       *"thiết kế cái thông báo cập nhật phải thật chuyên nghiệp và ko lộ AI hoặc
       màu AI, thông báo dễ nhìn và nhìn được toàn bộ thông tin update chứ ko bị
       che khuất như thông báo cũ"*

     ⛔ "KHÔNG BỊ CHE KHUẤT" LÀ MỘT RÀNG BUỘC KỸ THUẬT, không phải lời khen suông:
        hộp cao tối đa 88% màn hình, phần thân TỰ CUỘN bên trong. Dài mấy cũng đọc
        được hết, và không bao giờ tràn ra ngoài mép màn hình như dải cũ.

     ⛔ KHÔNG dải màu nhiều tông, KHÔNG bo góc to, KHÔNG chữ nhạt, KHÔNG emoji —
        cô Quỳnh đã chê "lộ rõ ui AI" ba lần. Nền thẻ trắng, viền mảnh, một vạch
        teal mảnh làm dấu nhận diện, đúng lối bảng điều khiển doanh nghiệp.
     ══════════════════════════════════════════════════════════════════════════ */
  /* ⛔ 19/08/2026 — LỚP PHẢI CAO HƠN MỌI THỨ ĐANG CÓ, nếu không thì bị che đúng
     cái bệnh cô Quỳnh than. Trong app có ba thứ cao hơn 100.000:
       2.147.483.000  ô chú thích nổi khi rê chuột  (.bcs-chuthich)
       2.147.482.901  ngăn kéo chuông               (.tb-bang)
       2.147.482.900  nền ngăn kéo                  (.tb-nen)
     ⛔ ĐỪNG dùng 2147483647 (trần tuyệt đối của số nguyên 32 bit) — xài hết là sau
        này không còn chỗ chèn lên trên. 2147483200 cao hơn tất cả, còn chừa 447 nấc.
     ⛔ Và nó cũng cao hơn màn khoá bảo trì (#manBaoTri, 99999) — CỐ Ý: app đang khoá
        bảo trì mà có bản mới thì vẫn phải cập nhật được, không thì máy ấy kẹt ở bản cũ. */
  #hopCapNhat { position:fixed; inset:0; z-index:2147483200; display:flex;
    align-items:center; justify-content:center; padding:18px;
    background:rgba(12,22,26,.62); }
  /* Lúc đang cập nhật thì KHOÁ CỨNG: không bấm được gì phía sau. Đây chính là
     phần "freeze" cô Quỳnh yêu cầu — app đứng yên cho tới khi nạp xong bản mới. */
  #hopCapNhat.dang { cursor:progress; }
  .hcn-hop { width:min(620px,100%); max-height:88vh; display:flex; flex-direction:column;
    background:var(--the,#fff); color:var(--chu,#1B2A2E); border:1px solid var(--vien,#D8DEE0);
    border-radius:var(--r-xl); box-shadow:0 18px 48px rgba(10,30,36,.34); overflow:hidden; }
  .hcn-dau { flex:none; display:flex; align-items:center; gap:12px;
    padding:15px 18px; border-bottom:1px solid var(--vien,#D8DEE0);
    border-left:3px solid var(--xanh,#14A0A0); }
  .hcn-tieu { flex:1; min-width:0; }
  .hcn-tieu h3 { margin:0; font-size:15.5px; font-weight:700; }
  .hcn-tieu .hcn-phu { margin-top:3px; font-size:12.5px; color:var(--mo,#5A6B70); }
  .hcn-so { flex:none; font-size:12.5px; font-weight:700; padding:4px 9px;
    border:1px solid var(--vien,#D8DEE0); border-radius:var(--r-sm); color:var(--chu,#1B2A2E);
    font-variant-numeric:tabular-nums; white-space:nowrap; }
  /* Nút X CHỈ hiện khi đã cập nhật xong — đúng lời cô Quỳnh. Lúc đang chạy thì
     KHÔNG có nút nào để bấm, kể cả bấm ra nền. */
  .hcn-x { flex:none; width:30px; height:30px; border:1px solid var(--vien,#D8DEE0);
    background:var(--the,#fff); border-radius:var(--r-md); cursor:pointer; font-size:16px;
    line-height:1; color:var(--chu,#1B2A2E); display:none; }
  #hopCapNhat.xong .hcn-x { display:block; }
  .hcn-x:hover { background:var(--nen-o,#F2F5F6); }
  .hcn-than { flex:1; min-width:0; overflow-y:auto; padding:4px 18px 14px; }
  /* Dòng trạng thái: vòng quay lúc đang chạy, dấu tích lúc xong. */
  .hcn-tt { display:flex; align-items:center; gap:9px; padding:13px 0 4px;
    font-size:13px; font-weight:700; color:var(--mo,#5A6B70); }
  .hcn-quay { width:15px; height:15px; border:2px solid var(--vien,#D8DEE0);
    border-top-color:var(--xanh,#14A0A0); border-radius:50%; flex:none;
    animation:hcnQuay .8s linear infinite; }
  @keyframes hcnQuay { to { transform:rotate(360deg); } }
  #hopCapNhat.xong .hcn-quay { display:none; }
  .hcn-nhan-ds { margin:14px 0 8px; font-size:11.5px; font-weight:700;
 color:var(--mo,#5A6B70); }
  .hcn-muc { padding:11px 0; border-top:1px solid var(--vien,#D8DEE0); }
  /* TÊN CÔNG CỤ nổi bật — cô Quỳnh: *"nên highlight tên của các công cụ trong app
     được thay đổi để họ nhìn ko chán"*. Vạch teal mảnh + chữ đậm, không dùng nền
     màu loè loẹt. */
  .hcn-cc { display:inline-block; font-size:13px; font-weight:700;
    padding-left:9px; border-left:3px solid var(--xanh,#14A0A0); margin-bottom:5px; }
  .hcn-chu { font-size:13.5px; line-height:1.55; }
  .hcn-anh { display:block; margin-top:9px; max-width:100%; height:auto;
    border:1px solid var(--vien,#D8DEE0); border-radius:var(--r-md); }
  /* Chức vụ này không có công cụ nào được sửa → nói thẳng, đừng để trống trơn
     làm người ta tưởng app hỏng. Cô Quỳnh dặn: *"phần chi tiết sửa đổi trống luôn"*. */
  .hcn-rong { margin-top:14px; padding:13px 14px; border:1px dashed var(--vien,#D8DEE0);
    border-radius:var(--r-md); font-size:13px; color:var(--mo,#5A6B70); line-height:1.55; }
  .hcn-day { flex:none; display:flex; justify-content:flex-end; gap:9px;
    padding:12px 18px; border-top:1px solid var(--vien,#D8DEE0); background:var(--nen-o,#F7F9FA); }
  .hcn-dong { display:none; border:1px solid var(--xanh,#14A0A0); background:var(--xanh,#14A0A0);
    color:#fff; border-radius:var(--r-md); font-weight:700; font-size:13px; padding:8px 18px; cursor:pointer; }
  #hopCapNhat.xong .hcn-dong { display:block; }
  #hopCapNhat.dang .hcn-day { display:none; }
  @media (max-width:260px) {
    .hcn-hop { max-height:92vh; }
    .hcn-dau { padding:13px 14px; }
    .hcn-than { padding:2px 14px 12px; }
    .hcn-day { padding:10px 14px; }
  }
  @media (prefers-reduced-motion:reduce) { .hcn-quay { animation:none; } }

  /* ⛔ 19/08/2026 — KHỐI DƯỚI ĐÂY LÀ CỦA DẢI ĐẾM NGƯỢC CŨ, nay KHÔNG CÒN AI DỰNG NỮA
     (xem `moHopCapNhat` thay thế). Giữ lại luật CSS vì máy nào còn mở tab bản cũ
     vẫn dựng ra thẻ ấy — gỡ luật đi thì tab cũ hiện một cục chữ trần không định dạng.
     Xoá được sau khi chắc chắn không còn tab bản cũ nào (khoảng một tuần). */
  /* 🔄 04/08 (cô Quỳnh): banner ĐẾM NGƯỢC cập nhật — GÓC trên-phải, nổi bật nhưng KHÔNG che;
     ai đang làm vẫn kịp lưu ô; hết 5s tự tải lại. */
  #bangDemNguoc { position:fixed; top:14px; right:14px; z-index:99998; max-width:min(340px,92vw);
    display:flex; align-items:flex-start; gap:10px;
    background:#0D8081; color:#fff; border-radius:var(--r-xl); padding:12px 14px;
    box-shadow:0 12px 34px rgba(13,128,129,.5); border:2px solid #7FE3E0;
    font-size:13.5px; line-height:1.5; animation:bdnHien .25s ease; }
  @keyframes bdnHien { from { transform:translateY(-12px); opacity:0; } to { transform:none; opacity:1; } }
  #bangDemNguoc .bdn-icon { font-size:22px; line-height:1; animation:bdnQuay 1.4s linear infinite; }
  @keyframes bdnQuay { to { transform:rotate(360deg); } }
  #bangDemNguoc .bdn-moi { opacity:.92; font-size:12.5px; }
  #bangDemNguoc .bdn-so { font-size:16px; }
  #bangDemNguoc .bdn-ngay { flex:none; align-self:center; background:#fff; color:#0D8081; border:0;
    border-radius:var(--r-md); font-weight:700; font-size:12.5px; padding:7px 11px; cursor:pointer; white-space:nowrap; }
  /* 🔒 KHOÁ BẢO TRÌ (17/08/2026) — hai thứ, hai người xem khác nhau.
     · #manBaoTri: NHÂN VIÊN thấy, che kín. Che kín chứ không phải một dòng nhắc,
       vì lúc khoá thì mọi thứ đều không bấm được — để bảng nguyên đó là họ bấm
       mãi rồi tưởng máy mình hỏng.
     · #daiBaoTri: CHỦ TÀI KHOẢN thấy, dải nhỏ ở đáy. Cô vẫn dùng app bình thường
       nên KHÔNG tự thấy là đang khoá — quên mở lại là sáng hôm sau cả trung tâm
       đứng hình. Dải này để nhắc, và mở được ngay tại chỗ. */
  #manBaoTri { position:fixed; inset:0; z-index:99999; display:flex; align-items:center;
    justify-content:center; padding:20px; background:var(--nen,#F4F6F8); }
  /* ══ 19/09/2026 — DỰNG LẠI THEO MẪU 21st.dev `@ravikatiyar162/components/card-6` ══
     Boss: *"thiết kế y hệt chỉ sửa đúng cái icon… nó phải có biểu tượng giống app
     đang bị khoá bảo trì"*. Số đo dưới đây LẤY THẲNG TỪ MÃ NGUỒN MẪU, không ước lượng
     bằng mắt: thẻ `max-w-md` 448px · viền 1px · `shadow-sm` · đầu thẻ `p-6` 24px ·
     vòng tròn icon `h-16 w-16` 64px nền `primary/10` · icon `h-8 w-8` 32px ·
     tiêu đề `text-2xl` 24px/600, `leading-none`, `tracking-tight` ·
     lời giải thích `text-base` 16px màu `muted-foreground` · chân thẻ `pt-4`.

     🔴 DẤU ĐỎ KHÔNG BỊ NÉM ĐI, NÓ ĐỔI CHỖ — đọc kỹ trước khi "dọn cho giống mẫu".
        30/08/2026 Boss chê màn này *"ko có thông báo đỏ gì cả"*: thẻ trắng trên nền
        xám trông như một trang đang tải dở chứ không như một lời báo, nên hồi ấy mới
        thêm vạch đỏ 3px trên đỉnh và tiêu đề đỏ. Mẫu card-6 không có hai thứ đó.
        Nay dấu đỏ nằm ở VÒNG TRÒN ICON 64px — to hơn vạch 3px nhiều lần và là thứ
        mắt nhìn vào đầu tiên. Bỏ nốt màu đỏ ở đây là dựng lại đúng lời chê 30/08. */
  #manBaoTri .mbt-hop { width:100%; max-width:448px; text-align:center;
    color:var(--chu,#1C2530); background:var(--the,#fff);
    border:1px solid var(--vien,#DDE3EA); border-radius:12px;
    box-shadow:0 1px 2px rgba(0,0,0,.05); }
  /* Đầu thẻ: `CardHeader` + `items-center`. */
  #manBaoTri .mbt-dau { display:flex; flex-direction:column; align-items:center;
    gap:6px; padding:24px; }
  /* ⛔ ĐỎ CHỈ Ở ĐÂY. Nền là chính màu đỏ pha loãng 10% — đúng cách mẫu làm
     (`bg-primary/10` + `text-primary`), nên vòng tròn nổi lên mà không chói. */
  #manBaoTri .mbt-ico { width:64px; height:64px; flex:none; margin-bottom:16px;
    display:flex; align-items:center; justify-content:center;
    border-radius:999px; color:var(--do,#C0392B); background:rgba(192,57,43,.10); }
  #manBaoTri .mbt-tieu { margin:0; font-size:24px; font-weight:600; line-height:1;
    letter-spacing:-.025em; color:inherit; }
  /* Thân thẻ: `CardContent` = `p-6 pt-0`. */
  #manBaoTri .mbt-than { padding:0 24px 24px; }
  #manBaoTri .mbt-chu { margin:0; font-size:16px; line-height:1.5; color:var(--mo,#67707B); }
  /* Chân thẻ: `CardFooter` = `p-6 pt-0` cộng `pt-4` của mẫu. Không viền ngăn, không
     nút — Boss chốt *"Không nút nào — chỉ để đọc"*. */
  #manBaoTri .mbt-chan { display:flex; justify-content:center; padding:16px 24px 24px; }
  #manBaoTri .mbt-nho { margin:0; font-size:14px; line-height:1.55; color:var(--mo,#67707B); }
  /* Nền tối: đỏ đậm quá thì chìm, dùng đúng sắc đỏ nhạt mà app vẫn dùng ở nền tối. */
  body.toi #manBaoTri .mbt-ico { color:#F0A79E; background:rgba(240,167,158,.14); }
  /* ⛔ CHUYỂN ĐỘNG LỆCH NHAU .15s — đây là phần làm nên cái mẫu, đừng bỏ cho gọn.
     Bốn khối vào lần lượt: vòng tròn → tiêu đề → lời giải thích → dòng chân.
     `both` để khối chưa tới lượt vẫn giữ trạng thái đầu (mờ hẳn), không thì nó hiện
     đủ một khung hình rồi mới biến mất để chạy lại — giật đúng một phát. */
  @keyframes mbtLen { from { opacity:0; transform:translateY(20px); } }
  #manBaoTri .mbt-ico,
  #manBaoTri .mbt-tieu,
  #manBaoTri .mbt-chu,
  #manBaoTri .mbt-nho { animation:mbtLen .5s cubic-bezier(0,0,.58,1) both; }
  #manBaoTri .mbt-ico  { animation-delay:0s; }
  #manBaoTri .mbt-tieu { animation-delay:.15s; }
  #manBaoTri .mbt-chu  { animation-delay:.3s; }
  #manBaoTri .mbt-nho  { animation-delay:.45s; }
  @media (prefers-reduced-motion: reduce) {
    #manBaoTri .mbt-ico, #manBaoTri .mbt-tieu,
    #manBaoTri .mbt-chu, #manBaoTri .mbt-nho { animation:none; }
  }
  /* Màn hẹp: giữ nguyên bố cục, chỉ thu đệm để chữ không sát mép. */
  @media (max-width: 480px) {
    #manBaoTri { padding:16px; }
    #manBaoTri .mbt-dau { padding:20px 18px; }
    #manBaoTri .mbt-than { padding:0 18px 20px; }
    #manBaoTri .mbt-chan { padding:14px 18px 20px; }
    #manBaoTri .mbt-tieu { font-size:21px; }
    #manBaoTri .mbt-chu { font-size:15px; }
  }
  #daiBaoTri { position:fixed; left:0; right:0; bottom:0; z-index:99997;
    display:flex; align-items:center; justify-content:center; gap:12px; flex-wrap:wrap;
    background:#8A1C1C; color:#fff; padding:9px 14px; font-size:13px; line-height:1.5; }
  #daiBaoTri button { background:#fff; color:#8A1C1C; border:0; border-radius:var(--r-sm);
    font-weight:700; font-size:12.5px; padding:6px 12px; cursor:pointer; }
  /* 💾 01/09/2026 — DẢI ĐỎ "MÁY CHỦ CHƯA LƯU ĐƯỢC XUỐNG ĐĨA".
     Máy chủ đổi số trong bộ nhớ rồi trả "đã lưu" NGAY, còn lượt ghi xuống đĩa thì
     chạy 400 ms sau. Đĩa đầy / sai quyền ghi / ổ lỗi thì lượt ấy ném lỗi vào cửa sổ
     đen của máy chủ — không một ai ở trung tâm nhìn thấy. Cả buổi ai cũng được báo
     "đã lưu" mà không ô nào xuống đĩa, tối khởi động lại là mất sạch.
     Dải này là chỗ DUY NHẤT người đang điền biết được chuyện đó.
     ⛔ ĐẶT Ở ĐÁY, KHÔNG ĐẶT Ở ĐỈNH. `.thanh-tren` dán dính ở `top:0`; che nó là trợ
        giảng mất luôn nút thoát lớp — cảnh báo mà chặn đường người ta thì thành lỗi mới.
     ⛔ KHÔNG dùng `:has()` (luật của kho này). Chỗ chồng lên dải bảo trì xử bằng
        JavaScript trong `veDaiGhiDia`. */
  #daiGhiDia { position:fixed; left:0; right:0; bottom:0; z-index:99998;
    background:#8A1C1C; color:#fff; padding:9px 14px; font-size:13px; line-height:1.55;
    text-align:center; box-shadow:0 -2px 10px rgba(0,0,0,.25); }
  #daiGhiDia b { display:block; font-size:14.5px; }
  #daiGhiDia .dgd-nho { opacity:.85; font-size:11.5px; margin-top:2px; }
  /* 📡 DẢI "KHÔNG CÓ INTERNET" — Boss chốt 08/09/2026. Dựng ở `veDaiMatMang`.
     ⛔ DÙNG LẠI ĐÚNG #8A1C1C của dải trên, KHÔNG đẻ thêm một sắc đỏ mới: hai dải là
        cùng một chuyện với người dùng ("lúc này gõ không ăn"), và chữ trắng chỉ đọc
        được trên nền đỏ ĐẬM. `var(--do)` đổi theo nền sáng/tối — ở nền tối nó thành
        #F0857C, chữ trắng trên đó là không đọc nổi.
     ⛔ Chỗ đứng (`bottom`) do JavaScript đặt, xem `xepLaiDaiMatMang` — kho này cấm
        `:has()` nên không xếp chồng bằng CSS được. */
  #daiMatMang { position:fixed; left:0; right:0; bottom:0; z-index:99998;
    background:#8A1C1C; color:#fff; padding:9px 14px; font-size:13px; line-height:1.55;
    text-align:center; box-shadow:0 -2px 10px rgba(0,0,0,.25); }
  #daiMatMang b { display:block; font-size:14.5px; }
  /* Màn phủ lúc đang cập nhật / vào lại — che khoảnh khắc reload cho mượt */
  #manCapNhat, #manKhoiDong { position:fixed; inset:0; z-index:99999; display:flex; flex-direction:column;
    align-items:center; justify-content:center; gap:16px;
    background:var(--nen,#F4F6F8); color:var(--chu,#1C2530); font-size:16px; font-weight:600; text-align:center; padding:20px; }
  .mkd-spin { width:40px; height:40px; border-radius:50%; border:4px solid rgba(13,128,129,.25);
    border-top-color:#0D8081; animation:bdnQuay .8s linear infinite; }

  /* 🔄 "Có bản cập nhật mới" (31/07 — cô: nút cũ dễ bỏ lơ). Giờ là HỘP NỔI GIỮA
     MÀN + phủ mờ nền + viền nhấp nháy → khó bỏ qua. Vẫn KHÔNG chặn cứng: bấm
     "Nhắc lại sau" là điền tiếp được. */
  /* 📌 Số phiên bản NHỎ ở góc màn hình (cô Quỳnh 03/08/2026: "thật bé ko nhìn rõ"). */
  #gocPhienBan { position:fixed; right:8px; bottom:5px; z-index:40; font-size:9.5px;
    font-family:Consolas,monospace; color:var(--mo); opacity:.4; pointer-events:none;
 user-select:none; }
  body.dang-trong-lop #gocPhienBan { display:none; }     /* trong lớp điền điểm thì ẩn cho gọn */
  .bcn-moi { display:inline-block; margin:6px 0 2px; color:var(--muc); font-weight:600; font-size:13.5px; }
  .bcn-ver { display:inline-block; background:var(--xanh); color:#fff; font-size:12px; font-weight:700; padding:2px 9px; border-radius:var(--r-xl); vertical-align:middle; }
  #bangCapNhat { position:fixed; inset:0; z-index:13500; display:flex;
                 align-items:center; justify-content:center; padding:16px;
                 background:rgba(20,30,35,.45); animation:bcnHien .18s ease-out; }
  @keyframes bcnHien { from { opacity:0; } to { opacity:1; } }
  #bangCapNhat .bcn-hop { background:#fff; border-radius:var(--r-xl); max-width:400px; width:100%;
                          padding:22px 22px 18px; text-align:center;
                          box-shadow:0 18px 50px rgba(0,0,0,.4);
                          border:3px solid var(--cam); animation:bcnDap 1.4s ease-in-out infinite; }
  @keyframes bcnDap { 0%,100% { box-shadow:0 18px 50px rgba(0,0,0,.4), 0 0 0 0 rgba(245,130,31,.55); }
                      50%     { box-shadow:0 18px 50px rgba(0,0,0,.4), 0 0 0 12px rgba(245,130,31,0); } }
  #bangCapNhat .bcn-icon { font-size:40px; line-height:1; margin-bottom:8px; }
  #bangCapNhat .bcn-chu { font-size:14.5px; line-height:1.5; color:var(--chu); margin-bottom:16px; }
  #bangCapNhat .bcn-nut { display:flex; flex-direction:column; gap:8px; }
  #bangCapNhat .bcn-tai { border:none; border-radius:var(--r-lg); padding:13px; font-size:15px;
                          font-weight:700; cursor:pointer; background:var(--cam); color:#fff; }
  #bangCapNhat .bcn-tai:hover { filter:brightness(1.05); }
  #bangCapNhat .bcn-de { border:none; background:transparent; color:var(--mo);
                         font-size:13px; cursor:pointer; padding:4px; text-decoration:underline; }

  .tdg-bang { width:100%; border-collapse:collapse; font-size:12.5px; }
  .tdg-bang th { text-align:left; padding:7px 10px; background:var(--dau-bang-nen);
                 color:var(--dau-bang-chu);
                 font-weight:700; position:sticky; top:0; white-space:nowrap; }
  .tdg-bang td { padding:6px 10px; border-top:1px solid var(--vien); white-space:nowrap; }
  .tdg-bang tr.tdg-loi td { background:#FDEAEA; color:#B0281C; }
  .tdg-bang tr.tdg-loi td:last-child { white-space:normal; max-width:320px; }
  .hang-tk.luu-tru .ten-tk b { text-decoration:line-through; }
  .tk-nut-hang { display:flex; gap:6px; flex-wrap:wrap; margin-left:auto; }
  @media (max-width:640px) {
    .tk-nut-hang { width:100%; margin-left:0; margin-top:8px; }
    .tk-nut-hang button { flex:1 1 auto; }
  }
  .nut-do { border:1px solid #E7B4AE; background:#FDF1EF; color:var(--do); border-radius:var(--r-md);
            padding:6px 10px; font-size:12px; font-weight:700; }
  /* nút cảnh báo ghi lỗi trên thanh trên — phải đập vào mắt */
  #nutGhiLoi { background:var(--do); border-color:var(--do); color:#fff; padding:9px 12px;
               font-size:12.5px; white-space:nowrap; }

  /* ---- Hộp thoại tự làm ----
     ⛔ KHÔNG dùng prompt()/confirm() của trình duyệt: Chrome/Edge đời mới CHẶN
     chúng trong nhiều tình huống ("prompt() is not supported") → nút bấm chết câm.
     User đã dính đúng lỗi này 24/07/2026. Mọi hỏi/đáp đi qua hộp thoại dưới đây. */
  .ht-o { margin-bottom:12px; }
  .ht-o label { display:block; font-size:12.5px; font-weight:700; color:var(--mo); margin-bottom:5px; }
  .ht-o input, .ht-o select { width:100%; height:42px; border:1px solid var(--vien); border-radius:var(--r-o, 8px);
                              padding:0 12px; font-size:14px; font-family:inherit; background:#fff; }
  .ht-o input:focus, .ht-o select:focus { outline:2px solid var(--xanh); border-color:transparent; }
  .ht-o .goiy { font-size:12px; color:var(--mo); margin-top:5px; }
  /* 🎨 29/08/2026 — TÔ MÀU TRẠNG THÁI TRONG DANH SÁCH XỔ (thanh chọn buổi caption).
     Cô Quỳnh: *"thay vì có mấy cái icon trẻ con thiếu chuyên nghiệp thì tôi muốn nó
     là highlight 1 xanh lên và có 1 cái tick thôi, còn đang sửa dở lưu lại chưa gửi
     caption lên zalo thì sẽ highlight màu vàng và ghi đang sửa"*.
     ⛔ Nền `<option>` là thứ TRÌNH DUYỆT VẼ, không phải app: Chrome/Edge trên Windows
        tô đúng, Safari và phần lớn trình duyệt điện thoại bỏ qua. Nên đây chỉ được là
        phần NHẤN MẠNH — chữ "✓ đã gửi" / "đang sửa" phải luôn nằm trong nhãn (xem
        `moTaoCaption`). Đừng bao giờ để màu là cách duy nhất nói ra trạng thái.
     ⛔ Ô đang chọn thì chính trình duyệt tô nền xanh dương của nó đè lên — đó là hành
        vi hệ điều hành, không sửa được, và cũng không cần sửa. */
  /* 📝 29/08/2026 — Ô DANH SÁCH: mỗi lựa chọn một dòng, có nút ✕ và nút ＋ Thêm.
     Cô Quỳnh: *"tôi ko muốn ghi theo kiểu ....,..... mà tôi muốn được viết vòa từng
     ô xong thêm lựa chọn"*. Xem khối lý do ở `kieu:"danhsach"`. */
  /* 🃏 29/08/2026 — THẺ BẤM chọn kiểu ô (xem `kieu:"the"`). Lưới tự xuống hàng, mỗi
     thẻ một dòng tên + một dòng nói dùng khi nào. */
  .ht-the-luoi { display:grid; grid-template-columns:repeat(auto-fill, minmax(215px, 1fr)); gap:7px; }
  .ht-the-o { display:flex; flex-direction:column; gap:2px; align-items:flex-start;
              padding:9px 11px; border:1px solid var(--vien); border-radius:var(--r-md);
              background:#fff; cursor:pointer; font-family:inherit; text-align:left; }
  .ht-the-o b { font-size:13.5px; font-weight:600; color:var(--chu); }
  .ht-the-o span { font-size:11.5px; color:var(--mo); line-height:1.45; }
  .ht-the-o:hover { border-color:var(--xanh); }
  .ht-the-o.chon { border-color:var(--xanh); background:#EEF7F1; box-shadow:inset 0 0 0 1px var(--xanh); }
  .ht-the-o:focus-visible { outline:2px solid var(--xanh); outline-offset:2px; }
  body.toi .ht-the-o { background:var(--the); }
  body.toi .ht-the-o.chon { background:#16301F; }
  /* ═══ HỘP "ẢNH & MÀU NỀN CỦA BẠN" — Boss chốt 08/09/2026 ═══════════════════
     *"ấn vào block avartar ở thanh avartar ở trang chủ thì giao diện bên trong còn
     quá sơ sài và thiếu chuyên nghiệp"*. Ba chỗ sơ sài và cách chữa:
       ① `<input type=file>` trần → trình duyệt vẽ "Choose File | No file chosen":
          chữ Anh, khung xám, không theo nếp nào của app. Ẩn nó, dùng `<label for>`
          làm nút mang đúng khuôn `.nut-nho`.
       ② Ô xem ảnh 56px, nền xám, có mỗi emoji 📷 → nâng lên 76px, viền tô đúng màu
          nhận diện vừa chọn, và dùng icon nét của app thay emoji (emoji là một
          trong mười thứ làm giao diện "lộ ra là máy làm").
       ③ Chọn màu bằng ô thả xuống ghi chữ "Cam", "Tím" → đổi sang lưới thẻ có ô
          màu THẬT. Thứ cần chọn là màu thì phải nhìn thấy màu. */
  .hs-anh-hang { display:flex; align-items:center; gap:14px; flex-wrap:wrap; }
  .hs-anh-xem { width:76px; height:76px; border-radius:50%; flex:none; padding:3px;
                display:flex; align-items:center; justify-content:center;
                background:var(--vien-ro); box-sizing:border-box; }
  .hs-anh-trong { width:100%; height:100%; border-radius:50%; overflow:hidden;
                  display:flex; align-items:center; justify-content:center;
                  background:var(--nen2); }
  .hs-anh-trong img { width:100%; height:100%; object-fit:cover; display:block; }
  .hs-anh-trong > i { width:30px; height:30px; margin:0; background:var(--mo); }
  /* ⛔ Ghim 36px: `.nut-nho` mặc định cao 44px trên điện thoại, mà đây là nút phụ
     đứng cạnh ô ảnh 76px — để 44px thì cụm trông nặng đầu. */
  .hs-anh-chon, .hs-anh-xoa { min-height:36px; height:36px; padding:0 12px;
                              display:inline-flex; align-items:center; gap:6px; }
  .hs-anh-cot { display:flex; gap:8px; flex-wrap:wrap; align-items:center; }
  /* ⛔ ĐỪNG `display:none` cho ô file: nhiều trình duyệt bỏ qua luôn phần tử ẩn hẳn,
     và `<label for>` mất chỗ để trỏ tới. Giấu bằng cách thu về 1px trong suốt. */
  /* ⛔ PHẢI viết `.ht-o input.hs-anh-file`, KHÔNG phải `.hs-anh-file` — 08/09/2026
     Bản đầu tôi viết bộ chọn một lớp, và luật hộp thoại `.ht-o input { width:100% }`
     (đặc hiệu cao hơn) đè mất: ô file đo ra **390×42** dù khai 1px. Nó `position:
     absolute` và trong suốt, nên mắt không thấy — nhưng nó NẰM ĐÈ lên vùng nút và
     nuốt cú bấm. Bài kiểm bắt được ngay lượt đầu, đúng việc của nó.
     ⛔ Đừng chữa bằng `display:none`: trình duyệt bỏ qua phần tử ẩn hẳn, và
        `<label for>` mất chỗ trỏ tới → hết đường chọn ảnh. */
  .ht-o input.hs-anh-file, .hs-anh-file {
    position:absolute; width:1px; height:1px; min-width:0; padding:0; margin:-1px;
    overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; opacity:0; }
  .hs-anh-chon { cursor:pointer; }
  .hs-anh-file:focus-visible + .hs-anh-chon,
  .hs-anh-chon:focus-visible { outline:2px solid var(--xanh); outline-offset:2px; }
  .hs-anh-xoa { color:var(--do); }
  /* Lưới màu: ô nhỏ hơn thẻ thường vì mỗi thẻ chỉ có một chấm màu và một tên ngắn. */
  .ht-the.hs-mau .ht-the-luoi { grid-template-columns:repeat(auto-fill, minmax(150px, 1fr)); }
  .ht-the.hs-mau .ht-the-o { flex-direction:row; align-items:center; gap:9px; padding:8px 10px; }
  .hs-mau-cham { width:26px; height:26px; border-radius:7px; flex:none;
                 border:1px solid rgba(0,0,0,.14); }
  body.toi .hs-mau-cham { border-color:rgba(255,255,255,.18); }

  /* ═══ BO GÓC MỀM CHO NÚT TRONG HỘP THOẠI — Boss chốt 08/09/2026 ═══════════
     *"tôi thấy phần này bạn vừa làm xong bị vuông góc ở nút quá"*.
     Đo được: nút "Lưu" bo **0px** (vuông hẳn), nút "Huỷ" và các thẻ 4px — trong một
     hộp mà ảnh đại diện tròn hoàn toàn và ô tìm bo tròn, mấy góc vuông ấy chọi hẳn.

     ⛔ KHÔNG đổi biến gốc `--r-md` / `--r-lg` / `--r-xl`. Bốn nấc bo góc ấy là con số
        ĐÃ CHỐT cho cả app (app cố ý vuông vức như bảng tính), và `thu-giao-dien-
        nen-tang.js` dòng ~97 canh đúng bộ số `4 · 4 · 0 · 0 · 0`. Đổi biến là vừa đỏ
        bài kiểm vừa đổi hình dạng của mọi bảng trong app — Boss chỉ nói về NÚT.
     ⛔ 8px chứ không phải 12px+: bo lớn hơn thì hộp bắt đầu trông như thẻ quảng cáo,
        đúng thứ nằm trong danh sách "mười thứ làm giao diện lộ ra là máy làm".
     ⚠️ Nút Lưu/Huỷ của hộp thoại là `#htOK.chinh` / `#htHuy` — KHÔNG mang `.nut-chinh`,
        nên phải bắt bằng `.modal .ht-nut button` chứ đừng trông vào tên lớp. */
  .modal .nut-chinh, .modal .nut-nho, .modal label.nut-nho,
  .modal .ht-nut button { border-radius:8px; }
  .modal .ht-the-o { border-radius:8px; }

  .ht-ds-khung { display:flex; flex-direction:column; gap:6px; }
  .ht-ds-dong { display:flex; gap:6px; align-items:center; }
  .ht-ds-dong .ht-ds-o { flex:1; min-width:0; height:38px; border:1px solid var(--vien);
                         border-radius:var(--r-md); padding:0 11px; font-size:14px;
                         font-family:inherit; background:#fff; color:var(--chu); }
  .ht-ds-dong .ht-ds-o:focus { outline:2px solid var(--xanh); border-color:transparent; }
  .ht-ds-xoa { flex:none; width:34px; height:34px; border:1px solid var(--vien);
               border-radius:var(--r-md); background:#F6F8FA; color:#7A838C; font-size:14px;
               line-height:1; cursor:pointer; }
  .ht-ds-xoa:hover { background:#FDE7E7; border-color:#F0B4AE; color:#B0281C; }
  .ht-ds-them { margin-top:7px; padding:6px 12px; font-size:13px; font-weight:600;
                border:1px dashed var(--vien); border-radius:var(--r-md); background:transparent;
                color:var(--xanh); cursor:pointer; font-family:inherit; }
  .ht-ds-them:hover { background:#EEF7F1; border-style:solid; border-color:var(--xanh); }
  body.toi .ht-ds-dong .ht-ds-o { background:var(--the); }
  body.toi .ht-ds-xoa { background:#2A3138; color:#A4ADB6; }
  .ht-o select option.ht-chon-xanh { background:#DCF5E6; color:#12613A; font-weight:600; }
  .ht-o select option.ht-chon-vang { background:#FEF3C7; color:#8A5A00; font-weight:600; }
  body.toi .ht-o select option.ht-chon-xanh { background:#173A2A; color:#8FE3B4; }
  body.toi .ht-o select option.ht-chon-vang { background:#3A2E10; color:#F4CE72; }
  /* 🏷 LỚP THEO TUẦN trong màn Gán lớp — cô Quỳnh 27/08/2026: lớp do Bảng phân lớp
     mở thì "có nhãn 'theo tuần - tự gỡ' và KHÔNG cho gỡ tay".
     ⛔ MỜ HẲN CẢ DÒNG, không chỉ mờ cái nhãn: người ta nhìn ô tích trước, đọc chữ
        sau. Một dòng đen bình thường với ô tích không bấm được thì bị hiểu là app
        đơ chứ không phải "lớp này đã bị khoá có chủ ý". */
  #dsLopTick label.lop-theo-tuan { opacity:.62; }
  #dsLopTick label.lop-theo-tuan input { cursor:not-allowed; }
  .nhan-tuan { display:inline-block; margin-left:6px; padding:1px 7px; border-radius:999px;
    font-size:11px; line-height:1.7; white-space:nowrap;
    background:rgba(126,87,194,.12); color:#5E35B1; border:1px solid rgba(126,87,194,.28); }
  body.toi .nhan-tuan { background:rgba(179,157,219,.16); color:#C7B6E8; border-color:rgba(179,157,219,.32); }
  /* ══════════════════════════════════════════════════════════════════════════════
     ✅ Ô MÁY VỪA ĐIỀN HỘ — cô Quỳnh 22/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     *"AI chạy xong thì nó phải hiện tích xanh xanh lên để nhận biết được nó điền
       chưa"*.
     ⛔ BA dấu hiệu cùng lúc, không phải một: chữ "✓ AI điền" cạnh nhãn · viền xanh
        · nền xanh rất nhạt. Chỉ đổi mỗi màu thì người nhìn màu kém không thấy gì,
        mà hộp thoại này là chỗ quyết định một dòng có vào sổ hay không.
     ⛔ ĐẶT TRÊN `.ht-o` BỌC NGOÀI, đừng đặt lên chính ô: ô ngày và ô giờ có nút
        lịch/nút xổ nằm cạnh, dấu đặt lên ô sẽ chồng lên nút.
     ⛔ "✓" là KÝ HIỆU chứ không phải emoji — đúng quy ước giao diện của app (không
        emoji). Đừng thay bằng ✅ hay 🟢.
     ⛔ Dấu này TỰ TẮT khi người ta sửa lại ô (xem `ctsAiGan`) — nó nói "chỗ này máy
        điền, ngó lại xem", người ngó rồi thì nó hết việc. */
  .ht-o.ai-dien > label::after { content:"✓ AI điền"; margin-left:8px; font-size:11px;
    font-weight:700; color:var(--ai-ok); }
  .ht-o.ai-dien input, .ht-o.ai-dien select, .ht-o.ai-dien textarea {
    border-color:var(--ai-ok); background:var(--ai-ok-nen); }
  /* Trạng thái chung của khối AI cũng chuyển xanh khi đã điền được ô nào. */
  .cts-ai-tt.xong { color:var(--ai-ok); font-weight:600; }
  /* ══════════════════════════════════════════════════════════════════════════════
     Ô NGÀY HỌC + Ô GIỜ HỌC — cô Quỳnh 21/08/2026
     ──────────────────────────────────────────────────────────────────────────────
     ⛔ MỌI MÀU LẤY TỪ BIẾN, không gõ mã màu vào đây. Nền tối đổi biến một lần là
        cả hai ô đi theo — không phải viết lại khối này lần thứ hai ở dưới.
        (`.ht-o input` ngay trên có `background:#fff` gõ cứng, và đó là lý do phải
        có một dòng đè riêng cho nền tối ở khối `@media (prefers-color-scheme:dark)`
        — đừng lặp lại lối ấy.)
     ⛔ Nút ngày ĐANG CHỌN phân biệt bằng CẢ nền lẫn chữ đậm, không chỉ bằng màu —
        người mù màu vẫn đọc được nút nào đang bật. */
  .ht-thu-hang { display:flex; gap:6px; flex-wrap:wrap; }
  .ht-thu-o { flex:1 1 0; min-width:46px; height:42px; border:1px solid var(--vien);
    border-radius:var(--r-lg); background:var(--the); color:var(--chu); font-family:inherit;
    font-size:14px; font-weight:600; cursor:pointer; padding:0 4px; }
  .ht-thu-o:hover { border-color:var(--xanh); color:var(--xanh); }
  .ht-thu-o.chon { background:var(--xanh); border-color:var(--xanh); color:#fff; font-weight:700; }
  .ht-thu-o:focus-visible { outline:2px solid var(--xanh); outline-offset:2px; }
  .ht-thu-xem { font-size:12.5px; color:var(--mo); margin-top:6px; }
  /* Ô TÍCH NHIỀU MỤC (28/08/2026). Cùng lối với ô ngày ngay trên, khác đúng một
     điểm: nhãn mục là CẢ CÂU ("Cần ôn thêm bài ở nhà") chứ không phải "T2" — nên
     nút xếp thành CỘT, mỗi mục một dòng, chữ canh trái và tự xuống dòng. Ép chúng
     vào hàng ngang như nút ngày là chữ bị cắt cụt, người tích không đọc nổi mình
     đang tích gì. Dùng lại đúng bảng màu của `.ht-thu-o`, không đẻ màu mới. */
  .ht-tich-hang { display:flex; flex-direction:column; gap:6px; }
  /* ⭐ 18/09/2026 — bo tròn theo cùng Boss chốt. Đây là bộ CŨ, JS chỉ dựng nó khi
     hộp có DƯỚI 2 mục để chọn; bộ mới `.ht-tich-the` lo phần còn lại. Hai bộ phải
     trông giống nhau, không thì cùng một thao tác mà hai lần mở ra hai kiểu. */
  .ht-tich-o { width:100%; min-height:38px; border:1px solid var(--vien-ro);
    border-radius:999px; background:var(--the); color:var(--chu); font-family:inherit;
    font-size:14px; font-weight:600; cursor:pointer; padding:8px 14px; text-align:left; }
  .ht-tich-o:hover { border-color:var(--xanh); color:var(--xanh); }
  .ht-tich-o.chon { background:var(--xanh); border-color:var(--xanh); color:#fff; font-weight:700; }
  .ht-tich-o:focus-visible { outline:2px solid var(--xanh); outline-offset:2px; }
  /* Mục đời cũ: hiện ra để người ta THẤY, nhưng không bấm được — cùng nếp với
     option "(cũ) disabled" của ô chọn. */
  .ht-tich-o.ht-tich-cu { opacity:.6; cursor:not-allowed; border-style:dashed; }
  .ht-tich-canh { font-size:12.5px; color:var(--cam-dam); margin-top:6px; line-height:1.45; }
  .ht-tich-xem { font-size:12.5px; color:var(--mo); margin-top:6px; }
  /* Ô chọn nhân viên (TVTS chính · backup). Danh sách có thể dài nên cho cuộn,
     đừng để nó đẩy nút Đồng ý xuống dưới màn hình. */
  .ht-nguoi-hang { display:flex; gap:6px; flex-wrap:wrap; max-height:168px; overflow:auto;
    padding:2px; }
  .ht-nguoi-o { display:flex; flex-direction:column; align-items:flex-start; gap:1px;
    padding:7px 11px; border:1px solid var(--vien); border-radius:var(--r-md); background:var(--nen-o);
    color:var(--chu); font:inherit; font-size:13px; cursor:pointer; text-align:left; }
  .ht-nguoi-o i { font-style:normal; font-size:11px; color:var(--mo); }
  .ht-nguoi-o:hover { border-color:var(--xanh); color:var(--xanh); }
  .ht-nguoi-o.chon { background:var(--xanh); border-color:var(--xanh); color:#fff; font-weight:600; }
  .ht-nguoi-o.chon i { color:rgba(255,255,255,.85); }
  .ht-nguoi-o:focus-visible { outline:2px solid var(--xanh); outline-offset:2px; }
  .ht-nguoi-xem { font-size:12.5px; color:var(--mo); margin-top:6px; }
  /* ⭐⭐ 23/08/2026 — BẤM MỚI XỔ RA, CÓ THANH TÌM.
     CÔ QUỲNH 22/08: *"lúc điền TVTS chính (người tư vấn lượt này) và TVTS backup
     (chọn được nhiều người) tôi thấy bạn trình bày hết ra trông rất khó nhìn và dài
     nên tôi muốn khi ấn vào mới ra list xong có thêm thanh tìm kiếm nữa nha"*.
     Trung tâm có 81 tài khoản. Trải hết ra là hộp Thêm học sinh dài gấp mấy màn
     hình, mà 79 cái tên trong đó không dính gì tới lượt đang gõ — người ta phải
     cuộn qua hết chỉ để tới nút Đồng ý.
     ⛔ Khối cũ `.ht-nguoi-hang` GIỮ NGUYÊN, chỉ đem nhét vào trong khối bung. Bỏ nó
        đi là mất luôn phần chọn — và bỏ `max-height` là danh sách 81 người đẩy nút
        Đồng ý ra khỏi màn hình, đúng cái lỗi khối ấy sinh ra để chặn. */
  .ht-nguoi-mo { display:flex; width:100%; align-items:center; justify-content:space-between;
    gap:10px; padding:10px 12px; border:1px solid var(--vien); border-radius:var(--r-lg);
    background:var(--the); color:var(--chu); font:inherit; font-size:14px;
    cursor:pointer; text-align:left; }
  .ht-nguoi-mo:hover, .ht-nguoi-mo[aria-expanded="true"] { border-color:var(--xanh); }
  .ht-nguoi-mo:focus-visible { outline:2px solid var(--xanh); outline-offset:2px; }
  /* Phần tóm tắt bên trái nút: chưa chọn thì chữ mờ, chọn rồi thì chữ thường. */
  .ht-nguoi-tom { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .ht-nguoi-tom.trong { color:var(--mo); }
  .ht-nguoi-mo em { font-style:normal; color:var(--mo); font-size:12px; flex:none; }
  .ht-nguoi-bung { margin-top:6px; border:1px solid var(--vien); border-radius:var(--r-lg);
    background:var(--the); padding:8px; }
  .ht-nguoi-tim { width:100%; height:36px; border:1px solid var(--vien); border-radius:var(--r-md);
    padding:8px 10px; font:inherit; font-size:13.5px; background:var(--the);
    color:var(--chu); margin-bottom:8px; }
  .ht-nguoi-tim:focus { outline:2px solid var(--xanh); border-color:transparent; }
  .ht-nguoi-khong { padding:8px 4px; color:var(--mo); font-size:13px; }
  .ht-gio-boc { display:flex; gap:6px; align-items:stretch; }
  /* Ô giờ là <textarea> (giữ được lớp hai khung giờ ngăn bằng xuống dòng) nhưng
     phải TRÔNG y hệt ô gõ thường — cùng chiều cao, cùng bo góc, không có tay kéo. */
  .ht-gio-in { flex:1; min-width:0; height:42px; min-height:42px; resize:none;
    border:1px solid var(--vien); border-radius:var(--r-lg); padding:10px 12px; font-size:14px;
    font-family:inherit; background:var(--the); color:var(--chu); line-height:20px;
    overflow:auto; white-space:pre; }
  .ht-gio-in:focus { outline:2px solid var(--xanh); border-color:transparent; }
  .ht-gio-nut { flex:none; width:42px; border:1px solid var(--vien); border-radius:var(--r-lg);
    background:var(--the); color:var(--mo); cursor:pointer; display:flex;
    align-items:center; justify-content:center; }
  .ht-gio-nut:hover { border-color:var(--xanh); color:var(--xanh); }
  .ht-gio-nut[aria-expanded="true"] { border-color:var(--xanh); color:var(--xanh); }
  .ht-gio-bang { margin-top:6px; border:1px solid var(--vien); border-radius:var(--r-lg);
    background:var(--the); padding:4px; max-height:210px; overflow:auto; }
  .ht-gio-mot { display:flex; width:100%; align-items:baseline; gap:10px; border:none;
    background:none; text-align:left; padding:8px 10px; border-radius:var(--r-md); cursor:pointer;
    font-family:inherit; font-size:14px; color:var(--chu); }
  .ht-gio-mot:hover { background:var(--nen2); }
  .ht-gio-mot b { font-weight:600; font-variant-numeric:tabular-nums; }
  .ht-gio-mot span { font-size:12px; color:var(--mo); margin-left:auto; }
  /* Mỗi ngày một dòng giờ — Boss chốt 03/09/2026. Nhãn ngày cố định 74px để
     mọi ô gõ thẳng hàng nhau; lệch hàng là mắt phải dò lại từ đầu mỗi dòng. */
  .ht-gio-hang { display:flex; flex-direction:column; gap:6px; }
  .ht-gio-dong { display:flex; align-items:center; gap:8px; }
  .ht-gio-nhan { flex:none; width:74px; font-size:13px; color:var(--mo); }
  .ht-gio-o { flex:1; min-width:0; height:42px; border:1px solid var(--vien);
    border-radius:var(--r-lg); padding:10px 12px; font-size:14px; font-family:inherit;
    background:var(--the); color:var(--chu); font-variant-numeric:tabular-nums; }
  .ht-gio-o:focus { outline:2px solid var(--xanh); border-color:transparent; }
  .ht-gio-xem { font-size:12.5px; color:var(--mo); margin-top:6px; }
  /* 🕐 GIỜ HỌC HAI Ô — Bắt đầu · Kết thúc (Boss chốt 21/09/2026; Coder dựng 22/09, chờ
     Designer duyệt). Mặc định một dòng, "＋ Thêm khung giờ" cho lớp học hai khung; mũi
     tên trong ô bày bảng chọn GIỜ rồi PHÚT (bước 5 phút). Màu lấy hết từ biến.
     ⛔ `.ht-o input` (dòng ~8952) đã lo cao 42px (48px trên điện thoại), viền, nền sáng /
        tối cho ô gõ. Ở đây CHỈ chừa chỗ cho mũi tên — phải viết `.ht-kg-boc .ht-kg-in`
        cho đủ độ đặc hiệu: viết `.ht-kg-in` trần là thua `.ht-o input` ở `padding`. */
  .ht-kg-hang { display:flex; flex-direction:column; gap:8px; }
  .ht-kg-dong { display:flex; flex-wrap:wrap; align-items:center; gap:6px 12px; }
  /* Ô giờ chỉ chứa 5 ký tự — kéo hết bề ngang hộp thoại là ô rộng 400px cho chữ "17:30". */
  .ht-kg-o { flex:0 1 240px; min-width:0; display:flex; align-items:center; gap:8px; }
  .ht-kg-nhan { flex:none; width:58px; font-size:13px; color:var(--mo); }
  .ht-kg-boc { position:relative; flex:1; min-width:0; }
  .ht-kg-boc .ht-kg-in { padding-right:42px; font-variant-numeric:tabular-nums; }
  .ht-kg-boc .ht-kg-in[aria-invalid="true"] { border-color:var(--do); }
  .ht-kg-xo { position:absolute; right:4px; top:50%; transform:translateY(-50%); width:34px;
    height:34px; border:none; border-radius:var(--r-md); background:transparent; color:var(--mo);
    cursor:pointer; display:flex; align-items:center; justify-content:center; font-size:14px; line-height:1; }
  .ht-kg-xo:hover, .ht-kg-xo[aria-expanded="true"] { background:var(--nen2); color:var(--xanh); }
  .ht-kg-xo:focus-visible { outline:2px solid var(--xanh); outline-offset:1px; }
  .ht-kg-bo { flex:none; width:34px; height:34px; border:1px solid var(--vien);
    border-radius:var(--r-md); background:var(--nen2); color:var(--mo); font-size:14px;
    line-height:1; cursor:pointer; }
  .ht-kg-bo:hover { background:var(--do-nen2); border-color:var(--do); color:var(--do); }
  .ht-kg-loi { flex-basis:100%; font-size:12.5px; color:var(--do); }
  .ht-kg-loi:empty { display:none; }
  .ht-kg-chon { flex-basis:100%; border:1px solid var(--vien); border-radius:var(--r-o, 8px);
    background:var(--the); padding:10px; display:flex; flex-direction:column; gap:6px; max-width:560px; }
  .ht-kg-chon-nhan { font-size:12px; font-weight:700; color:var(--mo); }
  /* 12 cột: hàng giờ trên là 00–11 (sáng), hàng dưới 12–23 (chiều tối); phút đủ một hàng. */
  .ht-kg-luoi { display:grid; grid-template-columns:repeat(12, minmax(0, 1fr)); gap:4px; }
  .ht-kg-luoi button { height:34px; border:1px solid var(--vien); border-radius:var(--r-md);
    background:var(--the); color:var(--chu); font-family:inherit; font-size:13.5px;
    font-variant-numeric:tabular-nums; cursor:pointer; }
  .ht-kg-luoi button:hover { border-color:var(--xanh); color:var(--xanh); }
  /* Đang chọn: đổi CẢ nền lẫn chữ đậm — người mù màu vẫn thấy (cùng nếp `.ht-thu-o.chon`). */
  .ht-kg-luoi button[aria-pressed="true"] { background:var(--xanh-dam); border-color:var(--xanh-dam);
    color:#fff; font-weight:700; }   /* xanh ĐẬM: chữ trắng 4,6:1 — xanh thường chỉ 3,2:1 */
  .ht-kg-duoi { display:flex; flex-wrap:wrap; gap:8px; margin-top:8px; }
  .ht-kg-them, .ht-kg-hay { display:inline-flex; align-items:center; gap:6px; padding:6px 12px;
    font-size:13px; font-weight:600; border:1px dashed var(--vien); border-radius:var(--r-md);
    background:transparent; color:var(--xanh); cursor:pointer; font-family:inherit; }
  .ht-kg-hay { border-style:solid; color:var(--chu); }
  .ht-kg-them:hover, .ht-kg-hay:hover, .ht-kg-hay[aria-expanded="true"] {
    border-color:var(--xanh); color:var(--xanh); }
  .ht-kg-bang { margin-top:6px; border:1px solid var(--vien); border-radius:var(--r-o, 8px);
    background:var(--the); padding:4px; max-height:210px; overflow:auto; max-width:560px; }
  .ht-kg-mot { display:flex; width:100%; align-items:baseline; gap:10px; border:none;
    background:none; text-align:left; padding:8px 10px; border-radius:var(--r-md); cursor:pointer;
    font-family:inherit; font-size:14px; color:var(--chu); }
  .ht-kg-mot:hover { background:var(--nen2); }
  .ht-kg-mot b { font-weight:600; font-variant-numeric:tabular-nums; }
  .ht-kg-mot span { font-size:12px; color:var(--mo); margin-left:auto; }
  /* Giờ cũ app đọc không chắc — báo nguyên văn, nền hổ phách như chip "đã tiếp nhận". */
  .ht-kg-cu { margin-bottom:8px; padding:8px 10px; border:1px solid var(--nhan-vien);
    border-radius:var(--r-md); background:var(--nhan-nen); color:var(--nhan-chu); font-size:12.5px; }
  .ht-kg-cu b { white-space:pre-wrap; color:var(--chu); }
  .ht-kg-xoacu { margin-left:4px; padding:2px 8px; border:1px solid var(--nhan-vien);
    border-radius:var(--r-md); background:transparent; color:var(--nhan-chu); font:inherit;
    font-weight:600; cursor:pointer; }
  .ht-kg-xem { font-size:12.5px; color:var(--mo); margin-top:6px; }
  .ht-kg-xem:empty { display:none; }
  .ht-kg-xem.canh { color:var(--nhan-chu); }
  /* Nền tối: chữ teal `--xanh` chỉ ~3:1 trên nền tối → `--muc` (luật chung, bài
     `thu-nen-toi-chu-sang-21-09` ⑥ canh). Nút giờ ĐANG CHỌN đứng SAU dòng rê chuột để
     giữ chữ trắng trên nền xanh đậm — cùng độ đặc hiệu, dòng sau thắng. */
  body.toi .ht-kg-hay { color:var(--chu); }
  body.toi .ht-kg-xo:hover, body.toi .ht-kg-xo[aria-expanded="true"], body.toi .ht-kg-luoi button:hover,
  body.toi .ht-kg-them, body.toi .ht-kg-them:hover, body.toi .ht-kg-hay:hover,
  body.toi .ht-kg-hay[aria-expanded="true"] { color:var(--muc); }
  body.toi .ht-kg-luoi button[aria-pressed="true"] { color:#fff; }
  /* Điện thoại: nhãn lên trên ô, hai ô + nút ✕ nằm CÙNG một dòng — mỗi dòng là một
     khung giờ. Để nhãn bên trái thì một khung bị bẻ làm hai dòng, dòng "Kết thúc" của
     khung này dính sát dòng "Bắt đầu" của khung sau (đo trên ảnh chụp 390px, 22/09). */
  @media (max-width: 560px) {
    .ht-kg-dong { align-items:flex-end; gap:6px 8px; }
    .ht-kg-o { flex:1 1 0; flex-direction:column; align-items:stretch; gap:3px; }
    .ht-kg-nhan { width:auto; font-size:12px; }
    .ht-kg-bo { margin-bottom:4px; }
    .ht-kg-luoi { grid-template-columns:repeat(6, minmax(0, 1fr)); }
  }
  /* 👁 Ô mật khẩu trong hộp thoại + nút hiện/ẩn (cô Quỳnh 03/08/2026: "lúc đổi mk cho nhìn mk"). */
  .ht-mk { position:relative; }
  .ht-mk input { padding-right:46px; }
  .ht-mk-hien { position:absolute; right:4px; top:50%; transform:translateY(-50%); border:none;
    background:transparent; cursor:pointer; font-size:19px; line-height:1; padding:4px 8px; border-radius:var(--r-md); }
  .ht-mk-hien:hover { background:var(--nen2); }
  /* Đang CHO XEM mật khẩu → gạch chéo qua icon con mắt, để liếc một cái là biết
     chữ đang phơi ra. Vẽ bằng CSS chứ không đổi icon: bản cũ gán thẳng emoji 🙈
     vào nút, bấm một cái là mất luôn icon nét mảnh. */
  .ht-mk-hien.dang-hien { color:var(--do); }
  .ht-mk-hien.dang-hien::after { content:""; position:absolute; left:50%; top:50%;
    width:22px; height:1.6px; background:var(--do); border-radius:var(--r-sm);
    transform:translate(-50%,-50%) rotate(-45deg); pointer-events:none; }
  .ht-loi { color:var(--do); font-size:13px; min-height:18px; margin-bottom:8px; }
  /* ⛔ VÁ — chữ đỏ đã dời lên ngay dưới tiêu đề (xem #htLoi). Lúc chưa có lỗi phải
     ẩn hẳn, không thì mọi hộp thoại đều hở một khoảng trống dưới tiêu đề. */
  .ht-loi:empty { display:none; }
  .ht-nut { display:flex; gap:9px; justify-content:flex-end; margin-top:16px; }
  .ht-nut button { border-radius:var(--r-lg); padding:11px 18px; font-size:14px; font-weight:700; border:1px solid var(--vien);
                   background:#fff; color:var(--chu); }
  .ht-nut button.chinh { background:var(--xanh); border-color:var(--xanh); color:#fff; }
  .ht-nut button.chinh:hover { background:var(--xanh-dam); }
  .ht-nut button.cam { background:var(--cam); border-color:var(--cam); color:#fff; }
  /* ⛔ 20/09/2026 — LUẬT NÀY TRƯỚC NAY THIẾU. `hoiHopThoai` nhận `mauOK` rồi gán
     thẳng làm tên lớp (`nut.className = mauOK`), và đã có BỐN chỗ gọi với "do" —
     hộp "Xoá lớp", "Bỏ khỏi lịch"… Không có luật nào bắt `.do` nên bấy lâu nay
     mấy nút ấy ra TRẮNG y như nút Huỷ bên cạnh: hai nút trông giống hệt nhau,
     mà một cái xoá thật. Mở Chrome thật nhìn tờ hỏi "Đăng xuất?" mới thấy.
     ⛔ Nút ĐẶC màu, không phải viền đỏ như `.cds-thoat` ở cột — ở đây nó là nút
        chính của hộp, đứng cạnh nút Huỷ trắng, nên phải nặng hơn hẳn mới đúng vai. */
  .ht-nut button.do { background:var(--do); border-color:var(--do); color:#fff; }
  .ht-nut button.do:hover { filter:brightness(.92); }
  .ht-mota { font-size:13.5px; color:var(--chu); line-height:1.6; margin:0 0 14px; white-space:pre-line; }
  /* ⓘ 29/08/2026 — dấu hỏi nhỏ mở phần giải thích dài (xem `motaThem` ở hoiHopThoai).
     Nằm ngay cuối dòng tóm tắt, không xuống dòng riêng — một dấu tròn 18px thì không
     đáng chiếm cả một dòng của màn hình vốn đang phải dọn cho gọn. */
  .ht-mota-i { display:inline-flex; align-items:center; justify-content:center;
               width:18px; height:18px; padding:0; margin-left:2px; vertical-align:-3px;
               border:0; border-radius:50%; background:#EDF1F5; color:#5A646E;
               font-size:12px; line-height:1; cursor:pointer; font-family:inherit; }
  .ht-mota-i:hover { background:#DFE6EC; color:#2D353D; }
  .ht-mota-i.mo { background:var(--xanh); color:#fff; }
  .ht-mota-dai { font-size:12.5px; color:var(--mo); line-height:1.65; margin:-8px 0 14px;
                 padding:9px 12px; border-radius:var(--r-md); background:#F6F8FA;
                 border:1px solid var(--vien); white-space:pre-line; }
  body.toi .ht-mota-i { background:#2E353D; color:#A4ADB6; }
  body.toi .ht-mota-dai { background:#242A30; }
  /* ============ 🏛 BỘ ICON NÉT MẢNH CHO NÚT & NHÃN (06/08/2026) ============
     Cô Quỳnh: "thay hết emoji sang nét mảnh và chỉ giữ lại báo trạng thái."

     ⛔⛔ VÌ SAO TÊN LỚP KHÔNG CÓ DẤU NHÁY — ĐỪNG "SỬA LẠI CHO ĐẸP".
     Icon này nằm trong hàng trăm chuỗi HTML rải khắp file JS. Lần đầu tôi viết
     <i class="ic ic-xoa"></i> và HỎNG NGAY: chỗ nào chuỗi JS dùng dấu nháy KÉP thì
     class="..." làm ĐỨT chuỗi → lỗi cú pháp. Nay dùng MỘT tên lớp không dấu nháy
     (<i class=ic-xoa></i>) — HTML5 cho phép, và không thể làm đứt chuỗi dù chuỗi
     bọc bằng nháy đơn hay nháy kép.

     Dùng CSS mask + currentColor → icon TỰ ăn theo màu chữ của nút, nên nút teal ra
     icon teal, nút đỏ ra icon đỏ, nền tối cũng tự đúng, khỏi khai màu từng chỗ.
     Tiền tố: ic-*  = có chừa lề phải (icon đứng trước chữ)
              icx-* = không lề (nút CHỈ có icon).
     ⛔ Emoji BÁO TRẠNG THÁI (🟢 🟠 🔴 ✅ ❌ ⚠️) CỐ Ý giữ nguyên theo yêu cầu. */
  i[class^="ic-"], i[class^="icx-"] {
    display:inline-block; width:15px; height:15px; flex:none; vertical-align:-2.5px;
    background-color:currentColor;
    -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
    -webkit-mask-position:center;  mask-position:center;
    -webkit-mask-size:contain;     mask-size:contain; }
  i[class^="ic-"] { margin-right:6px; }
  .ic-xoa, .icx-xoa { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 6h17M9.5 6V4.4A1.4 1.4 0 0 1 10.9 3h2.2a1.4 1.4 0 0 1 1.4 1.4V6'/%3E%3Cpath d='M18.2 6l-.8 13.1a1.6 1.6 0 0 1-1.6 1.5H8.2a1.6 1.6 0 0 1-1.6-1.5L5.8 6'/%3E%3Cpath d='M10 10.5v6M14 10.5v6'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 6h17M9.5 6V4.4A1.4 1.4 0 0 1 10.9 3h2.2a1.4 1.4 0 0 1 1.4 1.4V6'/%3E%3Cpath d='M18.2 6l-.8 13.1a1.6 1.6 0 0 1-1.6 1.5H8.2a1.6 1.6 0 0 1-1.6-1.5L5.8 6'/%3E%3Cpath d='M10 10.5v6M14 10.5v6'/%3E%3C/svg%3E"); }
  .ic-lammoi, .icx-lammoi { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20.5 12a8.5 8.5 0 1 1-2.6-6.1'/%3E%3Cpath d='M20.8 4.2v4.6h-4.6'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20.5 12a8.5 8.5 0 1 1-2.6-6.1'/%3E%3Cpath d='M20.8 4.2v4.6h-4.6'/%3E%3C/svg%3E"); }
  /* ⓘ Thông tin — thêm 18/09/2026 cho nút gom số liệu ở đầu bảng.
     ⛔⛔ PHẢI LÀ ICON VECTOR, ĐỪNG DÙNG KÝ TỰ `ⓘ` (U+24D8). Boss chê *"nhìn cái icon
        này hơi mờ và nhiễu"* — đúng, vì ký tự ấy do PHÔNG vẽ chứ không phải app vẽ.
        Phông chính của app không có glyph này nên trình duyệt rơi xuống phông DỰ PHÒNG
        của hệ điều hành: nét mảnh, không căn theo lưới điểm ảnh, và MỖI MÁY MỘT KIỂU.
     ⛔ `stroke-width` ở đây là **2**, không phải 1.8 như cả bộ: vòng tròn bán kính 9
        vẽ ở 16px thì nét 1.8 ra 1,2 điểm ảnh — rơi vào giữa hai điểm ảnh nên bị tán
        mờ. Icon khác trong bộ toàn nét THẲNG nên không dính; vòng tròn thì dính.
     ⛔ ĐẮNG ĐỔI `stroke-width` CỦA CẢ BỘ cho "đồng bộ": 1.8 là số đã chốt cho
        mọi icon khác, đổi hết là cả app dày lên một lượt. */
  .ic-tt, .icx-tt { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 11.2v4.6'/%3E%3Cpath d='M12 8.05h.01'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 11.2v4.6'/%3E%3Cpath d='M12 8.05h.01'/%3E%3C/svg%3E"); }
  .ic-them, .icx-them { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 5v14M5 12h14'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 5v14M5 12h14'/%3E%3C/svg%3E"); }
  .ic-luu, .icx-luu { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 5.9A1.4 1.4 0 0 1 5.9 4.5h10.2L19.5 8v10.1a1.4 1.4 0 0 1-1.4 1.4H5.9a1.4 1.4 0 0 1-1.4-1.4z'/%3E%3Cpath d='M8.2 4.5v5h7v-5'/%3E%3Cpath d='M8.2 19.5v-5.6h7.6v5.6'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 5.9A1.4 1.4 0 0 1 5.9 4.5h10.2L19.5 8v10.1a1.4 1.4 0 0 1-1.4 1.4H5.9a1.4 1.4 0 0 1-1.4-1.4z'/%3E%3Cpath d='M8.2 4.5v5h7v-5'/%3E%3Cpath d='M8.2 19.5v-5.6h7.6v5.6'/%3E%3C/svg%3E"); }
  .ic-xuong, .icx-xuong { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4.5v14M6 13l6 6 6-6'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4.5v14M6 13l6 6 6-6'/%3E%3C/svg%3E"); }
  .ic-len, .icx-len { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 19.5v-14M6 11l6-6 6 6'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 19.5v-14M6 11l6-6 6 6'/%3E%3C/svg%3E"); }
  .ic-trai, .icx-trai { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 5.5 8 12l6.5 6.5'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.5 5.5 8 12l6.5 6.5'/%3E%3C/svg%3E"); }
  .ic-phai, .icx-phai { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.5 5.5 16 12l-6.5 6.5'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.5 5.5 16 12l-6.5 6.5'/%3E%3C/svg%3E"); }
  .ic-doicho, .icx-doicho { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7.5 8.5 4 12l3.5 3.5M16.5 8.5 20 12l-3.5 3.5M4.6 12h14.8'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7.5 8.5 4 12l3.5 3.5M16.5 8.5 20 12l-3.5 3.5M4.6 12h14.8'/%3E%3C/svg%3E"); }
  .ic-tamdung, .icx-tamdung { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.5 5.5v13M14.5 5.5v13'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.5 5.5v13M14.5 5.5v13'/%3E%3C/svg%3E"); }
  .ic-hoantac, .icx-hoantac { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5h10a5.5 5.5 0 0 1 0 11H8'/%3E%3Cpath d='M7 4.5 3.2 8.5 7 12.5'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5h10a5.5 5.5 0 0 1 0 11H8'/%3E%3Cpath d='M7 4.5 3.2 8.5 7 12.5'/%3E%3C/svg%3E"); }
  .ic-but, .icx-but { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h4.2L19.4 8.8a2 2 0 0 0 0-2.8l-1.4-1.4a2 2 0 0 0-2.8 0L4 15.8z'/%3E%3Cpath d='M14.6 5.8 18.2 9.4'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h4.2L19.4 8.8a2 2 0 0 0 0-2.8l-1.4-1.4a2 2 0 0 0-2.8 0L4 15.8z'/%3E%3Cpath d='M14.6 5.8 18.2 9.4'/%3E%3C/svg%3E"); }
  .ic-tomau, .icx-tomau { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 15.5 15.6 8a2 2 0 0 1 2.8 0l.6.6a2 2 0 0 1 0 2.8L11.5 19H8z'/%3E%3Cpath d='M4 21h9'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 15.5 15.6 8a2 2 0 0 1 2.8 0l.6.6a2 2 0 0 1 0 2.8L11.5 19H8z'/%3E%3Cpath d='M4 21h9'/%3E%3C/svg%3E"); }
  .ic-mat, .icx-mat { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 12S6 5.6 12 5.6 21.5 12 21.5 12 18 18.4 12 18.4 2.5 12 2.5 12z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 12S6 5.6 12 5.6 21.5 12 21.5 12 18 18.4 12 18.4 2.5 12 2.5 12z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E"); }
  .ic-nguoi, .icx-nguoi { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8' r='3.4'/%3E%3Cpath d='M5 20c0-3.4 3.1-5.4 7-5.4s7 2 7 5.4'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8' r='3.4'/%3E%3Cpath d='M5 20c0-3.4 3.1-5.4 7-5.4s7 2 7 5.4'/%3E%3C/svg%3E"); }
  .ic-nhom, .icx-nhom { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='8' r='3.2'/%3E%3Cpath d='M3 19c0-3.1 2.7-4.9 6-4.9s6 1.8 6 4.9'/%3E%3Cpath d='M16.2 5.5a3.2 3.2 0 0 1 0 6M17.6 14.6c2 .6 3.4 2.2 3.4 4.4'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='8' r='3.2'/%3E%3Cpath d='M3 19c0-3.1 2.7-4.9 6-4.9s6 1.8 6 4.9'/%3E%3Cpath d='M16.2 5.5a3.2 3.2 0 0 1 0 6M17.6 14.6c2 .6 3.4 2.2 3.4 4.4'/%3E%3C/svg%3E"); }
  .ic-lop, .icx-lop { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 21h18'/%3E%3Cpath d='M5.2 21V8.2L12 4l6.8 4.2V21'/%3E%3Cpath d='M10 21v-5h4v5'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 21h18'/%3E%3Cpath d='M5.2 21V8.2L12 4l6.8 4.2V21'/%3E%3Cpath d='M10 21v-5h4v5'/%3E%3C/svg%3E"); }
  .ic-bang, .icx-bang { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='5' y='4' width='14' height='17' rx='2'/%3E%3Cpath d='M9 2.6h6v3H9z'/%3E%3Cpath d='M8.6 11h6.8M8.6 15h4.4'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='5' y='4' width='14' height='17' rx='2'/%3E%3Cpath d='M9 2.6h6v3H9z'/%3E%3Cpath d='M8.6 11h6.8M8.6 15h4.4'/%3E%3C/svg%3E"); }
  .ic-guilen, .icx-guilen { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 15.5V19a1.5 1.5 0 0 0 1.5 1.5h13A1.5 1.5 0 0 0 20 19v-3.5'/%3E%3Cpath d='M12 3.5v12M7.5 8 12 3.5 16.5 8'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 15.5V19a1.5 1.5 0 0 0 1.5 1.5h13A1.5 1.5 0 0 0 20 19v-3.5'/%3E%3Cpath d='M12 3.5v12M7.5 8 12 3.5 16.5 8'/%3E%3C/svg%3E"); }
  .ic-nhanve, .icx-nhanve { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 15.5V19a1.5 1.5 0 0 0 1.5 1.5h13A1.5 1.5 0 0 0 20 19v-3.5'/%3E%3Cpath d='M12 15.5v-12M7.5 11l4.5 4.5L16.5 11'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 15.5V19a1.5 1.5 0 0 0 1.5 1.5h13A1.5 1.5 0 0 0 20 19v-3.5'/%3E%3Cpath d='M12 15.5v-12M7.5 11l4.5 4.5L16.5 11'/%3E%3C/svg%3E"); }
  .ic-luutru, .icx-luutru { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4.5' width='18' height='4.5' rx='1.4'/%3E%3Cpath d='M5 9v9.5A1.5 1.5 0 0 0 6.5 20h11a1.5 1.5 0 0 0 1.5-1.5V9'/%3E%3Cpath d='M9.8 12.8h4.4'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4.5' width='18' height='4.5' rx='1.4'/%3E%3Cpath d='M5 9v9.5A1.5 1.5 0 0 0 6.5 20h11a1.5 1.5 0 0 0 1.5-1.5V9'/%3E%3Cpath d='M9.8 12.8h4.4'/%3E%3C/svg%3E"); }
  .ic-hop, .icx-hop { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8.5 12 4l9 4.5v7L12 20l-9-4.5z'/%3E%3Cpath d='M3 8.5 12 13l9-4.5M12 13v7'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8.5 12 4l9 4.5v7L12 20l-9-4.5z'/%3E%3Cpath d='M3 8.5 12 13l9-4.5M12 13v7'/%3E%3C/svg%3E"); }
  .ic-lich, .icx-lich { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.5' y='5' width='17' height='16' rx='2'/%3E%3Cpath d='M3.5 10h17M8 3v4M16 3v4'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.5' y='5' width='17' height='16' rx='2'/%3E%3Cpath d='M3.5 10h17M8 3v4M16 3v4'/%3E%3C/svg%3E"); }
  .ic-lienket, .icx-lienket { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 13.6a4 4 0 0 0 5.7 0l2.6-2.6a4 4 0 0 0-5.7-5.7l-1.4 1.4'/%3E%3Cpath d='M14 10.4a4 4 0 0 0-5.7 0l-2.6 2.6a4 4 0 0 0 5.7 5.7l1.4-1.4'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 13.6a4 4 0 0 0 5.7 0l2.6-2.6a4 4 0 0 0-5.7-5.7l-1.4 1.4'/%3E%3Cpath d='M14 10.4a4 4 0 0 0-5.7 0l-2.6 2.6a4 4 0 0 0 5.7 5.7l1.4-1.4'/%3E%3C/svg%3E"); }
  .ic-ghim, .icx-ghim { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 3.5h6l-.8 5.2 3.3 3.3H6.5l3.3-3.3z'/%3E%3Cpath d='M12 12v8.5'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 3.5h6l-.8 5.2 3.3 3.3H6.5l3.3-3.3z'/%3E%3Cpath d='M12 12v8.5'/%3E%3C/svg%3E"); }
  .ic-sach, .icx-sach { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 5.5C5 4 8.5 4 12 5.6 15.5 4 19 4 21 5.5v13c-2-1.5-5.5-1.5-9 .1-3.5-1.6-7-1.6-9-.1z'/%3E%3Cpath d='M12 5.6v13'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 5.5C5 4 8.5 4 12 5.6 15.5 4 19 4 21 5.5v13c-2-1.5-5.5-1.5-9 .1-3.5-1.6-7-1.6-9-.1z'/%3E%3Cpath d='M12 5.6v13'/%3E%3C/svg%3E"); }
  .ic-cup, .icx-cup { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 4h8v5.5a4 4 0 0 1-8 0z'/%3E%3Cpath d='M8 5.5H5.2a2.8 2.8 0 0 0 2.8 4M16 5.5h2.8a2.8 2.8 0 0 1-2.8 4'/%3E%3Cpath d='M12 13.5V17M8.5 20.5h7'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 4h8v5.5a4 4 0 0 1-8 0z'/%3E%3Cpath d='M8 5.5H5.2a2.8 2.8 0 0 0 2.8 4M16 5.5h2.8a2.8 2.8 0 0 1-2.8 4'/%3E%3Cpath d='M12 13.5V17M8.5 20.5h7'/%3E%3C/svg%3E"); }
  .ic-totnghiep, .icx-totnghiep { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4 2.6 9l9.4 5 9.4-5z'/%3E%3Cpath d='M6.6 11.3V16c0 1.5 2.4 2.8 5.4 2.8s5.4-1.3 5.4-2.8v-4.7'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4 2.6 9l9.4 5 9.4-5z'/%3E%3Cpath d='M6.6 11.3V16c0 1.5 2.4 2.8 5.4 2.8s5.4-1.3 5.4-2.8v-4.7'/%3E%3C/svg%3E"); }
  .ic-bieudo, .icx-bieudo { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 21h18'/%3E%3Cpath d='M6 18v-6M11 18V7M16 18v-9'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 21h18'/%3E%3Cpath d='M6 18v-6M11 18V7M16 18v-9'/%3E%3C/svg%3E"); }
  .ic-thehs, .icx-thehs { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.5' y='5' width='19' height='14' rx='2'/%3E%3Ccircle cx='8.4' cy='10.8' r='2.1'/%3E%3Cpath d='M5 16c.6-1.6 1.9-2.4 3.4-2.4S11.2 14.4 11.8 16'/%3E%3Cpath d='M14.6 10h4.2M14.6 13.4h4.2'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.5' y='5' width='19' height='14' rx='2'/%3E%3Ccircle cx='8.4' cy='10.8' r='2.1'/%3E%3Cpath d='M5 16c.6-1.6 1.9-2.4 3.4-2.4S11.2 14.4 11.8 16'/%3E%3Cpath d='M14.6 10h4.2M14.6 13.4h4.2'/%3E%3C/svg%3E"); }
  .ic-hoi, .icx-hoi { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.6'/%3E%3Cpath d='M9.6 9.4a2.5 2.5 0 1 1 3.3 2.4c-.6.2-.9.8-.9 1.4v.5'/%3E%3Cpath d='M12 17.1v.1'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.6'/%3E%3Cpath d='M9.6 9.4a2.5 2.5 0 1 1 3.3 2.4c-.6.2-.9.8-.9 1.4v.5'/%3E%3Cpath d='M12 17.1v.1'/%3E%3C/svg%3E"); }
  .ic-xong, .icx-xong { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 12.6l4.8 4.8L19.6 7.1'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 12.6l4.8 4.8L19.6 7.1'/%3E%3C/svg%3E"); }
  .ic-canhbao, .icx-canhbao { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.2L22 20.4H2z'/%3E%3Cpath d='M12 9.4v4.6'/%3E%3Ccircle cx='12' cy='17.4' r='.9' fill='%23000' stroke='none'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.2L22 20.4H2z'/%3E%3Cpath d='M12 9.4v4.6'/%3E%3Ccircle cx='12' cy='17.4' r='.9' fill='%23000' stroke='none'/%3E%3C/svg%3E"); }
  .ic-vongtron, .icx-vongtron { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8'%3E%3Ccircle cx='12' cy='12' r='8.4'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8'%3E%3Ccircle cx='12' cy='12' r='8.4'/%3E%3C/svg%3E"); }
  .ic-dongho, .icx-dongho { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.6'/%3E%3Cpath d='M12 7v5.2l3.2 2'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.6'/%3E%3Cpath d='M12 7v5.2l3.2 2'/%3E%3C/svg%3E"); }
  .ic-ytuong, .icx-ytuong { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.4 17.5h5.2'/%3E%3Cpath d='M10 20.5h4'/%3E%3Cpath d='M8.2 13.6a5 5 0 1 1 7.6 0c-.8.9-1.3 1.7-1.4 2.6H9.6c-.1-.9-.6-1.7-1.4-2.6z'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.4 17.5h5.2'/%3E%3Cpath d='M10 20.5h4'/%3E%3Cpath d='M8.2 13.6a5 5 0 1 1 7.6 0c-.8.9-1.3 1.7-1.4 2.6H9.6c-.1-.9-.6-1.7-1.4-2.6z'/%3E%3C/svg%3E"); }
  .ic-tocdo, .icx-tocdo { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.4 18a8.6 8.6 0 1 1 15.2 0'/%3E%3Cpath d='M12 13.6 15.6 9'/%3E%3Ccircle cx='12' cy='14.6' r='1.2'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.4 18a8.6 8.6 0 1 1 15.2 0'/%3E%3Cpath d='M12 13.6 15.6 9'/%3E%3Ccircle cx='12' cy='14.6' r='1.2'/%3E%3C/svg%3E"); }
  .ic-tim, .icx-tim { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='10.8' cy='10.8' r='6.3'/%3E%3Cpath d='M15.4 15.4 20.5 20.5'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='10.8' cy='10.8' r='6.3'/%3E%3Cpath d='M15.4 15.4 20.5 20.5'/%3E%3C/svg%3E"); }
  .ic-loc, .icx-loc { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 5.5h17l-6.6 7.6v5.6l-3.8 2.1v-7.7z'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 5.5h17l-6.6 7.6v5.6l-3.8 2.1v-7.7z'/%3E%3C/svg%3E"); }
  .ic-loa, .icx-loa { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 11v2a1 1 0 0 0 1 1h2l7 4.4V5.6L6 10H4a1 1 0 0 0-1 1z'/%3E%3Cpath d='M16.6 9.2a4 4 0 0 1 0 5.6'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 11v2a1 1 0 0 0 1 1h2l7 4.4V5.6L6 10H4a1 1 0 0 0-1 1z'/%3E%3Cpath d='M16.6 9.2a4 4 0 0 1 0 5.6'/%3E%3C/svg%3E"); }
  .ic-chuong2, .icx-chuong2 { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 9a6 6 0 1 0-12 0c0 6-2 7.5-2 7.5h16S18 15 18 9z'/%3E%3Cpath d='M13.7 20a2 2 0 0 1-3.4 0'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 9a6 6 0 1 0-12 0c0 6-2 7.5-2 7.5h16S18 15 18 9z'/%3E%3Cpath d='M13.7 20a2 2 0 0 1-3.4 0'/%3E%3C/svg%3E"); }
  .ic-thu, .icx-thu { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.5' y='5' width='19' height='14' rx='2'/%3E%3Cpath d='M3.2 6.6 12 13l8.8-6.4'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.5' y='5' width='19' height='14' rx='2'/%3E%3Cpath d='M3.2 6.6 12 13l8.8-6.4'/%3E%3C/svg%3E"); }
  .ic-khoa, .icx-khoa { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4.5' y='10.5' width='15' height='10' rx='2'/%3E%3Cpath d='M8 10.5V7.6a4 4 0 0 1 8 0v2.9'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4.5' y='10.5' width='15' height='10' rx='2'/%3E%3Cpath d='M8 10.5V7.6a4 4 0 0 1 8 0v2.9'/%3E%3C/svg%3E"); }
  .ic-mokhoa, .icx-mokhoa { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4.5' y='10.5' width='15' height='10' rx='2'/%3E%3Cpath d='M8 10.5V7.6a4 4 0 0 1 7.5-1.9'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4.5' y='10.5' width='15' height='10' rx='2'/%3E%3Cpath d='M8 10.5V7.6a4 4 0 0 1 7.5-1.9'/%3E%3C/svg%3E"); }
  /* 🔔 08/08/2026 — CHUÔNG cho nút thông báo. Trước đây dùng `ic-chuong` mà lớp này
     CHƯA HỀ được khai ở đây, nên thẻ <i> ra một ô trống — cô Quỳnh nói "nhìn như nút
     tắt máy tính". ⛔ Thêm icon mới cho thanh trên thì PHẢI khai một dòng ở khối này,
     không thì y hệt như vậy. */
  .ic-chuong, .icx-chuong { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 9a6 6 0 1 0-12 0c0 6-2 7.5-2 7.5h16S18 15 18 9z'/%3E%3Cpath d='M13.7 20a2 2 0 0 1-3.4 0'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 9a6 6 0 1 0-12 0c0 6-2 7.5-2 7.5h16S18 15 18 9z'/%3E%3Cpath d='M13.7 20a2 2 0 0 1-3.4 0'/%3E%3C/svg%3E"); }
  .ic-banhxe, .icx-banhxe { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12.2 2h-.4a2 2 0 0 0-2 2v.2a2 2 0 0 1-1 1.7l-.4.3a2 2 0 0 1-2 0l-.2-.1a2 2 0 0 0-2.7.7l-.2.4a2 2 0 0 0 .7 2.7l.2.1a2 2 0 0 1 1 1.7v.5a2 2 0 0 1-1 1.8l-.2.1a2 2 0 0 0-.7 2.7l.2.4a2 2 0 0 0 2.7.7l.2-.1a2 2 0 0 1 2 0l.4.3a2 2 0 0 1 1 1.7v.2a2 2 0 0 0 2 2h.4a2 2 0 0 0 2-2v-.2a2 2 0 0 1 1-1.7l.4-.3a2 2 0 0 1 2 0l.2.1a2 2 0 0 0 2.7-.7l.2-.4a2 2 0 0 0-.7-2.7l-.2-.1a2 2 0 0 1-1-1.8v-.5a2 2 0 0 1 1-1.7l.2-.1a2 2 0 0 0 .7-2.7l-.2-.4a2 2 0 0 0-2.7-.7l-.2.1a2 2 0 0 1-2 0l-.4-.3a2 2 0 0 1-1-1.7V4a2 2 0 0 0-2-2z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12.2 2h-.4a2 2 0 0 0-2 2v.2a2 2 0 0 1-1 1.7l-.4.3a2 2 0 0 1-2 0l-.2-.1a2 2 0 0 0-2.7.7l-.2.4a2 2 0 0 0 .7 2.7l.2.1a2 2 0 0 1 1 1.7v.5a2 2 0 0 1-1 1.8l-.2.1a2 2 0 0 0-.7 2.7l.2.4a2 2 0 0 0 2.7.7l.2-.1a2 2 0 0 1 2 0l.4.3a2 2 0 0 1 1 1.7v.2a2 2 0 0 0 2 2h.4a2 2 0 0 0 2-2v-.2a2 2 0 0 1 1-1.7l.4-.3a2 2 0 0 1 2 0l.2.1a2 2 0 0 0 2.7-.7l.2-.4a2 2 0 0 0-.7-2.7l-.2-.1a2 2 0 0 1-1-1.8v-.5a2 2 0 0 1 1-1.7l.2-.1a2 2 0 0 0 .7-2.7l-.2-.4a2 2 0 0 0-2.7-.7l-.2.1a2 2 0 0 1-2 0l-.4-.3a2 2 0 0 1-1-1.7V4a2 2 0 0 0-2-2z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E"); }
  .ic-dich, .icx-dich { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.4'/%3E%3Ccircle cx='12' cy='12' r='4'/%3E%3Ccircle cx='12' cy='12' r='.9'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.4'/%3E%3Ccircle cx='12' cy='12' r='4'/%3E%3Ccircle cx='12' cy='12' r='.9'/%3E%3C/svg%3E"); }
  .ic-lap, .icx-lap { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 9.5A3.5 3.5 0 0 1 7.5 6h11'/%3E%3Cpath d='M15.5 3 18.8 6l-3.3 3'/%3E%3Cpath d='M20 14.5a3.5 3.5 0 0 1-3.5 3.5h-11'/%3E%3Cpath d='M8.5 21 5.2 18l3.3-3'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 9.5A3.5 3.5 0 0 1 7.5 6h11'/%3E%3Cpath d='M15.5 3 18.8 6l-3.3 3'/%3E%3Cpath d='M20 14.5a3.5 3.5 0 0 1-3.5 3.5h-11'/%3E%3Cpath d='M8.5 21 5.2 18l3.3-3'/%3E%3C/svg%3E"); }
  .ic-anh, .icx-anh { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.6' y='6.5' width='18.8' height='13.5' rx='2'/%3E%3Cpath d='M8.5 6.5 10 3.8h4l1.5 2.7'/%3E%3Ccircle cx='12' cy='13.2' r='3.4'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.6' y='6.5' width='18.8' height='13.5' rx='2'/%3E%3Cpath d='M8.5 6.5 10 3.8h4l1.5 2.7'/%3E%3Ccircle cx='12' cy='13.2' r='3.4'/%3E%3C/svg%3E"); }
  .ic-mic, .icx-mic { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='9' y='2.6' width='6' height='11' rx='3'/%3E%3Cpath d='M5.5 11.5a6.5 6.5 0 0 0 13 0'/%3E%3Cpath d='M12 18v3.4'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='9' y='2.6' width='6' height='11' rx='3'/%3E%3Cpath d='M5.5 11.5a6.5 6.5 0 0 0 13 0'/%3E%3Cpath d='M12 18v3.4'/%3E%3C/svg%3E"); }
  .ic-tainghe, .icx-tainghe { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 14.5v-2a8 8 0 0 1 16 0v2'/%3E%3Crect x='2.8' y='14' width='4.4' height='6.4' rx='1.8'/%3E%3Crect x='16.8' y='14' width='4.4' height='6.4' rx='1.8'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 14.5v-2a8 8 0 0 1 16 0v2'/%3E%3Crect x='2.8' y='14' width='4.4' height='6.4' rx='1.8'/%3E%3Crect x='16.8' y='14' width='4.4' height='6.4' rx='1.8'/%3E%3C/svg%3E"); }
  .ic-nangsang, .icx-nangsang { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='4'/%3E%3Cpath d='M12 2.6v2.2M12 19.2v2.2M4.6 12H2.4M21.6 12h-2.2M6.8 6.8 5.2 5.2M18.8 18.8l-1.6-1.6M6.8 17.2l-1.6 1.6M18.8 5.2l-1.6 1.6'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='4'/%3E%3Cpath d='M12 2.6v2.2M12 19.2v2.2M4.6 12H2.4M21.6 12h-2.2M6.8 6.8 5.2 5.2M18.8 18.8l-1.6-1.6M6.8 17.2l-1.6 1.6M18.8 5.2l-1.6 1.6'/%3E%3C/svg%3E"); }
  .ic-nentoi, .icx-nentoi { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20.5 14.2A8.6 8.6 0 0 1 9.8 3.5a8.6 8.6 0 1 0 10.7 10.7z'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20.5 14.2A8.6 8.6 0 0 1 9.8 3.5a8.6 8.6 0 1 0 10.7 10.7z'/%3E%3C/svg%3E"); }
  .ic-dienthoai2, .icx-dienthoai2 { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='7' y='2.5' width='10' height='19' rx='2.2'/%3E%3Cpath d='M10.8 18.6h2.4'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='7' y='2.5' width='10' height='19' rx='2.2'/%3E%3Cpath d='M10.8 18.6h2.4'/%3E%3C/svg%3E"); }
  .ic-bangmau, .icx-bangmau { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.2a8.8 8.8 0 0 0 0 17.6c1.2 0 1.8-.8 1.8-1.7 0-.9-.7-1.5-.7-2.3 0-.8.7-1.4 1.5-1.4h1.6a4.6 4.6 0 0 0 4.6-4.6c0-4.2-3.9-7.6-8.8-7.6z'/%3E%3Ccircle cx='8' cy='10' r='1'/%3E%3Ccircle cx='12' cy='7.6' r='1'/%3E%3Ccircle cx='16' cy='10' r='1'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.2a8.8 8.8 0 0 0 0 17.6c1.2 0 1.8-.8 1.8-1.7 0-.9-.7-1.5-.7-2.3 0-.8.7-1.4 1.5-1.4h1.6a4.6 4.6 0 0 0 4.6-4.6c0-4.2-3.9-7.6-8.8-7.6z'/%3E%3Ccircle cx='8' cy='10' r='1'/%3E%3Ccircle cx='12' cy='7.6' r='1'/%3E%3Ccircle cx='16' cy='10' r='1'/%3E%3C/svg%3E"); }
  .ic-nha, .icx-nha { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 10.2 12 3l9 7.2'/%3E%3Cpath d='M5.5 9v11h13V9'/%3E%3Cpath d='M9.8 20v-6.2h4.4V20'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 10.2 12 3l9 7.2'/%3E%3Cpath d='M5.5 9v11h13V9'/%3E%3Cpath d='M9.8 20v-6.2h4.4V20'/%3E%3C/svg%3E"); }
  .ic-mam, .icx-mam { -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20.5V12'/%3E%3Cpath d='M12 12C12 8.2 9.1 5.8 5 5.8c0 3.8 2.9 6.2 7 6.2z'/%3E%3Cpath d='M12 14.2c0-3.2 2.4-5.3 5.9-5.3 0 3.2-2.4 5.3-5.9 5.3z'/%3E%3C/svg%3E"); mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20.5V12'/%3E%3Cpath d='M12 12C12 8.2 9.1 5.8 5 5.8c0 3.8 2.9 6.2 7 6.2z'/%3E%3Cpath d='M12 14.2c0-3.2 2.4-5.3 5.9-5.3 0 3.2-2.4 5.3-5.9 5.3z'/%3E%3C/svg%3E"); }

/* ══════════════════════════════════════════════════════════════════════════════
   📱 NĂM CÔNG CỤ TUYỂN SINH TRÊN ĐIỆN THOẠI — cô Quỳnh 16/08/2026
   *"giao diện toàn bộ công cụ tuyển sinh trên điện thoại đều có vấn đề"*
   *"Nhớ thiết kế thật chuyên nghiệp sắp xếp thật business và chuyên nghiệp nha"*
   ──────────────────────────────────────────────────────────────────────────────
   Gồm: Sổ tuyển sinh · Thống kê tuyển sinh · Lịch test · Test đầu vào · Hồ sơ kiểm tra.

   ⛔ DÁN Ở ĐÂY, NGAY TRƯỚC thẻ đóng của khối CSS — không rải vào từng khối từng công cụ.
      ⛔⛔ VÀ ĐỪNG VIẾT NGUYÊN VĂN TÊN THẺ ĐÓNG ẤY VÀO ĐÂY. Sự cố 16/08/2026: bản đầu
         của chú thích này ghi đúng chuỗi thẻ đóng, trình duyệt đọc HTML thấy chuỗi đó
         là ĐÓNG KHỐI CSS NGAY TẠI ĐÓ — dù nó nằm trong chú thích, vì HTML không hiểu
         chú thích của CSS. Toàn bộ phần sau biến thành CHỮ HIỆN RA MÀN HÌNH, cô Quỳnh
         mở app thấy một trang đầy chữ lạ. 144 bài kiểm KHÔNG bắt được (chúng đọc file
         dạng chuỗi, không dựng trang lên xem).
      Media query KHÔNG cộng điểm ưu tiên: cùng độ mạnh thì cái viết SAU thắng. Nằm
      cuối là thắng mọi luật gốc mà không phải tính toán gì. Và nó nằm NGOÀI mọi cửa
      sổ cắt chuỗi của bài kiểm (thu-lich-test-giao-dien.js cắt từ `  .lt-man {` tới
      `  .tks-thanh {`; thu-icon-va-khung.js cắt 900 ký tự từ `.tks-thanh-o {`), nên
      không bài nào bị xê dịch.

   ⛔ MỌI @media ĐỀU GHI `screen and` — lúc in, khổ A4 rộng 210mm ≈ 794px CSS nên LỌT
      vào mốc 820px. Thiếu chữ `screen` là tự dưng sửa luôn tờ phiếu in gửi phụ huynh
      (khối @media print dòng 1987–2055).

   ⛔ KHÔNG đẻ mốc màn hình mới: chỉ dùng 900 / 820 / 640 / 560 đã có sẵn trong app.
   ⛔ KHÔNG đóng đinh mã màu mới: chỉ var(--vien) --the --nen2 --nen-o --mo --chu
      --muc --do --ltt-cN. Riêng #fff cho chữ trên nền đậm là lối sẵn có của file.
   ⛔ KHÔNG emoji trong giao diện — emoji chỉ nằm trong chú thích, đúng nếp file này.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════════════════════
   PHẦN 0 · BỐN LUẬT CỐ Ý NẰM NGOÀI @media
   Đây là CÁI CHẶN và PHẦN ĐI KÈM BẮT BUỘC của mã, không phải trang trí màn nhỏ.
   ══════════════════════════════════════════════════════════════════════════════ */

/* 0a · THỐNG KÊ — bảng "So với kỳ trước" phải cuộn TRONG khung của nó.
   Bảng 4 cột, mọi ô `white-space:nowrap`, hai cột tiền ~105px mỗi cột → cần ~434px
   nhét vào khung 286px. `.bd-tam` không có overflow, `body` cũng không chặn, nên
   bảng thò ra ngoài viền tấm và ĐẨY CẢ TRANG cuộn ngang: tiêu đề lệch, các khối
   khác thụt vào.
   ⛔ Để ngoài @media là CỐ Ý: bảng vừa khung thì không có thanh cuộn nào hiện ra,
      máy tính không đổi một pixel. Nhét vào @media thì thu hẹp cửa sổ máy tính lại
      là vỡ y như cũ. */
#bdSoKy { overflow-x:auto; overscroll-behavior-x:contain; -webkit-overflow-scrolling:touch; }

/* 0b · HỒ SƠ KIỂM TRA — dòng thông tin đầu phiếu nay là các <span> rời
   (xem sửa mã số ⑤). Ba dòng này DỰNG LẠI dấu chấm giữa để MÁY TÍNH nhìn y hệt cũ,
   và bản IN cũng phải có dấu chấm nên không được bọc vào `screen`.
   ⛔ `min-width:0` bắt buộc: mục con của flex mặc định không co dưới cỡ chữ dài
      nhất, tên trường một từ rất dài sẽ tràn thay vì xuống dòng. */
.kq-phu { display:flex; flex-wrap:wrap; align-items:baseline; row-gap:2px; }
.kq-phu-o { min-width:0; overflow-wrap:anywhere; }
.kq-phu-o + .kq-phu-o::before { content:"·"; margin:0 6px; color:var(--mo); }

/* 0c · LỊCH TEST — XOÁ DẢI TRẮNG 58px DƯỚI ĐÁY LƯỚI (đúng cái "bẹp dí trống").
   Cột giờ sinh 17 nhãn (06:00…22:00, dòng 17315 chạy `g <= LTT_GIO_CUOI`) × 58px
   = 986px, còn cột ngày đặt cứng `soGio * 58` = 928px (dòng 17335). Lưới phải cao
   bằng đứa cao nhất → thừa đúng 58px trắng ở đáy.
   Cho nhãn CUỐI cao 0: chữ "22:00" vẫn hiện nguyên (nó có `top:-7px`, không bị cắt),
   chỉ thôi không cộng chiều cao nữa. Đúng cho cả máy tính lẫn điện thoại. */
.lt-cot-gio .lt-nhan-gio:last-child { height:0; }

/* 0d · LỊCH TEST — KHUNG LỊCH KHÔNG ĐƯỢC XẸP THẤP HƠN CỘT TRÁI.
   Bản gốc chỉ có TRẦN (max-height) mà không có SÀN, nên tuần vắng ca hoặc chế độ
   Danh sách là khung tụt còn ~230px trong khi cột trái cao 600px — hở một mảng
   trắng to bên cạnh.
   ⛔ SÀN phải viết `min(520px, calc(100vh - 214px))` chứ KHÔNG phải `min(520px,58vh)`:
      cửa sổ cao dưới ~734px thì sàn 520px thắng trần và khung tràn ra ngoài màn. */
.lt-man   { align-items:stretch; }
.lt-chinh { display:flex; flex-direction:column; }
.lt-khung { flex:1 1 auto; min-height:min(520px, calc(100vh - 214px - max(0px, var(--dnc-du, 0px)))); }
/* `dvh` = phần màn hình THẬT SỰ nhìn thấy. Trên điện thoại `vh` không trừ thanh địa
   chỉ trình duyệt nên khung luôn dài quá màn, sinh cuộn hai tầng. */
@supports (height:100dvh) { .lt-khung { max-height:calc(100dvh - 214px - var(--dnc-du, 0px)); } }

/* ══════════════════════════════════════════════════════════════════════════════
   PHẦN 1 · CHỈ MÁY TÍNH (từ 821px) — hai chỗ vá lỗi có sẵn
   ══════════════════════════════════════════════════════════════════════════════ */
@media screen and (min-width:821px) {

  /* 1a · VÁ LỖI CÓ SẴN: ô cột TVTS KHÔNG dính bên trái, kéo ngang là nó trôi theo
     tay — nhìn như bảng thủng đúng một ô.
     Gốc: dòng 1841 `.cts-bang td.cts-tv { position:relative }` có 2 lớp + 1 thẻ,
     mạnh hơn `.cts-bang .cts-g1` (2 lớp) và lại nằm SAU trong file → xoá mất
     position:sticky. Lớp `cts-tv` gắn ở dòng 13483 trong `if (ng.length)`, tức là
     MỌI dòng có TVTS chứ không phải chỉ dòng nhiều tên → gần như cả cột 1 đang hỏng.
     Khai lại sticky bằng ba lớp (mạnh hơn hẳn). `sticky` cũng là ô đã định vị y như
     `relative` nên nhãn "+N" đặt tuyệt đối bên trong vẫn bám đúng mép phải ô.
     ⛔ PHẢI bọc trong min-width:821px. Để trần thì trên điện thoại nó thắng luôn
        luật gỡ ghim ở dưới, cột TVTS dính lại và ĐÈ LÊN cột neo Tên PH.
     ⛔⛔ ĐỪNG VIẾT LẠI MẪU SELECTOR CỦA DÒNG 1841 VÀO CHÚ THÍCH.
        Bài kiểm thu-cts-tvts-tai-khoan.js (dòng 199–200) đọc CẢ FILE dạng chữ, nó
        không phân biệt được đâu là luật CSS đâu là lời giải thích. Bản đầu của chú
        thích này có chép nguyên mẫu selector ấy rồi vài chữ sau là hai chữ d-i-s-p-l-a-y
        kèm dấu hai chấm — mà giữa hai chỗ đó không có dấu đóng ngoặc nào, nên bài kiểm
        tưởng có người vừa thêm luật đổi cách hiển thị ô, và nó đỏ ngay.
        Tốn 10 phút mới tìm ra, vì luật CSS thật thì hoàn toàn vô can.
        Ý của luật cấm ấy: không ai được đổi cách hiển thị ô cột TVTS, vì làm thế là
        đổi chiều cao dòng, mà cuộn ảo lại tính chỗ đang xem bằng phép nhân số dòng ×
        chiều cao. Luật bên dưới chỉ khai lại vị trí dính, không đụng tới chuyện đó. */
  .cts-bang tbody td.cts-tv.cts-g1 { position:sticky; }

  /* 1b · ⛔ 21/08/2026 (chiều) — ĐÃ BỎ TRẦN 1.080px CỦA CHẾ ĐỘ NGÀY.
     Trần ấy sinh ra khi chế độ Ngày là MỘT CỘT: một cột ăn hết 1.900px thì ca 45
     phút thành sợi băng dài mà chỉ cao 41px. Nay chế độ Ngày là LƯỚI THÁNG 7 cột —
     bó lại 1.080px thì mỗi cột chỉ còn 154px, tên em nào cũng cụt.
     ⛔ Muốn dựng lại trần thì phải kiểm chế độ Ngày lúc ấy vẽ bằng hàm nào đã. */
}

/* ══════════════════════════════════════════════════════════════════════════════
   PHẦN 2 · MÁY TÍNH BẢNG (≤900px) — chỉ Lịch test, dọn lại cột trái
   ══════════════════════════════════════════════════════════════════════════════ */
@media screen and (max-width:900px) {
  /* Dòng 1458 biến `.lt-ben` thành hàng ngang, nhưng nút "+ Đặt lịch test" cũng là
     con của nó nên bị kẹp giữa lịch mini và bộ lọc. Cho nút ăn trọn hàng đầu. */
  .lt-ben { flex-wrap:wrap; align-items:flex-start; }
  .lt-ben > .lt-tao { flex:1 1 100%; }
  .lt-ben > .lt-mini, .lt-ben > .lt-nguoi { flex:1 1 210px; margin-bottom:0; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   PHẦN 3 · MỐC CHÍNH ≤820px — máy tính bảng dọc + điện thoại ngang
   ══════════════════════════════════════════════════════════════════════════════ */
@media screen and (max-width:820px) {

  /* ────────────────────────────────────────────────────────────────────────────
     3.0 · DÙNG CHUNG CẢ NĂM CÔNG CỤ
     `.cts-dau` là khung tiêu đề của CẢ NĂM màn (12862 · 14665 · 14971/15000 ·
     16298/16308/16429 · 17089). Ở đây CHỈ thu cỡ chữ tiêu đề — thứ tốt cho cả năm.
     Việc cuộn ngang dải nút thì bọc riêng cho Sổ tuyển sinh ở mục 3.1.
     ──────────────────────────────────────────────────────────────────────────── */
  .cts-dau h2 { font-size:14.5px; }
  .cts-chan  { font-size:11px; margin-top:3px; }

  /* ════════════════════════════════════════════════════════════════════════════
     3.1 · SỔ TUYỂN SINH
     Cô Quỳnh: *"cái bảng dữ liệu siêu bé thậm chí KHÔNG THỂ KÉO SANG 2 BÊN do dính
     6 cột mặc định ở đầu, trong khi các số dữ liệu bên trên lại rất tốn diện tích"*.
     ════════════════════════════════════════════════════════════════════════════ */

  /* ① CHỖ NGỒI — bớt lề, bảng rộng thêm ~40px và cao thêm ~25px.
     Hỏi "trong trang có bảng tuyển sinh không" chứ không gắn lớp vào body — rời màn
     là luật tự hết hiệu lực, không cần ai nhớ gỡ (đúng lối đã chốt 14/08 ở dòng 799). */
  body:has(#ctsBang).man-cong-cu .noi-dung { margin:6px; border-radius:var(--r-lg); }
  /* (1,2,1) — thắng cả dòng 822 lẫn dòng 3919, cả hai đều (1,1,1).
     Thanh nút đáy #thanhDuoi (dòng 3903) đo thật ~57px + vùng an toàn của máy; luật
     chung đang chừa 86px, dư gần 30px trắng dưới bảng. */
  body:has(#ctsBang):not(.dang-trong-lop) #noiDung {
    padding-top:8px; padding-left:7px; padding-right:7px;
    padding-bottom:calc(64px + env(safe-area-inset-bottom, 0px));
  }

  /* ② BA DẢI PHÍA TRÊN THU VỀ ĐÚNG MỘT HÀNG, thừa thì miết ngón tay sang trái.
     Không giấu con số nào, không giấu nút nào.
     ⛔ `.cts-dau` phải bọc `body:has(#ctsBang)` — bốn công cụ kia cũng dùng lớp này. */
  body:has(#ctsBang) .cts-dau {
      flex-wrap:nowrap; overflow-x:auto; overflow-y:hidden;
      gap:6px; margin-bottom:5px; padding-bottom:2px;
      scrollbar-width:none; -webkit-overflow-scrolling:touch; overscroll-behavior-x:contain; }
  body:has(#ctsBang) .cts-dau::-webkit-scrollbar { display:none; }
  body:has(#ctsBang) .cts-dau > *      { flex:0 0 auto; }   /* cấm co thành nút bẹp dí */

  /* ⭐ 16/08/2026 — TÊN SỔ RA HÀNG RIÊNG, CHỮ NHỎ, GÓC TRÊN BÊN TRÁI.
     Cô Quỳnh: *"cái tên tuyển sinh sổ CTS phải bé hơn ở góc bên trái trên cùng để dành
     chỗ cho các nút bấm bên dưới nhưng các nút bấm chức năng cũng cần phải được thiết
     kế bé đi, tôi thấy to chiếm diện tích quá"*.
     Trước: tên sổ + nhãn + 8 nút chen nhau trên CÙNG một dải cuộn ngang, nên tên sổ dài
     đẩy hết nút ra ngoài mép màn, phải miết mới thấy nút đầu tiên.
     Nay tách hai tầng: tầng trên là tên sổ + nhãn (chữ nhỏ, không cuộn), tầng dưới là
     dải nút — nút nào cũng nhìn thấy ngay từ mép trái. */
  body:has(#ctsBang) .cts-dau { flex-wrap:wrap; overflow:visible; }
  body:has(#ctsBang) .cts-dau .cts-ten {
      display:flex; align-items:center; gap:6px;
      flex:1 0 100%;                       /* chiếm trọn hàng → nút bị đẩy xuống hàng dưới */
      min-width:0; margin-bottom:1px; }
  body:has(#ctsBang) .cts-dau h2 {
      font-size:12px; font-weight:700;
      white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0; }
  body:has(#ctsBang) .cts-thu {
      font-size:9px; padding:1px 6px; letter-spacing:0;
      white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0; }

  /* ⭐ DẢI NÚT: MỘT HÀNG DUY NHẤT, TRƯỢT NGANG BẰNG NGÓN TAY.
     Cô Quỳnh 16/08: *"dạng kéo bánh xe sang 2 bên chứ không phải xuống dòng… đỡ tốn
     diện tích nhất có thể"*.
     Bản trước cho nút gãy xuống dòng: 8 nút trên màn 390px thành 3 hàng ≈ 150px.
     Nay 1 hàng ≈ 50px — tiết kiệm khoảng 100px, tức thêm hơn ba dòng bảng.

     ⛔⛔ 21/08/2026 (tối) — CHÚ THÍCH CŨ Ở ĐÂY GHI MỘT GIẢ ĐỊNH SAI, ĐỪNG TIN THEO.
        Nó bảo *"nút cuối bị cắt dở ở mép màn chính là dấu hiệu còn nữa"*. Đo thật ở
        màn 390px: dải nhìn thấy 348px, nội dung dài 845px — thừa 497px. KHÔNG phải
        một nút bị cắt dở, mà là BỐN nút khuất hoàn toàn cộng một nút bị cắt. Với
        người dùng thì đúng là nút BIẾN MẤT, và cô Quỳnh báo đúng như vậy:
        *"nút thêm học sinh vẫn bị che khuất ko hiện lên màn hình điện thoại"*.
        Lối Google/iOS mà chú thích cũ viện ra luôn đi kèm MỘT trong ba thứ: thanh
        cuộn mảnh, vệt mờ ở mép, hoặc nút ưu tiên đặt đầu dải. Trước đây không có
        cái nào cả. Nay có hai: thanh cuộn mảnh (dưới đây) và nút ưu tiên đứng đầu
        (xem `ctsVeMan`). */
  body:has(#ctsBang) .cts-dau .cts-nut {
      display:flex; flex:1 0 100%; gap:6px;
      flex-wrap:nowrap; overflow-x:auto; overflow-y:hidden;
      /* ⛔ ĐỪNG GIẤU THANH CUỘN Ở ĐÂY. Giấu là xoá mất dấu hiệu duy nhất cho biết
         còn nút phía sau — đúng lỗi cô Quỳnh báo 21/08/2026. Thanh mảnh chỉ tốn 6px. */
      scrollbar-width:thin; -webkit-overflow-scrolling:touch;
      overscroll-behavior-x:contain;
      /* Chừa mép phải một chút để nút cuối không dính sát viền khi miết tới cùng. */
      padding-right:2px; }
  body:has(#ctsBang) .cts-dau .cts-nut::-webkit-scrollbar { height:6px; }
  body:has(#ctsBang) .cts-dau .cts-nut::-webkit-scrollbar-thumb {
      background:var(--vien); border-radius:var(--r-sm); }
  body:has(#ctsBang) .cts-dau .cts-nut > * { flex:0 0 auto; }
  body:has(#ctsBang) .cts-dau .nut-nho {
      padding:0 9px; font-size:11.5px; gap:5px; border-radius:var(--r-md);
      /* ⛔⛔ 08/09/2026 — BOSS CHỐT LẠI: HẠ VỀ 36px NHƯ CẢ APP. ĐỪNG TRẢ VỀ 44px.
         Chú thích cũ ở đây bảo *"44px là luật chạm cô Quỳnh chốt — KHÔNG hạ xuống
         nữa"*, lý do là sổ 4.646 dòng thì bấm hụt tốn công hơn nút to. Lý do ấy có
         thật, nhưng nó viết cho bố cục CŨ, trước khi cả app về khuôn 36px sáng nay.
         Hỏi lại Boss, Boss chọn "hạ về 36px như cả app" — màn Tuyển sinh là màn
         công cụ, không có cớ gì đứng riêng một cỡ.

         ⛔ 36px VẪN LÀ SÀN ĐÍCH BẤM, không hạ tiếp. Muốn gọn hơn thì bóp NGANG
            (đệm, cỡ chữ) chứ đừng hạ chiều cao — hạ nữa là dựng lại đúng lỗi
            "bấm trượt sang nút bên cạnh" mà luật 44px sinh ra để chữa.
         ⛔ Hàng nút này CUỘN NGANG (xem luật `.cts-nut` ngay trên), nên nút thấp đi
            KHÔNG làm mất nút — chỉ bớt phải miết. Đừng lấy cớ "sợ mất nút" mà nâng
            lại chiều cao. */
      min-height:36px; }
  body:has(#ctsBang) .cts-dau .nut-nho i { transform:scale(.92); }

  /* Dải số hôm nay: đang 3 hàng ≈ 78px, nay 1 hàng ≈ 28px. Ô thứ tư bị cắt dở ở mép
     màn — chính chỗ cắt dở đó là dấu hiệu "còn nữa, miết sang trái đi", khỏi vẽ mũi tên. */
  .cts-phieu { flex-wrap:nowrap; overflow-x:auto; overflow-y:hidden;
      margin-bottom:5px; border-radius:var(--r-md);
      scrollbar-width:none; -webkit-overflow-scrolling:touch; overscroll-behavior-x:contain; }
  .cts-phieu::-webkit-scrollbar { display:none; }
  .cts-phieu > div { flex:0 0 auto; width:auto; min-width:0;
      padding:4px 10px; gap:5px; white-space:nowrap; }
  .cts-phieu b    { font-size:13px; }
  .cts-phieu span { font-size:10.5px; }
  /* Dòng "Cả sổ" thôi chiếm một hàng riêng — thành ô CUỐI của chính dải này, ngăn
     bằng vạch dọc và nền xám nhạt để vẫn đọc ra là số tích luỹ, không lẫn với sáu
     số của hôm nay. */
  .cts-phieu .cts-ca-so { flex:0 0 auto; width:auto; display:flex; align-items:center;
      border-top:none; border-left:1px solid var(--vien); background:var(--nen2);
      padding:4px 10px; font-size:10.5px; white-space:nowrap; }

  .cts-tab { margin-bottom:5px; }
  .cts-tab button      { font-size:12.5px; padding:5px 10px; gap:5px; }
  .cts-tab button span { font-size:10px; padding:1px 6px; }

  /* Hàng lọc: ô tìm + 5 ô chọn + ô tích đang gãy 4 hàng ≈ 130px, nay 1 hàng ≈ 32px.
     Ô tìm đứng đầu vì trên điện thoại người ta dùng nó nhiều nhất. */
  /* ⛔ 21/08/2026 — BỎ `overflow-x:auto` Ở ĐÂY. Năm ô sổ xuống đã thay bằng MỘT nút
     "Bộ lọc", nên hàng này không còn dài quá màn nữa. Mà quan trọng hơn: bảng lọc
     bung ra là một khối `position:absolute` nằm TRONG hàng này — để `overflow` khác
     `visible` thì trình duyệt CẮT PHẲNG nó, bấm nút xong chẳng thấy gì hiện ra.
     Đúng cái bẫy mà bộ lọc của giáo vụ đã tránh sẵn. */
  .cts-loc { flex-wrap:wrap; overflow:visible;
      gap:5px; margin-bottom:5px; padding-bottom:2px; }
  .cts-loc > * { flex:0 1 auto; }
  .cts-loc select, .cts-loc input { font-size:12px; padding:4px 7px; max-width:150px; }
  /* ⛔ PHẢI đứng SAU luật max-width:150px ngay trên, và PHẢI có `max-width:none`.
     Thiếu là ô tìm bị bóp còn 150px — đúng lỗi phản biện bắt được. */
  .cts-loc .cts-tim { flex:0 0 190px; width:190px; min-width:0; max-width:none; }
  .cts-loc .nv-ck   { font-size:12px; white-space:nowrap; }

  /* ══════════════════════════════════════════════════════════════════════════
     ③ CHỈ GIỮ MỘT CỘT NEO, BỎ GHIM PHẦN CÒN LẠI — CHỖ QUAN TRỌNG NHẤT CỦA CẢ BẢN VÁ
     Vùng ghim cộng lại 836px (08/09/2026: TVTS 190 + Ngày nhận 118 + Tên HS 210 +
     Trường 200 + Ngày sinh 118, xem ctsRongCot). Điện thoại chỉ có 390px → phần cuộn
     được còn ÂM, bảng đứng im hoàn toàn. Đây đúng là gốc của việc cô Quỳnh không kéo
     sang hai bên được. (Trước 08/09 là sáu cột, cộng lại 826px — cùng một chứng bệnh.)

     Vì sao chỉ giữ ĐÚNG MỘT cột neo:
       · Cột ghim thứ hai trở đi phải biết "cột trước kết thúc ở đâu" — con số đó do
         JS đo rồi ghi vào biến --g2…--g6 (ctsDoMocGhim). Ẩn một cột hay kéo rộng cột
         là mốc đổi. Trên điện thoại mọi cột ghim đều là chỗ CHẾT không kéo được, nên
         đổi lấy rủi ro đó là lỗ.
       · Cột neo dùng `left:0` — số cứng, không qua biến nào, không lệch được.
     Vì sao chọn cột NHÌN LÀ BIẾT DÒNG NÀY CỦA AI chứ không phải cột 1: cột 1 là TVTS
     (tên nhân viên tư vấn), nhìn nó không biết dòng này của ai. Kéo ngang mà mất tên
     người mới là mất phương hướng.

     ⭐⭐ 08/09/2026 — CỘT NEO DỜI TỪ `.cts-g5` SANG `.cts-g3`.
     Lớp `cts-gN` đánh theo VỊ TRÍ cột chứ không theo tên cột, mà Boss vừa chốt lại
     thứ tự năm cột đầu (TVTS · Ngày nhận · Tên HS · Trường · Ngày sinh — xem
     `CTS_COT_DAU` trong js/tinh-nang.js). Nên vị trí 5 nay KHÔNG còn là Tên PH nữa mà
     là NGÀY SINH, còn cột nhìn-là-biết-của-ai nay đứng ở vị trí 3 (Tên HS).
     ⛔ Để nguyên `.cts-g5` là điện thoại neo đúng cột ngày sinh: kéo ngang chỉ thấy
        một cột ngày tháng đứng im, không biết đang xem hồ sơ của em nào. Luật cũ
        KHÔNG sai, nó chỉ gắn với bố cục cũ — đổi bố cục thì phải rà lại nó.

     ⛔ JS KHÔNG PHẢI SỬA GÌ. Ô nào hết `position:sticky` thì trình duyệt bỏ qua luôn
        thuộc tính `left`, nên mấy biến --g2…--g6 mà ctsDoMocGhim vẫn ghi thành vô hại.
     ⛔ Hàng tiêu đề vẫn phải DÍNH TRÊN, chỉ bỏ dính TRÁI: ở thead chỉ đụng `left` và
        `z-index`, TUYỆT ĐỐI không đụng `position` (dòng 858 giữ nguyên).
     ⛔ KHÔNG đổi `.cts-bang td { height:30px }` ở đây. Cuộn ảo tính chỗ đang xem bằng
        số dòng × 30 (hằng CTS_CAO dòng 12673) — đổi CSS mà không đổi hằng số là cuộn
        tới đâu lệch tới đó.
     ══════════════════════════════════════════════════════════════════════════════ */
  .cts-bang tbody .cts-g1, .cts-bang tbody .cts-g2, .cts-bang tbody .cts-g4,
  .cts-bang tbody .cts-g5, .cts-bang tbody .cts-g6 { position:static; }
  .cts-bang thead .cts-g1, .cts-bang thead .cts-g2, .cts-bang thead .cts-g4,
  .cts-bang thead .cts-g5, .cts-bang thead .cts-g6 { left:auto; z-index:4; }
  .cts-bang .cts-g3       { left:0; }
  .cts-bang thead .cts-g3 { z-index:6; }
  /* Vạch dày "bên trái đứng yên, bên phải trôi" nằm ở CỘT NEO, không ở cột ghim cuối:
     trên điện thoại chỉ còn đúng một cột đứng yên. Hai luật dưới phải rút vạch dày
     của bản máy tính (nay ở `.cts-g5`) xuống vạch mảnh, rồi trao cho `.cts-g3`. */
  /* ⭐⭐ 08/09/2026 — CỘT NEO DỜI TỪ `.cts-g5` SANG `.cts-g3` (bản vá của kênh Coder 2,
     Designer chép sang nhánh này theo lệnh Boss).
     Lớp `cts-gN` đánh theo VỊ TRÍ cột chứ không theo tên cột, mà Boss vừa chốt lại
     thứ tự năm cột đầu (TVTS · Ngày nhận · Tên HS · Trường · Ngày sinh — xem
     `CTS_COT_DAU` trong js/tinh-nang.js). Nên vị trí 5 nay KHÔNG còn là Tên PH nữa mà
     là NGÀY SINH, còn cột nhìn-là-biết-của-ai nay đứng ở vị trí 3 (Tên HS).
     ⛔ Để nguyên `.cts-g5` là điện thoại neo đúng cột ngày sinh: kéo ngang chỉ thấy
        một cột ngày tháng đứng im, không biết đang xem hồ sơ của em nào. Luật cũ
        KHÔNG sai, nó chỉ gắn với bố cục cũ — đổi bố cục thì phải rà lại nó. */
  .cts-bang .cts-g5, .cts-bang thead .cts-g5 { border-right:1px solid var(--vien); }
  .cts-bang .cts-g6, .cts-bang thead .cts-g6 { border-right:1px solid var(--vien); }
  .cts-bang .cts-g3, .cts-bang thead .cts-g3 { border-right:2px solid var(--muc); }

  /* Tay nắm kéo rộng cột chỉ rộng 7px — ngón tay không bấm trúng, mà chạm hụt vào nó
     thì app tưởng đang kéo cột nên bảng ĐỨNG IM.
     ⛔⛔ BẢN ĐẦU 16/08/2026 GIẢI QUYẾT BẰNG `display:none` — SAI, ĐÃ SỬA.
        Ẩn đi là XOÁ HẲN việc nới rộng cột trên điện thoại, mà không bù lại đường nào.
        Đúng lúc cô Quỳnh vừa ra luật: *"không được bỏ đi các tính năng như máy tính…
        mỗi cái có thể có sự khác nhau và phù hợp riêng"*. Bày khác thì được, MẤT thì không.
     Nay giữ nguyên tay nắm, chỉ NỚI RA CHO VỪA NGÓN TAY: vùng bấm 24px thay vì 7px,
     còn cái vạch nhìn thấy vẫn mảnh như cũ nên bảng không rối thêm.
     Vùng bấm rộng ra phía TRÁI (right:-3px giữ nguyên, chỉ tăng width) nên nó nằm gọn
     trong ô tiêu đề, không thò sang ô bên cạnh. */
  .cts-bang .cot-nam { width:24px; right:-8px; }
  .cts-bang .cot-nam::after { left:9px; }

  /* ════════════════════════════════════════════════════════════════════════════
     3.2 · THỐNG KÊ TUYỂN SINH
     Cô Quỳnh: *"số liệu bị lòi ra khỏi viền màn hình trông xấu"*.
     Đo trên máy 390px: khung nội dung còn 346px (lề 8px dòng 564 + đệm 14px dòng 799).
     Màn này TRƯỚC NAY KHÔNG CÓ MỘT DÒNG CSS NÀO cho màn nhỏ.
     ════════════════════════════════════════════════════════════════════════════ */

  /* Dải sáu ô số → lưới hai cột, khe 1px lộ nền viền ra làm đường kẻ.
     Bản cũ chỉ có viền PHẢI nên xuống hai hàng là hai hàng dính vào nhau. */
  .bd-o { display:grid; grid-template-columns:1fr 1fr; gap:1px;
          background:var(--vien); margin-bottom:9px; }
  .bd-o > div { min-width:0; padding:8px 10px; border-right:none; background:var(--the); }
  .bd-o .bd-nhan { font-size:11px; margin-bottom:2px; }
  /* Nhỏ một nấc KÈM CHỐT CHẶN: lỡ tràn thì cắt gọn TRONG lòng ô, tuyệt đối không cho
     tràn sang ô bên như bản cũ (ô "Tiền thu" ghi đủ số "1.234.567.890đ" ở 23px đậm
     rộng ~190px, hơn ô 46px, mà số toàn chữ số và dấu chấm nên không có chỗ ngắt dòng). */
  .bd-o .bd-so  { font-size:18px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .bd-o .bd-doi { font-size:11px; }

  /* Hai ô TIỀN chiếm trọn một hàng: nhãn trái · số phải (lối bảng tài chính, và cũng
     là hai con số cô Quỳnh cần liếc thấy trước nhất).
     ⛔ Kèm `:nth-child(5),(6)` để luật CHẠY ĐƯỢC KỂ CẢ KHI KHÔNG áp sửa mã `tksOSo`.
        Thứ tự sáu ô do `tksVeBangDieuKhien` dựng cứng (dòng 14750–14755), hai ô cuối
        luôn là "Tiền thu" và "Hoàn phí". */
  .bd-o > div.bd-tien, .bd-o > div:nth-child(5), .bd-o > div:nth-child(6) {
      grid-column:1 / -1; display:grid; grid-template-columns:1fr auto;
      align-items:baseline; column-gap:10px; row-gap:1px; }
  .bd-o > div.bd-tien .bd-nhan,
  .bd-o > div:nth-child(5) .bd-nhan, .bd-o > div:nth-child(6) .bd-nhan { margin-bottom:0; }
  .bd-o > div.bd-tien .bd-so,
  .bd-o > div:nth-child(5) .bd-so, .bd-o > div:nth-child(6) .bd-so {
      font-size:17px; text-align:right; font-variant-numeric:tabular-nums; }
  .bd-o > div.bd-tien .bd-doi,
  .bd-o > div:nth-child(5) .bd-doi, .bd-o > div:nth-child(6) .bd-doi {
      grid-column:1 / -1; text-align:right; margin-top:0; }

  /* ⛔ KHÔNG ép `.bd-tam { flex:1 1 100% }`. Bản gốc đã là `flex:1 1 340px` +
     `flex-wrap:wrap`, tức hai tấm TỰ xuống dòng khi khung hẹp hơn 692px. Ép 100% chỉ
     ăn ở dải 712–820px — đúng chỗ hai tấm còn nằm cạnh nhau thoải mái — biến máy
     tính bảng thành hai tấm chồng nhau, phí nửa màn. */
  .bd-hang { gap:9px; margin-bottom:9px; }
  .bd-tam  { padding:10px 12px; }
  .bd-tam .bd-phu { margin-bottom:8px; }
  .bd-doi-chon    { margin-bottom:7px; }

  /* Vòng tròn nhỏ lại để nằm CẠNH chú giải thay vì đẩy nhau xuống hai tầng
     (140 vòng + 170 chú giải = 324px, thừa đúng 10px so với khung 314px).
     112 + khe 10 + 140 = 262 < 346 → vẫn nằm cạnh nhau, tiết kiệm ~140px chiều cao.
     ⛔ Chữ TRONG vòng tròn tính theo hệ toạ độ 140 của viewBox (dòng 14567–14569:
        font-size 19 và 10), nên thu vòng là chữ thu theo: 112/140 = 0,8 → 15px và
        8px, chữ "lượt" không ai đọc nổi. Nâng cỡ TRONG hệ toạ độ để thu xong vẫn ra
        đúng cỡ cũ. Thuộc tính font-size trên thẻ SVG là "thuộc tính trình bày", CSS
        thường đè được, không cần !important. */
  .bd-chia { gap:10px; }
  .bd-tron { width:112px; height:112px; }
  .bd-tron text        { font-size:24px; }
  .bd-tron text + text { font-size:13px; }
  .bd-chu     { flex:1 1 140px; font-size:11.5px; }
  .bd-chu div { padding:1.5px 0; }

  /* Bảng so kỳ: cột tên dán dính bên trái khi kéo ngang.
     ⛔ Đổi sang `separate` là cố ý: bảng `collapse` có ô dán dính thì đường kẻ của ô
        đó không đi theo, Chrome vẽ mất viền. Không có giãn ô nên nhìn không khác. */
  .bd-so-ky { border-collapse:separate; border-spacing:0; font-size:12px; }
  .bd-so-ky th, .bd-so-ky td { padding:5px 7px; }
  .bd-so-ky th:first-child, .bd-so-ky td:first-child {
      position:sticky; left:0; background:var(--the); z-index:1;
      box-shadow:1px 0 0 var(--vien); }

  /* Hàng bộ lọc. Ba nút mốc thời gian đã ~314px; cộng ba ô chọn mà ô chọn thì rộng
     bằng đúng dòng chữ dài nhất trong nó (tên nhân viên, tên nguồn) và trong flex nó
     KHÔNG tự co lại được → đẩy cả trang lệch. `min-width:0` là chỗ mấu chốt.
     ⛔ padding 11px chứ không 7px: dòng 3213 app đã chốt nút trên điện thoại tối
        thiểu 44px, 7px cho ra ~29px là nhân viên bấm trượt.
     `flex:1 1 45%` (không phải 100%): hai ô chọn chung một hàng — 45% của 346 ≈ 156px,
     đủ chứa "Cơ sở học (tất cả)" — ô thứ ba nở hết hàng dưới. Bớt được một hàng ~40px. */
  .tks-thanh { gap:6px; margin-bottom:9px; }
  .tks-moc   { width:100%; }
  .tks-moc button { flex:1 1 0; min-width:0; padding:11px 4px; font-size:12.5px; }
  .tks-thanh select { flex:1 1 45%; width:auto; min-width:0; max-width:100%;
      font-size:13px; padding:9px 8px; border:1px solid var(--vien);
      border-radius:var(--r-o, 8px); background:var(--nen-o); color:var(--chu); }

  /* Bảng số liệu vẫn cuộn trong khung của nó, chỉ đặc lại một nấc.
     64vh thay cho `calc(100vh - 300px)`: con số 300px đo trên máy tính, đem sang
     điện thoại XOAY NGANG (cao 390px) thì khung chỉ còn 90px, đúng hai dòng bảng.
     ⛔ GIỮ max-height, đừng bỏ: bỏ là hàng tiêu đề hết chỗ bám, kéo xuống mất tên cột.
     ⛔ GIỮ nguyên đệm ngang 12px của ô — thanh so sánh trong ô (dòng 2105–2110) căn
        theo đúng 12px đó (`left:12px; right:12px`). */
  .tks-cuon { max-height:64vh; overscroll-behavior:contain; }
  .tks-bang { font-size:12px; }
  .tks-bang th, .tks-bang td { padding:6px 12px; }
  .tks-bang th { font-size:11px; }

  /* ════════════════════════════════════════════════════════════════════════════
     3.3 · LỊCH TEST
     ════════════════════════════════════════════════════════════════════════════ */
  /* 300px trừ đi là: tiêu đề màn + thanh trên hai hàng + nút Đặt lịch + cột trái
     + thanh điều hướng dán đáy (#thanhDuoi ~57px + vùng an toàn). */
  .lt-khung { max-height:calc(100vh - 300px - var(--dnc-du, 0px)); min-height:320px; overscroll-behavior:contain; }

  /* ══════════════════════════════════════════════════════════════════════════
     KIỂU "DANH SÁCH" DỰNG LẠI THEO GOOGLE CALENDAR (Schedule) — 16/08/2026
     ──────────────────────────────────────────────────────────────────────────
     Cô Quỳnh gửi ảnh Google Calendar và bảo *"xem giao diện giống Google Calendar
     trên điện thoại đi và tối ưu giao diện cho nhìn thật dễ dùng và đẹp"*.
     Ba thứ học được từ ảnh ấy, làm y vậy:
       ① Ngày là một MỐC dán dính đỉnh màn, không phải một hàng trôi lẫn vào ca.
       ② Mỗi ca là một THẺ bo góc có vệt màu dọc bên trái theo người phụ trách —
          nhìn màu là biết ai, khỏi đọc chữ.
       ③ Màn hẹp thì thông tin XUỐNG HAI DÒNG (giờ + tên em / người phụ trách +
          cơ sở + số điện thoại) thay vì nhồi năm thứ vào một hàng 390px.
     ⛔ KHÔNG bỏ thông tin nào so với máy tính — chỉ xếp lại chỗ. Số điện thoại
        phụ huynh vẫn còn, vì đó là thứ nhân viên gọi ngay khi xem lịch.
     ══════════════════════════════════════════════════════════════════════════ */
  .lt-ds-ngay { border-bottom:none; margin-bottom:2px; }
  /* ① Mốc ngày: chữ to hơn, dán đỉnh, có vạch mảnh dưới chân cho ra "đầu mục". */
  .lt-ds-dau {
      padding:9px 2px 5px; font-size:13px;
      border-bottom:1px solid var(--vien); }
  .lt-ds-dau b { font-size:14px; font-weight:700; }
  /* Hôm nay: chấm tròn đậm như Google, thay vì chỉ đổi màu chữ. */
  /* ⛔ 21/08/2026 (tối) — TUYỆT ĐỐI KHÔNG ĐẶT LẠI `999px` HAY `50%`. Đây là ô bọc
     CON SỐ NGÀY, đúng thứ cô Quỳnh chỉ mặt: *"bỏ hình tròn đi nhìn tởm quá"*. Sáng
     nay quét sáu chỗ `50%` nhưng chỗ này viết bằng `999px` nên lọt lưới, sống thêm
     nguyên một ngày trên điện thoại. Ai quét lần sau nhớ tìm CẢ HAI cách viết. */
  .lt-ds-ngay.homnay .lt-ds-dau b {
      color:#fff; background:var(--muc); border-radius:var(--r-sm);
      padding:2px 10px; display:inline-block; }
  .lt-ds-ngay.dangxem .lt-ds-dau { background:var(--the); }
  .lt-ds-dem { font-size:10.5px; }

  /* ② + ③ Mỗi ca là một thẻ hai dòng, vệt màu chạy suốt cạnh trái. */
  .lt-ds-hang {
      display:grid; grid-template-columns:auto minmax(0,1fr); gap:2px 9px;
      align-items:center; padding:9px 11px; margin:6px 0 0;
      border:1px solid var(--vien); border-bottom:1px solid var(--vien);
      border-radius:var(--r-lg); background:var(--the);
      min-height:56px;                 /* thoải mái trên chuẩn chạm 44px */
      text-align:left; }
  .lt-ds-hang:last-child { border-bottom:1px solid var(--vien); }
  /* Giờ: cột hẹp bên trái, KHÔNG còn mang vệt màu (vệt chuyển ra cạnh thẻ). */
  .lt-ds-gio { width:auto; min-width:46px; font-size:12.5px; padding-left:0 !important;
      box-shadow:none !important; }
  .lt-ds-ten { font-size:13.5px; font-weight:700; min-width:0;
      overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  /* Dòng hai: người phụ trách · cơ sở · số điện thoại, gom về cột phải. */
  .lt-ds-nguoi { grid-column:2; font-size:11.5px; color:var(--mo);
      overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .lt-ds-sdt { grid-column:2; font-size:11.5px; }
  .lt-ds-hang .lt-cs { grid-row:1; grid-column:2; justify-self:end; font-size:11.5px;
      font-style:normal; font-weight:600; }

  /* Vệt màu người phụ trách — chạy suốt cạnh trái thẻ, đúng lối Google Calendar.
     Dùng box-shadow inset nên không cần thêm thẻ nào vào trang. */
  .lt-ds-hang.ltt-mau1 { box-shadow:inset 4px 0 0 var(--ltt-c1); }
  .lt-ds-hang.ltt-mau2 { box-shadow:inset 4px 0 0 var(--ltt-c2); }
  .lt-ds-hang.ltt-mau3 { box-shadow:inset 4px 0 0 var(--ltt-c3); }
  .lt-ds-hang.ltt-mau4 { box-shadow:inset 4px 0 0 var(--ltt-c4); }
  .lt-ds-hang.ltt-mau5 { box-shadow:inset 4px 0 0 var(--ltt-c5); }
  .lt-ds-hang.ltt-mau6 { box-shadow:inset 4px 0 0 var(--ltt-c6); }
  .lt-ds-hang.ltt-mau7 { box-shadow:inset 4px 0 0 var(--ltt-c7); }
  .lt-ds-hang.ltt-mau8 { box-shadow:inset 4px 0 0 var(--ltt-c8); }

  /* ══════════════════════════════════════════════════════════════════════════
     KIỂU "THÁNG" GỌN LẠI THEO GOOGLE CALENDAR — 16/08/2026
     ──────────────────────────────────────────────────────────────────────────
     Ảnh cô Quỳnh gửi: ô ngày nhỏ, mỗi ca là một VẠCH MÀU mảnh chỉ đủ vài chữ,
     thừa thì "…". Cả tháng gọn trong một màn, không phải cuộn.
     Ở app bản cũ mỗi ô cao tối thiểu 96px × 6 hàng = 576px — trên màn 390px là
     phải cuộn hai lần mới hết tháng, mà mỗi ô lại rỗng gần hết.
     ⛔ Ô ngày vẫn là đích chạm cả ô (bấm vào là nhảy sang xem Ngày hôm đó) nên
        dù ô thấp 62px thì vùng chạm vẫn quá thoải mái so với chuẩn 44px.
     ══════════════════════════════════════════════════════════════════════════ */
  /* CHẾ ĐỘ NGÀY trên điện thoại: cột giờ hẹp lại, chip ăn trọn bề ngang còn lại. */
  .lt-ngay-gio { grid-template-columns:46px minmax(0,1fr); }
  .lt-ng-gio { font-size:10.5px; padding:6px 5px 0 0; }
  .lt-ng-o { min-height:42px; padding:4px 5px; }
  .lt-ng-o .lt-the { width:100%; min-height:40px; }

  .lt-thang .lt-o-ngay { min-height:62px; padding:3px 3px 4px; }
  .lt-thang .lt-o-ngay .lt-sn {
      font-size:11px; text-align:center; margin:0 auto 2px; }
  .lt-thang .lt-o-ngay.homnay .lt-sn,
  .lt-thang .lt-o-ngay.dangxem .lt-sn {
      min-width:18px; width:auto; height:17px; line-height:17px; margin:0 auto 2px; font-size:11px; }
  /* Mỗi ca thành một vạch màu mảnh — đọc được vài chữ đầu, đủ để nhận ra. */
  .lt-thang .lt-the {
      padding:1px 4px; margin-bottom:1.5px; border-radius:var(--r-sm);
      font-size:10.5px; line-height:1.45;
      white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .lt-thang .lt-the .lt-cs { display:none; }   /* mã cơ sở không đủ chỗ ở cỡ này */
  .lt-them-nua { font-size:10.5px; text-align:center; padding:0; }

  /* ══════════════════════════════════════════════════════════════════════════
     NÚT ＋ TRÒN GÓC DƯỚI PHẢI (FAB) — 16/08/2026
     ──────────────────────────────────────────────────────────────────────────
     Đúng cái nút tròn xanh trong ảnh Google Calendar cô gửi.
     Vì sao cần: bản cũ nút "+ Đặt lịch test" nằm trong CỘT TRÁI, mà trên điện
     thoại cột trái tụt xuống tận cuối trang — muốn đặt một ca phải cuộn qua hết
     lịch. Nay nút luôn nổi ở góc, chạm được từ bất cứ đâu.
     ⛔ KHÔNG giấu nút cũ đi: nó vẫn nằm nguyên chỗ cũ (chỉ thu nhỏ), nên ai quen
        tay tìm ở cột trái vẫn thấy. Đây là THÊM đường, không phải ĐỔI đường —
        đúng luật cô Quỳnh 16/08: bày khác được, mất thì không.
     ⛔ Chừa chỗ cho thanh điều hướng đáy (#thanhDuoi ~57px) và vùng an toàn máy. */
  /* ⛔⛔ NÚT TRÒN PHẢI LÀ MỘT NÚT RIÊNG, ĐỪNG BIẾN `#ltTao` THÀNH NÓ.
     Đã thử và SAI: `#ltTao` nằm TRONG ngăn kéo `.lt-ben`, mà ngăn kéo có
     `transform` để trượt ra vào. Con `position:fixed` nằm trong thẻ có transform
     thì KHÔNG còn neo vào cửa sổ nữa — nó neo vào chính thẻ cha ấy. Hậu quả: nút
     tròn trượt ra khỏi màn cùng ngăn kéo, coi như biến mất.
     Nay dùng `#ltFab` đặt ngoài ngăn kéo. `#ltTao` giữ nguyên là nút thường trong
     ngăn kéo — hai đường cùng dẫn tới một việc, không ai mất gì. */
  #ltFab {
      display:flex !important; align-items:center; justify-content:center;
      position:fixed; z-index:60;
      right:14px; bottom:calc(70px + env(safe-area-inset-bottom, 0px));
      width:56px; height:56px; padding:0; border-radius:50%;
      font-size:30px; font-weight:400; line-height:1;
      box-shadow:0 3px 10px rgba(0,0,0,.22); }
  /* Lịch phải chừa chỗ dưới đáy cho nút khỏi che mất ca cuối cùng. */
  .lt-khung { padding-bottom:8px; }
  .lt-ds-ngay:last-child { padding-bottom:64px; }

  /* ══════════════════════════════════════════════════════════════════════════
     NGĂN KÉO TRƯỢT TỪ TRÁI (☰) — GOOGLE CALENDAR TRÊN ĐIỆN THOẠI, 16/08/2026
     ──────────────────────────────────────────────────────────────────────────
     Cột trái giữ lịch nhỏ + danh sách người phụ trách + danh sách cơ sở để tích
     lọc. Trên màn 390px nó tụt xuống DƯỚI lịch và ăn nguyên một màn — muốn bỏ
     tích một người phải cuộn qua hết lịch. Google giấu đúng khối này vào ngăn
     kéo, và đó là lý do màn hình của họ trông thoáng.
     ⛔ KHÔNG mất tính năng nào: mọi thứ trong cột trái vẫn còn nguyên, chỉ đổi
        chỗ đứng. Chạm ☰ là ra, chạm tấm mờ hoặc chọn xong là đóng.
     ══════════════════════════════════════════════════════════════════════════ */
  .lt-ham { display:flex !important; flex-direction:column; justify-content:center;
      gap:4px; width:44px; height:44px; padding:0 12px;
      background:none; border:1px solid var(--vien); border-radius:var(--r-md); }
  .lt-ham span { display:block; height:2px; width:100%; border-radius:var(--r-sm);
      background:var(--chu); }

  .lt-man { position:relative; }
  .lt-man .lt-ben {
      position:fixed; z-index:70; left:0; top:0; bottom:0; width:min(84vw, 320px);
      margin:0; padding:12px 12px calc(80px + env(safe-area-inset-bottom, 0px));
      background:var(--the); border-right:1px solid var(--vien);
      box-shadow:2px 0 16px rgba(0,0,0,.18);
      overflow-y:auto; overscroll-behavior:contain;
      transform:translateX(-102%);            /* nằm ngoài màn cho tới khi mở */
      transition:transform .22s ease; }
  .lt-man.mo-ngan .lt-ben { transform:translateX(0); }
  /* ⛔⛔ PHẢI KHAI `display:block` Ở ĐÂY. Sự cố 17/08/2026: phần chung có luật
     `.lt-ham, .lt-mo, #ltFab { display:none }` để máy tính khỏi mọc ba thứ lạ, mà ở
     khối này tôi chỉ khai opacity và pointer-events cho tấm mờ, QUÊN bật display.
     Hậu quả: tấm mờ không bao giờ tồn tại → chạm vào không đóng được ngăn kéo. Mà
     ngăn kéo lại phủ lên đúng chỗ nút ☰ nên bấm ☰ lần nữa cũng không tới. Kết quả:
     mở ngăn kéo ra là KHÔNG CÒN ĐƯỜNG NÀO ĐÓNG, phải thoát khỏi màn.
     Bài học: bật/tắt một thứ bằng hai luật ở hai chỗ thì phải soát cả hai chiều. */
  .lt-mo { display:block; position:fixed; inset:0; z-index:69; background:rgba(0,0,0,.34);
      opacity:0; pointer-events:none; transition:opacity .22s ease; }
  .lt-man.mo-ngan .lt-mo { opacity:1; pointer-events:auto; }

  /* Nút đóng ngăn kéo — cô Quỳnh 17/08 yêu cầu có nút hẳn hoi, đừng bắt người ta
     đoán là phải chạm ra ngoài. Ba đường đóng: nút này · chạm tấm mờ · chọn một ngày. */
  .lt-dong-ngan {
      display:flex !important; align-items:center; justify-content:center;
      position:absolute; top:10px; right:10px; width:36px; height:36px; padding:0;
      border:1px solid var(--vien); border-radius:var(--r-md); background:var(--the);
      color:var(--chu); font-size:20px; line-height:1; }
  .lt-man .lt-ben { padding-top:52px; }   /* chừa chỗ cho nút đóng */
  /* Nút "Đặt lịch test" trong ngăn kéo giữ nguyên dạng nút thường, chỉ trải rộng
     cho vừa ngăn — ai quen tay tìm ở đây vẫn thấy. */
  .lt-man .lt-ben .lt-tao { width:100%; padding:11px; border-radius:var(--r-lg); font-size:13.5px; }

  /* Thanh trên gọn về hai hàng:
       hàng 1: Hôm nay · ‹ · › · tên khoảng đang xem (dồn về phải)
       hàng 2: bộ chọn chế độ, chia đều hết bề ngang, cao 38px cho ngón tay. */
  .lt-top { display:grid; grid-template-columns:auto auto auto minmax(0,1fr);
      gap:6px; align-items:center; margin-bottom:8px; }
  .lt-top button { min-height:38px; }
  /* ⛔⛔ 09/09/2026 — DUOI 400px THI GRID NAY LAM TRAN CA TRANG.
     Do o man 320: bon cot that la [171.4, 73.9, 28.8, 0]px. Cot 1 rong 171px vi
     tieu de thang do mang `white-space:nowrap`, ma cot `auto` KHONG co duoc duoi
     min-content; cot `1fr` da co ve 0 roi van khong du, nen nut "›" (toi tuan sau)
     bi day ra 306->330, keo tran ngang CA TRANG 10px va nam ngoai man.
     Luat GOC ben `css/man.css` la `flex; flex-wrap:wrap` — BIET xuong dong.
     Ban danh rieng cho dien thoai lai kem mem hon ban chung: dung grid de xep hai
     hang cho dep, nhung grid thi khong bao gio xuong dong.
     Nay duoi 400px tra ve flex-wrap. Nut "›" xuong dong con hon bien mat.
     ⛔ Chi ap duoi 400px: tu 360 tro len grid van vua, doi ca loat la pha bo cuc
        hai hang dang chay tot o 390 va 430. */
  @media (max-width:400px){
    .lt-top { display:flex; flex-wrap:wrap; align-items:center; gap:6px; }
    .lt-top .lt-tieude { flex:1 1 100%; text-align:left; }
    .lt-top .lt-che { flex:1 1 100%; }
  }
  #ltNay   { padding:8px 11px; font-size:12.5px; }
  .lt-mui  { padding:8px 11px !important; }
  .lt-tieude { font-size:12.5px; margin:0; text-align:right; white-space:nowrap;
      overflow:hidden; text-overflow:ellipsis; }
  .lt-che  { grid-column:1 / -1; margin-left:0; width:100%; }
  .lt-che button { flex:1 1 0; min-width:0; padding:8px 4px; font-size:12px; }
  .lt-tao  { padding:12px; font-size:14px; }

  /* ════════════════════════════════════════════════════════════════════════════
     3.4 · TEST ĐẦU VÀO
     ⛔ Mấy lớp `.nn-*` DÙNG CHUNG với Hồ sơ kiểm tra (dòng 15001–15006, 15103–15143,
        15220, 15435, 15594). Ba luật dưới đây CỐ Ý dùng tên chung vì chúng tốt cho
        CẢ HAI công cụ. Thứ chỉ đúng cho Test đầu vào thì đẩy sang hai tên riêng
        `nn-thanh-ds` / `nn-thanh-cham` (xem sửa mã ⑥ và ⑦).
     ════════════════════════════════════════════════════════════════════════════ */

  /* ① CHỐNG iPHONE TỰ PHÓNG TO. Safari iPhone tự phóng to trang mỗi khi bấm vào ô
     nhập có cỡ chữ NHỎ HƠN 16px, và phóng xong KHÔNG tự thu lại — phải chụm tay thu
     về sau mỗi ô. Cho đúng 16px là hết (đúng cách đã chữa cho màn điểm danh, dòng 3318).
     ⛔ Đừng chữa bằng `user-scalable=no` ở thẻ viewport — làm vậy là cướp luôn quyền
        tự chụm tay phóng to của người dùng. */
  .nn-tim, .nn-o input, .nn-o select, .nn-o textarea, .nn-bang .c-so input { font-size:16px; }

  /* ② CẠNH TỐI THIỂU 44px CHO NGÓN TAY (trước đây 21–35px). */
  .nn-thanh button           { min-height:44px; padding:11px 14px; font-size:13.5px; }
  .nn-tim                    { min-height:44px; padding:9px 12px; }
  .nn-o input, .nn-o select  { min-height:44px; padding:9px 11px; }
  .nn-o textarea             { min-height:86px; padding:9px 11px; line-height:1.45; }
  .nn-them-lan, .nn-lop-them { min-height:44px; padding:10px 14px; font-size:13.5px; }
  .nn-de-o                   { min-height:48px; padding:10px 12px; font-size:13.5px; }
  .nn-muc-nut                { min-height:44px; }
  .nn-de-o input, .nn-lop-ten input { width:20px; height:20px; }
  .nn-bo-lan { margin-left:auto; min-width:40px; min-height:40px; font-size:19px; }

  /* ③ KHÔNG ĐỂ CHỮ DÀI ĐẨY TRÀN NGANG. */
  .nn-cham { max-width:100%; }
  .nn-the-dau b, .nn-tc-ten b, .nn-de-dau b, .nn-de-ten { overflow-wrap:anywhere; }

  /* ④ THANH MÀN DANH SÁCH — nút "+ Chấm bài mới" là việc chính, cho một hàng riêng. */
  .nn-thanh-ds { gap:8px; }
  .nn-thanh-ds .nn-nut-chinh { flex:1 1 100%; }
  .nn-thanh-ds .nn-tim       { flex:1 1 100%; max-width:none; min-width:0; }
  .nn-thanh-ds .nn-dem       { margin-left:0; }

  /* ⑤ THANH MÀN CHẤM — DÍNH LẠI KHI CUỘN.
     Form chấm trên điện thoại dài gần 3000px; trước đây nút Lưu chỉ ở đầu trang →
     chấm xong phải vuốt ngược lên tận trên mới lưu được, quên là mất cả bài đang
     chấm dở giữa buổi test.
     ⛔ top:58px KHÔNG phải 50px — `.thanh-tren` màn nhỏ = padding 6px×2 (dòng 3191)
        + nút cao 44px (min-height dòng 3213) + border-bottom 2px (dòng 479) = 58px.
        Lấy 50 là thanh Lưu bị nuốt 8px trên và lòi ra ở hai góc bo tròn.
     ⛔ z-index 40 (thấp hơn `.thanh-tren` là 50) để lệch vài pixel thì phần thừa nằm
        KHUẤT SAU thanh trên, không bao giờ chồng chữ lên nhau. */
  .nn-thanh-cham {
    position:sticky; top:calc(58px + var(--dnc-cao, 0px)); z-index:40;
    margin:0 0 12px; padding:8px 12px 10px;
    background:var(--the); border-bottom:1px solid var(--vien);
    row-gap:8px; column-gap:8px; align-items:center;
  }
  /* Lề âm chỉ mở khi BIẾT CHẮC đệm trang là 12px (dòng 564 `body.man-cong-cu`). Màn
     nào vào bằng đường khác thì đệm là 10px (dòng 3189) và lề âm 12px sẽ lòi 2px mỗi
     bên → sinh cuộn ngang, đúng thứ đang đi chữa. */
  body.man-cong-cu .nn-thanh-cham { margin:0 -12px 12px; }
  /* ⛔ PHẢI ép `order`: thứ tự thật trong DOM (dòng 16431–16435) là
     Về → mã → Lưu → Xong → điểm tạm, mà flexbox xuống hàng theo DOM chứ không theo
     ý muốn. Không ép thì Lưu nhảy lên nằm cạnh nút Về và phình ~278px, điểm tạm rớt
     xuống — ngược hẳn ý đồ.
     `flex-basis:160px` cho điểm tạm là chỗ mấu chốt: chấm xong nó chỉ còn "8,5 · khá"
     (~60px) thì Lưu lại nhảy lên hàng 1. Cho 160px cứng là hàng luôn vỡ đúng chỗ. */
  .nn-thanh-cham #nnVe        { order:1; flex:0 0 auto; }
  .nn-thanh-cham .nn-diem-tam { order:2; flex:1 1 160px; text-align:right;
                                margin-left:0; font-size:12.5px; line-height:1.3; }
  .nn-thanh-cham #nnLuu       { order:3; flex:1 1 58%; }
  .nn-thanh-cham #nnXongNut   { order:4; flex:1 1 34%; font-size:12.5px;
                                line-height:1.25; padding:9px 10px; }
  /* Mã bài (nn_00123) thu nhỏ xuống hàng cuối chứ KHÔNG giấu hẳn — cô Quỳnh gọi báo
     lỗi một bài thì vẫn phải đọc được mã cho người sửa. */
  .nn-thanh-cham .nn-ma { order:5; flex:1 1 100%; font-size:10.5px; }

  /* ⑥ HAI TAB PHẦN 1 / PHẦN 2 — CHIA ĐÔI MÀN HÌNH.
     Trước đây hai nút tự co theo độ dài chữ nên rơi thành hai hàng lệch nhau, viền
     hở, trông như hỏng. Đây lại là nút điều hướng quan trọng nhất màn chấm. */
  .nn-phan     { display:grid; grid-template-columns:1fr 1fr; width:100%; margin-bottom:12px; }
  .nn-phan-nut { min-height:46px; padding:10px 8px; font-size:12.5px; line-height:1.3; }

  /* ⑦ BÓP KHUNG CHO ĐẶC LẠI. */
  .nn-cham    { gap:11px; }
  .nn-khoi    { padding:12px 12px 14px; border-radius:var(--r-lg); }
  .nn-khoi h3 { font-size:12px; margin-bottom:9px; }
  .nn-o-luoi  { gap:9px; }
  .nn-lan-o   { padding:11px 11px 12px; gap:9px; }

  /* ════════════════════════════════════════════════════════════════════════════
     3.5 · HỒ SƠ KIỂM TRA
     ⛔⛔ BỆNH NẶNG NHẤT — LỀ CHỒNG LỀ. Khối `@media (max-width:720px)` dòng 2057 đặt
        `.kq-phieu { padding:18px 16px }`, mà mỗi mục bên trong CÒN 30px lề riêng
        (.kq-dau dòng 1930, .kq-khoi 1951, .kq-chan 1982). Màn 390px chỉ còn 258px cho
        chữ. Cách chữa: tờ bỏ hết lề ngang, từng mục tự lấy lề — MỘT lớp, không phải hai.
        Nhân thể vạch màu thương hiệu `.kq-phieu::before` chạy chạm mép trở lại thay vì
        thụt vào 16px như tờ giấy bị dán lệch.
     ⛔ Cả ba luật của khối 2057 đều bị đè ở đây → khối đó thành rác, xem mục cảnh báo.
     ════════════════════════════════════════════════════════════════════════════ */
  .kq-phieu { padding:0 0 18px; }
  .kq-khoi  { margin-top:17px; padding:0 20px; }
  .kq-chan  { margin:18px 20px 0; }
  /* Đè lại khối 720px: GIỮ MỘT HÀNG, tên trái — điểm phải (khối cũ đẩy vòng điểm
     xuống dưới tên, tụt thêm một khúc màn hình). */
  .kq-dau { flex-direction:row; align-items:flex-start; gap:14px;
            margin-right:140px; padding:20px 20px 15px; }
  .kq-dau-trai { flex:1 1 auto; min-width:0; }
  .kq-dau h1   { font-size:23px; overflow-wrap:anywhere; }
  /* ⛔ PHẢI thu logo thì mới được rút lề. `.kq-logo .cham` có `white-space:nowrap`
     (dòng 442) nên chuỗi "Perseverance and Success" KHÔNG BAO GIỜ xuống dòng, rộng
     ~125–132px. Rút lề mà không thu logo là chữ đè lên nhau ở dải 721–820px.
     ⛔ Chỉ đè trong @media — luật gốc dòng 1927 phải giữ NGUYÊN TỪNG CHỮ, bài kiểm
        thu-nghe-noi.js dòng 253 soi đúng dòng đó. */
  .kq-logo { top:18px; right:20px; }
  .kq-logo .logo-mypas .ten  { font-size:20px; }
  .kq-logo .logo-mypas .cham { font-size:8px; letter-spacing:.04em; }
  /* Ô tìm ở màn danh sách hồ sơ ăn trọn hàng, dòng đếm về bên trái. */
  #kqTim { max-width:none; flex:1 1 100%; }
  #kqTim ~ .nn-dem { margin-left:0; }
  #kqIn  { margin-left:auto; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   PHẦN 4 · ĐIỆN THOẠI (≤640px) — chỗ nhân viên dùng thật
   ══════════════════════════════════════════════════════════════════════════════ */
@media screen and (max-width:640px) {

  /* ── 4.1 SỔ TUYỂN SINH ──────────────────────────────────────────────────── */
  body:has(#ctsBang) .cts-dau h2 { font-size:13px; }
  .cts-loc .cts-tim { flex:0 0 170px; width:170px; max-width:none; }
  /* ⛔⛔ BẢN ĐẦU 16/08/2026 KHOÁ CỘT TÊN PH Ở 128px BẰNG `!important` — ĐÃ BỎ.
     Lý do bỏ: bảng chạy `table-layout:fixed`, bề rộng cột lấy từ con số ghi thẳng
     trong `style="width:…px"` của ô tiêu đề — mà chính cú KÉO CỘT của người dùng
     cũng ghi vào đúng chỗ ấy. Dùng `!important` thì CSS thắng tất, nghĩa là cô Quỳnh
     kéo kiểu gì cột cũng đứng im ở 128px: tính năng nới cột coi như mất trên điện thoại.
     Đúng thứ cô vừa cấm hôm nay.

     Nay KHÔNG ép con số nào. Cột giữ mặc định 190px như máy tính, và cô tự kéo hẹp
     lại được bằng tay nắm vừa nới rộng lên 24px ở trên — app nhớ bề rộng theo tài
     khoản, nên chỉnh một lần là xong mãi.
     Đổi lại phải chấp nhận: lần đầu mở trên màn 390px, cột này ăn khoảng một nửa
     bề ngang cho tới khi cô kéo hẹp. Thà vậy còn hơn khoá cứng rồi không ai sửa được.
     ⛔ Muốn đổi mặc định cho màn nhỏ thì phải sửa trong `ctsRongCot` (nơi sinh ra con
        số ban đầu) chứ ĐỪNG đè bằng CSS — đè bằng CSS là chặn luôn tay người dùng. */

  /* ── 4.2 LỊCH TEST ──────────────────────────────────────────────────────────
     ⛔ ĐỪNG bóp lịch tháng thu nhỏ + 2 khối lọc thành ba cột 120px như dòng 1457:
        mỗi ô ngày còn rộng 17px, bấm mười lần trượt chín. Đây đúng chỗ cô Quỳnh nói
        *"dồn hẹp lại trông xấu không dùng được"*. Cho xếp DỌC, mỗi khối một hàng. */
  .lt-man { gap:10px; }
  .lt-ben { display:block; width:100%; }
  .lt-ben > .lt-tao { width:100%; margin-bottom:9px; }
  .lt-mini { width:100%; margin-bottom:10px; }
  .lt-mini-luoi button { height:34px; font-size:13px; }   /* ô ngày ~46px, bấm trúng */
  .lt-mini-luoi span   { font-size:11px; }
  /* Danh sách người/cơ sở dài thì cuộn TRONG lòng nó, đừng đẩy lịch xuống đáy trang. */
  .lt-nguoi { width:100%; margin-bottom:10px; max-height:190px;
              overflow:auto; overscroll-behavior:contain; }
  .lt-nguoi:last-child { margin-bottom:0; }
  .lt-nguoi label { padding:6px 0; font-size:13px; }
  .lt-nguoi input { width:17px; height:17px; }
  .lt-coso { margin-top:0; }

  /* ⛔⛔ CHẾ ĐỘ TUẦN — CHO LƯỚI CUỘN NGANG THAY VÌ BÓP BẢY CỘT VÀO 390px.
     Đo thật: 390px trừ 64px cột giờ, chia bảy → mỗi ngày rộng 43px; ca trùng giờ còn
     chia đôi tiếp, còn ~20px. Không đọc nổi một chữ.
     Nay ép lưới rộng 820px → mỗi ngày 108px, cuộn ngang bằng ngón tay TRONG `.lt-khung`
     (nó vốn đã `overflow:auto`, dòng 1175). Hàng tiêu đề `.lt-dau-hang` và thân `.lt-than`
     nhận CÙNG một min-width nên trôi khớp nhau, và `position:sticky; top:0` của hàng
     tiêu đề vẫn giữ nguyên.
     ⛔ PHẢI bám lớp `lt-xem-tuan` do mã gắn (sửa mã ⑦). Không có lớp thì chế độ NGÀY
        (một cột) cũng bị ép 820px → cuộn ngang vô cớ. */
  .lt-khung.lt-xem-tuan .lt-dau-hang,
  .lt-khung.lt-xem-tuan .lt-than,
  .lt-khung.lt-xem-tuan .lt-tuan-o { min-width:820px; }

  .lt-dau-o { padding:7px 4px 8px; }
  .lt-dau-o .lt-thu { font-size:10px; }
  .lt-dau-o .lt-sn  { font-size:18px; }
  .lt-dau-o.homnay .lt-sn, .lt-dau-o.dangxem .lt-sn {
      min-width:29px; width:auto; height:26px; line-height:26px; font-size:14.5px; }
  .lt-nhan-gio { font-size:11px; padding-right:6px; }
  .lt-the      { font-size:12.5px; padding:4px 7px; }
  .lt-the span { font-size:11.5px; }

  /* LƯỚI THÁNG ở màn vừa: ô ngày thấp lại, đừng để một tấm lưới cao gần 700px mà
     chẳng đọc được gì. */
  .lt-thang .lt-o-ngay { min-height:74px; padding:4px 3px; }
  .lt-thang .lt-o-ngay .lt-sn { font-size:11.5px; }

  /* DANH SÁCH THEO NGÀY — mỗi ca MỘT KHỐI HAI DÒNG:
       dòng trên : giờ (vạch màu người phụ trách) · tên em · mã cơ sở
       dòng dưới : người phụ trách · số điện thoại
     ⛔ KHÔNG giấu người phụ trách và số điện thoại như dòng 1451–1453 — đó đúng là
        hai thứ nhân viên cần nhất khi cầm điện thoại gọi cho phụ huynh. Cho xuống
        dòng hai, đừng xoá. Khối này đứng SAU nên thắng luật `display:none` ở 1452. */
  .lt-ds-dau  { padding:8px 12px; font-size:12.5px; }
  .lt-ds-hang { display:grid;
      grid-template-columns:58px minmax(0,1fr) auto;
      grid-template-areas:"gio ten cs" "gio phu sdt";
      column-gap:9px; row-gap:2px; align-items:center;
      padding:9px 12px 9px 0; min-height:52px; }
  .lt-ds-gio  { grid-area:gio; width:auto; align-self:stretch;
                display:flex; align-items:center; font-size:13px; }
  .lt-ds-ten  { grid-area:ten; white-space:normal; line-height:1.3; font-size:13.5px; }
  .lt-ds-hang .lt-cs { grid-area:cs; align-self:center; }
  .lt-ds-nguoi { grid-area:phu; display:block; flex:none; font-size:11.5px; }
  .lt-ds-sdt   { grid-area:sdt; display:block; font-size:11.5px; }
  .lt-ds-hang:active { background:var(--nen2); }

  /* ── 4.3 TEST ĐẦU VÀO ───────────────────────────────────────────────────── */
  /* Thẻ học sinh: tên phải hiện ĐỦ, vì tên là thứ DUY NHẤT để nhận ra em nào
     (thẻ đã bỏ hiện điểm theo luật cô Quỳnh).
     ✅ 17/08/2026: việc CHO XUỐNG DÒNG nay đã nằm ở LUẬT GỐC (`.nn-the-dau b`,
        `.nn-the-phu` ở khối CSS chính) nên mọi cỡ màn đều đủ chữ. Mấy dòng dưới đây
        giữ lại chỉ để bóp lề và giãn dòng cho màn nhỏ — phần chống-cắt là thừa nhưng
        vô hại, cứ để cho khỏi vỡ nếu ai lỡ đổi luật gốc.
     ⛔ `.kq-the .nn-the-dau b` (độ mạnh 0-2-1) vẫn thắng luật này (0-1-1) ở màn
        Hồ sơ kiểm tra — đúng ý, bên đó đã có bản riêng. */
  .nn-luoi      { gap:9px; }
  .nn-the       { padding:12px 13px; }
  /* ⛔⛔ SỬA LẠI 09/09/2026 — BẢY Ô MỘT HÀNG, BÓP CHỮ CHỨ ĐỪNG GẬP HÀNG.
     Luật cũ ở đây cho gập hai hàng (`calc(25% - 6px)` = bốn ô mỗi hàng) vì lo chữ
     "22/08" vỡ đôi khi ô còn 45px. Lo ấy ĐÚNG với cỡ chữ 13,5px: "22/08" chiếm
     ~38px, cộng đệm 2px hai bên là chạm mép.
     Nhưng cái giá là dải ngày cao **142px** — mà cả màn Test đầu vào chỉ có 844px và
     đã mất 287px đầu màn (Boss: *"nút quá nhiều chiếm nửa màn hình"*).
     Nay: ô 44px, đệm ngang còn 1px, và cỡ ngày xuống 12px — "22/08" chỉ còn ~33px
     trong 42px lòng ô, còn dư 9px. Bảy ô: 7×44 + 6 khe×4 = 332px, vừa trong 366px.
     ⛔ ĐO LẠI CHỮ nếu đổi cỡ: chỗ này vỡ là ngày mất một nửa, mà ngày là thứ duy
        nhất phân biệt bảy ô với nhau. */
  .nn-dai-o     { flex:1 1 46px; min-width:46px; padding:6px 1px 7px; }
  /* Do that: chu "07/09" rong 43px. O 44px thi long o cung dung 43px — vua khit,
     khong con mot ly bien an toan, may nao chu nhinh hon mot chut la vo. Nay o 46px
     (long 44) va chu 11.5px (~41px): du 3px. Bay o van mot hang — 7x46 + 6 khe x4
     = 346px, con thua 20px trong 366px. */
  .nn-dai-ngay  { font-size:11.5px; }
  /* Hàng bài đổi sang xếp dọc: trên điện thoại không có bề ngang cho năm cột. */
  .nn-bai       { flex-wrap:wrap; gap:4px 10px; }
  .nn-bai-loai  { width:auto; flex:1 1 100%; }
  .nn-bai-ten   { flex:1 1 100%; }
  .nn-bai-nc    { width:auto; text-align:left; }
  .nn-bai-tt    { width:auto; margin-left:auto; }
  .nn-em-nut button { flex:1 1 100%; }
  .nn-the-dau b { white-space:normal; overflow:visible; text-overflow:clip; line-height:1.3; }
  .nn-the-phu   { white-space:normal; overflow:visible; text-overflow:clip;
                  line-height:1.4; min-height:0; margin-top:4px; }
  .nn-the-chan  { flex-wrap:wrap; gap:3px 9px; margin-top:7px; }
  .nn-the-chan .nn-xong, .nn-the-chan .nn-dodang { margin-left:auto; }
  .nn-trong     { padding:26px 14px; font-size:13px; }

  /* Tiêu chí chấm: số điểm sang trái, mô tả sang phải.
     ⛔ VẪN HIỆN NGUYÊN CÂU MÔ TẢ trên từng mức — người chấm phải đọc mô tả mới chấm
        đúng, đó là cả lý do form gốc viết câu dài như vậy.
     Chỗ tiết kiệm là CHỖ ĐỨNG của con số: trước đây "3/4" chiếm trọn một dòng riêng
     phía trên mô tả; nay thành ô vuông nhỏ bên trái, mô tả chảy sát bên cạnh → mỗi
     nút bớt một dòng, bốn tiêu chí bớt ~300px vuốt màn.
     Mức đang chọn thêm vạch dọc màu bên trái — đúng ngôn ngữ sẵn có của app
     (`.nn-the.xong { border-left:3px solid var(--o-tot) }`, dòng 1501). */
  .nn-tc        { padding:13px 0; }
  .nn-tc-ten    { flex-direction:column; align-items:flex-start; gap:2px; margin-bottom:9px; }
  .nn-tc-ten b  { font-size:14.5px; }
  .nn-tc-anh, .nn-tc-mo { font-size:11.5px; }
  .nn-muc       { grid-template-columns:1fr; gap:6px; }
  .nn-muc-nut   { flex-direction:row; align-items:flex-start; gap:9px;
                  padding:10px 11px; border-left-width:1px; }
  .nn-muc-so    { flex:none; width:32px; padding:2px 0; text-align:center;
                  border:1px solid var(--vien); border-radius:var(--r-sm);
                  font-size:11px; line-height:1.35; }
  .nn-muc-chu   { flex:1; min-width:0; font-size:12.5px; line-height:1.42; }
  .nn-muc-nut.chon { border-left:3px solid var(--muc); padding-left:9px; }
  .nn-muc-nut.chon .nn-muc-so { background:var(--muc); color:#fff; border-color:var(--muc); }

  /* Lớp phù hợp: hàng trên tên lớp + dấu ×, hàng dưới ba chặng chia đều, cao 42px.
     Trước đây tên lớp và ba nút Đầu/Giữa/Cuối chen nhau trên hàng 300px → mỗi nút
     ~40px, cao 21px, bấm là trượt — mà bấm trượt là xếp em vào SAI chặng lớp.
     ⛔ Điện thoại KHÔNG có rê chuột → dấu × phải tự nó nhìn thấy được (bản gốc để
        `opacity:.35` và chỉ rõ lên khi `:hover`). Để .55: có mặt mà không kéo mắt
        khỏi việc chính. Bấm vào vẫn có hộp thoại hỏi lại (hàm nnXoaLop dòng 16821). */
  .nn-lop       { grid-template-columns:1fr; gap:7px; margin-bottom:11px; }
  .nn-lop-o     { flex-wrap:wrap; padding:9px 10px 10px; row-gap:8px; }
  .nn-lop-ten   { flex:1 1 auto; font-size:13.5px; }
  .nn-lop-xoa   { order:2; opacity:.55; min-width:38px; min-height:38px; font-size:18px; }
  .nn-chang     { order:3; flex:1 1 100%; gap:6px; }
  .nn-chang-nut { flex:1; min-height:42px; border-radius:var(--r-md); font-size:12.5px; }

  /* Bảng điền số câu đúng: cột số thu 118 → 100px trả chỗ cho cột Chủ đề (tên chủ đề
     đang phải xuống 3–4 dòng). Ô điền cao lên 44px cho vừa ngón tay. */
  .nn-de-nhom  { margin-bottom:10px; }
  .nn-de-dau   { flex-wrap:wrap; row-gap:3px; column-gap:10px; padding:10px 11px; }
  .nn-de-dau b { flex:1 1 100%; min-width:0; }
  .nn-de-tong  { margin-left:0; }
  .nn-bang th, .nn-bang td { padding:7px 10px; }
  .nn-bang .c-cd      { line-height:1.4; }
  .nn-bang .c-cd .con { padding-left:8px; }
  .nn-bang .c-so      { width:100px; }
  .nn-bang .c-so input{ width:54px; min-height:44px; padding:6px 3px; }

  /* ── 4.4 HỒ SƠ KIỂM TRA ─────────────────────────────────────────────────── */
  /* Logo thôi ghim góc phải, xuống hàng riêng trên cùng bên trái — lối giấy tiêu đề
     in sẵn, đúng chất văn phòng. Nhờ vậy bỏ được lề 140px, trả toàn bộ bề ngang cho
     tên học sinh (trên 390px tên chỉ còn ~108px, phải bẻ 3–4 dòng rất xấu).
     ⛔ Chỉ đè trong @media — dòng gốc 1927 giữ nguyên chữ cho bài kiểm. */
  .kq-logo { position:static; text-align:left; padding:13px 14px 0; }
  .kq-logo .logo-mypas .ten  { font-size:19px; }
  .kq-logo .logo-mypas .cham { font-size:8px; letter-spacing:.045em; }

  .kq-dau    { margin-right:0; padding:11px 14px 13px; gap:11px; }
  .kq-nhan   { font-size:10.5px; }
  .kq-dau h1 { font-size:20px; margin:4px 0 5px; line-height:1.22; }

  /* Ngày sinh và số điện thoại — hai thứ DUY NHẤT tách được hai em trùng tên — mỗi
     thứ một dòng riêng, màu chữ thường chứ không màu mờ. Lớp và trường vẫn chung
     một dòng cho đỡ tốn chỗ. (Cần sửa mã ⑤; không có nó thì cả cụm vẫn là một dòng
     chữ như cũ, không hỏng gì.) */
  .kq-phu    { font-size:12.5px; line-height:1.5; }
  .kq-phu-id, .kq-phu-ngay { flex:1 1 100%; }
  .kq-phu-id::before, .kq-phu-ngay::before { content:none !important; }
  .kq-phu-id { color:var(--chu); font-variant-numeric:tabular-nums; }

  /* Vòng điểm nhỏ lại nhưng VẪN đứng cạnh tên: mở hồ sơ ra là thấy ngay điểm mà
     không mất thêm một khúc màn hình. */
  .kq-dau-phai { flex:none; }
  .kq-vong { width:62px; height:62px; border-width:4px; padding-top:15px; }
  .kq-so   { font-size:22px; }
  .kq-tren { font-size:10px; }
  .kq-hang { margin-top:5px; font-size:11px; }

  .kq-khoi    { margin-top:15px; padding:0 14px; }
  .kq-khoi h2 { font-size:11px; margin-bottom:9px; padding-left:9px; }
  .kq-chan    { margin:15px 14px 0; padding-top:11px; font-size:11px; }

  /* Tiêu chí chấm: tên + điểm một hàng, tên tiếng Anh xuống hàng riêng.
     `order:3` để tên tiếng Anh nhảy xuống SAU điểm — không có nó thì điểm bị đẩy
     xuống hàng ba, trông như lạc chỗ. */
  .kq-tc-ds    { gap:13px; }
  .kq-tc-dau   { flex-wrap:wrap; gap:4px 9px; margin-bottom:5px; }
  .kq-tc-dau b { flex:1 1 auto; min-width:0; font-size:14px; overflow-wrap:anywhere; }
  .kq-tc-dau i { order:3; flex:1 1 100%; font-size:11px; }
  .kq-tc-diem  { flex:none; font-size:13.5px; }
  .kq-tc-chu   { font-size:13px; line-height:1.5; }
  .kq-thanh    { gap:3px; margin-bottom:5px; }
  .kq-o        { height:8px; }

  .kq-lan     { padding:9px 11px; margin-bottom:8px; }
  .kq-lan-dau { gap:7px; font-size:12px; }
  .kq-chude   { font-size:13px; line-height:1.55; }
  .kq-vanban  { font-size:13px; line-height:1.6; }

  /* Bài viết ngữ âm — ngữ pháp: tên đề ăn trọn một hàng, "37/57 câu đúng" xuống hàng
     dưới ngay trên thanh tỉ lệ. Nhồi chung một hàng là tràn và bị cắt. */
  .kq-viet       { padding:10px 12px; margin-bottom:9px; }
  .kq-viet-dau   { flex-wrap:wrap; gap:2px 10px; }
  .kq-viet-dau b { flex:1 1 100%; font-size:13.5px; overflow-wrap:anywhere; }
  .kq-viet-so    { margin-left:0; font-size:13px; }
  .kq-viet-chan  { font-size:11px; line-height:1.5; }
  .kq-cd         { font-size:12px; }
  .kq-cd .c-ten  { overflow-wrap:anywhere; }
  .kq-cd .c-so   { width:56px; }

  .kq-lop-ds { gap:7px; }
  .kq-lop    { padding:6px 11px; }
  .kq-lop b  { font-size:13.5px; }

  /* Băng chọn bài test: xếp DỌC thành danh sách nút liền mạch, tên trái · ngày phải.
     Xếp ngang kiểu máy tính thì trên điện thoại chữ trong nút tự bẻ dòng, nút to nút
     nhỏ so le, mà mỗi nút lại quá bé để bấm bằng ngón tay. */
  .kq-bang-bai  { flex-direction:column; align-items:stretch; gap:6px;
                  padding:9px 10px; margin-bottom:11px; }
  .kq-bang-nhan { margin:0 0 1px; }
  .kq-bai-nut   { flex-direction:row; align-items:center; justify-content:space-between;
                  gap:10px; padding:9px 11px; min-height:42px; }
  .kq-bai-nut b { flex:1 1 auto; min-width:0; overflow-wrap:anywhere; }
  .kq-bai-nut span { flex:none; }
  .kq-bai-them  { margin-left:0; text-align:center; padding:11px 12px; }

  /* Thẻ ngoài danh sách hồ sơ.
     ⛔ TUYỆT ĐỐI KHÔNG đặt `font-weight:700` cho `.kq-the-dinh` — bài kiểm
        thu-ho-so-kiem-tra.js dòng 154 canh đúng chỗ này.
     `nowrap` để nhãn không bao giờ rời khỏi con số của nó: "SĐT:" cuối dòng còn số
     nhảy xuống dòng dưới là đọc nhầm ngay. */
  #kqLuoi { grid-template-columns:minmax(0,1fr); gap:9px; }
  #kqLuoi .nn-the       { padding:10px 12px; }
  #kqLuoi .nn-the-dau b { font-size:14.5px; }
  #kqLuoi .kq-the-dinh  { gap:2px 14px; font-size:12.5px; font-variant-numeric:tabular-nums; }
  #kqLuoi .kq-the-dinh span { white-space:nowrap; }
  #kqLuoi .nn-the-phu   { font-size:11.5px; }
  #kqLuoi .nn-the-chan  { margin-top:7px; font-size:11px; }
  #kqLuoi .nn-them-me   { padding:10px 12px; }
  #kqLuoi .nn-them-me .nut-nho { flex:1 1 auto; padding:9px 10px; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   PHẦN 5 · ĐIỆN THOẠI NHỎ (≤560px, tức máy 360px) — nhích thêm một nấc
   Giữ nguyên mọi chỗ bấm ở 42–44px, chỉ bóp lề và cỡ chữ.
   ══════════════════════════════════════════════════════════════════════════════ */
@media screen and (max-width:560px) {
  /* Lịch test */
  .lt-che button { padding:8px 2px; font-size:11.5px; }
  .lt-tieude     { font-size:12px; }
  .lt-ds-hang    { grid-template-columns:52px minmax(0,1fr) auto; column-gap:7px; }
  .lt-ds-gio     { font-size:12.5px; }
  .lt-ds-ten     { font-size:13px; }
  /* Test đầu vào */
  .nn-phan-nut   { font-size:12px; padding:10px 5px; }
  .nn-khoi       { padding:11px 11px 13px; }
  .nn-bang th, .nn-bang td { padding:7px 7px; }
  .nn-bang .c-so       { width:92px; }
  .nn-bang .c-so input { width:50px; }
  .nn-thanh-cham #nnXongNut { font-size:12px; }
  /* Hồ sơ kiểm tra */
  .kq-dau h1 { font-size:19px; }
  .kq-vong   { width:56px; height:56px; border-width:3px; padding-top:13px; }
  .kq-so     { font-size:20px; }
  .kq-logo .logo-mypas .ten { font-size:18px; }
}

  /* ⛔ KHỐI NÀY DÙNG MỐC KÉP: màn HẸP hoặc màn THẤP.
     Điện thoại xoay ngang rộng 844px nên lọt khỏi mọi khối `max-width:820px`,
     mà đó lại đúng lúc chiều cao chỉ còn 390px — đo thật 23/08/2026: bảng TRÀN
     79px ra ngoài màn và nút tròn không mọc. Thứ đang đau là CHIỀU CAO, nên phải
     hỏi thẳng chiều cao.
     ⛔ Ghi `screen and` cho CẢ HAI vế — đây là nếp mới (dùng từ phần Lịch test trở
        đi). Phần lớn khối cũ trong file còn viết `@media (max-width:…)` trần; thấy
        lệch thì đừng "sửa cho đồng bộ" xuống nếp cũ.
     ⛔ Đặt ở CUỐI phần CSS, sau mọi khối màn hẹp, để luật ở đây thắng — nhất là
        `#ddFab { display:none !important }` khai ở phần trên. */
@media screen and (max-width:820px), screen and (max-height:560px) {
  /* ══════════════════════════════════════════════════════════════════════════
     ⭐⭐ ĐIỀN ĐIỂM TRÊN ĐIỆN THOẠI: BẢNG CHIẾM TRỌN MÀN — cô Quỳnh 23/08/2026
     ──────────────────────────────────────────────────────────────────────────
     *"giao diện app điểm danh ở màn hình bé điện thoại trông rất khó sử dụng để
     điền điểm vì quá nhiều nút che và các thanh nó che hết luôn… khi điền điểm
     tôi nghĩ sẽ hiện đầy đủ phần bảng điểm danh toàn màn hình để mọi người ghi
     điểm, còn khi cần ấn nút nào sẽ ấn vào 1 nút để mở ra các nút rồi mọi người
     có thể ẩn các nút chức năng đi và mở lại lúc cần… phải linh hoạt màn hình
     điện thoại lên vì có rất nhiều kích cỡ khác nhau."*

     ĐO THẬT 23/08/2026, lớp đang có buổi mở, ba cỡ màn:
       320×568 → bảng chỉ được 178px = **31% màn**, nhìn được 4 em
       360×640 → bảng 250px = 39% màn, 7 em
       390×844 → bảng 454px = 54% màn, 15 em
     Hai thứ ăn chỗ nhiều nhất, đo được từng pixel:
       `.thanh-cong-cu` **167px** — dính đáy màn, luôn nằm đó dù không dùng tới
       `.dh-day`         **95px** — thanh nhảy buổi
     Cộng **262px**. Trên màn 568px thì riêng hai thanh này đã ăn 46% màn hình.

     CÁCH CHỮA đúng lời cô: gộp cả hai vào MỘT nút tròn, mặc định ĐÓNG.
     Đóng → bảng lấy lại trọn 262px ấy. Bấm nút tròn → cả hai trượt ra, dùng
     xong bấm lại là cất đi. Trạng thái được NHỚ nên mỗi người tự chọn một lần.

     ⛔ KHÔNG MẤT TÍNH NĂNG NÀO — đúng luật cô Quỳnh chốt 16/08/2026: *"không được
        bỏ đi các tính năng như máy tính… Bày khác thì được, MẤT thì không."*
        Mọi nút vẫn nguyên đó, nguyên quyền, chỉ đổi chỗ đứng.
     ⛔ KHÔNG đụng `.dau-lop`: trong đó có nút "← Danh sách lớp", đường ra duy nhất.
     ⛔ CHIỀU CAO BẢNG PHẢI ĐO, ĐỪNG GÕ SỐ. `.dau-lop` cao 113px ở màn 320/360
        nhưng 98px ở màn 390 — mọi con số cứng đều sai ở đâu đó. `ddDoCaoBang()`
        đo chỗ bảng BẮT ĐẦU rồi lấy phần còn lại của màn. Đó là chỗ "linh hoạt
        với rất nhiều kích cỡ" mà cô Quỳnh dặn.
     ⛔ CHỈ trong lớp điểm danh (`body.dang-trong-lop`). Lớp `.thanh-cong-cu` còn
        dùng ở hai màn Progress test — không khoanh lại là đổ sang đó ngay.
     ══════════════════════════════════════════════════════════════════════════ */
  /* ⛔⛔ SỬA LẠI 23/08/2026 (cùng ngày, sau khi cô Quỳnh xem bản đầu):
     *"Bạn thiết kế cái gom buổi vào trông lỗi quá, để cái nút chọn buổi và thanh kéo
     buổi và buổi đang điền như ban đầu đi, không cần ẩn đi — chỉ những nút chức năng
     khác cần ẩn thôi."*
     Bản đầu tôi gom cả `.dh-day` (thanh nhảy buổi) vào cụm nút ẩn đi. SAI: thanh ấy
     là thứ người điền dùng LIÊN TỤC để đổi buổi, giấu nó đi là bắt thao tác thêm một
     bước cho việc hay làm nhất. Nay `.dh-day` ĐỨNG YÊN như cũ, chỉ mỗi thanh nút
     chức năng là cất đi được.
     ⛔ ĐỪNG gom lại lần nữa. */
  body.dang-trong-lop.dd-gon-nut:not(.dd-nut-mo) .thanh-cong-cu { display:none; }
  body.dang-trong-lop.dd-gon-nut:not(.dd-nut-mo) #noiDung { padding-bottom:16px; }

  /* ⭐⭐ ÔM SÁT HƠN NỮA — cô Quỳnh 23/08/2026 (lượt hai):
     *"tổng thể cái bảng điểm danh trên điện thoại vẫn rất bé, tôi muốn ôm sát mở ra
     gần như toàn màn hình đi."*
     Đo thật lượt một: dải đầu lớp `.dau-lop` cao 113px trên màn 320/360, mà bên trong
     chỉ có nút "← Danh sách lớp", tên lớp và một dòng phụ (sĩ số, cơ sở, giáo viên).
     Dòng phụ xuống hàng riêng vì `width:100%` — chính nó làm dải cao gấp đôi.
     ⛔ KHÔNG ẩn cả dải: trong đó có nút "← Danh sách lớp", đường ra duy nhất.
     ⛔ CHỈ thu trong lớp điểm danh trên màn hẹp — `.dau-lop` dùng chung nhiều màn. */
  /* ══════════════════════════════════════════════════════════════════════════
     ⭐⭐⭐ ĐANG ĐIỀN THÌ NHƯỜNG HẾT CHỖ CHO BẢNG — cô Quỳnh 23/08/2026 (lượt ba)
     ──────────────────────────────────────────────────────────────────────────
     *"tôi muốn cái bảng điểm để điền ở trong điểm danh app chiếm toàn màn hình ý,
     phủ cả màn chứ không phải còn dư nhiều chỗ như này; xong cái bảng thì gom lại ở
     giữa màn rất khó điền, cứ phải kéo lên kéo xuống dù màn đủ để hiển thị hết cả
     chiều dài bảng điểm."*

     Lúc cụm nút đang ĐÓNG (tức đang điền điểm) thì thanh trên đi luôn — nó chỉ có
     logo, chuông và bóng đèn gợi ý, không dùng tới trong lúc điền. Bấm nút tròn để
     mở cụm nút là nó hiện lại ngay, nên KHÔNG MẤT gì.
     ⛔ Đó là lý do luật này gắn `:not(.dd-nut-mo)`. Bỏ vế ấy đi là chuông thông báo
        biến mất vĩnh viễn trong lớp — `#thanhDuoi` cũng đã bị ẩn khi trong lớp, nên
        sẽ không còn đường nào thấy việc mới.
     ══════════════════════════════════════════════════════════════════════════ */
  body.dang-trong-lop.dd-gon-nut:not(.dd-nut-mo) .thanh-tren { display:none; }
  body.dang-trong-lop.dd-gon-nut.dd-nut-mo .thanh-tren { padding:3px 8px; margin:0 6px 5px; }
  body.dang-trong-lop.dd-gon-nut .thanh-tren .ten-app { display:none; }
  /* Khoảng đệm quanh nội dung cũng thu lại — trên màn 320px thì 12px mỗi bên là
     ăn mất gần một cột điểm. */
  /* Lề hai bên cũng nhường nốt: cô Quỳnh *"cái bảng thì gom lại ở giữa màn"*.
     Trên màn 320px, 12px mỗi bên là ăn mất gần một cột điểm. Bảng chạm sát mép,
     bỏ bo góc và viền hai bên cho liền một khối như trang tính. */
  body.dang-trong-lop.dd-gon-nut:not(.dd-nut-mo) #noiDung { padding:6px 0 16px; }
  body.dang-trong-lop.dd-gon-nut:not(.dd-nut-mo) .dau-lop,
  body.dang-trong-lop.dd-gon-nut:not(.dd-nut-mo) .dh-day,
  body.dang-trong-lop.dd-gon-nut:not(.dd-nut-mo) .khung-note,
  body.dang-trong-lop.dd-gon-nut:not(.dd-nut-mo) .ghi-chu-gap { padding-left:10px; padding-right:10px; }
  body.dang-trong-lop.dd-gon-nut:not(.dd-nut-mo) .khung-cuon {
    width:100%; max-width:100%; border-left:0; border-right:0; border-radius:0; }
  body.dang-trong-lop.dd-gon-nut .dau-lop { margin-bottom:6px; gap:6px; }
  body.dang-trong-lop.dd-gon-nut .dau-lop .phu { display:none; }
  body.dang-trong-lop.dd-gon-nut .dau-lop .ten { font-size:16px; }
  /* Thanh nhảy buổi cũng gọn lại một chút — vẫn đủ 44px cho ngón tay bấm. */
  body.dang-trong-lop.dd-gon-nut .dh-day { margin-bottom:6px; gap:6px; }

  /* 📱 THANH CUỘN RIÊNG — dải dọc sát rìa phải, chạy gần hết chiều cao màn.
     Rộng 18px: đủ cho đầu ngón tay chạm trúng mà không ăn mất một cột của bảng.
     Con trượt cao tối thiểu 44px (chuẩn vùng chạm) — trang dài mấy thì nó cũng
     không teo thành một vạch không nắm nổi. */
  body.dang-trong-lop.dd-co-thanh #ddThanh {
    display:block; position:fixed; z-index:46;
    right:0; top:56px; bottom:8px; width:18px;
    background:rgba(120,132,144,.10); border-radius:var(--r-md);
    touch-action:none; -webkit-user-select:none; user-select:none; }
  body.dang-trong-lop.dd-co-thanh #ddThanhCon {
    position:absolute; left:3px; right:3px; top:0; height:44px;
    border-radius:var(--r-sm); background:rgba(96,108,120,.62);
    box-shadow:0 1px 3px rgba(0,0,0,.18); }
  body.dang-trong-lop.dd-co-thanh #ddThanh.dang-keo #ddThanhCon,
  body.dang-trong-lop.dd-co-thanh #ddThanhCon:active { background:rgba(70,82,94,.86); }
  body.toi.dang-trong-lop.dd-co-thanh #ddThanh { background:rgba(255,255,255,.08); }
  body.toi.dang-trong-lop.dd-co-thanh #ddThanhCon { background:rgba(200,210,220,.55); }
  body.toi.dang-trong-lop.dd-co-thanh #ddThanh.dang-keo #ddThanhCon { background:rgba(225,232,240,.8); }

  /* ⛔ KHÔNG ĐỂ THANH ĐÈ LÊN BẢNG — điều kiện cô Quỳnh nêu thẳng ("ko có gì được
     che cái bảng đó"). Vùng nội dung chừa ra đúng bề rộng thanh, nên bảng lùi vào
     chứ không nằm dưới nó. Chỉ chừa KHI thanh thật sự hiện. */
  body.dang-trong-lop.dd-co-thanh #noiDung,
  body.dang-trong-lop.dd-gon-nut.dd-co-thanh:not(.dd-nut-mo) #noiDung { padding-right:20px; }
  /* ⛔ HAI DÒNG, KHÔNG PHẢI MỘT — và phải viết `#noiDung`, đừng viết `.noi-dung`.
     Ngay bên trên có luật `body.dang-trong-lop.dd-gon-nut:not(.dd-nut-mo) #noiDung
     { padding:6px 0 16px }` của chế độ gọn nút. Nó có `id` trong tay nên nặng ký
     hơn selector chỉ toàn class, và `padding` viết gộp thì đè luôn cả
     `padding-right`. Viết `.noi-dung` là thua trong im lặng: CSS trông rất hợp lý
     mà bảng vẫn chui xuống dưới thanh — bài đo `thu-thanh-keo-dien-thoai.js` bắt
     được đúng cảnh này (khung bảng chạy tới 360px trong khi thanh bắt đầu ở 342px).
     Dòng thứ hai gánh đúng lúc chế độ gọn nút đang bật. */
  body.dang-trong-lop.dd-co-thanh #ddFab,
  body.dang-trong-lop.dd-co-thanh #ddTai { right:26px; }

  /* Nút tròn gọi cụm điều khiển ra. Neo góc dưới–phải, tránh cột dính bên trái. */
  body.dang-trong-lop #ddFab { display:flex !important; align-items:center; justify-content:center;
    flex-direction:column; gap:3px;
    position:fixed; z-index:46; right:14px;
    bottom:calc(16px + env(safe-area-inset-bottom, 0px));
    width:54px; height:54px; padding:0; border-radius:50%;
    background:var(--xanh); border:1px solid var(--xanh); color:#fff;
    box-shadow:0 3px 12px rgba(0,0,0,.26); }
  #ddFab span { display:block; width:20px; height:2px; border-radius:var(--r-sm); background:#fff;
    transition:transform .16s, opacity .16s; }
  /* Mở rồi thì ba gạch chụm thành dấu ✕ — nhìn là biết bấm nữa sẽ đóng lại. */
  body.dd-nut-mo #ddFab span:nth-child(1) { transform:translateY(5px) rotate(45deg); }
  body.dd-nut-mo #ddFab span:nth-child(2) { opacity:0; }
  body.dd-nut-mo #ddFab span:nth-child(3) { transform:translateY(-5px) rotate(-45deg); }
  /* Mở rồi thì nút tròn phải trèo lên TRÊN thanh nút, không thì nó đè lên nút thật.
     `--cao-thanhnut` do `ddDoCaoBang` đo — số nút đổi theo QUYỀN của từng người nên
     chiều cao thanh cũng đổi, gõ cứng là che nhầm. */
  body.dang-trong-lop.dd-gon-nut.dd-nut-mo #ddFab {
    bottom:calc(var(--cao-thanhnut, 167px) + 10px); }

  /* ⟳ NÚT TẢI LẠI — Boss 10/09/2026, xem lời dẫn ở thẻ `#ddTai` trong index.html.
     Bám ngay TRÊN nút tròn, cách 8px, nên nó tự trèo theo khi cụm nút mở.
     ⛔ Đích bấm 46px — trên mức tối thiểu 44px của Apple, dưới 54px của #ddFab để
        nhìn ra ngay đâu là nút chính. Nền nhạt, viền mảnh: nó là việc phụ.
     ⛔ Cùng z-index 46 với #ddFab, KHÔNG cao hơn: cao hơn thì lúc thanh nút mở nó
        đè lên chính cụm nút vừa gọi ra. */
  body.dang-trong-lop #ddTai { display:flex !important; align-items:center; justify-content:center;
    position:fixed; z-index:46; right:18px;
    bottom:calc(78px + env(safe-area-inset-bottom, 0px));
    width:46px; height:46px; padding:0; border-radius:50%;
    background:var(--nen); border:1px solid var(--vien); color:var(--chu);
    box-shadow:0 2px 8px rgba(0,0,0,.18); }
  /* ⛔⛔ 20/09/2026 — ⟳ ĐỨNG YÊN TUYỆT ĐỐI. Boss báo:
     *"cái nút reload trong điểm danh khi tôi kéo xuống và tôi ấn chuyển buổi thì
     nó bị lệch vị trí, nó cứ di chuyển theo"*.
     ──────────────────────────────────────────────────────────────────────────
     GỐC: dòng cũ ở đây neo ⟳ vào `--cao-thanhnut`, mà biến ấy do `ddDoCaoBang`
     đo và CHỈ đo được lúc cụm nút đang mở. Hai đường làm nó nhảy:
       ① Cuộn xuống → `ddNutTheoCuon` tự gập cụm nút → lớp `dd-nut-mo` rụng →
          ⟳ rơi từ ~239px xuống 78px. Đúng chữ "cứ di chuyển theo" của Boss.
       ② Bấm chuyển buổi → thanh nút vẽ lại, số nút đổi theo quyền nên nó có thể
          xuống thêm/bớt một hàng → `--cao-thanhnut` đổi → ⟳ trôi tiếp.
     ⇒ Bỏ hẳn mối neo ấy. ⟳ giữ nguyên `bottom:calc(78px + safe-area)` của luật
       gốc trong MỌI trạng thái — một con số cố định, không ai đo, không ai đổi.

     ⛔ VÀ PHẢI ẨN KHI CỤM NÚT MỞ — Boss chốt bằng nút 20/09/2026:
        **"ẩn ⟳ đi, đóng cụm thì hiện lại đúng chỗ cũ"**.
        Lý do bắt buộc: cụm nút cao ~167px tính từ đáy, còn ⟳ đứng ở 78px — tức
        nằm LỌT trong vùng cụm nút. Mà `#ddTai` z-index 46 > `.thanh-cong-cu`
        z-index 45, nên không ẩn thì ⟳ nổi ĐÈ lên một nút thật của cụm, bấm DONE
        lại trúng Tải lại. Ẩn là cách duy nhất vừa đứng yên vừa không che nút.
     ⛔ Ba lớp + id nên thắng luật `body.dang-trong-lop #ddTai{display:flex!important}`
        ở ngay trên; vẫn phải `!important` vì luật kia có. */
  /* ⛔ 21/09/2026 — CHỈ ẨN KHI ⟳ CÒN Ở GÓC DƯỚI (`:not(.dd-tai-canh)`). Lý do ẩn ở
     trên là ⟳ đè lên cụm nút ở đáy. Nay ⟳ đứng cạnh cụm phóng to trên đầu bảng,
     cách cụm nút cả màn hình — không đè gì. Mà cụm nút tự MỞ mỗi lần kéo về đầu
     danh sách, nên giữ luật ẩn là ⟳ chớp tắt theo từng cú vuốt: đúng cái Boss
     gọi là "không đứng yên tại chỗ". */
  body.dang-trong-lop.dd-gon-nut.dd-nut-mo #ddTai:not(.dd-tai-canh) { display:none !important; }
  #ddTai i { pointer-events:none; }
  /* Đang tải thì quay — người dùng biết máy đang làm, khỏi bấm chồng. */
  #ddTai.dang-tai { opacity:.75; pointer-events:none; }
  #ddTai.dang-tai i { animation:ddTaiQuay .9s linear infinite; }
  @keyframes ddTaiQuay { to { transform:rotate(360deg); } }
  @media (prefers-reduced-motion:reduce) { #ddTai.dang-tai i { animation:none; } }
}
  /* ══════════════════════════════════════════════════════════════════════════
     📱 KHÔNG ĐỂ ĐIỆN THOẠI TỰ PHÓNG TO KHI BẤM VÀO Ô NHẬP — cô Quỳnh 23/08/2026
     ────────────────────────────────────────────────────────────────────────────
     Cô Quỳnh: *"fix lại cho app khi điền chữ và số vào điểm danh cứ bị zoom vào
     tự động khiến người dùng điện thoại rất khó chịu, để yên vị trí khi ấn điền
     số và chữ trong các ô trong điểm danh đk. và cả các công cụ khác giống sheet
     nữa."*

     VÌ SAO NÓ PHÓNG TO: đây là LUẬT CỦA SAFARI trên iPhone/iPad, không phải app
     làm. Bấm vào một ô nhập có cỡ chữ NHỎ HƠN 16px thì Safari tự phóng cả trang
     lên cho chữ đủ to mà đọc — rồi KHÔNG tự thu lại. Người dùng phải chụm tay thu
     nhỏ sau mỗi ô, gõ một hàng điểm danh là chụm cả chục lần.
     App đang để ô nhập 12–15px ở rất nhiều chỗ (lưới điểm danh, các bảng dạng
     Sheet, ô lọc…) nên dính gần như mọi nơi.

     CÁCH CHỮA: trên máy CẢM ỨNG thì mọi ô nhập tối thiểu 16px. Đủ 16px là Safari
     không còn cớ để phóng.

     ⛔ CỐ Ý KHÔNG dùng `maximum-scale=1` / `user-scalable=no` trong thẻ viewport —
        cách ấy chặn zoom nhanh hơn nhưng CẤM LUÔN người dùng tự chụm tay phóng to,
        kể cả người mắt kém muốn xem cho rõ. Đổi một cái khó chịu lấy một cái tệ hơn.
     ⛔ CỐ Ý KHÔNG dùng `touch-action` — luật cô Quỳnh đã chốt cấm.
     ⛔ Dùng `hover: none` (máy không có chuột) cho KHỚP NẾP SẴN CÓ trong file —
        `kiem-thu/thu-keo-cot-rieng-va-cam-ung.js` canh đúng chuyện này. KHÔNG dùng bề
        rộng màn hình: máy tính bảng để ngang vẫn rộng mà vẫn gõ bằng ngón tay.
     ⛔ `!important` ở đây là CẦN: các luật cỡ chữ nằm rải khắp file, nhiều luật có
        độ ưu tiên cao hơn (`.nn-bang .c-so input`…). Thiếu nó là vá hụt đúng những
        chỗ hay gõ nhất.
     ══════════════════════════════════════════════════════════════════════════ */
  @media (hover: none) {
    input, select, textarea,
    input[type="text"], input[type="number"], input[type="search"],
    input[type="tel"], input[type="date"], input[type="time"],
    input[type="password"], input[type="email"] {
      font-size: 16px !important;
    }
    /* Ô trong lưới vốn hẹp: cho cỡ chữ 16px mà giữ ô không phình ra thì bớt đệm
       hai bên. Đo ở 390px: hàng điểm danh vẫn đủ chỗ, không đẩy cột nào khuất. */
    .luoi input, .luoi select, table input, table select {
      padding-left: 2px !important; padding-right: 2px !important;
    }
  }

  /* ══════════════════════════════════════════════════════════════════════════
     📐 MẪU CỘT LỚP — 26/08/2026
     Bảng khai cột, nếp Google Sheet: nền trắng, kẻ ngang mảnh, tiêu đề cột chữ
     nhỏ. ⛔ Dùng biến màu chung, đừng chép mã màu — app có chế độ tối.
     ══════════════════════════════════════════════════════════════════════════ */
  .mc-ds { display: flex; flex-direction: column; gap: 10px; }
  .mc-the {
    border: 1px solid var(--vien); border-radius:var(--r-md);
    background: var(--the); padding: 12px 14px;
  }
  .mc-the-dau { display: flex; align-items: center; gap: 8px; margin-bottom: 2px; }
  .mc-the-dau b { font-size: 15px; }
  .mc-cho {
    font-size: 11px; color: var(--mo); border: 1px solid var(--vien);
    border-radius: 999px; padding: 1px 8px;
  }
  .mc-mota { font-size: 12.5px; color: var(--mo); margin-bottom: 4px; }
  .mc-cot-tt { font-size: 13px; color: var(--chu); margin-bottom: 9px; }
  .mc-nut { display: flex; flex-wrap: wrap; gap: 6px; }

  /* ══════════════════════════════════════════════════════════════════════════
     BẢNG SỬA CỘT — dựng theo hình BẢNG TÍNH, cô Quỳnh 26/08/2026
     *"tôi muốn nó có giao diện sửa giống hệt sheet, sửa nhìn giao diện sheet thì
     mới hình dung được chứ"*.

     Bản cũ xếp mỗi cột thành MỘT DÒNG DỌC. Đúng về dữ liệu nhưng nhìn không ra
     bảng, nên không hình dung nổi lớp sẽ trông thế nào — đó chính là chỗ cô chê.
     Bản này dựng đúng hình bảng tính: cột nằm NGANG, có thanh chữ cái A B C, hàng
     tiêu đề xanh lá lấy đúng `--dau-bang-nen` của bảng điểm danh thật, và một hàng
     XEM THỬ vẽ đúng ô mà trợ giảng sẽ nhìn thấy.

     ⛔ Bo tròn CHỈ ở khung ngoài. Ô bên trong phải VUÔNG — lưới bảng tính mà bo góc
        từng ô thì hết ra lưới, và `border-radius` còn cắt cả viền vẽ sau nó.
     ⛔ Cột nhãn bên trái `position:sticky` để cuộn ngang vẫn biết đang xem hàng nào,
        y như cột số hàng của bảng tính.
     ══════════════════════════════════════════════════════════════════════════ */
  /* ══════════════════════════════════════════════════════════════════════════
     📋 BẢNG PHÂN CÔNG TRÊN APP — ĐÃ BỎ 28/08/2026
     Cô Quỳnh: *"thay luôn công cụ này vào nút bảng phân công, bỏ luôn bảng phân
     công cũ đi thay hẳn cái này vào"*. Chỗ của nó nay là BẢNG PHÂN LỚP (họ
     `.gtgb-*`), vào bằng đúng nút cũ trong Quản lý tài khoản.

     ⛔ GIỮ LẠI ĐÚNG MỘT DÒNG `.pc-rong` — Bảng phân lớp và màn đếm công đang
        dùng nó ở 4 chỗ để vẽ ô "chưa có gì". Xoá nốt cho sạch họ là ba màn hình
        mất hẳn phần đệm và căn giữa, chữ dính sát mép.
     ⛔ ĐỪNG tưởng mọi lớp `.pc-` đều là của bảng này. Họ `pc-ten` · `pc-keo` ·
        `pc-an` · `pc-dich` · `pc-dang-cam` ở khối PHIẾU CHẤM phía trên là thứ
        khác hẳn, trùng mỗi tiền tố.
     ══════════════════════════════════════════════════════════════════════════ */
  .pc-rong { padding: 22px 14px; text-align: center; color: var(--chu-mo); font-size: 13px; }

  /* 🔑 28/08/2026 — dòng dẫn của màn Quên mật khẩu. Chỉ một lớp, cố ý: màn đăng
     nhập đã có sẵn `.o-nhap`, `.dn-loi`, `.nut-chinh`, `.dn-doi` — dùng lại hết
     để hai màn trông đúng là một nhà, và để không phải bảo trì hai bộ nét. */
  .qmk-dan { font-size: 13px; color: var(--chu-mo); line-height: 1.55; margin: 2px 0 12px; }

  /* 📅 27/08/2026 — bảng ngày nghỉ lễ. Lối bảng tính: hàng tiêu đề nền nhạt,
     mỗi đợt nghỉ một hàng ba ô. */
  .nn-dau { font-size: 13px; color: var(--chu-mo); line-height: 1.5; margin-bottom: 10px; }
  .nn-canh { color: var(--cam, #B45309); }
  .nn-bang { border: 1px solid var(--vien-ro); border-radius:var(--r-md); overflow: hidden;
    background: var(--the); }
  .nn-hang { display: grid; grid-template-columns: 1fr 118px 118px 34px; gap: 8px;
    align-items: center; padding: 6px 8px; border-bottom: 1px solid var(--vien); }
  .nn-hang:last-child { border-bottom: 0; }
  .nn-tieu { background: var(--nen2); font-size: 12px; color: var(--chu-mo); padding: 7px 8px; }
  .nn-o { width: 100%; padding: 6px 8px; border: 1px solid var(--vien); border-radius:var(--r-sm);
    background: var(--nen-o); color: inherit; font: inherit; font-size: 13px; }
  .nn-tu, .nn-den { font-variant-numeric: tabular-nums; }
  .nn-bo { border: 0; background: none; color: var(--chu-mo); font-size: 18px; line-height: 1;
    cursor: pointer; padding: 4px; border-radius:var(--r-sm); }
  .nn-bo:hover { background: var(--nen2); color: var(--do, #B91C1C); }
  .nn-trong { padding: 14px 10px; color: var(--chu-mo); font-size: 13px; text-align: center; }
  .nn-chan { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
  /* 📅 DẢI CHỌN NĂM — ĐÃ BỎ HẲN 31/08/2026, và ĐỪNG DỰNG LẠI.
     Nó ra đời 28/08 để chữa chuyện màn này khoá cứng vào năm hiện tại (lớp khai
     giảng tháng 11 thì lịch chạy sang tận tháng 5 năm sau). Nhưng cô Quỳnh nói
     thẳng nó bắt người ta làm thừa một việc: *"nếu để năm thì mỗi năm lại phải ấn
     à họ ko nhớ ra đâu"*. Nay bảng gộp mọi năm, năm nằm sẵn trong ô ngày, app tự
     xếp — xem `nnVe` và `caiDatNgayNghi`. Kho vẫn khoá theo năm như cũ. */
  @media (max-width: 560px) {
    .nn-hang { grid-template-columns: 1fr 1fr 30px; }
    .nn-tieu { display: none; }
    .nn-ten { grid-column: 1 / 3; }
  }

  /* 📅 27/08/2026 — bảng xem trước trước khi dựng buổi cả khoá. Lối bảng kê:
     nhãn bên trái, con số bên phải, dòng giải thích nhỏ bên dưới. */
  .bck { margin-top: 10px; border: 1px solid var(--vien-ro); border-radius:var(--r-lg);
    overflow: hidden; background: var(--the); }
  .bck-hang { display: grid; grid-template-columns: 132px 1fr; gap: 2px 12px;
    padding: 9px 12px; border-bottom: 1px solid var(--vien); }
  .bck-hang:last-child { border-bottom: 0; }
  .bck-nhan { color: var(--chu-mo); font-size: 13px; }
  .bck-gt { font-size: 14px; }
  .bck-gt b { font-variant-numeric: tabular-nums; }
  .bck-ghi { grid-column: 2; color: var(--chu-mo); font-size: 12px; line-height: 1.45; }
  .bck-ghi .mo { color: var(--chu-mo); }
  @media (max-width: 560px) {
    .bck-hang { grid-template-columns: 1fr; }
    .bck-ghi { grid-column: 1; }
  }


  /* ══════════════════════════════════════════════════════════════════════════════
     📋 BẢNG PHÂN LỚP — bảng lịch mỗi lớp một dòng (cô Quỳnh 27/08/2026)
     ──────────────────────────────────────────────────────────────────────────────
     Cô đưa ảnh Sheet "LỊCH LÀM VIỆC TRỢ GIẢNG THÁNG 8" và dặn *"sẽ có bảng lịch
     làm y hệt tôi gửi trong ảnh thiết kế y hệt cho tôi"*. Ảnh ấy có năm cột trái
     (Cơ sở · Lớp · Khai giảng · Thứ · Giờ học) rồi hai cột Trợ giảng 1 / 2.

     BA MÀU Ô lấy đúng từ ảnh, và mỗi màu mang một nghĩa khác nhau:
       · xanh nhạt — chưa xếp ai vào ô ấy (app tự suy, KHÔNG lưu gì)
       · xám       — giáo vụ đánh dấu lớp này "k cần" trợ giảng
       · cam       — ghi chú tay, kiểu "Thi - cắt TA2"
     ⛔ Xám và cam là DỮ LIỆU THẬT nằm trong `chuLop` của kho giờ trợ giảng, không
        phải mẹo tô màu. Đổi màu thì đổi ở đây, đừng đi sửa chỗ lưu.

     ⛔ MỖI MÀU PHẢI CÓ BẢN `body.toi` ĐẶT NỀN. Luật đã ghi ở đầu file: bài
        `kiem-thu/thu-nen-toi-luoi-va-vien.js` lọc ra mọi luật gõ nền sáng mà
        không có bản nền tối. Ba ô này nền sáng nên đủ ba bản tối bên dưới.
     ⛔ KHÔNG emoji, KHÔNG font-weight 800 + uppercase + letter-spacing — mẫu gốc
        là Google Sheets, cô Quỳnh đã chê "lộ rõ ui AI" năm lần.
     ══════════════════════════════════════════════════════════════════════════ */
  .gtgb-loc { display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
              margin: 12px 0 6px; }
  .gtgb-loc .nv-in { font-size: 13px; }
  .gtgb-tim { max-width: 230px; }
  .gtgb-chon { max-width: 200px; }
  /* ⭐⭐ BOSS CHOT 13/09/2026 — SO LOP PHAI NAM NGAY CANH O "Tat ca lop".
     Boss: *"so 127/127 lop de ngay canh o chon Tat ca lop, dang bi tach doi hang"*.
     GOC: `margin-left: auto` day o dem ra TAN MEP PHAI cua khoi. Khoi lai co
     `flex-wrap: wrap`, nen:
       may tinh 1280 — o chon het o x=365, so bat dau o x=1206: cach nhau 841px,
                       nhin nhu hai thu chang lien quan gi den nhau.
       dien thoai 390 — het cho, so bi day HAN xuong dong duoi: lech doc 40px,
                       khoi loc cao 72px thay vi 37px. Dung canh "tach doi hang".
     ⇒ Bo `margin-left: auto`. So di lien ngay sau o chon, cach dung mot nhip
       `gap: 8px` cua khoi.
     ⛔ `white-space: nowrap` — chuoi "20/20 lop" ma gap chỗ hep se tu be gay giua
        hai chu so, doc ra hai dong "20/" va "20 lop".
     ⛔ `flex: 0 0 auto` — khong cho no co lai duoi be rong chu; co lai la lai
        sinh ra dung cai canh vua go. */
  .gtgb-dem {
    font-size: 12.5px; color: var(--chu-mo);
    flex: 0 0 auto; white-space: nowrap;
  }
  /* ⛔ Cuộn NGANG nằm ở lớp bọc riêng, không đặt lên chính lưới: đặt lên lưới thì
     hàng tiêu đề dán dính (sticky) mất tác dụng, mà bảng 142 dòng không có tiêu
     đề dính thì kéo xuống giữa là quên mất cột nào là cột nào. */
  .gtgb-cuon { overflow-x: auto; border: 1px solid var(--vien-ro); border-radius:var(--r-lg);
               background: var(--the); }
  .gtgb-hang { display: grid;
               grid-template-columns: 1.15fr 1.25fr .85fr .95fr .9fr 1.5fr 1.5fr 40px;
               border-bottom: 1px solid var(--vien); min-width: 940px; }
  .gtgb-hang > * { min-width: 0; padding: 6px 8px; display: flex; align-items: center;
                   font-size: 13px; }
  .gtgb-hang > * + * { border-left: 1px solid var(--vien); }
  .gtgb-hang:last-child { border-bottom: 0; }
  .gtgb-dau { background: #F8F9FA; color: #5F6368; font-size: 11.5px; font-weight: 700;
              position: sticky; top: 0; z-index: 2; }
  body.toi .gtgb-dau { background: #323942; color: #E0E3E6; }
  .gtgb-lop { font-weight: 600; }
  .gtgb-kt { color: var(--chu-mo); font-style: italic; }   /* lớp đã kết thúc */
  .gtgb-o-tg { padding: 3px 4px; }
  /* ⛔ `background: transparent` — ĐỪNG BỎ. Chụp ảnh lần đầu mới thấy: ô select
     mặc định nền TRẮNG, phủ kín ô nên màu xanh "chưa có" và màu xám "k cần" bên
     dưới không lộ ra một chấm nào. Nhìn mã nguồn thì tưởng đã tô màu rồi. */
  .gtgb-o-tg select { width: 100%; font-size: 12.5px; background: transparent; }
  /* 🔎 28/08 — hai ô ấy nay là Ô GÕ CÓ TÌM KIẾM (`oNguoiTim`), không còn `<select>`.
     ⛔ `background: transparent` VẪN LÀ CHỐT SỐNG CÒN, và nay còn quan trọng hơn:
        ô nhập mặc định nền TRẮNG ĐẶC, phủ kín cả ô — màu xanh "chưa có" và màu xám
        "k cần" bên dưới không lộ ra một chấm. Đúng cái bẫy đã chụp ảnh mới thấy hồi
        làm `<select>`; đổi loại thẻ mà quên chép luật này sang là dựng lại nó.
     ⛔ Bỏ luôn viền và bo góc: đây là một ô trong bảng tính, không phải một ô nhập
        trong biểu mẫu. Có viền là mỗi hàng thành một dãy hộp, rối mắt. */
  .gtgb-o-tg .ont { width: 100%; }
  .gtgb-o-tg .ont-in { width: 100%; font-size: 12.5px; background: transparent;
    border: 0; border-radius: 0; padding: 2px 18px 2px 2px; height: auto; color: inherit; }
  .gtgb-o-tg .ont-in:focus { outline: 2px solid var(--xanh); outline-offset: -2px; }
  .gtgb-o-tg .ont-in::placeholder { color: var(--mo); }
  /* Ô chưa ai — xanh nhạt như trong ảnh Sheet. */
  .gtgb-trong { background: #E0F7FA; }
  body.toi .gtgb-trong { background: #12333A; }
  body.toi .gtgb-o-tg select { color: var(--chu); }
  body.toi .gtgb-o-tg .ont-in { color: var(--chu); }
  /* Lớp đánh dấu KHÔNG cần trợ giảng — xám, và hai ô người khoá lại. */
  .gtgb-kcan { background: #F1F3F4; color: #5F6368; font-style: italic; font-size: 12.5px; }
  body.toi .gtgb-kcan { background: #32373D; color: #B3BAC2; }
  /* Ghi chú tay — cam. */
  .gtgb-ghichu { background: #FDEBD3; color: #9A5B00; font-size: 12.5px; }
  body.toi .gtgb-ghichu { background: #3A2E18; color: #E3A857; }
  .gtgb-nutchu { border: 0; background: transparent; cursor: pointer; color: var(--chu-mo);
                 padding: 2px 6px; line-height: 0; }
  .gtgb-nutchu.co { color: #9A5B00; }
  body.toi .gtgb-nutchu.co { color: #E3A857; }
  @media (max-width: 720px) {
    /* Điện thoại: xếp dọc thành thẻ. Lưới 8 cột ở cỡ này thì mỗi ô rộng hai chữ.
       Hàng tiêu đề bị ẩn nên phải dán nhãn vào từng ô — cùng nếp bảng phân công. */
    .gtgb-hang { grid-template-columns: 1fr; min-width: 0; border-bottom-width: 2px; }
    .gtgb-hang > * + * { border-left: 0; border-top: 1px solid var(--vien); }
    .gtgb-dau { display: none; }
    .gtgb-cuon { overflow-x: visible; }
    .gtgb-hang:not(.gtgb-dau) > * { display: block; }
    .gtgb-hang:not(.gtgb-dau) > *::before { display: block; width: 100%; font-size: 11px;
      color: var(--chu-mo); margin-bottom: 3px; }
    .gtgb-hang:not(.gtgb-dau) > .gtgb-o-cs::before  { content: "Cơ sở"; }
    .gtgb-hang:not(.gtgb-dau) > .gtgb-lop::before   { content: "Lớp"; }
    .gtgb-hang:not(.gtgb-dau) > .gtgb-o-kg::before  { content: "Khai giảng"; }
    .gtgb-hang:not(.gtgb-dau) > .gtgb-o-thu::before { content: "Thứ"; }
    .gtgb-hang:not(.gtgb-dau) > .gtgb-o-gio::before { content: "Giờ học"; }
    .gtgb-hang:not(.gtgb-dau) > .gtgb-o-tg1::before { content: "Trợ giảng 1"; }
    .gtgb-hang:not(.gtgb-dau) > .gtgb-o-tg2::before { content: "Trợ giảng 2"; }
  }

  /* ⏱ 27/08/2026 — GIỜ RẢNH TRỢ GIẢNG THEO TUẦN.
     Lối thẻ: mỗi trợ giảng một thẻ, trong thẻ hai hàng nhãn-giá trị (giờ rảnh ·
     lớp đã xếp). Dùng lại đúng bảng màu và cỡ chữ của bảng phân công ở trên, để
     hai màn đứng cạnh nhau không lệch nhau. */
  .gtg-thanh { display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin:10px 0 6px; }
  .gtg-thanh-nhan { font-size:12.5px; color:var(--chu-mo); margin-right:2px; }
  .gtg-nhip, .gtg-dot-tab, .gtg-tuan-tab {
    border:1px solid var(--vien); background:var(--the); color:var(--chu-mo);
    border-radius:var(--r-md); padding:6px 12px; font:inherit; font-size:13px; cursor:pointer; }
  .gtg-nhip.chon, .gtg-dot-tab.chon, .gtg-tuan-tab.chon {
    background:var(--dau-bang-nen); color:var(--dau-bang-chu);
    border-color:var(--dau-bang-vien); font-weight:600; }
  .gtg-tuan-tab { font-variant-numeric:tabular-nums; }
  /* ⛔ `.nut-chinh` của app khai `width:100%` (nó vốn là nút đáy màn đăng nhập).
     Để nguyên trong hàng flex này thì nút "Mở đợt" bung ra ngang hết màn hình — đã
     chụp ảnh thấy tận mắt. Ghim lại đúng cỡ chữ, và cấm mọi nút trong thanh co lại. */
  .gtg-thanh > button, .gtg-thanh > a { flex:0 0 auto; }
  /* ⛔ 03/09/2026 — NÚT HỘP THẢ PHẢI GIỮ NGUYÊN BỀ RỘNG KHI ĐỔI MỤC.
     Cô Quỳnh: *"mấy cái nút ở trên thanh cùng của màn hình ở tất cả công cụ
     trong app, tôi thấy nó cứ bị di chuyển thay đổi chỗ mỗi khi tôi ấn chọn"*.
     Nhãn nút là MỤC ĐANG CHỌN (cố ý, xem chú thích ở hàm `tha`), nên "Mỗi tháng
     một lần" → "Mỗi tuần một lần" là nút hẹp đi 8px và kéo "Mở đợt" trượt theo.
     ⛔ KHÔNG ghim `min-width` bằng px: đổi tên mục sau này là số ấy sai ngay mà
        không ai biết. Ở đây bóng chữ `::before` mang mục DÀI NHẤT của chính hộp
        ấy (`data-dai`, tính lúc dựng), nên bề rộng tự đúng theo dữ liệu thật.
     ⛔ `height:0` + `overflow:hidden` để bóng chỉ định bề rộng, không chiếm dòng.
     ⛔ `display:inline-block` là bắt buộc — thẻ inline không lấy bề rộng con. */
  .gtg-tha-chon { display:inline-block; }
  .gtg-tha-chon::before { content:attr(data-dai); display:block;
    height:0; overflow:hidden; visibility:hidden; }
  .gtg-thanh > .nut-chinh { width:auto; height:34px; padding:0 14px; font-size:13px; }
  /* 🧹 28/08/2026 (tối) — NHÓM NÚT GOM LẠI (cô Quỳnh kêu hàng nút quá rối).
     ⛔ Hộp thả phải NỔI (`absolute`), đừng để nó đẩy nội dung: mở inline thì mỗi lần
        bấm là cả bảng nhảy xuống một đoạn. Thanh nút nằm NGOÀI khung cuộn ngang
        `.gtgb-cuon` nên nổi ra không bị cắt.
     ⛔ `z-index` phải dưới nền hộp thoại (`.modal-nen` = 12000) mà trên bảng — hộp
        thoại luôn là thứ trên cùng. */
  .gtg-gom { position:relative; flex:0 0 auto; }
  .gtg-gom > summary { list-style:none; cursor:pointer; user-select:none;
    border:1px solid var(--vien); background:var(--the); color:var(--chu);
    border-radius:var(--r-md); padding:7px 12px; font:inherit; font-size:13px;
    display:inline-flex; align-items:center; gap:6px; }
  .gtg-gom > summary::-webkit-details-marker { display:none; }
  .gtg-gom > summary::after { content:"▾"; font-size:11px; color:var(--chu-mo); }
  .gtg-gom[open] > summary { background:var(--dau-bang-nen); color:var(--dau-bang-chu);
    border-color:var(--dau-bang-vien); }
  /* ⛔⛔ 09/09/2026 — MENU CUOI HANG PHAI CANH MEP PHAI, KHONG THI THO KHOI MAN.
     Do o man 390: `<summary>` "Viec khac" dung o x=261, menu neo `left:0` vao no
     nen chay tu 261 den 473 — **tho 83px** ra ngoai man 390, keo tran ngang CA
     TRANG. `max-width:calc(100vw - 28px)` ben duoi khong cuu duoc: no ghim BE RONG,
     ma loi nam o VI TRI.
     ⛔ Loi KHONG tang dan theo co man: o 360 thi `.gtg-thanh` xuong dong som hon,
        summary ve dau hang nen sach hoan toan; 390 moi la co nang nhat (83px), 430
        con 43px. Do mot co roi suy ra co khac la sai.
     Canh mep phai cho cai CUOI HANG: menu chay tu 261+93-212 = 142 den 354, nam
     tron trong man. Nhung cai dau hang van giu `left:0` — doi ca loat sang phai la
     cai dau hang tho ra mep TRAI. */
  .gtg-gom:last-child > .gtg-gom-ds,
  .gtg-tha:last-child > .gtg-gom-ds { left:auto; right:0; }
  /* ⛔⛔ 09/09/2026 (luot hai) — CANH MEP PHAI CHI CUU DUOC CAI CUOI HANG.
     Do lai sau luot vua roi: menu "Viec khac" da het tho (83px -> 0), nhung menu
     "Tuan 07/09 - 13/09" van tho **27px** o man 390 vi no dung GIUA hang, khong
     phai cuoi. Ma vi tri xuong dong cua `.gtg-thanh` doi theo be ngang man, nen
     khong the goi ten truoc cai nao se roi ra ngoai.
     Tren dien thoai: cho menu thanh MOT DAI NGANG duoi ca thanh nut, neo hai mep
     `.gtg-thanh` thay vi neo vao `<summary>`. Het tho o moi vi tri va moi co man,
     va day cung la loi menu quen thuoc tren dien thoai — de bam bang ngon tay hon
     mot cot hep 212px.
     ⛔ `top:calc(100% + 5px)` gio tinh theo `.gtg-thanh` (ca thanh, co the nhieu
        hang) chu khong theo `<summary>` — dung y: dai ngang phai nam duoi TRON
        thanh, khong cat ngang qua cac nut con lai.
     ⛔ Giu `.gtg-gom` la `position:static` de neo roi len `.gtg-thanh`; bo dong ay
        la menu quay ve bam `<summary>` va tho lai. */
  @media (max-width:640px){
    .gtg-thanh { position:relative; }
    .gtg-thanh > .gtg-gom, .gtg-thanh > .gtg-tha { position:static; }
    .gtg-thanh > .gtg-gom > .gtg-gom-ds,
    .gtg-thanh > .gtg-tha > .gtg-gom-ds {
      left:0; right:0; width:auto; min-width:0; max-width:none; }
  }
  .gtg-gom-ds { position:absolute; top:calc(100% + 5px); left:0; z-index:60;
    background:var(--the); border:1px solid var(--vien-ro); border-radius:var(--r-lg);
    box-shadow:0 8px 24px rgba(0,0,0,.14); padding:6px; min-width:212px;
    /* ⛔ Trên điện thoại, nhóm nút có thể nằm sát mép phải — không chặn thì hộp thả
       tràn khỏi màn và mất chữ bên phải. `max-width` theo bề ngang màn, trừ đệm. */
    max-width:calc(100vw - 28px);
    display:flex; flex-direction:column; gap:5px; }
  .gtg-gom-ds > button, .gtg-gom-ds > a { width:100%; text-align:left; justify-content:flex-start; }
  /* 🧹🧹 30/08/2026 — GOM TIẾP: BA DẢI CHIP THÀNH BA NÚT THẢ.
     Cô Quỳnh: *"mấy cái nút đang bị dài quá có nhiều nút quá cái nào gom được vào
     thanh 1 ô xong ấn vào ra lựa chọn là tốt nhất, NHẤT LÀ MẤY CÁI LỊCH SỬ THÁNG
     CÁC THỨ á, và sắp xếp lại cái nút cho thẳng hàng."*
     Dải TUẦN luôn 5–7 chip, dải ĐỢT dài thêm mỗi tháng một chip — sang năm là hai
     hàng chip chỉ để chọn một thứ. Nhãn nút LUÔN hiện mục đang chọn, nên gom vào
     không giấu mất thông tin: liếc một cái vẫn biết đang xem tuần nào, đợt nào.
     ⛔ `max-height` + cuộn đặt ở CHÍNH HỘP THẢ (12 tháng là hộp dài quá màn), tuyệt
        đối KHÔNG đặt lên `.gtg-thanh` — khung chứa mà cắt thì menu bung ra bị xén. */
  /* 📧 30/08/2026 — MÀN LIÊN KẾT GMAIL. Không đẻ bảng màu mới: mượn đúng ô nhập
     `.nv-in` và hai kiểu nút của app, để hộp này đứng cạnh mấy hộp khác không lệch. */
  .lkg-dan { font-size:13px; color:var(--chu-mo); line-height:1.6; margin:0 0 10px; }
  .lkg-yen { color:var(--chu); }
  .lkg-nhan { display:block; font-size:12.5px; color:var(--chu-mo); margin:12px 0 5px; }
  .lkg-hang { display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
  .lkg-hang > input { flex:1 1 220px; min-width:0; }
  .lkg-hang > button { flex:0 0 auto; height:36px; width:auto; padding:0 16px; font-size:13px; }
  /* Ô mã: chữ to, giãn ra, canh giữa — sáu chữ số gõ từ trong thư ra, người ta
     cần nhìn rõ từng số để dò lại chứ không đọc nó như một từ. */
  /* ⛔ PHẢI CÓ "input" TRONG CHỌN TỬ. Viết trần ".lkg-oma" thì ".lkg-hang > input"
     ở trên (độ ưu tiên cao hơn) thắng, và ô mã sáu số bung rộng cả hàng — chụp ảnh
     mới thấy, mã vẫn chạy đúng nên không ai báo. */
  .lkg-hang > input.lkg-oma { flex:0 0 156px; font-size:20px;
    text-align:center; font-variant-numeric:tabular-nums; }
  .lkg-buoc2 { border-top:1px solid var(--vien); margin-top:14px; padding-top:6px; }
  .lkg-xong { font-size:13px; color:#1B5E20; background:#E8F5E9; border:1px solid #A5D6A7;
    border-radius:var(--r-md); padding:9px 12px; margin:0 0 10px; }
  .lkg-canh { font-size:13px; color:#7A5B00; background:#FFF8E1; border:1px solid #E0A800;
    border-radius:var(--r-md); padding:9px 12px; margin:0 0 10px; }
  .lkg-loi { font-size:13px; color:#8E2A20; background:#FDECEA; border:1px solid #C0392B;
    border-radius:var(--r-md); padding:9px 12px; margin:12px 0 0; }

  /* ══════════════════════════════════════════════════════════════════════════
     📧 10/09/2026 — HÀNG GMAIL Ở CÀI ĐẶT KHI ĐÃ LIÊN KẾT
     Boss: *"liên kết gmail xong thì phải ko hiện cái nút liên kết gmail nữa mà
     nó sẽ hiện tài khoản gmail là gì và có cái nút đổi gmail bên cạnh, chữ màu
     xanh nước biển có gạch chân ở dưới"*.
     ⛔ Xanh NƯỚC BIỂN thật (#1A6FD4), không phải teal MyPAS — Boss nói rõ màu, và
        đây là lối-đi-tiếp kiểu đường dẫn chứ không phải nút hành động của app.
     ⛔ Vẫn là <button>, không phải <a>: nó mở hộp thoại chứ không đi đâu cả. Dùng
        <a href="#"> là bàn phím Enter nhảy lên đầu trang. */
  .cd-gmail { display:flex; align-items:center; gap:10px; flex-wrap:wrap;
    justify-content:flex-end; }
  .cd-gmail-dc { font-size:13px; color:var(--chu); font-weight:600;
    word-break:break-all; text-align:right; }
  .cd-doi-gmail { background:none; border:0; padding:0; cursor:pointer;
    font:inherit; font-size:13px; color:#1A6FD4; text-decoration:underline;
    text-underline-offset:2px; flex:0 0 auto; }
  .cd-doi-gmail:hover { color:#12539F; }
  .cd-doi-gmail:focus-visible { outline:2px solid #1A6FD4; outline-offset:2px; }

  /* Khối "đang liên kết với …" trong hộp thoại, để người ta thấy địa chỉ CŨ ngay
     trước khi gõ địa chỉ mới — không thì đổi xong mới nhớ ra mình vừa bỏ cái gì. */
  .lkg-hienco { background:var(--nen2); border:1px solid var(--vien);
    border-radius:var(--r-o, 8px); padding:10px 12px; margin:0 0 12px; }
  .lkg-hienco-nhan { font-size:12px; color:var(--chu-mo); margin-bottom:3px; }
  .lkg-hienco-dc { font-size:14px; color:var(--chu); font-weight:600;
    word-break:break-all; }

  /* ══════════════════════════════════════════════════════════════════════════
     🔢 10/09/2026 — MÀN NHẬP MÃ 6 SỐ, dựng theo mẫu Boss gửi
     Sáu ô rời, ô đang gõ có viền teal đậm; nút chính rộng hết hàng; dòng "gửi lại"
     nằm dưới cùng. Đây là khuôn quen thuộc của mọi app có mã OTP, nên người dùng
     không phải học lại.
     ⛔ 44px là SÀN, không phải con số cho đẹp: dưới ngưỡng ấy ngón tay trên điện
        thoại bấm trượt sang ô bên cạnh, mà gõ mã thì trượt một ô là gõ lại từ đầu. */
  .otp { text-align:center; padding:6px 0 0; }
  /* ⭐ 10/09/2026 — VÒNG TRÒN CÓ VIỀN ở đầu màn, theo mẫu Boss gửi
     (21st.dev @originui · dialog/otp-dialog).
     ⛔ Nền và viền gõ cứng thì CHỮ BÊN TRONG cũng phải gõ cứng — nhưng ở đây nền
        lấy từ biến nên chữ cũng lấy từ biến, hai bên cùng đổi theo chế độ tối. */
  .otp-huy { width:44px; height:44px; margin:0 auto 12px; border-radius:50%;
    display:flex; align-items:center; justify-content:center;
    background:var(--nen2); border:1px solid var(--vien); color:var(--xanh-dam); }
  .otp-huy svg { width:21px; height:21px; }
  .otp-tieu { font-size:17px; font-weight:700; color:var(--chu); margin:0 0 6px; }
  .otp-mota { font-size:13px; color:var(--chu-mo); line-height:1.6; margin:0 0 16px; }
  .otp-mota b { color:var(--chu); word-break:break-all; }
  .otp-o { display:flex; gap:8px; justify-content:center; margin:0 0 14px; }
  /* ⭐ Ô VUÔNG có bóng đổ rất nhẹ — nét thứ ba của mẫu.
     ⛔ 48px, KHÔNG phải 36px như mẫu: 44px là SÀN cho ngón tay trên điện thoại, và
        gõ mã mà trượt một ô là gõ lại từ đầu. Đẹp không đáng đổi lấy chỗ ấy. */
  .otp-o input { width:48px; height:48px; min-width:0; flex:0 0 auto;
    text-align:center; font-size:20px; font-weight:600; color:var(--chu);
    font-variant-numeric:tabular-nums;
    background:var(--nen-o); border:1px solid var(--vien);
    border-radius:var(--r-o, 8px); box-shadow:0 1px 2px rgba(31,29,26,.05);
    transition:border-color .12s, box-shadow .12s; }
  .otp-o input:hover { border-color:var(--vien-ro); }
  /* Ô đang gõ hiện QUẦNG — mẫu gọi là "ring". Không chỉ đổi màu viền: trên màn sáng
     một đường viền 1px đổi màu gần như không thấy, mà đây đúng là thứ người ta cần
     thấy để biết mình đang ở ô nào. */
  .otp-o input:focus { outline:none; border-color:var(--xanh);
    box-shadow:0 0 0 3px rgba(20,160,160,.20); }
  .otp-o input.co { border-color:var(--xanh-dam); }
  .otp.sai .otp-o input { border-color:#C0392B; box-shadow:0 0 0 3px rgba(192,57,43,.14); }
  body.toi .otp-o input { box-shadow:none; }
  body.toi .otp-o input:focus { box-shadow:0 0 0 3px rgba(20,160,160,.28); }
  .otp-tiep { display:block; width:100%; height:44px; margin:2px 0 12px;
    font-size:14.5px; font-weight:600; color:#FFFFFF; background:var(--xanh);
    border:0; border-radius:var(--r-md); cursor:pointer; }
  .otp-tiep:hover:not(:disabled) { background:var(--xanh-dam); }
  .otp-tiep:disabled { background:var(--vien); color:var(--mo); cursor:default; }
  .otp-lai { font-size:12.5px; color:var(--chu-mo); margin:0; }
  .otp-lai-nut { background:none; border:0; padding:0; cursor:pointer; font:inherit;
    font-size:12.5px; color:#1A6FD4; text-decoration:underline; text-underline-offset:2px; }
  .otp-lai-nut:disabled { color:var(--mo); text-decoration:none; cursor:default; }
  /* Ô nhỏ hơn một chút trên màn hẹp, để sáu ô vẫn nằm gọn MỘT hàng — xuống hai
     hàng thì nó thôi trông như một mã, và người ta gõ nhầm thứ tự. */
  @media (max-width:400px) {
    .otp-o { gap:6px; }
    .otp-o input { width:40px; height:48px; font-size:19px; }
  }
  .gtg-tha > summary { gap:5px; }
  .gtg-tha-nhan { color:var(--chu-mo); font-size:12px; }
  /* ⛔ Nút thả đang MỞ thì nền chuyển sang màu đậm — để nguyên màu chữ mờ là chữ
     "Tuần"/"Đợt" chìm hẳn vào nền, chụp ảnh mới thấy. Kế thừa màu chữ của nền
     đậm rồi hạ độ đục, giữ đúng thứ bậc mà vẫn đọc được. */
  .gtg-tha[open] > summary .gtg-tha-nhan { color:inherit; opacity:.72; }
  .gtg-tha-chon { font-weight:600; }
  .gtg-tha > .gtg-gom-ds { min-width:248px; max-height:min(58vh, 420px); overflow-y:auto; }
  /* Thẳng hàng: nút, thẻ liên kết và đầu nút thả cùng một chiều cao. Không ghim thì
     `.nut-nho` (32px), summary (35px) và `.nut-chinh` (34px) lệch nhau từng pixel —
     đứng cạnh nhau nhìn ra ngay là hàng nút gãy. */
  .gtg-thanh > button, .gtg-thanh > a, .gtg-thanh > .gtg-gom > summary {
    min-height:34px; box-sizing:border-box; display:inline-flex; align-items:center; }
  /* Dấu "tuần này" gắn bằng CSS chứ không chèn chữ vào HTML — nhãn tuần đã là
     một dãy số dài, nhồi thêm chữ vào nút là nút gãy dòng. */
  .gtg-tuan-tab.nay::after { content:"tuần này"; display:inline-block; margin-left:6px;
    font-size:10.5px; border:1px solid var(--vien); border-radius:var(--r-sm); padding:0 5px; }
  .gtg-tuan-tab.chon.nay::after { border-color:var(--dau-bang-vien); }
  .gtg-dot-so { margin-left:6px; font-size:11.5px; font-variant-numeric:tabular-nums; }
  .gtg-dan { font-size:12.5px; color:var(--chu-mo); line-height:1.6; margin:6px 0 10px;
    max-width:78ch; }
  .gtg-canh { border:1px solid #E0A800; background:#FFF8E1; color:#7A5B00;
    border-radius:var(--r-md); padding:9px 12px; font-size:13px; line-height:1.55; margin:8px 0; }
  .gtg-canh.do { border-color:#C0392B; background:#FDECEA; color:#8E2A20; }

  /* ⭐⭐ 28/08/2026 (chiều) — MÀN SOẠN GOOGLE FORM. Xem khối lý do ở `gtgSuaForm`.
     Mỗi câu hỏi một thẻ viền mảnh, hệt bảng trên Sheet: nền trắng, chữ đen, không
     bo tròn quá tay, không đổ bóng. Câu bị bỏ thì mờ đi và gạch ngang câu hỏi —
     nhìn phát biết ngay là "câu này sẽ không có trong Form". */
  .gtgs-dan { font-size:12.5px; color:var(--chu-mo); line-height:1.6;
    margin:0 0 12px; max-width:78ch; }
  .gtgs-ds { display:grid; gap:10px; margin-top:14px; }
  /* ══════════════════════════════════════════════════════════════════════════
     🚪 04/09/2026 — HỘP THOẠI "ĐÓNG BỚT GIỜ / THỨ" (Boss).
     Mượn đúng khuôn thẻ của màn soạn Form ngay trên (`.gtgs-cau`) để hai hộp
     thoại cùng chủ đề trông cùng một họ, không phải hai app khác nhau.
     ⛔ ĐỪNG dùng `font-weight:700`, `uppercase` hay giãn chữ ở đây — ba thứ ấy
        là chỗ Boss đã chê "lộ rõ ui AI" năm lần, và bài `thu-lich-gv-man` mục
        ①b canh nguyên văn chúng trong CSS mới. */
  .gtga-bang { display:grid; gap:10px; margin-top:12px; }
  .gtga-thu { border:1px solid var(--vien-ro); border-radius:var(--r-md);
    background:var(--the); padding:10px 12px 12px; display:grid; gap:8px; }
  /* ⛔ Thứ đã đóng phải NHÌN RA NGAY là khác — mờ đi và đổi nền, đúng nếp
     `.gtgs-cau.bo`. Chỉ dựa vào ô tick thì cả bảng 7 thứ trông y hệt nhau, phải
     dò từng ô mới biết mình vừa đóng cái nào. */
  .gtga-thu.dong { background:var(--nen2); }
  .gtga-dinh { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
  .gtga-so { font-size:11.5px; color:var(--chu-mo); margin-right:auto; }
  .gtga-catthu { display:flex; align-items:center; gap:6px; font-size:11.5px;
    color:var(--chu-mo); cursor:pointer; }
  .gtga-catthu input[type="checkbox"] { width:14px; height:14px; margin:0;
    accent-color:var(--muc); cursor:pointer; }
  .gtga-ds { display:flex; flex-wrap:wrap; gap:6px; }
  .gtga-o { display:flex; align-items:center; gap:6px; font-size:12.5px;
    border:1px solid var(--vien-ro); border-radius:999px; padding:4px 10px 4px 8px;
    background:var(--the); cursor:pointer; }
  .gtga-o input[type="checkbox"] { width:14px; height:14px; margin:0;
    accent-color:var(--muc); cursor:pointer; }
  /* Giờ đã đóng: gạch ngang + mờ. Gạch ngang là dấu hiệu "cái này không còn dùng"
     ai cũng đọc được, không cần chú giải. */
  .gtga-o.dong { opacity:.5; background:var(--nen2); }
  .gtga-o.dong .gtga-gio { text-decoration:line-through; }
  .gtga-o input:disabled { cursor:not-allowed; }
  .gtga-nhac { margin-bottom:0; }
  .gtgs-cau { border:1px solid var(--vien-ro); border-radius:var(--r-md); background:var(--the);
    padding:10px 12px 12px; display:grid; gap:8px; }
  /* Khối tên Form + lời dẫn: cùng khuôn thẻ, chỉ khác là không có hàng nút trên đỉnh. */
  .gtgs-dau { margin-bottom:4px; }
  .gtgs-dau input.gtgs-nhan, .gtgs-dau textarea.gtgs-mota { font:inherit; font-size:13px;
    color:var(--chu); background:var(--the); border:1px solid var(--vien-ro);
    border-radius:var(--r-o, 8px); padding:6px 8px; width:100%; box-sizing:border-box; }
  .gtgs-dau textarea.gtgs-mota { resize:vertical; line-height:1.5; }
  .gtgs-cau.bo { opacity:.55; background:var(--nen2); }
  .gtgs-cau.bo .gtgs-nhan { text-decoration:line-through; }
  .gtgs-dinh { display:flex; align-items:center; justify-content:space-between; gap:10px;
    flex-wrap:wrap; }
  .gtgs-loai { font-size:11.5px; color:var(--chu-mo); }
  .gtgs-nut { display:flex; gap:6px; }
  .gtgs-nut button, .gtgs-day button { font:inherit; font-size:11.5px; cursor:pointer;
    border:1px solid var(--vien-ro); background:var(--the); color:var(--chu);
    border-radius:var(--r-sm); padding:3px 9px; }
  .gtgs-nut button:hover, .gtgs-day button:hover { background:var(--nen2); }
  .gtgs-nhan-l { display:grid; gap:4px; font-size:11.5px; color:var(--chu-mo); }
  .gtgs-nhan-l em { font-style:normal; }
  .gtgs-cau input.gtgs-nhan, .gtgs-cau textarea.gtgs-mota { font:inherit; font-size:13px;
    color:var(--chu); background:var(--the); border:1px solid var(--vien-ro);
    border-radius:var(--r-o, 8px); padding:6px 8px; width:100%; box-sizing:border-box; }
  .gtgs-cau textarea.gtgs-mota { resize:vertical; line-height:1.5; }
  /* Danh sách giờ CHỈ ĐỂ XEM — cố ý không phải ô gõ, để không ai tưởng sửa được. */
  .gtgs-gio { display:flex; flex-wrap:wrap; gap:5px; align-items:center; }
  .gtgs-gio-nhan { width:100%; font-size:11.5px; color:var(--chu-mo); }
  .gtgs-gio i { font-style:normal; font-size:11.5px; color:var(--chu-mo);
    border:1px solid var(--vien); border-radius:var(--r-sm); padding:1px 6px;
    background:var(--nen2); font-variant-numeric:tabular-nums; }
  .gtgs-day { margin-top:14px; }
  .gtg-ds { display:grid; gap:8px; margin-top:10px; }
  .gtg-the { border:1px solid var(--vien-ro); border-radius:var(--r-lg); background:var(--the);
    padding:10px 12px; }
  .gtg-the-dau { display:flex; flex-wrap:wrap; gap:8px; align-items:baseline; }
  .gtg-ten { font-size:14px; }
  .gtg-theo { font-size:11.5px; color:var(--chu-mo); border:1px solid var(--vien);
    border-radius:var(--r-sm); padding:1px 6px; }
  .gtg-theo.la { border-color:#C0392B; color:#C0392B; }
  .gtg-tong { margin-left:auto; font-size:13px; font-variant-numeric:tabular-nums; }
  .gtg-lienlac { font-size:12px; color:var(--chu-mo); margin:2px 0 8px; }
  .gtg-hang { display:grid; grid-template-columns:92px 1fr; gap:6px 10px;
    padding:7px 0 0; border-top:1px solid var(--vien); align-items:start; }
  .gtg-nhan { font-size:12px; color:var(--chu-mo); padding-top:4px; }
  .gtg-khung, .gtg-lop { display:flex; flex-wrap:wrap; gap:4px; align-items:center; }
  .gtg-k { font-size:12px; background:var(--nen); border:1px solid var(--vien);
    border-radius:var(--r-sm); padding:2px 8px; font-variant-numeric:tabular-nums; }
  .gtg-lop-the { display:inline-flex; align-items:center; gap:3px; font-size:12px;
    background:var(--nen); border:1px solid var(--vien); border-radius:var(--r-sm);
    padding:2px 2px 2px 8px; }
  .gtg-lop-the.la { border-color:#C0392B; color:#C0392B; }
  .gtg-lop-the button { border:0; background:transparent; cursor:pointer; padding:2px 4px;
    color:var(--chu-mo); line-height:0; }
  .gtg-them-lop { max-width:210px; font-size:12.5px; }
  .gtg-chua { font-size:12px; color:var(--chu-mo); font-style:italic; }
  .gtg-sua { border:1px solid var(--vien); background:var(--the); color:var(--chu-mo);
    border-radius:var(--r-sm); padding:3px 10px; font:inherit; font-size:12px; cursor:pointer; }
  /* Hộp sửa giờ: mỗi khung một hàng thứ · từ · đến. */
  .gtg-kh-hang { display:grid; grid-template-columns:120px 1fr 1fr 32px; gap:6px;
    align-items:center; margin-bottom:6px; }
  .gtg-kh-hang input, .gtg-kh-hang select { width:100%; padding:6px 8px;
    border:1px solid var(--vien); border-radius:var(--r-o, 8px); background:var(--nen-o);
    color:inherit; font:inherit; font-size:13px; }
  .gtg-kh-hang input { font-variant-numeric:tabular-nums; }
  .gtg-kh-bo { border:0; background:none; color:var(--chu-mo); font-size:17px;
    line-height:1; cursor:pointer; padding:4px; border-radius:var(--r-sm); }
  .gtg-kh-bo:hover { background:var(--nen2); color:var(--do,#B91C1C); }
  .gtg-kh-tieu { display:grid; grid-template-columns:120px 1fr 1fr 32px; gap:6px;
    font-size:11.5px; color:var(--chu-mo); margin-bottom:4px; }
  /* Bảng công: bảng kê, con số canh phải. Hàng tiêu đề dùng đúng màu xanh của
     mọi bảng khác trong app (`--dau-bang-nen`), đừng đặt màu riêng cho một bảng. */
  .gtg-cong { width:100%; border-collapse:separate; border-spacing:0; font-size:13px; }
  .gtg-cong th, .gtg-cong td { padding:7px 10px; border-bottom:1px solid var(--vien);
    text-align:left; }
  .gtg-cong th { background:var(--dau-bang-nen); color:var(--dau-bang-chu);
    font-size:12px; font-weight:700; border-bottom-color:var(--dau-bang-vien); }
  .gtg-cong td.so, .gtg-cong th.so { text-align:right; font-variant-numeric:tabular-nums; }
  .gtg-cong tr:last-child td { border-bottom:0; }
  .gtg-cong-khung { border:1px solid var(--vien-ro); border-radius:var(--r-md); overflow:hidden;
    background:var(--the); }

  /* ⭐⭐ 28/08/2026 (chiều) — SỔ PHIẾU FORM. Xem khối lý do ở `gtgSoPhieu`.
     Mượn nguyên bộ `.gtg-cong` để bảng này và Bảng công nhìn là một nhà; ở đây chỉ
     thêm mấy thứ Bảng công không có: dấu thứ, nhãn "đủ / thiếu", dòng phiếu hỏng.
     ⛔ Bảng SÁU CỘT nên phải cuộn ngang được trên máy hẹp — `overflow:hidden` của
        khung mẹ mà đứng một mình thì nó CẮT CỤT cột cuối, im lặng. */
  .gtg-sp-tom { font-size:12.5px; color:var(--chu-mo); line-height:1.7; margin:0 0 10px; }
  .gtg-sp-tom b { color:var(--chu); font-variant-numeric:tabular-nums; }
  .gtg-sp-tab { margin:0 0 10px; }
  /* ⛔ Lớp riêng `.cuon` chứ KHÔNG dùng `:has(.gtg-sp-bang)` — luật của kho này cấm
     `:has()` trong CSS mới của index.html. */
  .gtg-cong-khung.cuon { overflow:auto; }
  .gtg-sp-bang { min-width:720px; }
  .gtg-sp-bang td.gtg-sp-lien { font-size:12px; color:var(--chu-mo); word-break:break-all; }
  .gtg-sp-bang tr.hong td { background:var(--do-nen); }
  .gtg-sp-thu { font-style:normal; font-size:11.5px; display:inline-block;
    border:1px solid var(--vien-ro); border-radius:var(--r-sm); padding:0 5px; margin-right:4px;
    font-variant-numeric:tabular-nums; }
  .gtg-sp-khong, .gtg-sp-du { font-size:11.5px; color:var(--chu-mo); }
  .gtg-sp-thieu { font-size:11.5px; color:var(--do); }
  @media (max-width:640px) {
    .gtg-hang { grid-template-columns:1fr; }
    .gtg-nhan { padding-top:0; }
    .gtg-kh-hang, .gtg-kh-tieu { grid-template-columns:1fr 1fr 1fr 30px; }
  }

  .mc-bang-khung {
    margin-top: 12px; border: 1px solid var(--vien-ro); border-radius: var(--r-sheet);
    overflow: hidden; background: var(--the);
  }
  .mc-cuon { overflow-x: auto; }
  table.mc-sheet { border-collapse: separate; border-spacing: 0; width: max-content; min-width: 100%; }
  .mc-sheet th, .mc-sheet td {
    border-right: 1px solid var(--vien); border-bottom: 1px solid var(--vien);
    padding: 0; vertical-align: middle;
  }
  .mc-sheet tr:last-child th, .mc-sheet tr:last-child td { border-bottom: 0; }
  .mc-sheet .mc-o-cuoi { border-right: 0; }

  /* cột nhãn trái — đứng yên khi cuộn ngang */
  .mc-sheet .mc-nhan {
    position: sticky; left: 0; z-index: 3; width: 104px; min-width: 104px;
    background: #F2F5F8; color: #3D4854; font-size: 11.5px; font-weight: 700;
    text-align: left; padding: 7px 10px; border-right: 2px solid #CBD4DC;
  }
  body.toi .mc-sheet .mc-nhan { background: #333B44; color: #E4E8EC; border-right-color: #4E5966; }

  /* thanh chữ cái A B C — kèm ba nút của chính cột đó */
  .mc-sheet .mc-abc {
    background: #F8F9FA; color: #5F6368; font-size: 11.5px; font-weight: 700;
    height: 32px; padding: 0 4px 0 8px; min-width: 150px;
  }
  body.toi .mc-sheet .mc-abc { background: #333B44; color: #E4E8EC; }
  /* Chữ cái đứng GIỮA ô như bảng tính, ba nút dồn về phải.
     ⛔ Chữ cái phải neo tuyệt đối mới giữa THẬT. Xếp nó thành một ô lưới cạnh bộ nút
        thì bộ nút rộng bao nhiêu chữ cái lệch bấy nhiêu — đã thấy tận mắt trên ảnh. */
  .mc-abc-trong { position: relative; display: flex; align-items: center;
                  justify-content: flex-end; min-height: 24px; }
  /* `right: 70px` = chừa đúng chỗ bộ ba nút. Để `right: 0` thì chữ cái nằm giữa cả ô
     và DÍNH vào nút đầu tiên — đã thấy trên ảnh chụp. */
  .mc-abc-chu { position: absolute; left: 0; right: 70px; text-align: center; pointer-events: none; }
  .mc-abc-nut { position: relative; display: flex; gap: 1px; }
  .mc-abc-nut button {
    display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid transparent; background: transparent; color: #5F6368;
    padding: 4px; border-radius:var(--r-sm); cursor: pointer; line-height: 0;
  }
  .mc-abc-nut button i { width: 14px; height: 14px; }
  .mc-abc-nut button:hover:not(:disabled) { background: #E4E7EA; border-color: var(--vien); }
  .mc-abc-nut button:disabled { opacity: .3; cursor: default; }
  .mc-abc-nut .mc-xoa:hover { background: #FBE9E7; color: var(--do); border-color: #E5B4AD; }
  body.toi .mc-abc-nut button { color: #E4E8EC; }
  body.toi .mc-abc-nut button:hover:not(:disabled) { background: #3A424C; }

  /* hàng tiêu đề — ĐÚNG MÀU hàng tiêu đề của bảng điểm danh thật */
  .mc-sheet .mc-ten-o { background: var(--dau-bang-nen); border-right-color: var(--dau-bang-vien); }
  .mc-sheet .mc-ten-o input {
    width: 100%; border: 0; background: transparent; color: var(--dau-bang-chu);
    font: inherit; font-size: 13px; font-weight: 700; text-align: center;
    height: 36px; padding: 0 8px; outline: 0;
  }
  .mc-sheet .mc-ten-o input::placeholder { color: rgba(255,255,255,.66); font-weight: 400; }
  .mc-sheet .mc-ten-o input:focus { background: rgba(255,255,255,.16); }

  /* hàng kiểu ô và hàng cài thêm */
  /* `top` chứ không phải giữa: cột chọn sẵn cao lên theo số lựa chọn, để giữa thì
     ô của mấy cột bên cạnh trôi lơ lửng giữa khoảng trống. */
  .mc-sheet .mc-o { padding: 5px 6px; background: var(--the); vertical-align: top; }
  /* Ô chọn chiều điểm ("Số câu SAI" / "Điểm CHẤM") dài hơn mọi ô khác. Cho riêng nó
     rộng thêm, ĐỪNG để chữ cụt — chiều tốt/xấu của cột số là thứ đọc nhầm là chấm
     ngược cả lớp. */
  .mc-sheet .mc-o-rong { min-width: 190px; }
  .mc-sheet .mc-o-chon { min-width: 176px; }

  /* Lựa chọn của cột "Ô chọn sẵn": mỗi cái MỘT KHỐI riêng, có nút bỏ. Cô Quỳnh
     26/08/2026 — không gõ chuỗi ngăn nhau bằng dấu phẩy nữa. */
  .mc-chon-ds { display: flex; flex-direction: column; gap: 4px; }
  .mc-chon-mot {
    display: flex; align-items: center; gap: 4px; font-size: 12.5px;
    background: var(--nen); border: 1px solid var(--vien); border-radius:var(--r-sm);
    padding: 3px 3px 3px 9px;
  }
  .mc-chon-mot span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .mc-chon-mot button {
    flex: none; display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid transparent; background: transparent; color: var(--mo);
    padding: 3px; border-radius:var(--r-sm); cursor: pointer; line-height: 0;
  }
  .mc-chon-mot button i { width: 13px; height: 13px; }
  .mc-chon-mot button:hover { background: #FBE9E7; color: var(--do); border-color: #E5B4AD; }
  .mc-chon-them { display: flex; gap: 4px; }
  .mc-chon-them input { flex: 1; min-width: 0; }
  .mc-chon-them button {
    flex: none; display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid var(--vien-ro); background: var(--the); color: var(--xanh-dam);
    padding: 4px 7px; border-radius:var(--r-sm); cursor: pointer; line-height: 0;
  }
  .mc-chon-them button i { width: 14px; height: 14px; }
  .mc-chon-them button:hover { background: var(--xanh-nhat); border-color: var(--xanh); }
  .mc-sheet .mc-o select, .mc-sheet .mc-o input {
    width: 100%; font-size: 12.5px; padding: 5px 6px; border-radius:var(--r-o, 8px);
  }
  .mc-o-mo { font-size: 12px; color: var(--mo); text-align: center; display: block; padding: 7px 0; }

  /* hàng xem thử — vẽ đúng ô trợ giảng sẽ thấy khi chấm */
  .mc-sheet .mc-thu {
    background: #FFFFFF; text-align: center; font-size: 12.5px; font-weight: 700;
    color: var(--chu); height: 34px; padding: 0 6px;
  }
  body.toi .mc-sheet .mc-thu { background: var(--the); }
  .mc-thu-chu { font-weight: 400; color: var(--mo); font-size: 12px; }

  /* ô "+" cuối bảng — chỗ thêm cột, đứng đúng chỗ bảng tính hay đặt */
  .mc-sheet .mc-them-o { background: #F8F9FA; padding: 0; width: 48px; min-width: 48px; }
  body.toi .mc-sheet .mc-them-o { background: #333B44; }
  .mc-sheet .mc-them-o button {
    width: 100%; height: 100%; min-height: 130px; border: 0; background: transparent;
    color: var(--xanh-dam); cursor: pointer; display: flex;
    align-items: center; justify-content: center;
  }
  .mc-sheet .mc-them-o button i { width: 18px; height: 18px; }
  .mc-sheet .mc-them-o button:hover { background: var(--xanh-nhat); }
  /* Vùng trống bên phải: `width:100%` để nó hút hết bề ngang thừa, nhờ vậy các cột
     thật giữ đúng bề rộng của mình thay vì giãn ra chiếm màn. */
  .mc-sheet .mc-dem { width: 100%; background: var(--the); border-bottom: 0; }
  body.toi .mc-sheet .mc-dem { background: var(--the); }

  .mc-bang-chan {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    padding: 8px 12px; background: #F8F9FA; border-top: 1px solid var(--vien);
    font-size: 12px; color: var(--mo);
  }
  body.toi .mc-bang-chan { background: #333B44; }
  .mc-trong { font-size: 12.5px; color: var(--mo); }

  /* 🗑️ 01/09/2026 — THÙNG RÁC LỚP. Khung cuộn dùng chung `--r-sheet` như mọi bảng
     dạng sheet khác (cô Quỳnh chốt góc vuông 31/08) — đừng cắm số cứng trở lại. */
  .ql-tr-ds { max-height: 52vh; overflow-y: auto; border: 1px solid var(--vien);
      border-radius: var(--r-sheet); background: var(--nen); padding: 4px; }
  .ql-tr-hang { display: flex; align-items: center; gap: 10px; padding: 9px 10px;
      border-bottom: 1px solid var(--vien); }
  .ql-tr-hang:last-child { border-bottom: none; }
  .ql-tr-trai { flex: 1 1 auto; min-width: 0; }
  .ql-tr-ten { font-size: 13.5px; font-weight: 600; color: var(--chu);
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ql-tr-phu { font-size: 11.5px; color: var(--mo); margin-top: 2px; }
  .ql-tr-nut { flex: 0 0 auto; display: flex; gap: 6px; }
  /* Nút "Xoá hẳn" ĐỎ ngay từ đầu, không đợi tới lượt bấm xác nhận: đây là việc
     duy nhất trong hộp này không lùi lại được. */
  .ql-tr-han { color: var(--lgv-do-c); border-color: var(--lgv-do-c); }
  .ql-tr-han.chac { background: var(--lgv-do-c); color: #fff; }
  .mc-bang-rong { padding: 20px 14px; text-align: center; }

  /* ══════════════════════════════════════════════════════════════════════════
     🏗 MÀN SETUP LỚP CHƯA ĐƯA LÊN ĐIỂM DANH — 26/08/2026
     Cố ý KHÔNG giống màn điểm danh chút nào: không bảng nhiều cột màu, không dải
     nâu DAY. Nhìn là biết đây chưa phải chỗ chấm điểm.
     ══════════════════════════════════════════════════════════════════════════ */
  .st-bang {
    margin: 12px 0; padding: 11px 14px; border-radius:var(--r-md);
    background: var(--xanh-nhat); border: 1px solid var(--vien);
    font-size: 13.5px; line-height: 1.55; color: var(--chu);
  }
  /* ⛔ 26/08/2026 — bảng cột XUỐNG HÀNG RIÊNG, chiếm cả bề ngang. Trước đây nó nằm
     cạnh khối thông tin lớp nên bị ép còn ~1.100px: lớp 7 cột là phải cuộn ngang mới
     nhìn hết, mà đây lại chính là việc chính của cả màn này. */
  .st-luoi { display: grid; grid-template-columns: 1fr; gap: 14px; align-items: start; }
  /* ⛔ BẪY GRID: ô lưới mặc định `min-width:auto`, nên bảng rộng theo nội dung sẽ
     NỞ CẢ Ô ra, kéo tràn ngang cả trang thay vì tự cuộn trong khung. Đo được: 1.632px
     nội dung trong màn 1.440px. `min-width:0` mới trả việc cuộn về cho `.mc-cuon`. */
  .st-luoi > * { min-width: 0; }
  .st-khoi { border: 1px solid var(--vien); border-radius:var(--r-md); background: var(--the); padding: 14px 16px; }
  .st-khoi-dau { font-size: 13px; color: var(--mo); margin-bottom: 10px; }
  .st-hang { display: flex; gap: 10px; padding: 6px 0; border-bottom: 1px solid var(--vien); font-size: 13.5px; }
  .st-hang:last-of-type { border-bottom: 0; }
  .st-hang span { width: 92px; flex: none; color: var(--mo); }
  .st-hang b { font-weight: 600; }
  .st-nut { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
  .st-nut-cot { margin-top: 14px; }
  /* ⛔ 31/08/2026 — `.nut-chinh` khai `width:100%` (di sản nút "Đăng nhập", xem chú
     thích dài ở `.nv-thanh > .nut-chinh` phía trên). Trong hàng nút này nó biến
     "Lưu các cột" thành DẢI TEAL chạy suốt bề ngang khối, đẩy hai nút bên cạnh
     XUỐNG HÀNG DƯỚI. Hậu quả thật, không phải lo xa: nút mở ô đặt tên tụt xuống
     dưới dải teal, thành nút xám bé cuối hàng — cô Quỳnh không nhìn ra bao giờ,
     tưởng app chưa có chỗ đặt tên cho bộ cột (trong khi ô ấy có từ 26/08/2026).
     Ghim lại đúng cỡ chữ để CẢ BA nút đứng cùng một hàng.
     Cùng một cách vá với `.gtg-thanh > .nut-chinh` và `.ql-the-nut .nut-chinh`.
     ⛔ ĐỪNG mở `.st-nut { align-items: center }`: ba nút nay cao đều 34px nhờ
        `align-items` mặc định là stretch, mở ra là chúng lệch nhau ngay. */
  .st-nut > .nut-chinh { width: auto; height: 34px; padding: 0 14px; font-size: 13px; }
  /* Dòng nói rõ HAI nút "Lưu" khác nhau chỗ nào. Chặng ② của luật công cụ cho người
     thật: có trong mã chưa đủ, người ta phải ĐỌC LÀ HIỂU mình đang bấm cái gì. */
  .st-nut-ghi { margin-top: 8px; font-size: 12.5px; line-height: 1.55; color: var(--mo); }
  .st-khoa {
    padding: 11px 13px; border-radius:var(--r-md); border: 1px solid var(--vien);
    background: var(--nen); font-size: 13px; line-height: 1.55; margin-bottom: 10px;
  }
  .st-cot-xem { font-size: 13.5px; }
  .st-day {
    margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--vien);
    display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
  }
  .st-day-ghi { font-size: 12.5px; color: var(--mo); }
  .st-khoi-phu { display: block; margin-top: 3px; font-size: 12px; color: var(--mo); }
  @media (max-width: 860px) { .st-luoi { grid-template-columns: 1fr; } }

  /* ── Thẻ lớp ở Quản lý lớp: ba nhóm có nhãn (26/08/2026) ── */
  .ql-nhom-nhan {
    font-size: 11.5px; color: var(--mo); margin: 10px 0 5px;
    padding-top: 9px; border-top: 1px solid var(--vien);
  }
  .ql-nhom-nhan:first-child { padding-top: 0; border-top: 0; margin-top: 4px; }
  .ql-nhom { display: flex; flex-wrap: wrap; gap: 5px; }
  .ql-nhom .ql-b2 { flex: 0 1 auto; }
  /* Ba nút sửa đứng đầu thẻ: chia đều bề ngang, cùng cỡ — nhìn là thấy ngay. */
  .ql-the-nut .ql-nhom .nut-nho { flex: 1 1 30%; justify-content: center; }
  .ql-nhom-chinh { margin-top: 7px; }
  .ql-nhom-chinh .nut-chinh { flex: 1 1 100%; width: 100%; justify-content: center; }

  /* ══════════════════════════════════════════════════════════════════════════════
/* ════════════════════════════════════════════════════════════════════════════════
   PHẦN A — KHỐI MỚI. DÁN VÀO ĐÚNG CHỖ KHỐI `#noiDung > .cc-thanh-nut` VỪA XOÁ
   (dòng 11525–11606), tức GẦN CUỐI <style>, NGAY TRƯỚC khối `.chu-rut` (11608).
   ────────────────────────────────────────────────────────────────────────────────
   ⛔ ĐẶT Ở CUỐI, CỐ Ý — y hệt lý do khối cũ đã ghi: `.dau-lop` `.nv-thanh` `.cts-dau`
      đã có lề riêng ở hàng chục chỗ phía trên, có luật nặng ký hơn
      (`body:has(#ctsBang) .cts-dau` là (1,1,1)). Viết ở trên thì lề cũ thắng và dải
      cao gấp đôi.
   ⛔ TIỀN TỐ `dnc-` / `DNC_` (dải nút công cụ). KHÔNG dùng `tt-`/`TT_`: trong file này
      chúng ĐÃ thuộc về THANH TIẾN TRÌNH (`.tt-chay`, `.tt-dung`, `ttThanh` 12021, `TT_PT`,
      `TT_NHIP`, `TT_THEO_BOCUC`). Kho này đã một lần chết vì trùng tên (`.pt-muc`,
      21/08). Đã kiểm: `grep -c "dnc-" index.html` = 0.
   ⛔ KHÔNG SỬA MỘT KÝ TỰ NÀO trong khối `.thanh-tren { … }` (882) và luật màn hẹp
      (5116). `thu-home-plus.js` dòng 62/71/75 đọc NGUYÊN VĂN hai khối ấy kể cả cửa sổ
      900/200 ký tự; thêm một thuộc tính là `border-radius` bị đẩy khỏi cửa sổ và bài
      đỏ, mà lời báo lỗi lại nói về "bo tròn". Mọi thứ cần đổi viết Ở ĐÂY.
   ⛔ Mọi luật đụng `.thanh-tren` đều phải bọc `body:not(.dang-trong-lop)`: ba luật bố
      cục màn điểm danh (10856–10858) phải còn nguyên văn — `thu-dien-diem-toan-man.js`
      dòng 198 và 201 so khớp chúng TỪNG KÝ TỰ.
   ════════════════════════════════════════════════════════════════════════════════ */

  /* ── ① HAI BIẾN CHIỀU CAO. Khai ở `:root` với giá trị 0px là AN TOÀN và đúng —
     0px chính là giá trị đúng khi chưa có dải (Trang chủ, trong lớp, JS chưa chạy),
     nên không có chuyện "giá trị mặc định ở :root giết mất giá trị đỡ của từng chỗ".
       --dnc-cao : chiều cao THẬT của dải        → dùng cho các mốc DÍNH (sticky top)
       --dnc-du  : phần đầu màn DÀY THÊM bao nhiêu (ÂM = mỏng đi) → dùng cho 13 chỗ
                   `calc(100vh − N)`
     ⛔ HAI BIẾN KHÁC NHAU, ĐỪNG GỘP. Đây là chỗ ba phương án trước cùng sai:
        gom là BỚT hàng khỏi `#noiDung` rồi THÊM dải bên ngoài, nên phần đầu thường
        MỎNG ĐI chứ không dày lên. Trừ nguyên chiều cao dải là trừ thừa 46–90px —
        đúng thứ đang đi giành lại. `--dnc-du` do JS ĐO THẬT (hiệu số vị trí ruột màn
        trước/sau khi gom), không phải cộng tay. */
  :root { --dnc-cao: 0px; --dnc-du: 0px; }

  /* ── ② HÀN DẢI VÀO THANH TRÊN THÀNH MỘT KHỐI ────────────────────────────────────
     ⭐ CÔ QUỲNH BÁC BẢN TRƯỚC ĐÚNG CHỖ NÀY: *"Vạch màu đậm 2px là dấu hiệu KẾT THÚC
        một khối; đặt nút bên dưới nó thì mắt tôi vẫn đọc ra HAI thanh… Muốn thành một
        khối thì vạch teal phải chuyển xuống đáy của cả cụm, chỗ giáp nhau để nét mảnh.
        Bài kiểm sửa được, mắt tôi thì không."*
     → Ở ĐÂY teal chuyển xuống đáy dải, chỗ giáp còn nét mảnh 1px.
     → Khối gốc (882) vẫn giữ nguyên `border-bottom:2px solid var(--xanh)` nên
       `thu-giao-dien-nen-tang.js:93` (đòi `.thanh-tren` mang `var(--xanh`) VẪN XANH;
       và ở Trang chủ, nơi không có dải, teal vẫn nằm đúng chỗ cũ. */
  /* 🔄 02/09/2026 — CÔ QUỲNH ĐẢO LẠI, chọn bằng nút bấm: *"vạch teal luôn ngay
     dưới thanh trên cùng"*, sau khi báo *"1 số công cụ khi ấn vào còn ko có cái
     viền xanh ngăn cách"*.

     Luật 29/08 ở trên KHÔNG SAI lúc nó ra đời: hồi đó thanh trên và dải nút cùng
     bề rộng, cùng lề, cùng bo góc — mắt đọc ra MỘT khối thật, nên giấu vạch ở chỗ
     giáp là đúng. Cùng ngày 02/09 thanh trên đổi thành dải CỐ ĐỊNH CHẠY SUỐT bề
     ngang kiểu Supabase, còn dải nút thì nằm trong cột nội dung nên hẹp hơn — đo
     được 1500px so với 1444px (màn Công việc) và 1224px (màn Quản lý lớp). Hai
     hình lệch mép thì không còn là một cụm, và chỗ giáp chỉ còn nét xám: nhìn ra
     đúng "màn này thiếu vạch".

     → BỎ HẲN dòng `border-bottom` khỏi luật này, để luật gốc (hoặc luật màn rộng)
       kẻ vạch teal như mọi màn khác.
     ⛔ BA VIỆC CÒN LẠI GIỮ NGUYÊN — triệt lề, bỏ bo góc, dồn về một cái bóng. Đó
        mới là phần làm dải nút dính liền thanh trên, và nó vẫn cần.
     ⛔ ĐỪNG THÊM LẠI vạch teal cho `.dnc-dai` (xem luật của nó bên dưới). Hai vạch
        teal đậm cách nhau 50px chính là thứ cô Quỳnh chê 29/08 — chỉ đổi chỗ chứ
        không chữa được gì. MỘT dấu nhận diện, MỘT chỗ duy nhất. */
  body.dnc-co-dai:not(.dang-trong-lop) .thanh-tren {
    margin-bottom: 0;                              /* triệt đúng 8px → khe hở = 0px */
    border-radius: 0;                              /* nhường bộ góc bo cho ĐÁY dải */
    box-shadow: none;                              /* cả cụm chỉ đổ MỘT cái bóng */
  }

  /* ── ③ DẢI NÚT — anh em của `.thanh-tren` trong `#app`, đứng ngay TRƯỚC `#noiDung`.
     ⛔ Nằm NGOÀI `#noiDung` nên 74 chỗ gán `innerHTML` KHÔNG quét tới → JS phải tự
        tháo mỗi lượt bằng cơ chế CỌC `.dnc-moc` (xem `dncThao`). Đây là chỗ hỏng cấu
        trúc lớn nhất của cách làm này, và nó được xử bằng dữ kiện thật, không may rủi.
     ⛔ z-index 45: THẤP hơn `.thanh-tren` (50) để chui xuống dưới nếu lệch vài pixel,
        CAO hơn `.nn-thanh-cham` (40) và hàng tiêu đề bảng (4). TUYỆT ĐỐI không nâng
        z-index thanh trên — `thu-thanh-tien-trinh.js:307–311` khoá hộp thanh chờ < 50.
     ⛔⛔ VÀ ĐỪNG VIẾT NGUYÊN VĂN CÁI ID CỦA HỘP THANH CHỜ Ở BẤT CỨ ĐÂU DƯỚI DÒNG 8466.
        Bài `thu-thanh-tien-trinh.js` cắt khối CSS của hộp bằng `lastIndexOf` cái id ấy;
        nhắc lại nó trong một chú thích ở tận đây là mốc cắt nhảy xuống, đoạn cắt phình
        từ 9.210 lên 251.920 ký tự, và bài đỏ oan với "272 mã màu, 25 biến ma" — toàn
        thứ của CSS người khác. Đã dính đúng bẫy ấy một lần ngày 29/08/2026.
     ⛔ margin ngang PHẢI đúng 14px (màn hẹp 8px) như thanh trên: `soi-giao-dien.js:349`
        đo lệch mép trái/phải và kêu khi > 2px. */
  .dnc-dai {
    position: sticky;
    top: var(--dnc-cao-thanh, 44px);   /* chiều cao THẬT của thanh trên, JS đo, xem dncDoCao */
    z-index: 45;
    margin: 0;                         /* 02/09/2026 — cùng mép 0 với thanh trên */
    background: var(--the);
    border: 1px solid var(--vien);
    border-top: none;                              /* không đẻ nét thứ hai ở chỗ giáp */
    /* 🔄 02/09/2026 (lượt 2) — TRẢ VẠCH TEAL VỀ THANH TRÊN, dải này chỉ còn viền
       xám. Cô Quỳnh chọn bằng nút bấm: *"vạch teal luôn ngay dưới thanh trên cùng"*.
       Lý do đầy đủ nằm ở luật `body.dnc-co-dai` phía trên — tóm tắt: thanh trên nay
       chạy suốt bề ngang còn dải này hẹp hơn 56–276px, nên hai cái không còn đọc ra
       một cụm nữa.
       ⛔ ĐỪNG TRẢ TEAL VỀ ĐÂY. Để cả hai cùng teal là hai vạch đậm cách nhau 50px —
          đúng thứ cô Quỳnh bác 29/08 (*"mắt tôi vẫn đọc ra HAI thanh"*).
       ⛔ `border-top: none` ngay trên GIỮ NGUYÊN: vạch teal của thanh trên đã nằm
          sẵn ở chỗ giáp, thêm nét nữa là hai đường chồng nhau. */
    border-bottom: 1px solid var(--vien);          /* teal đã về thanh trên cùng */
    border-radius: 0 0 var(--r-xl) var(--r-xl);
    box-shadow: var(--bong-1);
    /* ⛔⛔ TUYỆT ĐỐI KHÔNG `overflow` HAY `max-height` Ở ĐÂY — chép nguyên bài học của
       khối cũ (chú thích 11557–11569). Cô Quỳnh báo 29/08: *"các nút đó đang bị lỗi ko
       ấn được"*. Thủ phạm đúng là `max-height:38vh; overflow-y:auto` đặt lên khung
       chứa nút: khung có overflow thì CẮT MỌI THỨ BUNG RA TỪ BÊN TRONG (menu
       `<details>`, bảng bộ lọc, danh sách gợi ý). Đo được: menu cao 123px tràn khỏi
       thanh 79px, ba nút nằm hẳn ngoài vùng thấy.
       Dải cao quá thì chữa bằng BỐ CỤC (cho xuống hàng), KHÔNG BAO GIỜ bằng cách cắt.
       NGOẠI LỆ DUY NHẤT: `overflow:hidden` nội tuyến sống đúng 0,34s chạy hiệu ứng rồi
       GỠ HẲN ở `transitionend` — lúc ấy chưa menu nào mở được. */
  }
  .dnc-dai > .dnc-hang {
    display: flex; align-items: center;
    flex-wrap: wrap;                    /* ⛔ XUỐNG DÒNG, không cuộn ngang, không giấu.
       Đo cũ: cho cuộn ngang thì thanh dài 4.746px trên cửa sổ 1.464px — miết ngang hơn
       ba màn mới thấy hết nút. Gọn mắt mà không ai dùng nổi thì vẫn là hỏng. */
    column-gap: 14px; row-gap: 5px;
    padding: 6px 13px;
  }
  /* Mỗi tầng giữ đúng bề ngang của nó. `!important` ở đây là CẦN — xem lời dặn ở đầu. */
  .dnc-dai > .dnc-hang > * {
    flex: 0 1 auto;                     /* co được, kẻo tầng dài đẩy cả dải quá bề ngang */
    min-width: 0;                       /* ⛔ thiếu dòng này thì flex con KHÔNG chịu co */
    margin: 0 !important;
    flex-wrap: wrap !important;         /* ⛔⛔ PHẢI `wrap`, không được `nowrap` — bản
       `nowrap` cắt cụt nút thứ ba của tầng chọn mục ở màn Chăm sóc HS trên điện thoại
       (ảnh 29/08). Cha đã cấm `overflow`, nên tầng nào không xuống dòng được là nút
       của nó nằm hẳn ngoài màn: thấy mà bấm không tới. Nhóm hơi loãng còn hơn mất nút. */
    overflow: visible !important;       /* cha đã không cuộn, con cũng đừng cuộn lồng */
  }
  /* Tên màn lên dải thì thành NHÃN, không còn là đầu mục.
     ⛔ Không `font-weight:700`, không `uppercase`, không `letter-spacing` — ba thứ làm
        *"lộ rõ ui AI"* mà cô Quỳnh đã chê NĂM lần. Nét chữ là chỗ lộ số một. */
  .dnc-dai .dau-lop { gap: 10px !important; }
  .dnc-dai .dau-lop .ten { font-size: 15px; font-weight: 600; }
  .dnc-dai .dau-lop .phu { font-size: 12.5px; font-weight: 400; color: var(--mo); }
  .dnc-dai .dau-lop .day { display: none; }   /* spacer đẩy nút ra mép — trên dải là thừa */
  /* Tầng bị rút sạch con thì giấu, kẻo để lại 8–10px lề chết ở 13 màn. */
  .dnc-rong { display: none !important; }
  /* Cọc đánh dấu chỗ cũ — không bao giờ được thấy, không bao giờ được chiếm chỗ. */
  .dnc-moc { display: none !important; }

  /* ── NÚT « ← Trang chủ » — cô Quỳnh chốt 29/08/2026 ───────────────────────────
     > *"sửa lại bỏ cái nút về trang chủ trong các công cụ đi"*
     Cô chọn: BỎ Ở MÁY TÍNH, GIỮ Ở ĐIỆN THOẠI.
     ⛔ 821px KHÔNG phải con số tuỳ tiện — đúng mốc cột biểu tượng bên trái hiện ra
        (dòng 6839 `@media (min-width:821px)`, và `#app { padding-left:304px }` ngay
        dưới). Từ 821px trở lên người dùng có cột ấy để về Trang chủ; dưới 821px cột
        thu vào nút ba gạch nên PHẢI giữ nút, không thì trên điện thoại mỗi lần về
        nhà mất hai cú bấm.
     ⛔ `body:not(.cc-thu)` là chốt an toàn: người dùng THU hẳn cột trái đi (04/08,
        để rộng màn nhìn bảng) thì nút Trang chủ hiện lại — không thì vừa mất cột
        vừa mất nút, đứng trong công cụ không có đường ra.
     ⛔ Chỉ 18 nút MANG ĐÚNG class này bị ẩn. `gtgVe` (← Quản lý tài khoản) và
        `nvVeDs` (← Danh sách nhân viên) KHÔNG mang class — chúng quay lại màn con,
        không phải về nhà, bỏ là người ta kẹt. */
  @media (min-width: 821px) {
    body:not(.cc-thu) .nut-ve-home { display: none !important; }
  }

  /* ── CÂU DẪN GIẢI CẠNH TÊN CÔNG CỤ — cô Quỳnh chốt 29/08/2026 ─────────────────
     > *"bỏ mấy cái chữ câu giải thích tên bên canh tên công cụ trong giao diện như
     >  kiểu: 'Điền thẳng vào ô, tự lưu.' (của Nhắc phụ đạo) bỏ hết mấy câu đấy ở
     >  các công cụ đi thừa thãi lắm"*
     ⛔ ẨN THEO `.dan-giai`, TUYỆT ĐỐI KHÔNG ẩn cả `.phu`. Đúng thẻ `.phu` ấy còn
        chở DỮ LIỆU THẬT ở hai chỗ — tên cơ sở + lịch học của thẻ lớp, và
        thứ · giờ · phòng · giáo viên. Ẩn sạch là mất thông tin người ta cần đọc,
        mà không một lỗi nào báo.
     ⭐ Ẩn chứ không xoá khỏi mã: máy đọc màn hình vẫn đọc được câu giải thích, và
        hôm nào cô muốn bật lại thì chỉ cần bỏ đúng khối này. */
  .dan-giai { display: none !important; }

  /* ── ④ HÀNG BỐN THỨ Ở LẠI — trong `#noiDung`, DỒN TRÁI, đúng thứ tự cô Quỳnh chốt:
     [nút xanh] [ô tìm] [bộ lọc] [làm mới].
     Nằm trong `#noiDung` nên `innerHTML` tự dọn hộ, và `veLaiGiuUI` giữ được chữ đang
     gõ trong ô tìm y như hôm nay. */
  .dnc-hang-trai {
    display: flex; align-items: center; flex-wrap: wrap;
    justify-content: flex-start;                   /* ⛔ dồn TRÁI, không giãn đều */
    gap: 8px; margin: 0 0 10px;
  }
  .dnc-hang-trai > .nut-chinh {
    width: auto; height: 36px; padding: 0 16px; font-size: 13.5px;
    flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px;
  }
  /* ⛔ `.bl-timhang` là vỏ do `blGanBoLoc` dựng (13399), ôm sẵn [ô tìm][nút Bộ lọc].
     ĐỪNG THÁO VỎ NÀY RA: bảng lọc `.bl-bang` neo vào `.bl-locvo { position:relative }`
     (8100) bên trong nó — đúng chỗ đã phải vá 19/08 vì cô Quỳnh báo *"bộ lọc đặt sai
     vị trí, tôi cần nó phải đặt ở ngay dưới nút bộ lọc"*. Dời CẢ CỤM thì thứ tự
     [ô tìm][bộ lọc] tự đúng mà không đụng gì bên trong. */
  .dnc-hang-trai > .bl-timhang { flex: 1 1 340px; min-width: 0; max-width: 560px; margin: 0 !important; }
  .dnc-hang-trai .bl-tim-ngan { min-width: 0; }
  .dnc-hang-trai > input.o-tim-dep,
  .dnc-hang-trai > input[id$="Tim"] {
    flex: 1 1 320px; min-width: 150px; max-width: 460px;
    margin: 0 !important; padding: 8px 15px; font-size: 13.5px;
  }
  .dnc-hang-trai > .bl-locvo,
  .dnc-hang-trai > .nut-nho { flex: 0 0 auto; margin: 0 !important; }

  /* ── ⑤ NÚT CHỌN CƠ SỞ — ba chip thành MỘT nút thả xuống ────────────────────────
     Ba `button.nv-tab` cũ VẪN CÒN NGUYÊN trong `#noiDung`, chỉ bị `hidden`. Bấm một
     dòng trong bảng thả là JS gọi `.click()` lên đúng nút gốc → dùng lại nguyên
     onclick đã gắn ở cả 8 màn. Không sờ 16 chỗ dựng/gán, không đụng 7 biến cơ sở
     (`NV_COSO` `PD_COSO` `LT_COSO` `DG_COSO` `FHS_COSO` `CS_COSO` `YC_COSO`), không
     đụng 7 khoá localStorage, không đụng CSS `.nv-tab` (725–726, 8745–8748). */
  .dnc-cs {
    display: inline-flex; align-items: center; gap: 7px;
    height: 32px; padding: 0 11px;
    border: 1px solid var(--vien); border-radius:var(--r-md);
    background: var(--nen2); color: var(--chu);
    font: inherit; font-size: 13px; cursor: pointer;
  }
  .dnc-cs:hover { border-color: var(--xanh); }
  .dnc-cs[aria-expanded="true"] { border-color: var(--xanh); background: var(--the); }
  .dnc-cs .dnc-cs-nhan { color: var(--mo); }
  .dnc-cs .dnc-cs-ten { font-weight: 600; max-width: 22ch;
                        overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .dnc-cs .dnc-cs-mui { font-size: 10px; color: var(--mo); }

  /* ⛔⛔ GIỮ BỀ NGANG KHI ĐỔI LỰA CHỌN — Boss chốt 03/09/2026: "đổi cơ sở cũng bị vậy".
     Nhãn nút dựng bằng ĐÚNG TÊN ĐANG CHỌN, mà tên các cơ sở dài chênh nhau rất xa
     ("Nguyễn Tuân/Nguyễn Chánh" 24 ký tự so với "Phố Vọng" 8). Dải .dnc-hang là
     flex-wrap, nên nút co lại bao nhiêu là mọi nút bên phải trượt sang bấy nhiêu,
     và ở cửa sổ chớm chật thì có nút rơi hẳn xuống hàng dưới.
     Chữa: JS đo mục DÀI NHẤT trong chính danh sách rồi đặt --dnc-cs-dai (đơn vị ch).
     Nút giữ nguyên bề ngang ấy dù chọn mục nào. ⛔ Đừng ghim px: tên cơ sở là dữ
        liệu máy chủ, trung tâm thêm cơ sở mới lúc nào cũng được. */
  .dnc-cs .dnc-cs-ten { min-width: min(var(--dnc-cs-dai, 0px), 22ch); }
  .dnc-cs-taicho .dnc-cs-ten { min-width: min(var(--dnc-cs-dai, 0px), 30ch); }

  /* ⛔ Ô ĐỰNG CON SỐ ĐẾM trong nhãn nút — Boss chốt 03/09/2026.
     Nhãn kiểu "Đang chăm sóc (7)" đổi sang "(197)" là nút rộng thêm chừng 16px,
     ba nút cộng lại đủ đẩy mọi nút bên phải trượt đi, hoặc rơi xuống hàng dưới vì
     dải nút là flex-wrap. Bọc riêng con số vào ô này thì một chữ số hay ba chữ số
     cũng chiếm đúng một bề ngang. tabular-nums để chữ số nào cũng rộng bằng nhau. */
  .so-dem { display: inline-block; min-width: 3ch; text-align: center;
            font-variant-numeric: tabular-nums; }
  /* Bản rộng: dùng khi chỗ ấy có lúc là số, có lúc là cả một chữ ("mọi lớp"). */
  .so-dem.rong { min-width: 7ch; }

  /* Nút ĐỔI TẠI CHỖ đứng trong lòng màn, không tranh chỗ với ai trên dải đỉnh — nên
     cho chữ dài hơn. 22ch cắt cụt đúng tên cơ sở dài nhất ("Nguyễn Tuân/Nguyễn
     Chánh" — 24 ký tự), mà cụt tên cơ sở thì người dùng không biết mình đang xem đâu. */
  .dnc-cs-taicho .dnc-cs-ten { max-width: 30ch; }

  /* ── ⑥ BẢNG THẢ — VẼ THẲNG VÀO <body>, position:fixed ──────────────────────────
     ⛔ BẮT BUỘC. `.thanh-tren` có `z-index:50` nên nó là MỘT STACKING CONTEXT: mọi
        menu là con của nó bị kẹp trần ở mức 50 so với trang dù tự khai 60. Trên điện
        thoại `#thanhDuoi` khai 60 (6240) và `.toast` khai 200 (5316) → menu vừa mở đã
        bị thanh đáy đè lên. Vẽ vào `<body>` là thoát hẳn cái trần ấy.
        (Dải khai z45 nên cũng dính y hệt — đây là lý do bảng thả KHÔNG được là con
         của dải.)
     z-index 12000: trên `#thanhDuoi` (60) và `.toast` (200); DƯỚI `.ont-bang` (12500)
     để bảng gợi ý tên người vẫn thắng khi hai thứ chồng nhau. */
  .dnc-tha {
    position: fixed; z-index: 12000;
    min-width: 190px; max-height: min(64vh, 460px); overflow: auto;
    background: var(--the); border: 1px solid var(--vien); border-radius:var(--r-lg);
    box-shadow: 0 10px 28px rgba(0,0,0,.16); padding: 5px;
  }
  /* Chuyển động MỞ RA — Boss chốt 08/09/2026: *"lúc ấn vào phải có aniamtion kéo
     xuống"*. Bảng hiện ra tức thì thì mắt không kịp nối nó với nút vừa bấm; trượt
     xuống một quãng ngắn là cái nối ấy.
     ⛔ Chỉ chạy khi có class `.dnc-tha-vao` — `dncMoTha` gắn nó SAU khi đo xong. Cho
        `.dnc-tha` tự chạy thì phép đo tràn màn lấy nhầm hộp đang trượt (xem lời dặn
        trong `dncMoTha`).
     ⛔ Chỉ `translateY` + `opacity`, KHÔNG `scale`: bảng có `overflow:auto` và
        `max-height`, kéo giãn là chữ bên trong méo theo.
     ⛔ 140ms là trần. Menu mở là thao tác người ta làm liên tục; chậm hơn nữa thì mỗi
        lần đổi cơ sở phải chờ, và chờ đúng chỗ ấy là thứ người dùng thấy ngay. */
  @keyframes dncThaXuong { from { opacity: 0; transform: translateY(-7px); }
                           to   { opacity: 1; transform: none; } }
  @keyframes dncThaLen   { from { opacity: 0; transform: translateY(7px); }
                           to   { opacity: 1; transform: none; } }
  .dnc-tha.dnc-tha-vao     { animation: dncThaXuong .14s cubic-bezier(.22,.9,.28,1) both; }
  .dnc-tha.dnc-tha-vao.len { animation-name: dncThaLen; }
  @media (prefers-reduced-motion: reduce) {
    .dnc-tha.dnc-tha-vao { animation: none; }
  }

  .dnc-tha .dnc-tha-muc {
    display: block; width: 100%; text-align: left;
    border: none; background: none; padding: 9px 11px; border-radius:var(--r-md);
    font: inherit; font-size: 13.5px; color: var(--chu); cursor: pointer;
  }
  .dnc-tha .dnc-tha-muc:hover { background: var(--nen2); }
  /* ⛔ Dùng BIẾN, đừng gõ mã màu: `.nv-loc.chon` gõ cứng `#E8F4F2` nên phải có thêm
     một luật `body.toi` vá nền tối. Lấy biến thì hai chế độ tự đúng, khỏi vá. */
  .dnc-tha .dnc-tha-muc.chon { background: var(--nen2); color: var(--xanh); font-weight: 600; }
  .dnc-tha .dnc-tha-muc.chon::before { content: "✓ "; }

  /* ── ⑦ MÀN HẸP ≤820px ─────────────────────────────────────────────────────────
     ⛔ 820px chứ KHÔNG phải 700px: dòng 5141 cho MỌI `.nut-nho` `min-height:44px` từ
        ≤820px trở xuống. Lấy mốc 700 thì trong quãng 700–820 dải đã phình nút 44px mà
        vẫn xếp kiểu máy tính → tự tụt 3–4 hàng. */
  @media (max-width: 820px) {
    .dnc-dai { margin: 0 8px 8px; top: var(--dnc-cao-thanh, 58px); }
    .dnc-dai > .dnc-hang { padding: 4px 6px; column-gap: 7px; row-gap: 5px; }
    /* ⛔ VẪN `flex-wrap:wrap` — KHÔNG có nút "⋯ Thêm", KHÔNG giấu nút nào.
       Cô Quỳnh bác thẳng bản trước: *"★ Tôi phụ đạo là thứ trợ giảng bấm ĐẦU TIÊN mỗi
       buổi. Giấu nó sau một dấu ba chấm nghĩa là với người ta nó không tồn tại"* —
       đúng chặng ② của skill `cong-cu-cho-nguoi-that`. Và luật dự án: *"KHÔNG được bỏ
       bất kỳ nút nào. GOM KHÔNG PHẢI LÀ BỚT."* */
    .dnc-dai .dau-lop .phu { display: none; }      /* câu dẫn: trên điện thoại là thừa */
    .dnc-dai .dau-lop .ten { font-size: 14px; }

    /* ══ ĐẦU MÀN CÔNG CỤ TRÊN ĐIỆN THOẠI — MỘT KHUÔN CHUNG CHO MỌI CÔNG CỤ ══════
       Boss chốt 08/09/2026 (lượt 2), gửi ảnh màn Công việc:
       > *"bỏ nút quay về đi, mấy cái nút cơ sở và giáo vụ.. để xuống dưới tên công
       >  cụ ở trên. Nút tạo block nhân viên bị to chiếm diện tích và thiếu thẩm mĩ,
       >  cả thanh tìm kiếm cũng vậy, cả nút làm mới cũng quá to trong khi nút này là
       >  ko quan trọng nhất… nhìn sang các công cụ khác của giáo vụ tự sửa theo…
       >  nó cần có sự đồng nhất và chuyên nghiệp giữa các công cụ"*

       ⭐ VÌ SAO SỬA Ở ĐÂY LÀ SỬA HẾT: `.dnc-dai` và `.dnc-hang-trai` là hai cái vỏ
          DÙNG CHUNG — `dncGom` dồn đầu màn của MỌI công cụ vào đúng hai vỏ ấy. Nên
          một khuôn ở đây là 9 màn cùng đổi, đúng chữ "đồng nhất" Boss dặn. Đừng đi
          vá từng màn một: vá lẻ là mỗi màn một kiểu, đúng thứ Boss vừa chê.

       CHUẨN CHUNG: mọi ô điều khiển ở đầu màn cao **36px**.
          Vì sao 36: nhà mình đã có sẵn một chuẩn 34px cho hàng nút (`.gtg-thanh`,
          chú thích ~7798: *"nút, thẻ liên kết và đầu nút thả cùng một chiều cao"*).
          36 là 34 ấy cộng chút cho ngón tay trên điện thoại, và mọi thứ bằng nhau
          thì hàng nút mới thẳng — Boss gọi đó là "chuẩn" và "chuyên nghiệp".
       ⛔ 36px LÀ SÀN, ĐỪNG HẠ TIẾP. Dòng 1126 ghi: *"Trước đây nút cao ~38px, cô
          Quỳnh bấm hay trượt sang nút bên cạnh"*. Bù lại chỗ hụt so với 44px bằng
          KHE RỘNG giữa các nút (7px) — bấm trượt là do nút DÍNH nhau, không chỉ do
          nút thấp. Muốn gọn thêm thì bóp bề ngang, đừng gặm chiều cao. */

    /* ① BỎ NÚT ← TRÊN ĐIỆN THOẠI — Boss: *"bỏ nút quay về đi"*.
       ⛔ Luật cũ ở khối `@media (min-width:821px)` phía trên nói PHẢI giữ nút này
          trên điện thoại, kẻo "mỗi lần về nhà mất hai cú bấm". Luật ấy viết ngày
          29/08, trước khi có thanh đáy và nút ba gạch. Nay đã ĐO trên cả 8 màn công
          cụ: thanh đáy luôn hiện, luôn có nút **Trang chủ**, và bấm tới được thật
          (`elementFromPoint` ở tâm nút). Mọi bảng ưu tiên thanh đáy đều mở đầu bằng
          `home` (`TD_UU_TIEN` và cả hai bản khai riêng của ban), nên không chức vụ
          nào mất đường về. Cộng thêm nút ba gạch ở thanh trên. Về nhà vẫn ĐÚNG MỘT
          cú bấm — luật cũ hết hiệu lực vì tiền đề của nó không còn.
       ⛔ Chỉ ẩn trên màn hẹp. Máy tính vẫn theo luật cũ (ẩn khi có cột trái). */
    .nut-ve-home { display: none !important; }

    /* ② TÊN CÔNG CỤ RIÊNG MỘT HÀNG, TRÊN CÙNG — Boss: *"mấy cái nút cơ sở và giáo
       vụ.. để xuống dưới tên công cụ ở trên"*.
       Trước đây `.dau-lop` chỉ rộng bằng nội dung nên chip Cơ sở leo lên nằm cạnh
       tên. `flex-basis:100%` bắt nó chiếm trọn hàng → mọi nút rơi xuống dưới.
       ⛔ Hàng này nay chỉ còn chữ (nút ← đã ẩn ở trên) nên cao ~20px, KHÔNG phải
          44px như hồi còn nút. Đó là lý do tách hàng mà đầu màn vẫn không phình. */
    .dnc-dai .dau-lop { flex: 1 1 100%; gap: 7px !important; align-items: center; }

    .dnc-cs { height: 36px; }                      /* chuẩn chung 36px, xem trên */
    .dnc-cs .dnc-cs-nhan { display: none; }        /* bỏ chữ "Cơ sở:", giữ trong title= */
    /* ⛔ 15ch, ĐỪNG HẠ. Thử 14ch ngày 08/09/2026 để bóp dải cho gọn: đo bằng
       `scrollWidth` vs `clientWidth` thì "Giáo vụ (2 người)" cần 103px mà ô chỉ còn
       101px — cụt mất hai chữ số cuối. Bề ngang tiết kiệm được 6px không đáng đổi
       lấy một cái nhãn đọc không ra. */
    .dnc-cs .dnc-cs-ten { max-width: 15ch;
                          min-width: min(var(--dnc-cs-dai, 0px), 15ch); }

    /* ── BÓP BỀ NGANG DẢI GOM — Boss chốt 08/09/2026 ───────────────────────────
       > *"tôi đề nghị bạn thiết kế sao cho nút thật gọn và bé lại dùng được và ko
       >  bị quá to chiếm diện tích như bây giờ"*
       Đo trước khi sửa (390×844, màn Công việc): dải cao **155px**, ba hàng, và
       nội dung thật mãi y=371 — 44% chiều cao màn đã bị đầu màn ăn mất.

       ⛔⛔ CHIỀU CAO 44px GIỮ NGUYÊN, TUYỆT ĐỐI KHÔNG HẠ. Dòng 1126 ghi rõ vì sao:
          *"Trước đây nút cao ~38px, cô Quỳnh bấm hay trượt sang nút bên cạnh."*
          Hạ chiều cao là dựng lại đúng lỗi Boss đã kêu. Chỗ béo thật nằm ở BỀ NGANG:
          `padding: 11px 14px` cho mỗi nút, mà bề ngang thừa thì không ai bấm vào,
          nó chỉ đẩy nút cuối hàng rơi xuống dòng dưới. Bóp ngang → bớt HÀNG →
          bớt 44px một phát, nhiều hơn mọi cách gọt chiều cao mà không mất gì.

       ⛔ `font-size:12.5px` ở đây KHÔNG phá luật "13,5px đã chốt" trong
          `thiet-ke/BANG-MAU-VA-CHU.md` — con số ấy là của **thanh công cụ DỌC**
          (cột biểu tượng bên trái, dòng 90 của bảng), không phải dải gom nằm ngang.

       ⛔ Số 19 dưới đây KHÔNG phải cảm tính. Dải là flex-wrap gồm ĐÚNG BỐN khối:
          [← + tên công cụ] 124px · [Cơ sở] 126 · [Xem: Giáo vụ] 140 ·
          [Xem dạng sheet + Thùng rác] 232. Hàng chứa được 360px (390 trừ 2×8 lề,
          trừ 2×7 đệm). Hàng 1 ôm hai khối đầu (257) — còn hàng 2 cần 140+232+7 =
          **379**, THỪA 19px, nên khối cuối rơi xuống hàng ba. Gọt đúng 19px thừa ấy
          là ba hàng còn hai, bớt hẳn 51px mà không ai mất gì. */
    /* ⛔ `gap:5px` LÀ BẮT BUỘC, không phải trang trí — 08/09/2026
       Chụp màn Công việc thấy nút "Thùng rác" ra thành «🗑Thùng rác», icon DÍNH
       chữ. Lý do: icon dùng lớp `icx-*` (bản KHÔNG chừa lề phải, xem dòng ~6252),
       và `display:inline-flex` ở đây đã xoá luôn cách xếp theo dòng chữ vốn tự
       chừa khoảng trắng. Nút cùng dải mà dùng `ic-*` thì lại có lề — nên không có
       `gap` là hai nút cạnh nhau trông khác hẳn nhau. */
    .dnc-dai .nut-nho {
      min-height: 36px; height: 36px; padding: 0 10px; font-size: 12.5px;
      display: inline-flex; align-items: center; justify-content: center; gap: 5px;
    }

    /* ⛔ NÚT QUAY VỀ CÒN SÓT Ở MÀN GIỜ TRỢ GIẢNG — 08/09/2026
       Boss: *"bỏ nút quay về đi"*. Tôi ẩn `.nut-ve-home` và tưởng xong, nhưng chụp
       màn Giờ trợ giảng vẫn thấy một nút ← ở góc trái: nó là `<button class="nut-nho">
       ← Quản lý tài khoản</button>`, KHÔNG mang lớp `.nut-ve-home` nên luật kia
       không với tới. Nó còn chỉ rộng 33px — dưới cả ngưỡng đích bấm 34px.
       ⛔ Đường về vẫn còn nguyên: ngăn kéo ☰ mở được mọi công cụ, thanh đáy có nút
          Trang chủ. Đây cũng đúng lý do đã bỏ `.nut-ve-home`.
       ⛔ Bắt theo VỊ TRÍ (con trực tiếp của `.dau-lop`) chứ CSS không đọc được chữ
          "←". Ai định đặt một nút có ích vào `.dau-lop` thì phải sửa luật này trước,
          không thì nút ấy vô hình trên điện thoại mà không báo gì. */
    .dnc-dai .dau-lop > .nut-nho { display: none !important; }

    /* ⛔ HAI NÚT ĐẾM Ở MÀN CHĂM SÓC — 29px, thấp hơn chuẩn chung
       "còn 166 em chưa liên hệ" / "chưa trao đổi" là nút bấm thật (lọc danh sách),
       nhưng cao 29px giữa một dải toàn 36px: vừa lệch nhìn thấy được, vừa hụt đích
       bấm. Đưa về đúng chuẩn. */
    .dnc-dai .cs-con-thieu {
      min-height: 36px; padding: 5px 11px;
      display: inline-flex; align-items: center; gap: 5px;
    }
    .dnc-cs { padding: 0 9px; gap: 5px; }
    /* `.nv-thanh` là MỘT khối gồm nhiều nút — nó rơi xuống hàng cả cụm, nên khe bên
       trong nó cũng tính vào bài toán bề ngang. */
    .dnc-dai .nv-thanh { gap: 6px; }
    /* ③ HÀNG BỐN NÚT — hàng 1 [nút xanh] · hàng 2 [ô tìm][bộ lọc][làm mới]
       → đọc trái→phải, trên→dưới ra ĐÚNG thứ tự cô Quỳnh chốt. Không phải hỏi cô.
       ⛔ Ô tìm nhận `flex: 1 1 230px` chứ KHÔNG phải `100%`: lấy trọn hàng thì nút
          "Làm mới" bị đẩy hẳn xuống dòng ba, tốn thêm 52px chiều cao cho đúng một
          nút (ảnh đo 29/08). 230px vẫn đủ rộng để gõ, mà ba món về chung một hàng
          trên màn 390px. Không vừa thì flex tự cho xuống dòng — không cắt gì cả. */
    .dnc-hang-trai { gap: 7px; margin: 0 0 9px; align-items: center; }

    /* ⛔⛔ NÚT XANH THÔI TRẢI HẾT HÀNG — Boss: *"Nút tạo block nhân viên bị to chiếm
       diện tích và thiếu thẩm mĩ"*.
       Đây là LẦN THỨ HAI Boss chê đúng chuyện này. Lần đầu 21/08/2026, cũng gửi ảnh:
       *nút "Giao việc cho …" trải nguyên bề ngang màn hình như một dải màu, nhìn rất
       thô* — chỗ ấy đã phải chặn riêng bằng `.nv-ng-thanh > button` (~dòng 5523).
       Gốc rễ: `.nut-chinh` khai `width:100%` vì nó vốn là nút "Đăng nhập" ở đáy màn
       đăng nhập, rồi được dùng lại khắp nơi. Nay chặn hẳn tại vỏ dùng chung này,
       khỏi phải đi chặn lần thứ ba ở màn thứ ba.
       ⛔ `width:auto` một mình KHÔNG đủ — `flex:1 1 100%` vẫn kéo nó ra. Phải hạ cả
          `flex-basis` về `auto` và cấm nở. */
    .dnc-hang-trai > .nut-chinh {
      flex: 0 1 auto; width: auto; max-width: 100%;
      height: 36px; min-height: 36px; padding: 0 13px; font-size: 13px;
      justify-content: center;
    }

    /* Ô tìm + Bộ lọc + Làm mới — cùng 36px cho thẳng hàng.
       ⛔ CỠ CHỮ Ô NHẬP GIỮ 16px, TUYỆT ĐỐI KHÔNG HẠ. Xem chú thích dài ở dòng ~1229:
          Safari iPhone tự phóng to cả trang khi bấm vào ô nhập có chữ dưới 16px, và
          KHÔNG tự thu lại. Boss đã kêu đúng chuyện đó: *"mỗi lần ấn vào ô điền số là
          lại bị zoom gần vào rất khó chịu"*. Ô trông "to" là do ĐỆM, nên bóp đệm và
          chiều cao — không đụng cỡ chữ. */
    /* ⛔ 180px CHỨ KHÔNG PHẢI 230px — con số này sửa một lỗi ĐO SÓT của chính tôi.
       Tôi đo đầu màn ở đúng 390px rồi kết luận "hai hàng, xong". Boss gửi ảnh máy
       mình thì nút "Làm mới" nằm hẳn một hàng riêng. Đo lại ở năm bề ngang máy thật
       (320 · 360 · 390 · 414 · 430) mới thấy: từ **360px trở lên** mới là hai hàng,
       còn **320px (iPhone SE, và mọi máy cỡ ấy) là BA hàng** — tốn thêm 43px.
       Nguyên nhân: [ô tìm 230][Làm mới 94] cộng khe = 331 > 296 chỗ có ở màn 320.
       Hạ mốc xuống 180 thì vừa ở mọi bề ngang; ô tìm vẫn NỞ hết chỗ thừa (`flex-grow`
       bằng 1) nên ở máy rộng nó không hề nhỏ đi.
       ⛔ ĐO MỘT BỀ NGANG RỒI KẾT LUẬN LÀ TỰ LỪA MÌNH. Chỗ gãy luôn nằm ở bề ngang
          khác — lần sau quét cả dải 320→430. */
    .dnc-hang-trai > .bl-timhang { flex: 1 1 180px; min-width: 0; max-width: none;
                                   gap: 7px; align-items: center; }
    /* ⛔ `margin: 0 !important` KHÔNG phải cho đẹp mã. Ô tìm nằm TRONG vỏ `.bl-timhang`
       mang sẵn lề `8px 0 4px` từ luật chung, mà luật dọn lề ở dòng ~8364 chỉ bắt con
       TRỰC TIẾP của `.dnc-hang-trai` nên không với tới. Hậu quả: ô cao đúng 36px mà
       cả hàng vẫn 48px — đo mới thấy, nhìn thì tưởng luật không ăn. */
    .dnc-hang-trai .bl-timhang > input,
    .dnc-hang-trai > input.o-tim-dep,
    .dnc-hang-trai > input[id$="Tim"] {
      flex: 1 1 180px; min-width: 0; max-width: none; margin: 0 !important;
      height: 36px; padding: 0 12px; font-size: 16px;
    }
    /* Làm mới là nút ÍT QUAN TRỌNG NHẤT ở hàng này — Boss nói thẳng. Nên nó nhận
       phần chỗ nhỏ nhất: không nở, đệm hẹp, chữ nhỏ hơn nút xanh một bậc.
       ⛔ Vẫn GIỮ CHỮ "Làm mới", không rút thành mỗi biểu tượng. Ẩn chữ bằng CSS là
          máy đọc màn hình mất tên nút (nút không có `aria-label`), mà đây là nút ai
          cũng bấm nhầm nhất nếu không đọc được. Nhỏ đi thì được, câm thì không. */
    /* ⛔ `.bl-timhang > button` KHÔNG với tới nút "Bộ lọc": nó nằm sâu thêm một tầng,
       trong vỏ `.bl-locvo` (vỏ ấy giữ bảng lọc neo vào, đừng tháo — xem chú thích
       ~8359). Phải bắt theo hậu duệ, không phải con trực tiếp. Đo được: nút vẫn
       89×44 trong khi ô tìm cạnh nó đã 36 — hàng gãy đúng chỗ dễ thấy nhất. */
    .dnc-hang-trai > .nut-nho,
    .dnc-hang-trai .bl-timhang .nut-nho {
      flex: 0 0 auto;
      height: 36px; min-height: 36px; padding: 0 11px; font-size: 12.5px;
      display: inline-flex; align-items: center; justify-content: center;
    }
    .dnc-hang-trai .bl-locvo { flex: 0 0 auto; height: 36px; }

    /* ── Ô TÌM ĐƯỢC TRỌN MỘT HÀNG, "LÀM MỚI" LÊN NẰM CẠNH NÚT XANH ─────────────
       Chụp lại ở 360px mới thấy: ô tìm chỉ còn **148px** và cắt cụt chữ gợi ý
       ("Tìm (lớp · giáo viê…"), trong khi nút "Làm mới" — thứ Boss nói *"ko quan
       trọng nhất"* — chiếm 94px ngay cạnh nó. Thứ dùng nhiều nhất lại được ít chỗ
       nhất: sai thứ tự ưu tiên.
       Đổi lại: hàng 1 [nút xanh] … [Làm mới dạt hẳn phải] · hàng 2 [ô tìm][Bộ lọc]
       trọn bề ngang → ô tìm từ 148px lên ~250px, mà vẫn đúng HAI hàng.

       ⛔ `:has(> .nut-chinh)` KHÔNG phải để cho sang. Màn nào KHÔNG có nút xanh
          (Chăm sóc HS · Thông tin HS) thì ba món [ô tìm][Bộ lọc][Làm mới] vốn đã
          vừa MỘT hàng 36px. Đẩy "Làm mới" lên hàng riêng ở đó là đẻ thêm một hàng
          trống — tự làm tệ đi đúng chỗ đang tốt. Nên luật này chỉ áp cho màn CÓ nút
          xanh. Trình duyệt nào cũng hiểu `:has` từ 2023, và app đã dùng nó sẵn ở
          `.noi-dung:has(.lt-fullw)`. */
    .dnc-hang-trai:has(> .nut-chinh) > .nut-nho {
      order: 2; margin-left: auto !important;
    }
    .dnc-hang-trai:has(> .nut-chinh) > .bl-timhang,
    .dnc-hang-trai:has(> .nut-chinh) > .bl-locvo,
    .dnc-hang-trai:has(> .nut-chinh) > input.o-tim-dep,
    .dnc-hang-trai:has(> .nut-chinh) > input[id$="Tim"] { order: 3; }
    .dnc-hang-trai:has(> .nut-chinh) > .bl-timhang,
    .dnc-hang-trai:has(> .nut-chinh) > input.o-tim-dep,
    .dnc-hang-trai:has(> .nut-chinh) > input[id$="Tim"] { flex: 1 1 100%; }

    /* ④ DẢI MỤC MÀN CHĂM SÓC HỌC SINH — bốn nút, mỗi nút CHIẾM TRỌN MỘT HÀNG.
       Đo được: 188 · 174 · 196 · 157px, mà hàng chỉ chứa 360 → 188+174 = 362, hụt
       đúng 2px nên không cặp nào ghép được, thành bốn hàng = 160px. Đây là màn tốn
       đầu màn nhất trong chín màn (51% chiều cao). Bóp đệm và cỡ chữ cho hai nút
       ghép được một hàng → 160px còn ~80px.
       ⛔ Và nâng 34px lên 36px cho khớp chuẩn chung — bốn nút này còn THẤP HƠN cả
          mức cũ, đúng chỗ `thu-thanh-nut-cong-cu` mục ⑨ đang đòi ≥36px. */
    /* ⛔ LƯỚI HAI CỘT, không phải flex-wrap. Bốn nhãn ở đây dài ngắn khác nhau
       (166 · 154 · 173 · 139px), nên xếp kiểu flex thì ở màn 320px không cặp nào
       ghép nổi một hàng → BỐN hàng, dải phình lên 315px (55% màn). Lưới hai cột
       cho mỗi nút đúng nửa hàng, chữ nào dài thì XUỐNG DÒNG chứ không bị cắt —
       nên vẫn đọc đủ. Đo: màn 320px từ 4 hàng còn 2. Màn 390px không đổi (vốn đã
       2 hàng), nên không đánh đổi gì. */
    .dnc-dai .cs-muc-bar { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
    .dnc-dai .cs-muc-b {
      height: auto; min-height: 36px; padding: 5px 9px; font-size: 12.5px;
      display: inline-flex; align-items: center; justify-content: center;
      text-align: center; line-height: 1.25;
    }

    /* ⑤ MÀN GIỜ TRỢ GIẢNG — màn tốn đầu màn nhất trong cả app: đo được **52%**
       chiều cao màn 844px trước khi thấy dòng dữ liệu đầu tiên.
       Hai họ điều khiển riêng của nó lệch chuẩn chung: đầu nút thả `<details>` cao
       **34px** (theo chuẩn máy tính ở ~7800) và ô chọn `<select>` cao **41px**. Ba
       thứ 34/36/41 đứng cạnh nhau là hàng nút gãy — đúng cái Boss gọi là thiếu
       "đồng nhất". Kéo cả hai về 36px.
       ⛔ `<select>` GIỮ CỠ CHỮ 16px như ô nhập. Safari iPhone phóng to trang khi bấm
          vào cả `<select>` chữ nhỏ, không riêng `<input>`. */
    .dnc-dai .gtg-thanh > .gtg-gom > summary,
    .dnc-dai .gtg-tha > summary,
    .dnc-dai .gtg-thanh > button,
    .dnc-dai .gtg-thanh > a {
      height: 36px; min-height: 36px; padding: 0 11px;
      box-sizing: border-box; display: inline-flex; align-items: center;
    }
    .dnc-dai .gtg-thanh { gap: 7px; }
    /* ⛔ `flex-basis:100%` ở đây là để BỚT một hàng, không phải cho rộng.
       Khối này gồm [ô chọn lớp 200px] + [dòng đếm "127/127 lớp" 67px]. Nó tự co
       về 250px nên dòng đếm phải xuống dòng — mà hàng của dải còn thừa 110px bỏ
       không. Cho nó dùng trọn hàng thì hai món về chung một dòng: 59px còn 36px. */
    .dnc-dai .gtgb-loc { gap: 7px; flex: 1 1 100%; align-items: center; }
    .dnc-dai select, .dnc-dai select.nv-in {
      height: 36px; min-height: 36px; padding: 0 9px; font-size: 16px;
      box-sizing: border-box;
    }

    /* ══ ⑥ CHUẨN 36px ÁP CHO CẢ RUỘT MÀN CÔNG CỤ, KHÔNG CHỈ ĐẦU MÀN ═══════════
       Boss xem bản đầu rồi bác tiếp:
       > *"nhìn các công cụ vẫn ko hề gọn lại và các nút vẫn to đùng rất chiếm
       >  diện tích"* (gửi ảnh màn Dự giờ và Follow up)

       Tôi đã sửa đúng hai cái vỏ ĐẦU MÀN rồi tưởng là xong. Chụp lại đúng như Boss
       nhìn thì lộ ra: các nút NẰM DƯỚI đầu màn vẫn nguyên 44px — *"Lưu đoạn đang gõ
       thành mẫu"* 234×44, *"Hiện thêm"*, … Chúng ăn luật chung ở dòng ~1126
       (`.nut-nho … { min-height:44px; padding:11px 14px }`), không dính gì tới hai
       cái vỏ tôi sửa. Nên với Boss thì màn "vẫn y như cũ" — và Boss đúng.

       ⛔ KHOANH VÀO `body.man-cong-cu`, ĐỪNG ĐỔI THẲNG LUẬT 1126. Luật ấy phủ CẢ APP
          trên điện thoại, kể cả màn Điểm danh — nơi trợ giảng gõ điểm từng ô, bấm
          trượt là hỏng dữ liệu thật. Boss nói về **các công cụ**, nên chỉ đổi trong
          màn công cụ. Điểm danh và Trang chủ giữ nguyên 44px.
       ⛔ 36px là SÀN — xem lời dặn dài ở đầu khối. Bù bằng khe giữa các nút, không
          hạ tiếp.
       ⛔ Đệm `6px 11px` chứ không phải `0 11px`: nút nào chữ dài phải xuống được hai
          dòng mà không bị cắt. `min-height` lo phần cao tối thiểu. */
    body.man-cong-cu .noi-dung .nut-nho,
    body.man-cong-cu .noi-dung .nut-chinh,
    body.man-cong-cu .noi-dung .nut-molai,
    body.man-cong-cu .noi-dung .nut-phieu,
    body.man-cong-cu .noi-dung .nut-caption,
    body.man-cong-cu .noi-dung .chip {
      min-height: 36px; padding: 6px 11px; font-size: 12.5px;
    }

    /* ⛔ NÚT CÓ ICON — chỗ `min-height` KHÔNG cứu được, 08/09/2026
       Nút "Thêm lần" ở màn Follow up đo ra 90×46 dù `min-height:36px` và
       `box-sizing:border-box` đều đúng. Lý do: nút vẫn là `inline-block`, nên icon
       `<i class="ic-them">` bên trong xếp theo ĐƯỜNG CHỮ (baseline) như một chữ cái.
       Icon cao 15px đứng trên đường ấy làm hộp dòng phồng lên 32px, cộng đệm 12 và
       viền 2 thành 46px. Đây là NỘI DUNG đẩy cao, không phải đệm — nên bóp `padding`
       hay đặt `height` đều không phải cách chữa đúng.
       ⛔ Chỉ bắt nút CÓ icon (`:has(> i)`), đừng đổi `display` của mọi nút: `.chip`
          có chỗ nằm lẫn trong dòng chữ, đổi thành flex là nó rơi khỏi dòng. */
    body.man-cong-cu .noi-dung .nut-nho:has(> i),
    body.man-cong-cu .noi-dung .nut-nho:has(> svg),
    body.man-cong-cu .noi-dung .nut-chinh:has(> i),
    body.man-cong-cu .noi-dung .nut-chinh:has(> svg),
    body.man-cong-cu .noi-dung .nut-molai:has(> i),
    body.man-cong-cu .noi-dung .nut-phieu:has(> i),
    body.man-cong-cu .noi-dung .nut-caption:has(> i) {
      display: inline-flex; align-items: center; justify-content: center; gap: 5px;
      white-space: nowrap;
    }

    /* ⛔ Ô TÌM NẰM TRONG RUỘT MÀN — 08/09/2026
       Luật hàng bốn nút ở trên chỉ với tới ô tìm nào nằm trong `.dnc-hang-trai`.
       Bốn màn (Progress test · Việc của tôi · Lịch thi · Yêu cầu GV) đặt ô tìm thẳng
       trong ruột, nên chúng còn nguyên 45px trong khi mọi thứ quanh đó đã 36px.
       ⛔ Cỡ chữ giữ 16px — dưới ngần ấy là Safari iPhone tự phóng to cả trang.
       ⛔ Không bóp bề ngang ô tìm: Boss chê NÚT to, còn ô để gõ thì rộng mới dễ dùng. */
    body.man-cong-cu .noi-dung input.o-tim-dep,
    body.man-cong-cu .noi-dung input[type="search"] {
      height: 36px; min-height: 36px; padding: 0 11px;
      font-size: 16px; box-sizing: border-box;
    }

    /* ⛔ NÚT XANH TRONG RUỘT MÀN CŨNG KHÔNG ĐƯỢC TRẢI HẾT BỀ NGANG
       Màn Lịch thi có nút "Thêm tháng" đo ra 44×336 — nguyên bề ngang màn, đúng thứ
       Boss chê hai lần (21/08 và 08/09). Gốc rễ là `.nut-chinh` khai `width:100%` vì
       nó vốn là nút "Đăng nhập" ở đáy màn đăng nhập.
       ⛔ Đừng đổi `.nut-chinh` ở gốc — màn đăng nhập cần nguyên `width:100%` ấy.
       ⛔ PHẢI có `height:auto`: `.nut-chinh` còn khai `height:44px` CỨNG (cùng khối,
          nhưng ở dòng khác nên `grep ".nut-chinh.*height"` KHÔNG ra — tôi đã mất bốn
          lượt đo vì tin cái grep ấy). `min-height` và `padding` không đè nổi `height`,
          nên nút "Thêm tháng" cứ 44px dù mọi thứ khác đã 36. Cách soi dứt điểm là hỏi
          CSSOM: duyệt `document.styleSheets`, lọc `e.matches(r.selectorText)`. */
    body.man-cong-cu .noi-dung .nut-chinh {
      width: auto; max-width: 100%; height: auto;
    }
  }

  /* ── ⑧ BẢN IN ──────────────────────────────────────────────────────────────────
     Dòng 3439 đã ẩn `.thanh-tren` khi in; dải, bảng thả và hàng bốn nút cũng phải ẩn
     theo, không thì chúng in ra giữa tờ giấy. NHƯNG ẩn dải là mất luôn tên cơ sở đang
     xem — người cầm tờ giấy không có cách nào biết. Nên JS chèn thêm một dòng phụ
     `.dnc-chi-in` trong ruột màn, chỉ hiện khi in.
     ⛔ Viết @media print RIÊNG ở đây thay vì sửa dòng 3439 — bớt một chỗ đụng vào mã cũ. */
  @media print {
    .dnc-dai, .dnc-tha, .dnc-hang-trai { display: none !important; }
    .dnc-chi-in { display: block !important; margin: 0 0 8px; font-size: 12px; color: #444; }
  }
  .dnc-chi-in { display: none; }

  @media (prefers-reduced-motion: reduce) {
    /* JS tự bỏ qua hẳn hiệu ứng; luật này chỉ để chắc thêm một lớp. */
    .dnc-dai, .dnc-dai > .dnc-hang { transition: none !important; }
  }


/* ════════════════════════════════════════════════════════════════════════════════

  /* ── ✂️ Câu dẫn giải dài: rút còn một dòng, nút ⓘ mở ra xem đủ (29/08/2026) ──
     Phần dựng nút do JS lo (xem `ccRutChuDan`); đây chỉ là hình dáng.
     ⛔ Cắt cái `<span>` BÊN TRONG, không cắt thẻ ngoài — nút ⓘ phải nằm ngoài vùng
        bị cắt, không thì chính nó bị ẩn đi và câu không mở ra được nữa. */
  .chu-rut { display: inline-flex; align-items: baseline; gap: 6px; max-width: 100%; }
  .chu-rut .chu-rut-noi {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 44ch;
  }
  .chu-rut.chu-rut-mo .chu-rut-noi { white-space: normal; max-width: none; }
  .chu-rut-i {
    flex: 0 0 auto; width: 18px; height: 18px; padding: 0; line-height: 1;
    font-size: 11.5px; cursor: pointer; border-radius: 50%;
    border: 1px solid var(--vien); background: var(--the); color: var(--mo);
  }
  /* Icon vector thay chỗ ký tự ⓘ — 14px chẵn để mép vòng tròn rơi đúng điểm ảnh.
     Nút chỉ có icon nên phải bật `flex` canh giữa: trước đây ký tự tự canh theo dòng chữ,
     đổi sang thẻ `<i>` mà không canh lại là icon dính lệch lên trên. */
  .chu-rut-i { display: inline-flex; align-items: center; justify-content: center; }
  .chu-rut-i > i { width: 14px; height: 14px; margin: 0; vertical-align: 0; }
  .chu-rut-i:hover { color: var(--chu); border-color: var(--mo); }
  .chu-rut-i:focus-visible { outline: 2px solid var(--xanh); outline-offset: 1px; }
  @media (max-width: 700px) { .chu-rut .chu-rut-noi { max-width: 26ch; } }

  /* ══════════════════════════════════════════════════════════════════════════
     🗺️ LỘ TRÌNH HỌC — bảng tuần × lớp (09/09/2026)
     ──────────────────────────────────────────────────────────────────────────
     Boss muốn *"vẫn giữ được cảm giác của tờ Sheet"* mà không lạc khỏi app. Nên:
     nền trắng · vạch kẻ mảnh cả hai chiều · đầu bảng dính khi cuộn · cột "Lớp"
     đứng yên khi cuộn ngang · dòng cao 30px y như bảng sổ tuyển sinh.
     ⛔ TỰ CÓ TÊN LỚP RIÊNG `.lt2-*`, KHÔNG mượn `.cts-*`. Mượn là mai kia ai đổi
        bảng tuyển sinh thì bảng này xê theo mà không ai ngờ tới.
     ⛔ 30px LÀ CON SỐ CÓ Ý: nó khớp `.cts-bang td`, và đợt sau cuộn ảo sẽ tính
        theo đúng số này. Đổi ở đây là đợt sau lệch dòng.
     ══════════════════════════════════════════════════════════════════════════ */
  .lt2-dau { display:flex; flex-direction:column; align-items:flex-start; gap:6px; margin-bottom:7px; }
  .lt2-ten { display:flex; align-items:center; flex-wrap:wrap; gap:8px; }
  .lt2-ten h2 { margin:0; font-size:17px; font-weight:700; }
  .lt2-nhan { font-size:12px; color:var(--mo); border:1px solid var(--vien);
    border-radius:var(--r-sm, 4px); padding:2px 7px; background:var(--the); }
  .lt2-nhan-mo { border-style:dashed; }
  .lt2-nhan-cho { color:var(--cam-dam); border-color:var(--cam); background:#FFF6EC; }
  /* ⛔ GOM KHÔNG PHẢI LÀ BỚT: dải nút CUỘN NGANG trên máy hẹp, không nút nào bị giấu. */
  .lt2-nut { display:flex; align-items:center; gap:7px; flex-wrap:nowrap;
    overflow-x:auto; max-width:100%; padding-bottom:2px; }
  .lt2-nut > * { flex:0 0 auto; }
  .lt2-loc { display:flex; gap:7px; flex-wrap:wrap; align-items:center; margin-bottom:7px; }
  .lt2-loc select, .lt2-loc input[type=text], .lt2-loc .lt2-tim {
    font-family:inherit; font-size:12.5px; padding:5px 8px; min-height:30px;
    border:1px solid var(--vien); border-radius:var(--r-o, 8px);
    background:var(--the); color:var(--chu); }
  .lt2-loc .lt2-tim { flex:0 1 320px; min-width:200px; }
  .lt2-dem { font-size:12px; color:var(--mo); }

  .lt2-cuon { overflow:auto; max-height:calc(100vh - 210px); border:1px solid var(--vien);
    border-radius:var(--r-sm, 4px); background:var(--the); }
  .lt2-bang { border-collapse:separate; border-spacing:0; table-layout:fixed; font-size:12.5px; }
  .lt2-bang th, .lt2-bang td { border-right:1px solid var(--vien);
    border-bottom:1px solid var(--vien); padding:2px 6px; height:30px;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap; vertical-align:middle; }
  .lt2-bang thead th { position:sticky; top:0; z-index:4; font-weight:700;
    background:var(--dau-bang-nen, var(--nen)); color:var(--dau-bang-chu, var(--chu));
    text-align:left; }
  /* Cột "Lớp" đứng yên khi cuộn ngang — chỗ duy nhất giáo vụ dùng để dò dòng.
     ⛔⛔ BỎ `border-right: 2px solid var(--muc)` — 12/09/2026, ĐỪNG KHÔI PHỤC.
     Dòng ấy chính là thứ làm Lộ trình đạt 4,36:1 hồi ba màn kia mới có 1,80, nên
     nó đã làm xong việc của mình: nay LUẬT CHUNG `.sheet-cot-gham-cuoi` vẽ đúng
     vạch 2px màu `--muc` ấy cho MỌI bảng dạng Sheet (xem khối ① ở dòng ~11378).
     Giữ lại là vẽ HAI LẦN: 2px viền + 2px bóng = vạch 4px, riêng Lộ trình đậm
     gấp đôi chỗ khác — đo được đúng 4px ở cả 5 khổ ngày 12/09.
     ⇒ Bỏ đi thì ô này rơi về đúng nét kẻ chung `1px solid var(--sheet-ke)` như
       Dự giờ · Chăm sóc · Follow up · Sổ tuyển sinh (đã đo: cả bốn đều vậy),
       còn vạch ranh giới thì luật chung lo.
     ⛔⛔ GIỮ NGUYÊN `2px`, CHỈ ĐỔI MÀU — đừng hạ xuống `1px` và cũng đừng xoá hẳn
        dòng viền. Đã thử cả hai và ĐO:
          · xoá hẳn (rơi về nét kẻ chung 1px) → cột tụt từ 296,328px xuống
            295,328px. `box-sizing: border-box` KHÔNG cứu được vì bề rộng ô này do
            nội dung quyết chứ không phải do `width` khai ở đây (296 ≠ 126).
          · `transparent` → giữ đúng bề rộng, nhưng ở khổ hẹp lúc KHÔNG ghim thì
            cột này mất sạch nét kẻ trong khi mọi cột khác vẫn có.
        `var(--sheet-ke)` được cả hai: đúng 2px như cũ (không xê dịch pixel nào) và
        vẫn là một nét kẻ thật khi bảng không ghim. */
  .lt2-bang .lt2-g1 { position:sticky; left:0; z-index:3; width:126px;
    background:var(--the); border-right:2px solid var(--sheet-ke, var(--vien)); }
  .lt2-bang thead .lt2-g1 { z-index:6; background:var(--dau-bang-nen, var(--nen)); }
  .lt2-bang tbody tr.le > td { background:var(--nen); }
  .lt2-bang tbody tr.le .lt2-g1 { background:var(--nen); }
  /* ══ 19/09/2026 — GHĂM THÊM CƠ SỞ VÀ THỨ·GIỜ (Boss chốt: "Ghăm Lớp + Cơ sở +
     Thứ·Giờ"). Đo lượt trước khi sửa: hai cột này là `static`, kéo ngang 900px thì
     trôi ra ngoài màn (192px → -708px và 342px → -558px) — đó chính là cảnh Boss
     gọi là "cột cố định ko đi theo".
     ⛔ MỐC `left` LÀ BIẾN, KHÔNG PHẢI SỐ GÕ CỨNG: ba cột này kéo rộng được, nên mốc
        đổi theo mỗi cú kéo. `lt2DatMocGhim()` đo bề rộng thật rồi ghi vào
        `--lt2-ghim1/2`. Gõ cứng 126px/214px là sau một cú kéo thì ba cột ghăm vẽ
        chồng lên nhau — đúng lỗi "cột trèn lên nhau" Boss chê ở Sổ tuyển sinh.
     ⛔ CHỈ GHĂM KHI `data-lt2-ghim="day"`. Trên điện thoại cả dải chiếm 85%
        bề ngang màn, ghăm hết thì còn đúng một mẩu để cuộn — JS hạ xuống "1" và chỉ
        cột Lớp còn ghăm. (Bộ Sheet chung cũng bỏ ghăm khi dải > 55% khung.)
     ⛔ NỀN PHẢI ĐẶC, kể cả hàng lẻ: ghăm mà nền trong suốt thì chữ cột tuần chạy
        xuyên qua — nhìn ra đúng cảnh "cột trèn lên nhau". */
  /* ⛔⛔ CỘT **TẦNG** NẰM GIỮA DẢI, PHẢI GHĂM THEO — đo 19/09 mới ra. Hàng đầu của
     tiêu đề là `lt2-g1 · lt2-c-coso · lt2-c-tang · lt2-c-lich`; bỏ Tầng ra thì nó
     trôi đi để lại lỗ trắng, còn Thứ·Giờ tụt lùi 62px và đè lên nó. Ghăm là ghăm CẢ
     DẢI LIỀN, không nhặt cột. */
  .lt2-bang[data-lt2-ghim="day"] .lt2-c-coso {
    position:sticky; left:var(--lt2-ghim1, 126px); z-index:3; background:var(--the); }
  .lt2-bang[data-lt2-ghim="day"] .lt2-c-tang {
    position:sticky; left:var(--lt2-ghim2, 214px); z-index:3; background:var(--the); }
  .lt2-bang[data-lt2-ghim="day"] .lt2-c-lich {
    position:sticky; left:var(--lt2-ghim3, 276px); z-index:3; background:var(--the);
    border-right:2px solid var(--sheet-ke, var(--vien)); }
  .lt2-bang[data-lt2-ghim="day"] thead .lt2-c-coso,
  .lt2-bang[data-lt2-ghim="day"] thead .lt2-c-tang,
  .lt2-bang[data-lt2-ghim="day"] thead .lt2-c-lich {
    z-index:6; background:var(--dau-bang-nen, var(--nen)); }
  .lt2-bang[data-lt2-ghim="day"] tbody tr.le .lt2-c-coso,
  .lt2-bang[data-lt2-ghim="day"] tbody tr.le .lt2-c-tang,
  .lt2-bang[data-lt2-ghim="day"] tbody tr.le .lt2-c-lich { background:var(--nen); }
  /* Ghăm cả dải thì vạch ranh giới 2px chuyển sang cột CUỐI của dải; cột Lớp trả về
     nét kẻ thường, không thì giữa dải có một vạch đậm chẳng ngăn cách gì. */
  .lt2-bang[data-lt2-ghim="day"] .lt2-g1 {
    border-right:1px solid var(--sheet-ke, var(--vien)); }

  /* ── TAY NẮM KÉO RỘNG CHO 11 CỘT THÔNG TIN (19/09/2026) ───────────────────
     Đo lượt trước khi sửa: kéo mép phải tiêu đề cột Lớp cho ra 126px → 126px, không
     đổi một ly. Vì bộ kéo cột dùng chung chỉ gắn tay nắm cho HÀNG CUỐI của tiêu đề,
     mà hàng cuối ở bảng này là 54 cột tuần — 11 cột thông tin nằm ở hàng trên bằng
     `rowspan`, không có tay nắm nào.
     ⛔ Tên lớp `.lt2-nam` CỐ Ý KHÁC `.cot-nam` của bộ chung: bộ chung uỷ quyền theo
        `.cot-nam` và đọc `dataset.i` như chỉ số trong dãy 54 cột tuần. Dùng chung tên
        là mỗi cú kéo cột Lớp lại đi nới một cột tuần nào đó. */
  /* ⛔⛔ ĐỪNG THÊM LẠI `.lt2-bang thead th { position: relative }` VÀO ĐÂY.
     19/09/2026 tôi thêm đúng dòng ấy để tay nắm `.lt2-nam` (`position:absolute`) có
     chỗ neo — và nó ĐÈ CHẾT `position:sticky` của chính bộ chọn ấy ở css:11613 (hai
     luật ngang cơ, cái đứng sau thắng), làm CẢ HÀNG TIÊU ĐỀ mất ghăm dọc: cuộn xuống
     là tên cột biến mất.
     `sticky` cũng là thẻ CÓ ĐỊNH VỊ, nên tay nắm neo vào `th` vẫn đúng mà không cần
     thêm gì. Bắt được nhờ `thu-lo-trinh-lich.js` (41/45), và chứng minh là lỗi MỚI
     bằng cách chạy đúng bài ấy trên worktree ở mốc `1aaad2f`: 45/45. */
  /* ⛔ `right:0`, ĐỪNG ĐỂ `right:-3px`. Thẻ con tràn ra ngoài ô vẫn tính vào
     `scrollWidth`, nên chỉ 3px thò ra là `scrollWidth > clientWidth` và bài kiểm
     "không ô nào bị cắt cụt chữ" đỏ ở đúng năm cột có tay nắm. 9px vẫn đủ rộng để
     trỏ chuột bắt được. */
  .lt2-nam { position:absolute; top:0; right:0; width:9px; height:100%;
    cursor:col-resize; z-index:7; touch-action:none; }
  .lt2-nam::after { content:""; position:absolute; top:4px; bottom:4px; left:3px;
    width:2px; border-radius:2px; background:transparent; transition:background .12s; }
  .lt2-nam:hover::after { background:var(--xanh); }
  /* Đang kéo thì đừng để trình duyệt bôi đen chữ trong tiêu đề — vệt bôi đen lướt
     qua cả hàng nhìn như màn hình lỗi. */
  body.lt2-dang-keo-cot { cursor:col-resize; user-select:none; }
  .lt2-ma { display:block; font-size:10.5px; color:var(--mo); line-height:1.1; }
  .lt2-c-coso { width:88px; }
  .lt2-c-lich { width:118px; }
  .lt2-c-ngay { width:92px; }
  .lt2-c-tt   { width:112px; }
  .lt2-c-nguoi{ width:124px; }
  .lt2-c-lt   { width:168px; }
  .lt2-c-ct   { width:148px; }
  .lt2-c-tuan { width:46px; text-align:center; padding:2px 2px; }
  .lt2-bang thead .lt2-c-tuan { line-height:1.15; }
  .lt2-tuan-so { display:block; font-size:11px; }
  .lt2-tuan-ngay { display:block; font-size:10px; color:var(--mo); font-weight:400; }
  .lt2-o { text-align:center; padding:2px 2px; cursor:pointer; }
  .lt2-o:hover { background:var(--xanh-nhat); }
  .lt2-chip { display:inline-block; min-width:17px; padding:0 3px; margin:0 1px;
    border-radius:var(--r-sm, 4px); background:var(--xanh-nhat); color:var(--xanh-dam);
    font-size:11px; line-height:17px; }
  /* Tuần trùng nghỉ lễ — nền vàng nhạt, KHÔNG che mất số ai đã điền. */
  .lt2-bang .lt2-nghi { background:#FFF8E1; }
  .lt2-bang tbody tr.le .lt2-nghi { background:#FFF4D6; }
  /* ⛔⛔ 10/09/2026 — ĐỔI NỀN THÌ PHẢI ĐỔI CẢ CHỮ. Boss: *"các cột ngày nghỉ đang
     bị khó nhìn ở cái tên tiêu đề nó trắng xoá chữ màu trắng không nhìn được."*
     Ô đầu bảng vốn là NỀN XANH #00793A + CHỮ TRẮNG. Hai luật ngay trên thay nền
     thành kem nhưng KHÔNG đụng chữ, nên chữ trắng nằm trên nền kem — mất sạch.
     ⛔ Chữ ở đây phải GÕ CỨNG, đừng lấy var(--chu): nền kem gõ cứng và giống nhau
        ở cả chế độ sáng lẫn tối, mà var(--chu) chế độ tối trả về chữ SÁNG — vá
        xong sáng đọc được thì tối lại mất, đúng lỗi cũ đổi chỗ. */
  .lt2-bang thead th.lt2-nghi { color:#7A5B00; }
  .lt2-bang thead th.lt2-nghi .lt2-tuan-ngay { color:#9A7B20; }
  .lt2-tt { font-size:11px; padding:1px 6px; border-radius:999px; }
  .lt2-tt-tren { background:var(--xanh-nhat); color:var(--xanh-dam); }
  .lt2-tt-chua { background:var(--nen); color:var(--mo); border:1px dashed var(--vien); }
  .lt2-thieu { color:var(--mo); font-style:italic; }
  .lt2-trong { text-align:center; color:var(--mo); padding:18px 0; white-space:normal; }
  .lt2-chan { font-size:12px; color:var(--mo); margin:7px 0 0; }
  @media (max-width: 700px) {
    .lt2-ten h2 { font-size:15.5px; }
    .lt2-cuon { max-height:calc(100vh - 240px); }
    .lt2-bang .lt2-g1 { width:104px; }
  }

  /* ── Lộ trình học · Đợt 2: sửa ô ngay tại chỗ (09/09/2026) ──────────────────
     Bấm ô là ô hoá thành chỗ gõ, giống hệt tờ Sheet. Chỗ gõ phải VỪA KHÍT ô để
     dòng không nảy lên một nhịp lúc mở — nảy dòng là mất chỗ nhìn của cả bảng. */
  .lt2-c-bt { width:70px; text-align:center; }
  .lt2-sua-boc { display:flex; align-items:center; gap:2px; }
  .lt2-sua { flex:1 1 auto; width:100%; min-width:0; height:24px; padding:0 3px;
    font-family:inherit; font-size:12px; text-align:center;
    border:1px solid var(--xanh); border-radius:var(--r-o, 8px);
    background:var(--the); color:var(--chu); }
  .lt2-sua:focus { outline:2px solid var(--xanh); outline-offset:-1px; }
  /* Nút "Tự tạo" nằm ngay trong ô đang mở — chỗ tay người ta đang ở.
     ⛔ Nút bé hơn ngưỡng 34px CỐ Ý: nó chỉ sống trong lúc ô đang mở, và ô bảng
        cao 30px. Bấm nhầm thì bấm lại, không mất gì. */
  .lt2-tutao { flex:0 0 auto; height:24px; padding:0 6px; font-family:inherit;
    font-size:11px; white-space:nowrap; cursor:pointer;
    border:1px solid var(--vien); border-radius:var(--r-sm, 4px);
    background:var(--nen); color:var(--mo); }
  .lt2-tutao:hover { background:var(--xanh-nhat); color:var(--xanh-dam);
    border-color:var(--xanh); }
  /* Ô mở ra thì rộng thêm để chứa cả chỗ gõ lẫn nút, không bóp chữ thành ba chấm. */
  /* ⛔⛔ 19/09/2026 — THÊM `z-index`. ĐỪNG BỎ.
     Boss: *"tôi thấy nút tự tọa ko thể hiện lên được"*. Đo ra thì nút VẪN VẼ RA
     (48×24px, `display:block`, độ mờ 1, nằm trọn trong màn) — chỉ là bấm vào giữa
     nút thì cú bấm rơi vào một `td.lt2-o` khác. Tức nút hiện mà KHÔNG BẤM ĐƯỢC, và
     với người dùng thì hai chuyện ấy là một.
     Gốc: `.lt2-bang td.lt2-o { position:relative }` cho MỌI ô, mà ô đang mở thì
     không có `z-index` nào — hộp gõ thả xuống dưới đáy ô, đè vào vùng của các ô
     hàng sau, và những ô ấy là phần tử có vị trí đứng SAU trong cây nên vẽ chồng
     lên trên. Cột "Lộ trình dự kiến" đã có `z-index:6` từ trước nên không dính;
     ô số thì bị bỏ quên.
     ⛔ ĐO BẰNG `elementFromPoint`, ĐỪNG ĐO `display`/`opacity`: ba thứ ấy đều đẹp
        trong khi nút đã chết. Xem mục ④ của `do-lt.js`. */
  .lt2-bang td.lt2-o:focus-within { overflow:visible; z-index:8; }
  /* ⭐⭐ 09/09/2026 — Ô ĐANG GÕ NỔI LÊN VÀ NỞ RỘNG. Boss: *"cái ô nhập số nó to ra xíu
     chứ để mặc định thế này bé quá ko nhập đc số"*.
     Cột tuần rộng 46px, mà trong ô lúc mở còn có cả nút "Tự tạo" — chỗ gõ còn lại chưa
     nổi 20px, gõ "26, 27 Trung thu" thì không nhìn thấy mình đang gõ gì.
     ⛔ NỞ BẰNG CÁCH NỔI LÊN TRÊN, TUYỆT ĐỐI KHÔNG NỚI `width` CỦA CỘT. Bảng này 54 cột
        tuần; nới một cột là 54 cột giãn theo và cả bảng hết vừa màn hình.
     ⛔ Neo giữa ô theo cả hai chiều nên HÀNG KHÔNG CAO LÊN — chiều cao 30px của
        `.lt2-bang td` là con số đã chốt, đội hàng lên là cả bảng nhảy một nhịp.
     ⛔ `max-width:60vw` để trên điện thoại hộp không tràn ra ngoài màn. */
  .lt2-bang td.lt2-o { position:relative; }
  /* ⛔⛔ 10/09/2026 — BỎ `width:198px` GÕ CỨNG. Boss báo kèm ảnh: *"cái ô điền số
     khi ấn vào ô đang bị to quá mức nó chỉ to ra theo số lượng chữ hoặc số tôi
     nhập thôi"*. 198px là bề rộng đủ cho câu DÀI NHẤT, nên gõ một chữ "9" cũng nở
     bằng gõ cả câu — hộp trùm qua bốn cột tuần bên cạnh.
     Nay hộp co theo ruột (`width:auto` của một thẻ neo tuyệt đối là "vừa đủ
     ruột"), còn bề rộng chỗ gõ do `lt2CoORong` đo từng chữ mà đặt.
     ⛔ VẪN GIỮ `max-width`, và giữ cả cách nổi lên trên: nới `width` của CỘT thì
        54 cột tuần giãn theo và cả bảng hết vừa màn hình. */
  .lt2-bang td.lt2-o:focus-within .lt2-sua-boc {
    position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
    width:auto; max-width:min(300px, 60vw); z-index:7; padding:3px;
    background:var(--the); border-radius:var(--r-sm, 4px);
    box-shadow:0 2px 10px rgba(0,0,0,.18); }
  /* ⛔ ĐỪNG THÊM `flex:0 0 auto` VÀO ĐÂY "cho chắc" — đã thử và ĐO 10/09/2026:
     đổi `flex` ở luật này cho ra bề rộng Y HỆT (93px lúc gõ một chữ, 208px lúc gõ
     cả câu). Lý do: hộp bọc `.lt2-sua-boc` co theo ruột (`width:auto` của một thẻ
     neo tuyệt đối), nên chỗ gõ chẳng có khoảng thừa nào để giãn vào. Thêm một luật
     không gánh việc gì là để lại một cái bẫy cho lượt sau. */
  .lt2-bang td.lt2-o:focus-within .lt2-sua { height:28px; font-size:13px; text-align:left; }

/* ── 🗺️ Lộ trình học · Đợt 4: hai cột chữ ─────────────────────────────────── */
/* Ô trống mà bấm được thì phải NÓI RA bằng con trỏ, không thì chẳng ai bấm thử. */
.lt2-bang td.lt2-c-lt, .lt2-bang td.lt2-c-ct { cursor: text; }
.lt2-bang td.lt2-c-ct a { color: var(--xanh-dam); text-decoration: none; }
.lt2-bang td.lt2-c-ct a:hover { text-decoration: underline; }
/* Nút sửa của ô Chương trình — xem lời dặn ở `lt2ORuotCT`: thiếu nó thì cột này
   chỉ điền được đúng một lần. Cùng cỡ với nút "Tự tạo" bên ô số, vì cùng nằm
   trong hàng cao 30px và cùng một luật: bấm nhầm thì bấm lại, không mất gì. */
/* ⛔ KHÔNG cho `display:flex` vào `<td>` — ô thôi là ô bảng thì cột hết ăn theo
   `table-layout:fixed` và hàng lệch chiều cao 30px đã chốt. Xếp bằng inline-block. */
/* ⛔⛔ 19/09/2026 — BỎ `max-width: calc(100% - 26px)`. ĐỪNG KHÔI PHỤC.
   Cột này nay chứa NHIỀU viên thuốc (Boss: *"nhập được nhiều đường link"* ·
   **"Viên thuốc, KHÔNG gấp lại"**). Trần ấy viết cho đúng MỘT thẻ chiếm gần trọn ô;
   để nguyên thì viên thứ hai trở đi bị bóp còn vài chữ rồi cụt thành ba chấm — bày ra
   ba viên mà không viên nào đọc được tên.
   Bảng chạy `width: max-content` nên cột tự nới vừa đủ số viên; muốn hẹp lại thì kéo
   tay cột ấy (tay nắm mới thêm cùng ngày, xem `lt2GanKeoCotDinh`). */
.lt2-bang td.lt2-c-ct a.lt2-ct-vien { display: inline-block; vertical-align: middle;
  max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  margin: 0 3px 0 0; padding: 0 8px; line-height: 19px;
  border-radius: 999px; background: var(--xanh-nhat); color: var(--xanh-dam);
  font-size: 11.5px; text-decoration: none; }
.lt2-bang td.lt2-c-ct a.lt2-ct-vien:hover { background: var(--xanh); color: #FFFFFF;
  text-decoration: none; }

/* ⛔⛔ NÚT ✎ PHẢI LUÔN NHÌN THẤY — vá 19/09/2026, lỗi do chính bản vá cùng ngày.
   Bản cũ ghim `max-width: calc(100% - 26px)` cho thẻ liên kết, và 26px ấy chính là
   CHỖ ĐỂ DÀNH cho nút ✎. Gỡ trần ấy đi (vì nhiều viên thì nó bóp mỗi viên còn vài
   chữ) thì các viên ăn hết bề ngang, nút ✎ bị đẩy ra ngoài ô rồi `overflow:hidden`
   cắt mất — bấm không ra hộp sửa nữa, tức cột lại về đúng cảnh "điền được một lần"
   đã phải vá hôm 09/09.
   Nay neo nút TUYỆT ĐỐI ở mép phải ô và chừa sẵn đệm cho nó: viên bày hết từ trái
   sang (đúng chốt **"Viên thuốc, KHÔNG gấp lại"**), nút vẫn nằm nguyên chỗ cũ.
   ⛔ Nền đặc + bóng mảnh bên trái để viên trôi qua dưới nút vẫn đọc được mép nút. */
.lt2-bang td.lt2-c-ct { position: relative; padding-right: 26px; }
.lt2-bang td.lt2-c-ct .lt2-sua-ct {
  position: absolute; right: 2px; top: 50%; transform: translateY(-50%);
  z-index: 2; background: var(--the); box-shadow: -4px 0 6px -2px var(--the); }
.lt2-bang tbody tr.le td.lt2-c-ct .lt2-sua-ct {
  background: var(--nen); box-shadow: -4px 0 6px -2px var(--nen); }

/* ── Hộp sửa cột Chương trình: mỗi dòng một đường dẫn ────────────────────────
   ⛔ Xếp bằng `grid` ba khu để ô đường dẫn và ô tên thẳng hàng qua các dòng — lệch
      hàng thì nhìn ra một mớ ô rời rạc chứ không ra một danh sách. */
.lt2-ct-ds { display: flex; flex-direction: column; gap: 6px; }
.lt2-ct-dong { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) 30px;
  gap: 6px; align-items: center; }
.lt2-ct-dong input { width: 100%; min-width: 0; font: inherit; font-size: 13px;
  padding: 7px 9px; min-height: 36px; border: 1px solid var(--vien);
  border-radius: var(--r-o, 8px); background: var(--the); color: var(--chu); }
.lt2-ct-go { min-height: 30px; width: 30px; padding: 0; cursor: pointer;
  border: 1px solid var(--vien); border-radius: var(--r-sm, 4px);
  background: var(--nen); color: var(--mo); font: inherit; font-size: 13px; }
.lt2-ct-go:hover { color: #C0392B; border-color: #EBC3BD; background: #FDECEA; }
.lt2-ct-them { display: inline-flex; align-items: center; gap: 6px; margin-top: 8px;
  min-height: 34px; padding: 0 12px; cursor: pointer; font: inherit; font-size: 13px;
  border: 1px dashed var(--vien); border-radius: 999px;
  background: none; color: var(--chu); }
.lt2-ct-them:hover:not(:disabled) { border-style: solid; border-color: var(--xanh);
  color: var(--xanh-dam); background: var(--xanh-nhat); }
.lt2-ct-them:disabled { opacity: .5; cursor: default; }
/* Màn hẹp: hai ô xuống hai dòng, nút gỡ nằm cuối — ba khu trên 390px là mỗi ô còn
   hơn trăm điểm ảnh, gõ một đường dẫn không nhìn thấy mình gõ gì. */
@media (max-width: 520px) {
  .lt2-ct-dong { grid-template-columns: minmax(0, 1fr) 30px;
    grid-template-areas: "link go" "ten ten"; }
  .lt2-ct-dong .lt2-ct-link { grid-area: link; }
  .lt2-ct-dong .lt2-ct-go { grid-area: go; }
  .lt2-ct-dong .lt2-ct-ten { grid-area: ten; }
}
.lt2-sua-ct { width: 22px; padding: 0; margin-left: 3px; text-align: center;
  vertical-align: middle; }
/* Ô gõ chữ rộng hơn ô gõ số — lộ trình là một câu, không phải hai con số. */
.lt2-sua-chu { width: 100%; min-width: 90px; text-align: left; }
/* Nút "Áp cho N lớp" phải đọc được cả con số, nên không bóp chữ. */
.lt2-apnhieu { white-space: nowrap; }
/* Bảng chọn lại thứ đã gõ — thay cho <datalist> (Boss đã bác hai lần).
   ⛔ Nổi lên trên bảng chứ không nong ô ra: nong ô là cả hàng cao lên, 54 cột
      tuần bên cạnh giãn theo, mắt người đang dò mất dấu hàng. */
.lt2-goiy {
  position: fixed; z-index: 60;
  max-height: 220px; overflow-y: auto; min-width: 180px; max-width: 320px;
  background: var(--the); border: 1px solid var(--vien);
  border-radius: var(--r-sm); box-shadow: var(--bong-2);
  display: flex; flex-direction: column;
}
.lt2-goiy button {
  display: block; width: 100%; text-align: left; border: 0; background: none;
  padding: 7px 10px; font: inherit; color: var(--chu); cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  min-height: 34px;                 /* ⛔ ngón tay phải chạm trúng — sàn 34px */
}
.lt2-goiy button:hover { background: var(--xanh-nhat); }
/* ⛔⛔ Ô bảng nào cũng `overflow:hidden` để chữ dài cụt thành ba chấm — nhưng khi
   ô ĐANG MỞ RA GÕ thì cái đó cắt mất cả bảng gợi ý lẫn nút "Áp cho N lớp": bấm ▾
   ra danh sách mà không ai nhìn thấy gì. Nhìn ảnh chụp mới ra, `hidden` vẫn false
   nên phép canh cũ xanh oan. Cùng cách chữa với ô số ở Đợt 2. */
.lt2-bang td.lt2-c-lt { position: relative; }
.lt2-bang td.lt2-c-lt:focus-within { overflow: visible; z-index: 6; }
/* ⛔ Nới ô thôi CHƯA ĐỦ: cái bọc bên trong cũng `overflow:hidden`, và chính nó cắt
   cụt nút "Áp cho N lớp" (đo được: nút cần tới 1155px, bọc dừng ở 1117px). Chỉ nới
   ở cột chữ — ô số của Đợt 2 giữ nguyên nếp cũ. */
.lt2-bang td.lt2-c-lt .lt2-sua-boc { overflow: visible; }

/* ⛔⛔ MỘT DÒNG NÀY LÀ THỨ LÀM CHO MỌI `width` CỦA BẢNG CÓ HIỆU LỰC.
   `table-layout:fixed` CHỈ CHẠY KHI BẢNG CÓ BỀ RỘNG CỤ THỂ. Bảng để `width:auto`
   thì trình duyệt lặng lẽ quay về cách đo theo nội dung — `getComputedStyle` vẫn
   trả về "fixed", nên nhìn mã thì tưởng đang chạy. Hậu quả đo được ngày 09/09/2026:
   cột "Lớp" khai 126px chỉ ra 59px, cột "Lộ trình dự kiến" khai 168px ra 114px và
   CẮT CỤT tên lộ trình. Mọi con số width bên trên là mã chết cho tới dòng này.
   ⛔ Đừng đổi thành `100%`: 54 cột tuần bị nhồi vào bề ngang màn hình thì cột nào
      cũng nát. Bảng này vốn để cuộn ngang. */
.lt2-bang { width: max-content; }

/* ══════════════════════════════════════════════════════════════════════════════
   ⭐⭐ CỘT "LỘ TRÌNH DỰ KIẾN" — TỐI ĐA HAI DÒNG RỒI "…"  (Boss chốt 13/09/2026)
   ──────────────────────────────────────────────────────────────────────────────
   Boss: *"cột lộ trình dự kiến tối đa 2 dòng rồi …, bấm vào mở đủ và … biến mất"*.

   ĐO TRƯỚC KHI SỬA (khổ 1400, lộ trình thật 59 ký tự):
     · cột khai `width: 168px` mà ĐO RA **349px** — và 349px ở CẢ khổ 390 lẫn 1400.
     · chữ nằm gọn MỘT dòng, `scrollWidth === clientWidth` nên không hề "bị cắt".
   Vì sao: `.lt2-bang { width: max-content }` ngay trên. Với `max-content`, bề rộng
   bảng tính theo nội dung KHÔNG XUỐNG DÒNG (`white-space: nowrap` của `.lt2-bang
   td`), nên một lộ trình dài kéo NGUYÊN CỘT rộng ra theo nó. Con số `168px` khai
   ở `.lt2-c-lt` vẫn khớp — CDP xác nhận — nhưng nó thua `max-content`.
   ⛔ ĐỪNG đi gỡ `width: max-content`: chú thích ngay trên đã ghi vì sao nó phải ở
      đó (bảng 54 cột tuần, đổi sang `100%` là cột nào cũng nát).
   ⇒ Chặn ở THẺ CON: kẹp trần bề rộng cho `.lt2-lt-chu` thì `max-content` của cột
     chỉ còn bằng trần ấy cộng hai bên đệm.

   ⛔ VÌ SAO PHẢI CÓ THẺ CON `.lt2-lt-chu` (sinh ở `lt2ORuotLT`):
      Cách duy nhất kẹp đúng N dòng là `display: -webkit-box` + `-webkit-line-clamp`.
      Đặt `display` khác `table-cell` lên một `<td>` là VỠ CẤU TRÚC BẢNG — ô rơi
      khỏi hàng, mọi cột lệch. Nên ruột đi vào `<span>`, `<td>` giữ `table-cell`.
   ⛔ Ô TRỐNG KHÔNG SINH THẺ NÀY (xem `lt2ORuotLT`) — thẻ rỗng vẫn chiếm một dòng.
   ══════════════════════════════════════════════════════════════════════════════ */
/* ⛔⛔ HAI LUẬT CỦA SÂN SHEET ĐANG ĐÈ — đo bằng CDP 13/09, tôi đã nhắm hụt một vòng:
     · `.sheet-moi tbody tr.sheet-hang td > *   { max-height: 22px }`  (0,3,4)
     · `.sheet-moi tbody tr.sheet-hang td > span { display: inline-flex }` (0,3,4)
   Bảng Lộ trình cũng được khoác `sheet-moi`/`sheet-hang` LÚC CHẠY, nên hai luật ấy
   với tới thẻ con này. Cái `max-height: 22px` kẹp ruột lại đúng 22px — chưa đủ cho
   một dòng rưỡi — còn `display: inline-flex` cướp mất `-webkit-box`, mà thiếu
   `-webkit-box` thì `-webkit-line-clamp` KHÔNG CHẠY, im lặng, không lỗi nào báo.
   Triệu chứng đo được: ruột 49px nội dung mà chỗ hiện 22px, đọc được ĐÚNG 1 dòng.
   ⇒ Luật dưới phải nặng hơn (0,3,4). `.sheet-moi … td.lt2-c-lt > .lt2-lt-chu` cho
     (0,4,3): bốn lớp thắng ba lớp, so tiếp số thẻ là thừa.
   ⛔ GỠ TRẦN CHO ĐÚNG THẺ NÀY THÔI — `max-height: 22px` của sân sheet còn phải giữ
      cho mọi ô khác, gỡ chung là mở toang chiều cao cả bảng Điểm danh. */
.lt2-bang td.lt2-c-lt .lt2-lt-chu,
.sheet-moi tbody tr.sheet-hang td.lt2-c-lt > .lt2-lt-chu {
  display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: 2; line-clamp: 2;
  overflow: hidden; text-overflow: ellipsis;
  /* ⛔ `normal` phải khai ĐÈ: `.lt2-bang th, .lt2-bang td` đặt `nowrap` và thẻ con
     thừa kế nó; để nguyên thì line-clamp chẳng có dòng thứ hai nào để kẹp. */
  white-space: normal;
  /* Lộ trình hay có chuỗi dài không dấu cách ("Starters1→Starters2"). `anywhere`
     cho bẻ giữa chuỗi ấy thay vì để nó thò ra ngoài ô. */
  overflow-wrap: anywhere;
  /* 168px cột − 6px đệm trái − 6px đệm phải = 156px.
     ⛔ CÂU CŨ Ở ĐÂY NÓI DÒNG NÀY LÀ THỨ KẸP CỘT LẠI — SAI, ca thử phá đã bác bỏ:
        gỡ hẳn nó ra (kể cả `max-width: none !important`) thì cột VẪN đúng 168px,
        không một phép canh nào đỏ. Thứ thật sự giữ cột là VIỆC CÓ THẺ CON: luật
        sẵn có `.bang-keo-cot td > span { max-width: 100% }` kẹp thẻ con vào 100%
        bề rộng ô, nên `max-content` của cột thôi tính theo cả câu. Ca phá đúng là
        bỏ thẻ con đi (trả ruột về chuỗi trần) — làm thế cột nở lại 349px.
     ⇒ Dòng này giữ lại làm lưới an toàn, vì `bang-keo-cot` là lớp gắn LÚC CHẠY:
       màn nào không bật kéo cột thì luật kia không có, và trần này đỡ. Nói rõ nó
       KHÔNG gánh việc chính, để lượt sau đừng tưởng gỡ nó là hỏng. */
  max-width: 156px;
  line-height: 1.25;
  /* ⛔ Gỡ trần 22px của sân sheet — hai dòng cần 2 × 16,25 = 32,5px. */
  max-height: none;
}
/* ⛔⛔ Ô PHẢI CAO LÊN CHO ĐỦ HAI DÒNG — CÂU TRÊN TÔI VIẾT LÀ SAI, ĐO ĐÃ BÁC BỎ.
   Tôi đã đoán `height: 30px` của `.lt2-bang td` là chiều cao TỐI THIỂU nên ô tự
   cao lên. ĐO RA KHÔNG PHẢI: ô vẫn đúng 32px, ruột cần 33px mà chỗ hiện chỉ 31px
   — dòng thứ hai bị xén ngang thân chữ. Thủ phạm là `overflow: hidden` của chính
   `.lt2-bang td` (cùng khai một chỗ với `height`): nó cắt phần tràn TRƯỚC KHI ô kịp
   cao lên. Triệu chứng dễ tưởng là line-clamp hỏng, nhưng line-clamp chạy đúng —
   chữ vẫn hai dòng, chỉ là không có chỗ mà hiện.
   ⇒ Trả `height: auto` cho riêng ô này. Hàng tự cao theo ô cao nhất, nên hàng nào
     có lộ trình dài thì cao hai dòng, hàng còn lại giữ nguyên 30px.
   ⛔ CHỈ ĐỔI Ô NÀY. Đổi `.lt2-bang td` là 54 cột tuần cùng nhả chiều cao — bảng
      nhảy một nhịp, đúng thứ lời dặn ở `.lt2-o` đã cấm.
   ⛔ `vertical-align: top` đi kèm: để `middle` thì ô một dòng nằm giữa còn ô hai
      dòng bắt đầu cao hơn, hai ô cạnh nhau lệch chân chữ.
   ⛔⛔ ĐỘ ĐẶC HIỆU — VÒNG ĐẦU TÔI NHẮM HỤT, ĐO RA Y NGUYÊN 32px:
      viết `.lt2-bang td.lt2-c-lt` (0,2,1) là CHƯA ĐỦ NẶNG. Bảng Lộ trình cũng
      được khoác `sheet-moi`/`sheet-hang` lúc chạy, nên `.sheet-moi tbody
      tr.sheet-hang td { height: var(--sheet-o-cao) }` (0,3,3) đè lên. Lớp ấy gắn
      bằng JS nên GREP FILE CSS KHÔNG BAO GIỜ THẤY — chỉ CDP mới chỉ ra.
      ⇒ Phải khai cả hai đường, đường sau (0,4,3) mới thắng. */
.lt2-bang td.lt2-c-lt,
.sheet-moi tbody tr.sheet-hang td.lt2-c-lt {
  height: auto; min-height: 30px; vertical-align: top;
}

/* ⭐⭐ "BẤM VÀO MỞ ĐỦ VÀ … BIẾN MẤT" — hộp gõ nổi lên và nở theo chữ.
   ⛔ Kẹp cột về 168px mà để hộp gõ vẫn bằng bề rộng cột thì bấm vào VẪN không đọc
      được hết — vá nửa vời. Đo trước: ô gõ 151px, chữ cần 344px.
   ⛔ NEO GIỮA Ô, y hệt ô tuần `.lt2-o`. `lt2CoORong` — hàm JS đặt bề rộng ô gõ —
      tính trần theo giả định hộp nở ra HAI PHÍA (`2 × min(trái, phải)`); neo lệch
      một bên là trần tính ra rộng gấp đôi chỗ thật có, hộp thò khỏi khung cuộn.
   ⛔ KHÔNG nới `width` của CỘT: bảng 54 cột tuần, nới một cột là cả bảng hết vừa
      màn — đúng lời dặn đã có ở luật của `.lt2-o`. */
.lt2-bang td.lt2-c-lt:focus-within .lt2-sua-boc {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: auto; max-width: min(520px, 72vw); z-index: 7; padding: 3px;
  background: var(--the); border-radius: var(--r-sm, 4px);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .18);
}
/* ⛔ Ô đầu bảng của cột tuần có HAI DÒNG (số tuần + ngày thứ Hai). Ở chiều cao
   30px chung thì dòng ngày bị cắt ngang — mà giáo vụ dò cột chủ yếu bằng NGÀY.
   Chỉ nới hàng đầu bảng; hàng dữ liệu giữ nguyên 30px đã chốt. */
.lt2-bang thead th { height: 42px; }


  /* ══════════════════════════════════════════════════════════════════════════════
     MÀN CÀNG BÉ, NÚT CÀNG BÉ — VÀ KHE GIỮA CÁC NÚT RỘNG RA — Boss chốt 08/09/2026
     *"với các màn hình càng bé thì hãy cho nút càng bé lại để có thể để đúng form
     mình đề ra trên tất cả các máy"* · *"đa số nút trên cả app bạn đang để sát nhau
     quá sát quá mực khiến các nút ko có chỗ tách ra làm app xắp xếp bố cục trở nên
     xấu rõ"*.

     Đo trước khi sửa (màn Công việc): khe ngang 7px nhưng khe DỌC chỉ **5px** — đó
     là chỗ Boss thấy dính nhất, vì màn hẹp thì các nút xếp chồng lên nhau theo chiều
     dọc. Và ở 280px dải phình thành **4 hàng** (151px).

     Hai yêu cầu nghe như ngược nhau — nới khe thì tốn chỗ — nhưng đi cùng nhau được:
     bóp NGANG cho nút hẹp lại thì hai nút vào vừa MỘT hàng, tiết kiệm nguyên một
     hàng 36px, thừa sức trả tiền cho 3px khe.

     ⛔ BÓP NGANG, ĐỪNG HẠ CHIỀU CAO. 36px là sàn đích bấm (nút từng cao 38px và Boss
        báo *"bấm hay trượt sang nút bên cạnh"*). Chỉ ở khổ ≤340px — hẹp hơn cả iPhone
        SE — mới hạ 34px, và lúc ấy khe rộng 8px bù lại phần đích bấm mất đi.
     ⛔ TRẦN CHIP GIỮ 15ch, ĐỪNG HẠ. Hạ xuống 14ch đã từng cắt cụt "Giáo vụ (2 người)"
        (đo được: cần 103px, chỉ cho 101px). Muốn chip hẹp lại thì hạ CỠ CHỮ — `ch`
        đo theo cỡ chữ nên chip tự hẹp theo mà không mất chữ nào.
     ══════════════════════════════════════════════════════════════════════════════ */
  @media (max-width: 430px) {
    .dnc-dai > .dnc-hang { column-gap: 8px; row-gap: 8px; }
    .dnc-hang-trai { gap: 8px; }
    .dnc-dai .nut-nho { padding: 0 9px; font-size: 12px; }
    .dnc-dai .dnc-cs { padding: 0 8px; font-size: 12px; }
    .dnc-dai .cs-muc-bar { gap: 8px; }
    .dnc-dai .gtg-thanh, .dnc-dai .gtgb-loc, .dnc-dai .nv-thanh { gap: 8px; }
  }
  @media (max-width: 360px) {
    .dnc-dai .nut-nho { padding: 0 8px; font-size: 11.5px; }
    .dnc-dai .dnc-cs { padding: 0 7px; font-size: 11.5px; }
    .dnc-hang-trai > .nut-chinh { padding: 0 10px; font-size: 12px; }
    .dnc-hang-trai > .nut-nho,
    .dnc-hang-trai .bl-timhang .nut-nho { padding: 0 9px; font-size: 11.5px; }
  }
  @media (max-width: 340px) {
    /* ⛔ Bậc cuối, và chỉ ở đây mới đụng tới chiều cao. Khe 8px giữ nguyên — nút
       thấp mà lại DÍNH nhau mới là lúc bấm trượt. */
    .dnc-dai .nut-nho, .dnc-dai .dnc-cs,
    .dnc-hang-trai > .nut-nho, .dnc-hang-trai > .nut-chinh,
    .dnc-hang-trai .bl-timhang .nut-nho, .dnc-dai .cs-muc-b {
      height: 34px; min-height: 34px;
    }
    .dnc-dai .nut-nho, .dnc-dai .dnc-cs { padding: 0 7px; }
  }

  /* ══════════════════════════════════════════════════════════════════════════════
     BỎ CHỮ, CHỈ CÒN ICON — Boss chốt 08/09/2026
     *"mấy cái nút làm mới bỏ chữ làm mới đi bỏ cả block đi chỉ còn dữ lại đúng cái
     icon thôi mọi người tự hiểu, áp dụng cho tất cả công cụ trong app"* và *"bỏ hết
     mấy cái chữ xử lí gì đó chưa xủ lí… chỉ cần icon… nhưng làm sao cái icon đó đủ
     rõ ràng và dễ hiểu"*.

     ⛔ LÀM BẰNG CSS, KHÔNG SỬA `js/tinh-nang.js`. App có 20 nút "Làm mới" nằm rải khắp
        mã; sửa tay 20 chỗ là 20 dịp gõ sót, mà `js/tinh-nang.js` lại là file kênh Coder
        cũng đụng. `:has(> i.ic-lammoi)` bắt trọn cả 20 trong một luật, và nút mới ai
        thêm sau này cũng tự vào khuôn.

     ⛔ `font-size: 0` là cách DUY NHẤT ẩn được chữ ở đây. Chữ "Làm mới" là **text
        node trần** (`<button><i class=ic-lammoi></i>Làm mới</button>`) — CSS không có
        bộ chọn nào trỏ tới text node. Trả lại cỡ chữ cho con nào cần hiện.
     ══════════════════════════════════════════════════════════════════════════════ */

  /* ── ① NÚT "LÀM MỚI": bỏ chữ, bỏ luôn khung ─────────────────────────────────── */
  /* ⛔ `!important` ở đây KHÔNG phải cho tiện — 08/09/2026
     Lần đầu viết luật này không có `!important`, chụp lại thì nút vẫn nguyên chữ
     "Làm mới" và còn TRÀN khỏi mép phải màn. Lý do: luật đầu màn công cụ
     `body.man-cong-cu .noi-dung .nut-nho` đặc hiệu 0,3,1 — cao hơn hẳn
     `button:has(> i.ic-lammoi)` (0,1,1) — nên nó đặt lại `font-size:12.5px` và
     `padding`. Luật này phải phủ CẢ APP, đứng trên mọi luật riêng của từng màn, nên
     đây đúng là chỗ `!important` dùng cho việc của nó. */
  /* ⛔ NGOẠI LỆ DUY NHẤT: `#ddTai` — nút ⟳ nổi ở màn Điểm danh (Boss 10/09/2026).
     Nó cũng mang `<i class=ic-lammoi>` nên dính trọn khuôn 36px + bỏ viền + bỏ nền
     của luật này. Đo thật 10/09: nút ra 36×36 thay vì 46×46, dưới mức 44px của cả
     Apple lẫn Google — mà đây là nút NỔI đứng một mình trên bảng, không phải nút
     nhỏ nép trong một thanh như 20 nút kia.
     ⛔ Nêu ngoại lệ NGAY ĐÂY thay vì chồng thêm `!important` ở luật `#ddTai`: hai
        khối `!important` giành nhau thì người sau đọc không biết bên nào thắng và
        vì sao. Ở đây thì thấy ngay là cố ý chừa ra. */
  /* ⭐ 10/09/2026 — khối này nay có bạn: luật ngay DƯỚI đây trả chữ về khi nút
     nằm trong block thu gọn `.nv-gon` và người dùng rê chuột vào. Đừng gỡ luật
     ấy vì tưởng nó phá khuôn icon — hai luật chia nhau theo trạng thái. */
  button:has(> i.ic-lammoi):not(#ddTai) {
    font-size: 0 !important; gap: 0 !important;
    width: 36px !important; min-width: 36px !important; max-width: 36px !important;
    padding: 0 !important;
    height: 36px !important; min-height: 36px !important;
    border: none !important; background: none !important; box-shadow: none !important;
    display: inline-flex !important; align-items: center; justify-content: center;
    color: var(--mo); flex: 0 0 auto !important; position: relative;
  }
  button:has(> i.ic-lammoi) > i.ic-lammoi { margin-right: 0; width: 19px; height: 19px; }
  button:has(> i.ic-lammoi):hover { background: var(--nen2); color: var(--chu); }
  button:has(> i.ic-lammoi):disabled { opacity: .45; }

  /* ── ⛔⛔ TRẢ CHỮ VỀ KHI RÊ VÀO BLOCK THU GỌN (Boss giao 10/09/2026) ────────
     Boss đưa mẫu `expandable-action-bar` của 21st.dev: *"di chuột vào nó show
     full ra thì mọi người dùng sẽ dễ hơn"*. Tức là phần việc 08/09 ở khối ngay
     trên mới xong một nửa — nút đã gọn thành icon, nhưng ai không đoán được cái
     dấu hiệu ấy nghĩa gì thì chịu. Nay rê vào là chữ nở ra.

     ⛔ `!important` Ở ĐÂY LÀ BẮT BUỘC, KHÔNG PHẢI CHO TIỆN. Khối trên đặt
        `font-size:0 !important` và `width:36px !important` để phủ cả app; muốn mở
        chữ ra thì chỉ có cách đè lại bằng `!important`. Đây đúng là hai khối
        `!important` giành nhau mà chính khối trên đã cảnh báo — nên chép luôn lời
        giải ở đây cho người sau khỏi phải đi tìm:
          · khối TRÊN thắng lúc BÌNH THƯỜNG (nút gọn còn mỗi icon);
          · khối NÀY thắng lúc ĐANG RÊ / ĐANG MỞ, vì bộ chọn dài hơn hẳn
            (`.nv-gon:hover >` thêm hẳn một tầng), nên đặc hiệu cao hơn.
        Không có luật nào bị vô hiệu — chúng chia nhau theo trạng thái.

     ⛔ Và `font-size` mới là thứ quyết định, không phải `max-width`. Đo thật
        10/09/2026 lúc đang rê: `max-width` đã lên 200px, `opacity` đã lên 1, mà
        chữ vẫn rộng ĐÚNG 0px — vì cỡ chữ đang là 0. Đo bề rộng THẬT của chữ,
        đừng tin mỗi `opacity`. */
  /* ── KHUON CHUNG DE THANG LUAT ICON-ONLY ────────────────────────────────
     Do that 10/09/2026 sau khi Boss che *"phai giong nhau"*: ba nut trong block
     ra 161x32 / 99x36 / 85x32 — nut Lam moi CAO HON hai nut kia 4px.

     ⛔ Ly do KHONG phai thieu `!important`, ma la DAC HIEU. Luat icon-only o tren
        viet `button:has(> i.ic-lammoi):not(#ddTai)` — trong do `:not(#ddTai)` mang
        mot ID, nen dac hieu la (1,1,1). Luat `.nv-gon button` chi (0,1,1), thua
        du co `!important` ca hai ben. Muon thang thi phai co ID trong bo chon:
        (1,2,1) > (1,1,1). Do la ly do luat duoi day dai dong the — dung rut gon.

     Chi ep KHUON (cao · bo goc · vien · nen). Cho chu va padding van do khoi
     ngay duoi lo, vi chung doi theo trang thai dong/mo. */
  .nv-gon button:has(> i.ic-lammoi):not(#ddTai) {
    height: 32px !important; min-height: 32px !important;
    width: auto !important; min-width: 32px !important; max-width: none !important;
    border: 0 !important; border-radius: 999px !important;
    background: transparent !important; box-shadow: none !important;
    margin: 0 !important;
  }
  /* ⛔⛔ NÚT "LÀM MỚI" KHÔNG CÓ LUẬT NGHỈ RIÊNG — gỡ bỏ 12/09/2026.
     `2aad561` từng thêm ở đây một luật nghỉ đặt sẵn `font-size:12.5px` + `gap:6px`
     + `padding:0 10px` cho nút này để nó cũng "chừa sẵn chỗ". Boss đã bác cách ấy.
     Đo thật: giữ luật này thì riêng nút Làm mới đứng rộng 93,1px lúc nghỉ (đáng lẽ
     32px), kéo cả cụm từ 377,4 lên 438,6px — tức vẫn mất cái "gọn" Boss ưng.
     ⛔ Đừng thêm lại: nút này chỉ có LUẬT MỞ (ngay dưới), lúc nghỉ ăn khuôn 32px
        của luật ngay trên — đúng như `dfeac73`. */
  .nv-gon button:has(> i.ic-lammoi):not(#ddTai) > i {
    width: 18px !important; height: 18px !important; margin: 0 !important; }
  .nv-gon button:has(> i.ic-lammoi):not(#ddTai):hover {
    background: var(--nen-o) !important; color: var(--chu) !important; }

  /* ⛔ `.giu-mo` phải có mặt ở ĐÂY NỮA. Bỏ sót một luật mở là cụm "giữ mở" nở
     thiếu đúng một nút: đo được 425,9px thay vì 487px, tức vẫn dở dang. */
  .nv-gon:hover > button:has(> i.ic-lammoi):not(#ddTai),
  .nv-gon.mo > button:has(> i.ic-lammoi):not(#ddTai),
  .nv-gon.giu-mo > button:has(> i.ic-lammoi):not(#ddTai),
  .nv-gon:has(:focus-visible) > button:has(> i.ic-lammoi):not(#ddTai) {
    font-size: 12.5px !important; gap: 6px !important;
    width: auto !important; min-width: 34px !important; max-width: 220px !important;
    padding: 0 10px !important;
  }
  /* Màn hẹp hoặc máy không rê chuột được (iPad, điện thoại xoay ngang — Boss chốt
     22/09/2026) — mở sẵn, xem lý do ở khối `.nv-gon` "MÀN HẸP: MỞ SẴN" phía trên. */
  @media (max-width:820px), (hover:none) {
    .nv-gon > button:has(> i.ic-lammoi):not(#ddTai) {
      font-size: 12.5px !important; gap: 6px !important;
      width: auto !important; min-width: 34px !important; max-width: 220px !important;
      padding: 0 10px !important;
    }
  }

  /* ⛔ Bỏ chữ thì phải bù lại đường hiểu nghĩa, không thì nút thành câu đố:
     máy tính có mách chữ khi rê chuột · máy đọc màn hình đọc được `aria-label` do
     JS gắn (nếu chưa có thì icon vẫn là biểu tượng làm mới quen thuộc). */
  @media (hover: hover) {
    button:has(> i.ic-lammoi):hover::after {
      content: "Làm mới"; position: absolute; top: calc(100% + 3px); left: 50%;
      transform: translateX(-50%);
      background: var(--chu); color: var(--the);
      font-size: 11.5px; padding: 3px 8px; border-radius: var(--r-sm);
      white-space: nowrap; z-index: 60; pointer-events: none;
    }
  }

  /* ── ①b ICON `icx-*` ĐỨNG CẠNH CHỮ THÌ PHẢI CHỪA KHE — cả app ───────────────
     Hai bản icon: `ic-*` chừa sẵn lề phải 6px, `icx-*` thì KHÔNG (nó dành cho nút
     chỉ có mỗi icon). Nút "Thùng rác" lỡ dùng bản `icx-` mà vẫn có chữ, nên ra
     «🗑Thùng rác» dính liền — trên điện thoại đã vá trong khối @media, còn máy tính
     thì vẫn dính. Luật này lo cho cả hai khổ.
     ⛔ `:not(:only-child)` là phần quan trọng: icon đứng MỘT MÌNH trong nút thì vẫn
        phải sát mép, thêm lề vào là nút lệch tâm. */
  button > i[class^="icx-"]:not(:only-child),
  a > i[class^="icx-"]:not(:only-child),
  summary > i[class^="icx-"]:not(:only-child) { margin-right: 5px; }

  /* ── ② CẶP "ĐANG CHỜ / KHO ĐÃ XỬ LÝ" (màn Yêu cầu của giáo viên) ─────────────
     ⛔⛔ 20/09/2026 — ICON BỊ NHÂN ĐÔI, ĐÃ BỎ PHẦN VẼ BẰNG CSS.
     Boss: *"Icon đang chờ của công cụ yêu cầu của giáo viên đang bị nhân đôi"*.
     Khối này viết hồi hai nút còn là `<button class="yc-ngan">Kho đã xử lý…` —
     KHÔNG có thẻ icon nào, nên phải tự vẽ bằng `::before`. Sau đó `man-hinh/yeu-cau-giao-vien.js`
     thêm `<i class="ic-dongho">` / `<i class="ic-luutru">` vào chính hai nút ấy (để
     icon còn lại khi chữ bị ẩn trên điện thoại), mà `::before` ở đây vẫn vẽ tiếp —
     thành hai đồng hồ cạnh nhau, và hai dấu ✓🗑 ở nút bên kia.
     ⛔ BỎ BÊN CSS, GIỮ BÊN JS: thẻ `<i>` trong JS mới là chỗ chọn được icon theo
        từng nút và đọc được khi soi mã; `::before` thì vô hình với người sửa sau.
     ⛔ `font-size: 0` cũng phải đi theo: nó có từ thời nút KHÔNG có icon riêng, cốt
        ẩn chữ để chừa chỗ cho hình vẽ. Nay chữ "Đang chờ" là thứ Boss muốn đọc
        được — giữ lại là nút chỉ còn icon với con số. */
  .yc-ngan {
    gap: 5px;
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 32px; padding: 0 11px;
  }
  .yc-ngan .yc-ngan-so { font-size: 12.5px; }

  /* ── ③ BỐN Ô SỐ Ở THẺ NHÂN VIÊN (màn Công việc) ─────────────────────────────
     `<span class="nv-bl-o"><b>3</b><i>Đã xong</i></span>` — bốn ô theo thứ tự CỐ ĐỊNH
     trong `.nv-bl-so`: đang mở · quá hạn · hôm nay · đã xong.

     ⛔⛔ 08/09/2026 — TRẢ CHỮ VỀ. LUẬT "CHỈ CÒN ICON" Ở BỐN Ô NÀY ĐÃ HẾT HIỆU LỰC.
     Boss: *"trong công cụ công việc bạn sửa mấy cái icon thành chữ đi chứ tôi nhìn
     ko hiểu"*. Sáng cùng ngày Boss bảo bỏ chữ *"chỉ cần icon… nhưng làm sao cái icon
     đó đủ rõ ràng và dễ hiểu"* — VẾ SAU mới là điều kiện, và bốn icon này trượt nó:
     vòng tròn ○ / tam giác ⚠ / tờ lịch 📅 / dấu ✓ không nói được "đang mở, quá hạn,
     hôm nay, đã xong". Người xem thấy bốn con số mà không biết số nào là số gì.

     ⛔ ĐỪNG DỰNG LẠI icon ở đây. Chỗ này là BẢNG SỐ, không phải hàng nút: mỗi ô là
        một con số kèm nhãn, mà nhãn thì không có hình vẽ nào thay được. Nút "Làm mới"
        thì khác — nó có một hình quen thuộc ai cũng đọc ra, nên luật icon của nút ấy
        (mục ① phía trên) VẪN GIỮ.
     ⛔ Chữ phải nhỏ và mờ hơn số: số là thứ người ta liếc, nhãn chỉ để biết cột nào
        là cột nào. Chữ to bằng số thì bốn ô thành bốn khối chữ, mất luôn cái nhìn
        lướt. 10,5px + màu mờ là vừa. */
  .nv-bl-o > i {
    display: block; font-style: normal; font-size: 10.5px; font-weight: 500;
    color: var(--mo); line-height: 1.25; margin-top: 1px; white-space: nowrap;
  }

  /* ── ④ NGĂN KÉO CÔNG CỤ: bỏ thanh kéo lên xuống ────────────────────────────
     Boss: *"trong thanh công cụ bỏ cái thanh kéo lên xuống đi trên điện thoại có thể
     di màn hình tự kéo được"*. Vẫn cuộn được y như cũ — vuốt trên điện thoại, lăn
     chuột trên máy tính — chỉ là không vẽ cái thanh xám ra nữa.
     ⛔ Giữ nguyên `overflow-y:auto`. Đổi thành `hidden` là danh sách 6.300px chỉ hiện
        được 340px đầu, mất hẳn phần công cụ bên dưới mà không một dấu hiệu nào. */
  .tts-than { scrollbar-width: none; -ms-overflow-style: none; }
  .tts-than::-webkit-scrollbar { width: 0; height: 0; display: none; }

  /* ⛔ CHỈ `.tts-than` — ĐỪNG ĐỘNG VÀO `.tk-tl-cuon`
     Soi lần đầu tôi mở ngăn kéo rồi liệt kê "mọi thứ đang cuộn" và thấy `.tk-tl-cuon`
     ruột 6.323px — tưởng đó là danh sách công cụ, suýt ẩn thanh cuộn của nó. Thật ra
     `.tk-tl-cuon` là vùng cuộn của một **bảng thống kê** (`<table class="tk-tl">`,
     xem `js/tinh-nang.js`), tình cờ cũng đang mở dưới nền. Ngăn kéo công cụ là
     `#ttSheet`, thân cuộn là `.tts-than` — mở bằng `moSheetCongCu()`.
     Bảng số dài sáu nghìn pixel thì thanh cuộn là thứ DUY NHẤT cho biết mình đang ở
     đoạn nào; giấu nó đi là lấy mất chỗ dựa, không phải dọn cho gọn. */

  /* ⛔ Đo bằng Playwright KHÔNG thấy được cái thanh Boss chụp. Trình duyệt lúc đo
     dùng thanh cuộn NỔI (đè lên nội dung, rộng 0px), nên
     `offsetWidth - clientWidth` ra 0 ở cả hai khổ — trông như "không có thanh nào".
     Trên Windows thật thì thanh cuộn CHIẾM CHỖ và hiện xám. Nên chỗ này tin ảnh
     Boss chụp, đừng tin số đo. */


  /* ══════════════════════════════════════════════════════════════════════════
     ANIMATION MO XUONG CHO MOI MENU THA XUONG — Boss chot 09/09/2026
     ──────────────────────────────────────────────────────────────────────────
     *"rà xoát cả app xem chỗ nào có nút ấn vào xong hiện kéo xuống nhiều lựa chọn
     thì hãy add thêm animation nó kéo mở xuống như mình hay làm, áp cho toàn bộ"*

     Ra soat het app: 10 cho la menu tha xuong that. Hai cho DA CO tu truoc
     (`.dnc-tha` chon co so, `.dh-chon-menu` chon buoi); tam cho con lai o day.

     ⛔ DAT O CUOI `css/lop.css` CHU KHONG PHAI CANH TUNG KHOI.
        `css/man.css` nap TRUOC file nay (xem `index.html`). Khoi
        `prefers-reduced-motion` ben duoi co cung do dac hieu voi luat bat o tren,
        nen no chi thang khi dung SAU. Rai luat sang hai file la luat tat cho
        `.phan-menu` (dinh nghia ben man.css) thua im lang: nguoi da xin bot
        chuyen dong van thay menu nhay.

     ⛔ CHI `opacity` + `translateY`. KHONG `scale`, KHONG `height`:
        · `scale` lam sai moi phep do — `.ont-bang` do `scrollHeight` roi chot
          `maxHeight`, `.gtg-tha` do be ngang chu de giu cho.
        · `height` bat trinh duyet tinh lai bo cuc tung khung hinh, giat tren may yeu.
        `translateY` khong doi mot con so nao trong cac phep do ay.

     ⛔ KHONG dat `animation` truc tiep len `.dg-chips` hay `.nv-link-ds` tran —
        phai co `[open] >` o truoc. Hai ten lop ay CON DUNG O CHO KHAC luon hien
        (`.dg-chipcell .dg-chips` trong o bang, `.fhs-chipbox`), dat tran la moi
        lan ve lai bang chung nhay mot cai.

     ⛔ `.ont-bang` KHONG bam `:not([hidden])` duoc — no LAT LEN khi thieu cho duoi
        (xem `ontMo`), bam tran thi luc menu bat len tren no van truot xuong, nguoc
        chieu, trong sai hon la khong co gi. Class `ont-vao`/`len` do JS gan dung
        luc mo. */
  /* ══════════════════════════════════════════════════════════════════════════
     LỊCH GIÁO VIÊN: LƯỚI ĂN HẾT PHẦN DƯỚI MÀN — Boss 09/09/2026 (lần thứ hai)
     ──────────────────────────────────────────────────────────────────────────
     Boss: *"cái bảng nó phải chiếm hết bên dưới màn hình khi ở điện thoại... nó
     dừng lại ở dưới thừa ra 1 chút khoảng trống chữ và ô trắng ở dưới, và cái
     block ghi Bấm ô lớp... bạn để chỗ khác đi... cho cái đấy gọn lại hết mức"*.

     Lần trước (08/09) tôi mới nới TRẦN của lưới. Nhưng thứ ăn mất chỗ không phải
     trần — mà là DẢI CHÚ GIẢI nằm chắn NGAY TRÊN lưới: đo ở 360px nó cao 44px,
     đẩy lưới tụt xuống đúng chừng ấy, rồi lưới hết chỗ trước khi chạm đáy.

     Nay ở điện thoại:
       · dải chú giải TỤT XUỐNG DƯỚI lưới (`order`), thôi chắn đường;
       · câu hướng dẫn dài ẩn đi, chỉ còn ba chấm màu trên MỘT dòng;
       · `lgvDoTran` tính lại trần theo vị trí thật nên lưới tự dài thêm.

     ⛔ ĐỪNG dùng `display:none` cho cả dải: ba chấm màu là thứ duy nhất giải
        nghĩa ô xanh / ô đỏ / ô vàng. Mất nó thì người dùng nhìn màu mà đoán mò.
     ⛔ Máy tính giữ nguyên như cũ — chỗ rộng, không việc gì phải giấu chữ.
     ══════════════════════════════════════════════════════════════════════════ */
  @media (max-width:820px) {
    .lgv-chinh { display:flex; flex-direction:column; }
    .lgv-chinh > .lgv-khung { order:1; }
    .lgv-chinh > .lgv-hong  { order:2; }
    .lgv-chinh > .lgv-bao   { order:3; margin:6px 0 0; padding:5px 8px;
                              font-size:11.5px; border-left-width:3px; }
    /* Câu hướng dẫn: chỉ máy tính mới hiện. */
    .lgv-bao > .lgv-huong { display:none; }
    /* Ba chấm màu gọn một dòng, không đội thêm khoảng cách phía trên nữa. */
    .lgv-bao > .lgv-chugiai { margin-top:0; gap:10px; font-size:11px; }

    /* ⛔⛔ ĐÂY MỚI LÀ THỨ ĂN MẤT NHIỀU CHỖ NHẤT — đo thật 09/09 ở màn 360:
       nội dung lưới cần 1011px mà trần chỉ cho 475px, trong khi tới thanh đáy còn
       tận 641px. 158px chênh ấy rơi vào hai dòng chữ nằm dưới lưới, mà nặng nhất
       là đoạn chú thích chân `.cts-chan` — ba dòng giải thích "ô lịch dựng từ thứ
       và giờ học cố định…". Trên máy tính nó nằm gọn một dòng, trên điện thoại nó
       vỡ thành ba, và `lgvDoTran` trừ đúng chừng ấy khỏi trần của lưới.
       Boss: *"nó dừng lại ở dưới thừa ra 1 chút khoảng trống chữ và ô trắng ở dưới"*.
       ⛔ Chỉ ẩn Ở MÀN LỊCH GV VÀ CHỈ TRÊN ĐIỆN THOẠI. Đây là câu GIẢI THÍCH, không
          phải dữ liệu — máy tính vẫn hiện đủ. Đừng gỡ luôn khỏi mã: người mới vào
          cần biết vì sao lớp chưa điểm danh vẫn có ô. */
    body:has(.lgv-chinh) .cts-chan { display:none; }
    /* Dòng nhắc lớp hỏng: giữ lại (nó có thật, chỉ đúng một lớp) nhưng bóp mỏng. */
    .lgv-chinh > .lgv-hong { margin-top:4px; font-size:11.5px; line-height:1.35; }

    /* ⛔⛔ THỨ TỰ TRONG DẢI NÚT LỊCH GV — Boss 09/09/2026: *"nút bị lỗi hết rồi"*.
       Đo thật ở màn 390: dải cần 851px mà khung chỉ 366px, nên BỐN nhóm khuất hẳn
       — chọn Ngày/Tuần/Tháng · phóng to · Nghỉ nhiều buổi · Xuất Excel.
       Không có cách nào nhét vừa 851px vào 366px, nên việc phải làm là XẾP LẠI ƯU
       TIÊN: thứ hay bấm đứng trước, thứ chỉ để đọc lùi ra sau.
         · `.lgv-dem` ("720 buổi") là CON SỐ, không bấm được → đẩy xuống cuối, trả
           lại 46px cho nút.
         · `.zoom-nut` (phóng to lưới) ít dùng và đã có cách khác (chụm hai ngón)
           → xuống áp chót, trả thêm 136px.
       Nhờ vậy nhóm Ngày/Tuần/Tháng lùi từ x=336 lên x=246, tức nhìn thấy được
       ngay chứ không phải kéo mới biết là có.
       ⛔ ĐỪNG đẩy `.lgv-tieude` ("tháng 9 2026") ra sau cho gọn: mất nó là người
          dùng không biết mình đang xem tháng nào — đúng thứ phải luôn thấy. */
    .lgv-top.tnn > .zoom-nut { order:8; }
    .lgv-top.tnn > .lgv-dem  { order:9; }
  }

  /* ══════════════════════════════════════════════════════════════════════════
     PROGRESS TEST: THANH CHỌN KỲ LÊN TRÊN, THÔI DÁN ĐÁY MÀN — Boss 09/09/2026
     ──────────────────────────────────────────────────────────────────────────
     Boss: *"trong progress test cái thanh công cụ đang che mất cái nút chuyển kì
     của lớp đó nên bạn cho cái nút chọn kì và nút quay về danh sách lên trên"*.

     NGUYÊN NHÂN THẬT, không phải lỗi của màn Progress test: luật
     `.thanh-cong-cu { position:fixed; bottom:0 }` ở khối màn nhỏ phía trên vốn
     dựng cho MÀN ĐIỂM DANH (nút DONE · Thêm cột · Đổi chỗ cột phải luôn thấy,
     Boss chốt 25/07/2026). Progress test dùng chung tên lớp `.thanh-cong-cu` nên
     bị dán xuống đáy theo, nằm chồng đúng chỗ thanh công cụ dưới cùng của app —
     và ô chọn Kỳ thi khuất hẳn sau nó.

     ⛔⛔ ĐỪNG CHỮA BẰNG CÁCH SỬA LUẬT CHUNG Ở TRÊN. Gỡ `position:fixed` ra khỏi
        `.thanh-cong-cu` là màn Điểm danh mất thanh đáy — đúng thứ Boss đòi phải
        có từ tháng 7. Ở đây chỉ TÁCH RIÊNG hai thanh của Progress test bằng
        class `pt-thanh` (xem `ptKhung` trong `js/tinh-nang.js`).
     ══════════════════════════════════════════════════════════════════════════ */
  @media (max-width:820px) {
    .thanh-cong-cu.pt-thanh {
      position:static; z-index:auto; box-shadow:none; border-top:0;
      background:transparent; padding:0; margin:0 0 10px;
      justify-content:flex-start;
    }
    /* ⛔ Nút trong thanh này KHÔNG được `flex:1 1 30%` như thanh đáy Điểm danh —
       ở thanh cuộn ngang thì "chiếm 30% bề ngang" làm nút giãn ra vô nghĩa. */
    .thanh-cong-cu.pt-thanh > button,
    .thanh-cong-cu.pt-thanh > label { flex:0 0 auto; }
    /* Ô chọn Kỳ thi phải đủ cao để bấm trúng, ngang hàng với nút bên cạnh. */
    .thanh-cong-cu.pt-thanh select { min-height:38px; }
  }

  /* ══════════════════════════════════════════════════════════════════════════
     THANH NÚT MỘT HÀNG, KÉO NGANG — Boss chốt 09/09/2026
     ──────────────────────────────────────────────────────────────────────────
     Boss: *"các nút sẽ cho thẳng hàng về 1 hàng ở trên nhưng vẫn phải ở dưới tên
     công cụ, các nút sẽ ở ngay cạnh nhau nếu nhiều nút quá sẽ có chức năng di ấn
     kéo sang 2 bên... giúp màn hình đỡ bị chiếm diện tích mà mọi người vẫn có thể
     sử dụng đầy đủ công dụng của app"*.

     ĐO THẬT TRƯỚC KHI SỬA (màn 360px, `kiem-thu/_do-thanh-nut.js`):
       Quản lý lớp    778px = 92% màn hình chỉ để bày nút   (4 thanh xuống dòng)
       Lịch giáo viên 594px = 70%                           (thanh trên 3 hàng)
       Bảng phân lớp  257px = 30%                           (2 thanh xuống dòng)
       Chăm sóc HS    242px = 29%                           (1 thanh ăn 4 hàng)
       Báo cáo ĐD     177px = 21%
       Sổ tuyển sinh  134px = 16%  ← ĐÃ LÀM ĐÚNG TỪ 16/08, 9 nút gọn 1 hàng

     ⛔⛔ KHUÔN NÀY CHÉP TỪ `.cts-nut` CỦA SỔ TUYỂN SINH, KHÔNG NGHĨ MỚI.
        Nó chạy thật từ 16/08/2026 và Boss đã quen tay. Đổi khuôn ở đây thì sửa
        cả hai chỗ, đừng để hai kiểu cuộn ngang khác nhau trong cùng một app.

     ⛔⛔ ĐỪNG GIẤU THANH CUỘN. Đây là bài học đã trả giá 21/08/2026: giấu đi là
        xoá mất dấu hiệu duy nhất cho biết còn nút phía sau, và Boss báo đúng lỗi
        ấy — *"nút thêm học sinh vẫn bị che khuất ko hiện lên màn hình"*. Thanh
        mảnh 6px là rẻ. Kéo bằng ngón tay là THÊM VÀO, không thay thế nó
        (W3C 2.5.7: thao tác kéo luôn phải có đường khác đi cùng).

     ⛔ `overflow-x:auto` ép `overflow-y` thành auto — nên MỌI hộp thả xuống nằm
        trong thanh sẽ bị cắt cụt. Chỗ nào có hộp thả thì hộp phải nổi kiểu
        `fixed` (JS đặt toạ độ), xem `tnnHopTha` trong `js/tinh-nang.js`.
     ══════════════════════════════════════════════════════════════════════════ */
  @media (max-width:820px) {
    .tnn {
      display:flex !important;
      flex-wrap:nowrap !important;
      overflow-x:auto; overflow-y:hidden;
      /* ⛔⛔ 09/09/2026 — BOSS BẮT BỎ THANH CUỘN: *"sao vẫn có cái thanh kéo sang
         2 bên ở dưới nó gây tốn diện tích í"*. Thanh cuộn ăn 6-8px chiều cao trên
         MỌI thanh nút của app, mà cả app có tới bảy thanh như vậy.
         ⛔ NHƯNG KHÔNG ĐƯỢC BỎ TRẮNG DẤU HIỆU. Bài học 21/08/2026 còn nguyên giá
            trị: không có gì báo "còn nút phía sau" thì với người dùng là nút BIẾN
            MẤT, và Boss đã báo đúng lỗi ấy một lần. Nay dấu hiệu là VỆT MỜ ở mép
            (`.tnn-con-phai` / `.tnn-con-trai`, JS bật tắt theo chỗ đang cuộn) —
            nó nằm ĐÈ lên chính dải nút nên tốn 0px chiều cao. Đây đúng là một
            trong ba lối Google/iOS vẫn dùng, ghi ở chú thích `.cts-nut`. */
      scrollbar-width:none; -webkit-overflow-scrolling:touch;
      overscroll-behavior-x:contain;
      /* Kéo tới đâu dừng đúng mép nút tới đó — thôi cắt ngang một nút, thôi cắt
         cụt chữ giữa chừng (Boss: *"nút bị lỗi hết rồi"*, ảnh 09/09 cho thấy
         "1036 buổi" đứt còn "1036"). */
      scroll-snap-type:x proximity;
      /* ⛔⛔ KHÔNG khai `touch-action:pan-y` ở đây — nó CHẶN đúng cái Boss xin.
         `pan-y` nghĩa là "chỉ cho vuốt dọc", nên ngón tay miết ngang sẽ không cuộn
         thanh nút. Khác hẳn `.lgv-khung`: ở đó JS tự lo kéo ngang nên mới cần chặn.
         Ở đây để trình duyệt tự lo cả hai chiều — vuốt ngang cuộn thanh, vuốt dọc
         cuộn trang — đó là hành vi sẵn có, không tốn một dòng mã nào. */
      /* Không còn thanh cuộn thì cũng không cần chừa chỗ cho nó ở dưới. */
      padding-right:2px; padding-bottom:0;
      gap:6px;
    }
    .tnn::-webkit-scrollbar { display:none; }
    /* Vệt mờ báo "còn nút bên này". JS gắn/gỡ hai lớp ấy theo chỗ đang cuộn. */
    .tnn.tnn-con-phai {
      -webkit-mask-image:linear-gradient(90deg, #000 calc(100% - 26px), transparent);
              mask-image:linear-gradient(90deg, #000 calc(100% - 26px), transparent); }
    .tnn.tnn-con-trai {
      -webkit-mask-image:linear-gradient(90deg, transparent, #000 26px);
              mask-image:linear-gradient(90deg, transparent, #000 26px); }
    .tnn.tnn-con-trai.tnn-con-phai {
      -webkit-mask-image:linear-gradient(90deg, transparent, #000 26px,
                                         #000 calc(100% - 26px), transparent);
              mask-image:linear-gradient(90deg, transparent, #000 26px,
                                         #000 calc(100% - 26px), transparent); }
    /* ⛔ Cấm mọi thứ trong thanh co lại — co là chữ trong nút vỡ dòng, cao gấp đôi. */
    .tnn > * { flex:0 0 auto; scroll-snap-align:start; }
    /* Đang kéo thì cấm bôi đen chữ, kẻo kéo một cái là bôi xanh cả hàng. */
    .tnn.tnn-dang-keo { cursor:grabbing; user-select:none; }
    .tnn.tnn-dang-keo * { pointer-events:none; }
  }

  /* ⭐ Máy tính cũng kéo được: chuột không có ngón tay để miết, mà thanh cuộn
     ngang 6px thì rất khó trúng. Con trỏ đổi thành bàn tay để người ta biết. */
  .tnn-keo-duoc { cursor:grab; }

  @keyframes mnMoXuong { from { opacity:0; transform:translateY(-7px); }
                         to   { opacity:1; transform:none; } }
  @keyframes mnMoLen   { from { opacity:0; transform:translateY(7px); }
                         to   { opacity:1; transform:none; } }

  /* Menu dong/mo bang thuoc tinh `hidden` */
  .tk-menu:not([hidden]),
  .phan-menu:not([hidden]),
  .bl-bang:not([hidden]),
  .ht-gio-bang:not([hidden]),
  .ht-kg-bang:not([hidden]), .ht-kg-chon:not([hidden]),   /* o Gio hoc hai dau — 22/09 */
  .ht-nguoi-bung:not([hidden]),
  /* Menu dung the `<details>` */
  .gtg-gom[open] > .gtg-gom-ds,
  .dg-chipbox[open] > .dg-chips,
  /* GHI CHU: `#nvLinkBox` chu KHONG phai `.nv-link-ds`. Cai sau nam SAU MOT CAP
     nua (`<details class="nv-link"> > <div id="nvLinkBox"> > <div class="nv-link-ds">`)
     va no BIEN MAT khi chua co link nao — luc do `nvVeLink()` tra ve mot khoi khac
     han. Bam `> .nv-link-ds` thi luat khop 0 phan tu: chet cam, khong mot loi bao. */
  .nv-link[open] > #nvLinkBox,
  /* O goi y ten nguoi — JS gan class vi no biet menu bat len hay xuong */
  .ont-bang.ont-vao {
    animation: mnMoXuong .14s cubic-bezier(.22,.9,.28,1) both;
  }
  .ont-bang.ont-vao.len { animation-name: mnMoLen; }

  @media (prefers-reduced-motion: reduce) {
    .tk-menu:not([hidden]),
    .phan-menu:not([hidden]),
    .bl-bang:not([hidden]),
    .ht-gio-bang:not([hidden]),
    .ht-kg-bang:not([hidden]), .ht-kg-chon:not([hidden]),
    .ht-nguoi-bung:not([hidden]),
    .gtg-gom[open] > .gtg-gom-ds,
    .dg-chipbox[open] > .dg-chips,
    .nv-link[open] > #nvLinkBox,
    .ont-bang.ont-vao { animation: none; }
  }

/* 🗺️ Lộ trình học — Đợt 6: cột Tầng và cột Sĩ số (Boss 09/09/2026). */
.lt2-bang th.lt2-c-tang, .lt2-bang td.lt2-c-tang { width: 62px; text-align: center; }
.lt2-bang th.lt2-c-siso, .lt2-bang td.lt2-c-siso { width: 58px; text-align: center; }
/* Số đếm thì cho các chữ số thẳng cột với nhau, đọc lướt một phát thấy ngay lớp nào ít em. */
.lt2-siso { font-variant-numeric: tabular-nums; }

/* 🗺️ Lộ trình học — Đợt 6: chữ ngày ở tiêu đề tuần bị lt2-tuan-ngay chìm vào nền.
   Đo trước khi sửa: #6B6660 trên #00793A = 1,03 lần (ngưỡng đọc được 4,5).
   ⛔ Lấy màu chữ của CHÍNH tiêu đề rồi hạ đậm, đừng gán trắng cứng — nền đổi thì
      màu này tự đi theo. Sau khi vá: 4,65 lần. */
.lt2-bang thead th .lt2-tuan-ngay {
  color: var(--dau-bang-chu, var(--chu));
  opacity: .88;
  font-size: 11px;          /* 10px quá bé cho một ngày tháng đọc lướt */
}
/* Số tuần vẫn phải nổi hơn ngày — nó là thứ giáo vụ dò trước. */
.lt2-bang thead th .lt2-tuan-so { opacity: 1; font-weight: 700; }

/* 🗺️ Lộ trình học — Đợt 6: kéo bảng sang hai bên (Boss 09/09/2026).
   ⛔ `touch-action: pan-x pan-y` để cú vuốt ngang KHÔNG bị trình duyệt nuốt thành
      cử chỉ lùi trang — đó mới là thứ hỏng trên điện thoại, không phải thiếu mã.
   ⛔ `-webkit-overflow-scrolling` cho cú vuốt có đà trượt tiếp như người ta quen. */
.lt2-cuon { touch-action: pan-x pan-y; -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain; cursor: grab; }
.lt2-cuon.lt2-dang-keo { cursor: grabbing; user-select: none; }
/* Đang kéo thì đừng đổi màu ô dưới con trỏ — nhìn cứ như sắp bấm nhầm vào đó. */
.lt2-cuon.lt2-dang-keo .lt2-o:hover { background: transparent; }
/* Ô chữ vẫn phải ra con trỏ gõ chữ, đừng để bàn tay đè lên. */
.lt2-cuon td.lt2-c-lt, .lt2-cuon td.lt2-c-ct { cursor: text; }

/* 🗺️ Lộ trình học — Đợt 6: nút Bộ lọc nhỏ + dãy thẻ đang lọc (Boss 09/09/2026). */
.lt2-nut-loc b { display:inline-block; min-width:16px; margin-left:4px; padding:0 4px;
  border-radius:9px; background:var(--xanh-dam); color:#fff; font-size:11px; font-weight:700; }
.lt2-the-loc { display:inline-flex; flex-wrap:wrap; gap:4px; align-items:center; }
/* Sàn 34px cho ngón tay — thẻ này bấm được chứ không phải chỉ để đọc. */
.lt2-the { min-height:34px; padding:0 9px; border:1px solid var(--vien);
  border-radius:999px; background:var(--xanh-nhat); color:var(--chu);
  font:inherit; font-size:12px; cursor:pointer; white-space:nowrap; }
.lt2-the:hover { border-color:var(--xanh-dam); }

/* 🗺️ Lộ trình học — Đợt 6: chữ ghi chú trong ô tuần (Boss 09/09/2026).
   Boss: *"chữ viết vào cột đó phải sắp xếp thật đúng ko lể tẻ"*.
   ⛔ Chữ XUỐNG HÀNG RIÊNG dưới dãy số, canh giữa, cắt theo bề rộng cột. Để nó
      chạy xen ngang dãy số là đúng cái lể tẻ Boss chê.
   ⛔ Chiều cao hàng 30px giữ nguyên làm SÀN — ô có chữ tự cao thêm, ô không có
      chữ vẫn y như cũ. Đừng hạ 30px xuống, đó là con số đã chốt. */
.lt2-bang td.lt2-o { white-space: normal; }
.lt2-ghi {
  display: block;
  margin-top: 1px;
  font-size: 11px;
  line-height: 1.25;
  color: var(--mo);
  text-align: center;
  /* ⛔⛔ ĐẶT THẲNG `white-space: normal` TẠI ĐÂY, ĐỪNG TRÔNG VÀO THỪA KẾ TỪ Ô.
     Mẻ D chỉ đặt `td.lt2-o { white-space: normal }` và tưởng thế là xong. Đo trên
     trình duyệt thật 09/09/2026: ô đúng là `normal` mà `.lt2-ghi` vẫn tính ra
     `nowrap` — chữ rộng THẬT 126px nhồi vào 43px, cắt cụt, cao đúng một dòng 14px.
     Đặt thẳng vào đây: cao 14 → 55px, bề rộng thật 126 → 43px (hết tràn).
     ⛔ Bài kiểm màn hình của mẻ D chỉ soi CHUỖI HTML sinh ra nên không thấy —
        "có vẽ" khác "có chạy". Nay `thu-lo-trinh-bam-that` đo bằng trình duyệt. */
  white-space: normal;
  overflow-wrap: anywhere;   /* chữ dài không đẩy toác cột */
  hyphens: auto;
}
/* Tuần nghỉ lễ nền vàng — chữ ghi chú phải đậm hơn một chút mới đọc được trên nền ấy.
   ⛔ 10/09/2026 — BỎ var(--chu). Nền ô là #FFF8E1 gõ cứng, GIỐNG NHAU cả hai chế độ;
      var(--chu) ở chế độ tối là chữ SÁNG nên ghi chú biến mất trên nền kem. Cùng
      một lỗi với tiêu đề cột Boss vừa báo, chỉ khác nó nằm dưới một hàng. */
.lt2-bang td.lt2-nghi .lt2-ghi { color:#4A3B10; }
/* ⛔⛔ NGOẠI LỆ CHO ĐÚNG THẺ GHI CHÚ — Boss 09/09/2026.
   Bảng này có kéo rộng/hẹp cột (bộ dùng chung `gaKeoCot` tự gắn), nên nó mang lớp
   `bang-keo-cot`. Kèm theo đó là luật `.bang-keo-cot td > span { white-space:nowrap;
   overflow:hidden; text-overflow:ellipsis }` (~dòng 4050) — cố ý cắt gọn chữ trong
   ô để kéo hẹp cột không làm vỡ dòng. Độ ưu tiên (0,0,2,2) ăn đứt `.lt2-ghi`.
   Hậu quả đo được: chữ ghi chú rộng THẬT 126px nhồi vào ô 43px, cắt cụt, cao đúng
   một dòng 14px — trái hẳn lời Boss *"chữ sẽ xuống dòng sao cho phù hợp khoảng
   cách độ rộng của cột đó do người dùng chỉnh"*.
   ⛔ ĐỪNG GỠ LUẬT CHUNG KIA. Nó đang phục vụ mọi bảng khác, và chính nó là thứ
      làm việc kéo hẹp cột không vỡ dòng — cũng là lời cô Quỳnh. Chỉ mở ngoại lệ
      cho ĐÚNG thẻ ghi chú, bằng selector nhỉnh hơn một bậc (0,0,3,2).
   ⛔ PHẢI GỠ CẢ `overflow` LẪN `text-overflow`. Chỉ đổi `white-space` thì chữ
      xuống dòng được nhưng vẫn bị xén — cắt nửa vời còn khó hiểu hơn cắt hẳn. */
/* ⛔ MỘT BỘ CHỌN THÔI. Bản đầu tôi viết thêm `.bang-keo-cot .lt2-bang td > .lt2-ghi`
   — bộ ấy CHẾT: nó đòi `.bang-keo-cot` là TỔ TIÊN của `.lt2-bang`, mà hai lớp này
   nằm trên CÙNG MỘT thẻ <table>. Bộ chọn chết còn tệ hơn thừa: thử phá trúng nó
   thì bài vẫn xanh, và suýt nữa tôi kết luận nhầm là phép canh không có răng. */
.lt2-bang.bang-keo-cot td > .lt2-ghi {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  max-width: 100%;
}

/* ══════════════════════════════════════════════════════════════════════════════
   📊 BẢNG KIỂU SHEET — Boss giao 10/09/2026, theo mẫu xlsx-viewer Boss gửi.
   Phần JS ở `js/tinh-nang.js`, tìm chữ `sheetGan`. Ba thứ Boss chốt bằng nút bấm:
   ghăm dòng tiêu đề + cột đầu · menu nhỏ trên đầu mỗi cột · kéo rộng cột.

   ⛔ ĐỪNG đổi màu ở đây thành màu riêng. Mẫu gốc của app là Google Sheets
      (`thiet-ke/BANG-MAU-VA-CHU.md`) — bảng phải mang đúng nền và viền của app,
      chỉ khác ở chỗ ghăm và menu. Tự pha màu mới là dựng lại đúng lỗi "lộ ra là
      máy làm" Boss đã chê năm lần.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ── ① GHĂM CỘT ĐỊNH DANH ──────────────────────────────────────────────────────
   Cột Tên HS dính vào mép trái khi cuộn ngang — Boss chốt 10/09 sau khi xem màn
   mẫu: *"Chỉ ghăm cột Tên HS"*.

   ⛔⛔ NHƯNG GHĂM MỘT CỘT Ở GIỮA THÌ TỰ ĐÀO RA MỘT CÁI LỖ TRẮNG. Cột Tên HS bị
      kéo về mép trái, còn hai cột đứng trước nó (nút thùng rác, số thứ tự) vẫn
      cuộn đi mất; chỗ chúng vừa rời khỏi không ai lấp. Đo được đúng 308px khoảng
      trắng giữa "Tên HS" và "Trường" ở Sổ tuyển sinh — Boss bắt tận mắt 10/09.
   ⇒ Nay ghăm CẢ DẢI từ cột đầu tới cột Tên HS, y như "freeze panes" của Google
     Sheets: mỗi cột trong dải dính ở một mốc `left` riêng, do JS đo và đặt thẳng
     vào `style.left`. Cả dải đứng yên liền một khối, không còn chỗ nào hở.
     Ý Boss vẫn được giữ: cột thùng rác KHÔNG phải là cột duy nhất đứng yên, nó
     chỉ đi kèm để lấp chỗ trống — thứ người ta đọc vẫn là Tên HS.

   Cột nào được ghăm do JS quyết (`sheetChiSoGham`); mọi ô trong dải mang
   `.sheet-cot-gham`, riêng ô ngoài cùng bên phải mang thêm `.sheet-cot-gham-cuoi`
   để vẽ vạch ranh giới. Chỉ bật khi cột Tên HS đủ rộng (>= 60px) và cả dải không
   nuốt quá 55% bề ngang khung cuộn.

   ⛔ `z-index` phải xếp ba tầng, sai một tầng là chữ chồng lên nhau lúc cuộn:
        ô góc (vừa hàng tiêu đề vừa cột đầu)  = 6
        hàng tiêu đề                          = 5   ← đã có sẵn trong app
        cột đầu ở thân bảng                   = 3
   ⛔ Ô ghăm PHẢI có nền đục. Nền trong suốt thì chữ cột sau chạy xuyên qua nó,
      nhìn như bảng vỡ. */
.sheet-moi.sheet-gham tbody td.sheet-cot-gham {
  position: sticky;
  /* `left` thật do JS đặt inline cho TỪNG cột trong dải. Số 0 ở đây chỉ là chỗ
     đỡ cho khoảnh khắc JS chưa kịp chạy — để trống thì `sticky` không có mốc nào
     mà bám và cột trôi đi như thường. */
  left: 0;
  /* ⛔⛔ 7, KHÔNG PHẢI 3 — vá 12/09/2026, CHIỀU CHE NGƯỢC.
     Đo được ở Phụ đạo và Follow up lúc đang cuộn ngang: ô TRÔI đang mở vẽ ĐÈ lên
     dải ghăm — `elementFromPoint` giữa lòng ô ghăm trả về `TD.cs-ptcell`,
     `SELECT.fhs-pt`, `BUTTON.fhs-them-o` của cột trôi.
     ⚠ Cột ghăm che cột trôi là ĐÚNG (freeze panes của Excel). Cái sai là CHIỀU:
       thứ nổi lên từ cột trôi lại đè lên cột ghăm.
     Thang bậc phải xếp lại cho đủ, sai một bậc là hỏng chỗ khác:
         ô trôi thường            = auto
         ô trôi đang gõ           = 5   (luật `td:focus-within`)
         ô trôi bung ra           = 6   (luật `td.sheet-o-bung`)
         ô ghăm ở thân bảng       = 7   ← chỗ này
         ô ghăm bung ra           = 8   (đã có sẵn)
         hàng tiêu đề             = 9   ← phải nâng theo, xem luật dưới
         ô góc (tiêu đề × ghăm)   = 10
     ⛔ ĐỪNG chỉ nâng ô ghăm rồi thôi: nâng lên 7 mà để tiêu đề ở 5–6 thì lúc cuộn
        DỌC, dải ghăm lại trèo lên che hàng tiêu đề — đổi một lỗi lấy một lỗi. */
  z-index: 7;
  /* ⛔⛔ MỘT MÀU CHO CẢ DẢI — Boss 11/09/2026:
     *"Toàn bộ cột cố định bị 2 màu xám và trắng liền kề từng hàng, tôi muốn nó
     chỉ màu xám thôi (tất cả công cụ giao diện sheet nha)"*, chốt bằng nút bấm:
     **"Xám nhạt như hàng chẵn hiện nay"**.
     Đo được trước khi sửa (CSSOM lúc chạy, 4 màn): dải ghăm sọc trắng/xám trong
     khi VÙNG TRÔI trắng trơn — nên sọc kẻ chỉ có ở dải ghăm, nhìn ra hai khối
     rời. Nay cả dải lấy đúng màu HÀNG CHẴN.
     ⛔ Vẫn là màu JS ĐO ĐƯỢC (`--sheet-nen-td2`, xem `sheetGhamCot`), lùi về
        `--nen2`. Cả hai đều đọc lúc chạy — ⛔ đừng ép một mã màu cứng vào đây:
        hàng tiêu đề Sổ tuyển sinh nền xanh lá, ép xám vào là chữ trắng chìm
        nghỉm (đã xảy ra thật, bắt được trên ảnh 10/09). */
  background: var(--sheet-nen-td2, var(--nen2));
}
/* Hàng tiêu đề phải nằm TRÊN cả thân bảng, kể cả dải ghăm (nay 7) và ô ghăm bung
   ra (8). Mỗi bảng tự khai `position: sticky` cho `thead th` với một `z-index`
   riêng (Dự giờ 5, Lộ trình 4, Quản lý học 3…) — ở đây chỉ nâng số, KHÔNG đụng
   `position`, và chỉ trong phạm vi bảng CÓ GHĂM. */
.sheet-moi.sheet-gham thead th { z-index: 9; }
.sheet-moi.sheet-gham thead th.sheet-cot-gham {
  position: sticky;
  left: 0;
  z-index: 10;
  /* ⛔ ÉP CỨNG MÀU Ở ĐÂY LÀ HỎNG. Hàng tiêu đề Sổ tuyển sinh nền XANH LÁ, ép
     `--nen2` (xám) vào ô đầu thì chữ trắng "TVTS" chìm nghỉm — đã xảy ra thật,
     bắt được trên ảnh chụp 10/09. Màu này do JS đo từ ô tiêu đề bên cạnh. */
  background: var(--sheet-nen-th, var(--nen2));
}
/* ⛔ LUẬT KẺ SỌC CHO DẢI GHĂM ĐÃ BỎ — 12/09/2026. Nó là thứ đẻ ra đúng cái
   "hai màu xám và trắng liền kề từng hàng" Boss kêu. Cả dải nay một màu, khai
   một lần ở luật ngay trên.
   ⛔ ĐỪNG KHÔI PHỤC "cho khớp sọc với vùng trôi": đo được là VÙNG TRÔI KHÔNG HỀ
      CÓ SỌC (mọi ô trôi đều trong suốt, nền thật là trắng ở cả hàng chẵn lẫn
      hàng lẻ). Sọc chỉ tồn tại trong dải ghăm — nên bỏ sọc là dải ghăm thành
      một mảng liền, đúng nếp freeze panes. */

/* Ranh giới giữa phần đứng yên và phần trôi — một vạch đậm ở mép phải.
   ⛔ CHỈ Ô CUỐI DẢI mới được vẽ vạch này. Vẽ cho mọi ô trong dải thì cột thùng
      rác và cột số thứ tự cũng có vạch, nhìn ra ba khối rời chứ không phải một
      mảng ghăm liền.

   ⛔⛔ 2px MÀU `--muc`, KHÔNG PHẢI 1px `--vien-ro` — vá 12/09/2026, Boss chốt
      bằng nút bấm: **"Kẻ đậm đường ngăn"**.
   VÌ SAO PHẢI ĐỔI: hôm 11/09 cả dải ghăm về MỘT màu xám (mốc `bff9a5e`, đúng ý
   Boss, ⛔ đừng đụng lại màu NỀN). Cái giá là ranh giới hai vùng gần như biến
   mất — đo bằng PIXEL THẬT (chụp màn rồi giải PNG, không hỏi `getComputedStyle`)
   ở ba màn Dự giờ · Chăm sóc · Follow up, bốn khổ 1001/1280/1366/2320:
       vạch cũ rgb(185,179,170) dày 1px → **1,80:1**   (chuẩn nét đồ hoạ WCAG ≥ 3:1)
   Cùng lúc ấy màn **Lộ trình** đo được **4,36:1** — vì `.lt2-bang .lt2-g1` tự khai
   `border-right: 2px solid var(--muc)` từ trước. App đang không nhất quán với
   chính nó; nay lấy đúng cách Lộ trình làm áp cho cả bộ.
   ⛔ VẪN LÀ `box-shadow`, ĐỪNG ĐỔI SANG `border-right`: bảng đang
      `table-layout: fixed`, thêm viền là bề rộng cột lệch một pixel ở MỌI bảng
      (lời dặn cũ ở khối ô đang chọn bên dưới, đã trả giá một lần).
   ⛔ ĐỪNG ép mã màu cứng: `--muc` đọc lúc chạy nên nền tối tự đổi theo
      (#0D8081 sáng · #4DB6AC tối, cả hai đều đã trên ngưỡng). */
.sheet-moi.sheet-gham .sheet-cot-gham-cuoi { box-shadow: 2px 0 0 var(--muc, var(--vien-ro, var(--vien))); }

/* ⛔ CỐ Ý KHÔNG tô màu ô ghăm khi rê chuột. Mỗi bảng trong app tô hover một màu
   KHÁC NHAU — Lộ trình `#FFF7E6` (vàng), Thời khoá biểu `var(--xanh-nhat)`,
   Quản lý học `var(--nen2)`. Luật chung ở đây không đoán được bảng nào màu nào,
   mà tô sai màu thì cột đầu lệch hẳn khỏi phần dòng còn lại — tệ hơn là để yên.
   Bảng nào muốn cột ghăm sáng theo dòng thì tự khai một dòng ở khối riêng của nó. */

/* ── ①bis TÊN CỘT DÀI XUỐNG HAI DÒNG ─────────────────────────────────────────
   Boss chốt 10/09 sau khi tôi đo: 15 trong 41 tên cột dài hơn bề rộng cột nên bị
   cắt cụt — "Ngày nhận thông tin" hiện thành "Ngày nhận thô...", "Mã định danh
   của học sinh" cần 205px mà cột chỉ có 148px. Boss chọn *"Cho xuống 2 dòng"*.

   ⛔ CHẶN Ở HAI DÒNG, đừng thả tự do. Tên cột ba dòng thì hàng tiêu đề cao vọt
      và bảng 41 cột nhìn như cái hàng rào; hai dòng đủ cho mọi tên đang có.
   ⛔ `line-height: 1.3` — KHÔNG được đặt 1. Chân chữ tiếng Việt (g, y, p) và dấu
      đội đầu bị cắt ngay ở `line-height:1`; đã phải sửa 137 chỗ vì đúng lỗi này.
   ⛔ `-webkit-line-clamp` cần `display:-webkit-box`, mà ô bảng đang là `table-cell`.
      Đổi `display` của `th` là vỡ cả bảng. Nên kẹp chiều cao bằng `max-height`
      tính từ số dòng, cách này không đụng tới kiểu hiển thị của ô. */
/* ⛔⛔ TÊN CỘT MỘT DÒNG, RÊ CHUỘT HIỆN ĐỦ — Boss chốt 10/09/2026 (lần 2).

   ⚠️ CHỖ NÀY TRƯỚC ĐÂY LÀ 'CHO XUỐNG 2 DÒNG', CŨNG DO BOSS RA LỆNH cùng ngày,
   sau khi tôi đo được 15/41 tên cột bị cắt cụt ("Ngày nhận thông tin" hiện
   thành "Ngày nhận thô...", "Mã định danh của học sinh" cần 205px mà cột chỉ
   có 148px). ⇒ NHU CẦU GỐC CỦA BOSS LÀ **ĐỌC ĐƯỢC TÊN CỘT**, không phải là
   "thích hai dòng". Xuống dòng chỉ là cách giải lúc ấy.

   Nay nhu cầu ấy có đường giải khác, gọn hơn: **rê chuột vào là hiện đủ tên**
   (`title`, gắn ở `sheetTenCotDayDu`). Nên Boss chốt lại **một dòng**, vì hai
   dòng làm hàng tiêu đề cao 40–42px (Lịch thi tới 94px, vỡ 3 tầng) trong khi
   mẫu 21st.dev là ~24px — đo được ở mọi màn.

   ⛔⛔ ĐỪNG ĐỌC LỆNH CŨ ("Cho xuống 2 dòng") RỒI SỬA NGƯỢC LẠI. Lệnh ấy đã bị
      chính Boss thay bằng lệnh này, cùng lý do và cùng ngày. Muốn đổi lại thì
      phải hỏi Boss, đừng suy từ chú thích cũ.
   ⛔ MỘT DÒNG THÌ BẮT BUỘC PHẢI CÓ ĐƯỜNG ĐỌC ĐỦ TÊN. Cắt cụt mà không có
      `title` là quay về đúng lỗi Boss chê ban đầu, còn tệ hơn hai dòng.
   ⛔ ĐIỆN THOẠI KHÔNG CÓ CHUỘT nên không rê được: ở màn hẹp (<700px) cho tên
      cột xuống dòng lại như cũ — thà hàng tiêu đề cao hơn còn hơn người dùng
      điện thoại không có cách nào biết cột ấy là cột gì. */
.sheet-moi thead th {
  white-space: nowrap;
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
}
@media (max-width: 700px) {
  /* Không có chuột để rê ⇒ trả lại hai dòng, xem lời dẫn ở trên. */
  .sheet-moi thead th {
    white-space: normal;
    overflow-wrap: anywhere;
    max-height: calc(12px * 1.3 * 2 + 10px);
  }
}

/* ── ② MENU NHỎ TRÊN ĐẦU MỖI CỘT ──────────────────────────────────────────────
   Nút ba chấm nằm ĐÈ lên góc phải ô tiêu đề, ẩn cho tới khi rê chuột vào cột.

   ⛔ ĐỪNG CHỪA CHỖ BẰNG `padding-right`. Tôi đã làm thế lúc đầu và Boss chê ngay
      *"chữ tiêu đề đang khó nhìn"* — 22px padding ăn mất đuôi mọi tên cột, "Ngày
      nhận thông tin" cụt thành "Ngày nhận t...". Tên cột là thứ giáo vụ đọc để
      biết đang điền ô gì; cắt nó đi để lấy chỗ cho một cái nút chỉ thỉnh thoảng
      mới bấm là đổi nhầm thứ tự ưu tiên.
   ⇒ Nút đè lên, và mang theo một dải nền cùng màu tiêu đề để lúc hiện ra chữ
     không lẫn vào ba chấm. Google Sheets cũng làm đúng vậy. */
/* ⛔⛔⛔ `:where(...)` — ĐIỂM BẰNG KHÔNG. ĐỪNG BỎ, VÀ ĐỪNG VIẾT LẠI THÀNH
   `.sheet-moi thead th { position: relative }` CHO GỌN. Vá 10/09/2026.

   Bản trước tôi viết đúng câu gọn ấy. Nó có điểm (0,1,2) — NGANG CƠ với
   `.lt2-bang thead th { position: sticky }` (~10432), `.lt-bang` (~5980),
   `.qlh-bang` (~368), `.bdc-bang` (~1185), `.pq-bang` (~2542) — mà nằm SAU
   tất cả, nên nó THẮNG và THAY `sticky` bằng `relative`: đầu bảng của NĂM
   bảng kia thôi không dính nữa. Kênh Coder đo trên bản gốc, cuộn 209px: hàng
   tiêu đề trôi lên -51px, riêng ô "Lớp" (điểm 0,2,1 nên thoát) đứng lại ở
   158px ⇒ ĐẦU BẢNG VỠ LÀM ĐÔI. Không một lỗi JS nào — hỏng câm.
   Đây gần như chắc chắn là gốc thật của lỗi Boss báo: *"tên cột liên hệ đang
   bị mất, lỗi không hiện lên"* ở Follow up. Tiêu đề hết dính thì cuộn xuống
   là nó trôi khỏi màn, chẳng cần ai đè lên cả.

   ⇒ `:where()` cho câu này ĐIỂM 0. Nghĩa là:
       · bảng nào tự khai `position` cho ô tiêu đề → luật của bảng ấy LUÔN thắng;
       · bảng nào không khai gì → vẫn được `relative` để nút ba chấm bám đúng.
     Và `sticky` cũng là ô ĐÃ ĐỊNH VỊ y như `relative`, nên nút ba chấm vẫn
     bám đúng góc — không mất gì cả.

   ⛔⛔ FILE NÀY ĐÃ CHÉP SẴN ĐÚNG BÀI HỌC NÀY TỪ 06/08/2026 (xem khối
      `:where(.bang-keo-cot thead th)` ~4454) VÀ TÔI VẪN DẪM PHẢI. Nay là lần
      thứ BA trong một ngày cùng một kiểu: luật mới của `.sheet-moi` đè mất
      luật cũ của bảng khác (trước đó: `text-align` ở Chăm sóc, và luật ép
      một dòng đè luật bung).
   ⇒ LUẬT CHUNG, ÁP CHO MỌI LUẬT `.sheet-moi ... thead/tbody/th/td` THÊM VÀO
     FILE NÀY: trước khi thêm, đi tìm xem có luật nào CÙNG THUỘC TÍNH, điểm
     NGANG hoặc THẤP HƠN, đứng TRƯỚC trong file không. Có thì hoặc dùng
     `:where()` như đây, hoặc khai lại cho từng bảng. Đừng tin mắt — hỏi CSSOM.
   ⛔ Kiểu lỗi này KHÔNG BAO GIỜ báo lỗi. Chỉ lộ ra LÚC ĐANG CUỘN; đứng yên thì
      mọi thứ trông hoàn hảo. */
:where(.sheet-moi thead th) { position: relative; }

.sheet-nut-menu {
  position: absolute;
  right: 3px;
  top: 50%;
  transform: translateY(-50%);
  width: 18px;
  height: 18px;
  padding: 0;
  border: 0;
  border-radius: var(--r-sm, 4px);
  background: transparent;
  cursor: pointer;
  opacity: 0;
  transition: opacity .15s ease, background-color .15s ease;
}
/* ⛔ Trên điện thoại KHÔNG có chuột để rê — `:hover` không bao giờ xảy ra, nút
   sẽ vô hình vĩnh viễn. Máy cảm ứng thì hiện sẵn, mờ nhẹ cho đỡ rối. */
@media (hover: hover) {
  .sheet-moi thead th:hover .sheet-nut-menu,
  .sheet-nut-menu:focus-visible,
  thead th.dang-mo-menu .sheet-nut-menu { opacity: 1; }
}
@media (hover: none) { .sheet-nut-menu { opacity: .55; } }
/* Nền của nút phải TRÙNG nền ô tiêu đề, để nút đè lên chữ mà không lộ ra một
   mảng màu lạ.

   ⛔⛔ ĐỪNG DÙNG BIẾN `--sheet-nen-th` Ở ĐÂY. Biến ấy do JS đo và chỉ được đặt khi
      bảng CÓ cột đáng ghăm; bảng nào không có cột "Tên…" thì hàm thoát sớm, biến
      không tồn tại, CSS lùi về `--nen2` (xám rất nhạt) — và trên hàng tiêu đề nền
      xanh lá nó hiện ra thành MỘT CỤC TRẮNG đè lên tên cột. Boss bắt được đúng
      cảnh này ở cột "Trạng thái" ngày 10/09.
   ⇒ `inherit` lấy thẳng nền của chính ô tiêu đề đang chứa nút, nên đúng ở mọi
     bảng mà không cần JS đo, không cần giá trị lùi, và không thể lệch màu.
   ⛔ Cũng vì thế mà BỎ dải `box-shadow` mờ: shadow không nhận `inherit`, viết màu
      gì vào đó cũng là đoán, và đoán sai thì lại đúng cục trắng ấy. */
.sheet-moi thead th:hover .sheet-nut-menu,
thead th.dang-mo-menu .sheet-nut-menu,
.sheet-nut-menu:focus-visible {
  background-color: inherit;
}
.sheet-nut-menu:hover { filter: brightness(1.12); }

/* ⛔ ĐÍCH BẤM PHẢI RỘNG HƠN HÌNH. Ba chấm vẽ ra chỉ 18×18px — đo 10/09 —
   trong khi chuẩn tối thiểu là 44×44 (Apple) / 48×48 (Google Material). Trên
   điện thoại 18px là bấm mười lần trượt ba. Nới bằng một lớp trong suốt phủ ra
   ngoài, KHÔNG nới `width`/`height`: nới thật thì ba chấm to lên và ô tiêu đề
   phải giãn theo, kéo cả bảng rộng ra.
   ⛔ Vẫn chưa chạm 44 theo chiều dọc — ô tiêu đề của bảng vốn chỉ cao khoảng 30px,
      nới quá thì vùng bấm tràn sang dòng dữ liệu bên dưới và người ta bấm menu lại
      trúng ô nhập. 34×42 là mức cao nhất còn nằm gọn trong ô. Nói rõ ra đây để
      lượt sau khỏi tưởng là bỏ sót. */
.sheet-nut-menu::before {
  content: "";
  position: absolute;
  inset: -12px -8px;
}

/* Ba chấm vẽ bằng bóng đổ — nhẹ hơn ba thẻ con, và không lọt vào textContent
   của ô tiêu đề (nếu lọt thì hàm sắp xếp đọc nhầm tên cột).

   ⛔⛔ PHẢI LÀ `currentColor`, KHÔNG PHẢI `--chu-mo`. Hàng tiêu đề Sổ tuyển sinh
      nền XANH LÁ đậm, mà `--chu-mo` là xám #6B6660 — đo ra tương phản **1,0**,
      tức ba chấm biến mất hoàn toàn. Boss nhìn ảnh là thấy ngay. `currentColor`
      lấy đúng màu chữ của ô ấy nên trắng trên nền xanh, đen trên nền xám, và tự
      đúng ở mọi bảng khác mà không phải khai thêm dòng nào. */
.sheet-nut-menu > span {
  display: block;
  width: 3px;
  height: 3px;
  margin: 0 auto;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 -4px 0 currentColor, 0 4px 0 currentColor;
}

/* Bảng menu — JS đặt vào `body` với `position:fixed`, xem lời dẫn trong `sheetMenuCot`. */
.sheet-menu {
  position: fixed;
  z-index: 9000;
  min-width: 176px;
  padding: 4px;
  border-radius: var(--r-md, 8px);
  border: 1px solid var(--vien);
  background: var(--the);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .16);
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.sheet-menu > button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 7px 10px;
  border: 0;
  border-radius: var(--r-sm, 4px);
  background: transparent;
  color: var(--chu);
  font-size: 13px;
  /* ⛔ 1.45 chứ không phải 1 — `line-height:1` cắt cụt chân chữ tiếng Việt
     (dấu đội lên trên, chân g/y/p thò xuống). Đã sửa 137 chỗ vì lỗi này. */
  line-height: 1.45;
  cursor: pointer;
  white-space: nowrap;
}
.sheet-menu > button:hover { background: var(--nen2); }
.sheet-menu-vach { height: 1px; margin: 3px 6px; background: var(--vien); }

/* Cột đang được sắp xếp: một mũi tên nhỏ sau tên cột. */
.sheet-moi thead th[data-xep]::after {
  content: "▲";
  margin-left: 4px;
  font-size: 8px;
  color: var(--chu-mo);
  vertical-align: middle;
}
.sheet-moi thead th[data-xep="xuong"]::after { content: "▼"; }

/* Cột đã ẩn. Ẩn cả ô tiêu đề lẫn ô thân, không thì bảng lệch cột. */
.sheet-moi .sheet-cot-an { display: none !important; }


/* ══════════════════════════════════════════════════════════════════════════════
   🟦 BÔI XANH NHIỀU Ô — Boss giao 10/09/2026. Phần JS ở `js/tinh-nang.js`, tìm
   `sheetGanChonO`. Boss chốt: kéo chuột chọn vùng · Ctrl+C ra Excel · Ctrl+V từ
   Excel vào · Delete có hỏi trước và Ctrl+Z lấy lại được.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ⛔ TÔ BẰNG LỚP PHỦ `::after`, ĐỪNG ĐỔI `background` CỦA Ô. Ô trong sổ tuyển sinh
   đã mang màu riêng theo nghiệp vụ — dòng quá hạn nền đỏ nhạt, dòng đã tiếp nhận
   nền hổ phách, ô Boss tự tô màu. Đè `background` lên là nuốt sạch những màu ấy,
   và bỏ chọn xong cũng không biết trả về màu nào cho đúng.
   Lớp phủ mờ thì màu gốc vẫn nhìn thấy xuyên qua. */
/* ⛔⛔ TÔ BẰNG `box-shadow: inset`, ĐỪNG DÙNG LỚP PHỦ `position:absolute`.
   Lớp phủ đòi ô mang `position: relative`, mà đặt `relative` lên một `<td>` trong
   bảng `table-layout: fixed` nằm cạnh cột ghăm `position: sticky` thì Chrome dựng
   lại bố cục hàng ấy: đo 10/09 ra ô kế bên nhảy từ 590px sang 1108px — lệch đúng
   518px, và CHỈ ở những dòng có ô đang chọn. Nhìn trên ảnh thì tên trường rơi
   xuống dưới tiêu đề "Tên PH", như thể dữ liệu sai cột.
   `inset` phủ kín ô mà không đụng gì tới bố cục, và vẫn nằm dưới chữ nên đọc được. */
.sheet-moi td.sheet-o-chon {
  /* Sắc xanh của app pha loãng — không bịa màu mới. */
  box-shadow: inset 0 0 0 9999px rgba(0, 121, 58, .13),
              inset 0 0 0 1px rgba(0, 121, 58, .38);
}
body.toi .sheet-moi td.sheet-o-chon {
  box-shadow: inset 0 0 0 9999px rgba(90, 200, 140, .16),
              inset 0 0 0 1px rgba(90, 200, 140, .45);
}

/* ⛔⛔ Ô VỪA GHĂM VỪA ĐANG CHỌN PHẢI GỘP HAI BÓNG. Vạch kẻ mép phải của cột ghăm
   cũng vẽ bằng `box-shadow`; hai luật cùng một thuộc tính thì luật sau đè hẳn
   luật trước, và cột ghăm — đúng cột Tên HS người ta hay bôi nhất — không hiện
   màu xanh nào cả. Nhìn ảnh 10/09 thì cột Trường xanh còn cột Tên HS trắng trơn,
   như thể chỉ chọn được một cột.
   ⛔ Đừng "chữa" bằng cách đổi vạch ghăm sang `border-right`: bảng đang
      `table-layout: fixed`, thêm viền là bề rộng cột lệch đi một pixel ở mọi bảng. */
/* ⛔ CHỈ Ô CUỐI DẢI GHĂM mới cần gộp vạch — nó là ô duy nhất vẽ vạch ranh giới.
   Mấy ô ghăm còn lại (thùng rác, số thứ tự) dùng luật chọn thường ở khối ③.
   ⛔ Độ đặc hiệu của luật này CAO HƠN khối ③ ở cuối file, nên nếu để nguyên
      `.sheet-cot-gham` thì nó nuốt luôn viền 2px kiểu Sheets của cả dải.
   ⛔⛔ ĐOẠN VẠCH (`2px 0 0 var(--muc…)`) PHẢI KHỚP TỪNG CHỮ với luật gốc ở khối ①.
      Có BỐN chỗ chép lại nó (sáng/tối × hai khối này) — sửa màu hay bề dày ở khối
      ① mà quên bốn chỗ này thì ô ĐANG CHỌN tụt về vạch cũ, mà chỉ lộ ra đúng lúc
      người dùng bôi ô — không ai báo, bài kiểm nhìn màn tĩnh cũng không thấy. */
.sheet-moi.sheet-gham tbody td.sheet-cot-gham-cuoi.sheet-o-chon {
  box-shadow: inset 0 0 0 9999px rgba(0, 121, 58, .13),
              inset 0 0 0 1px rgba(0, 121, 58, .38),
              2px 0 0 var(--muc, var(--vien-ro, var(--vien)));
}
body.toi .sheet-moi.sheet-gham tbody td.sheet-cot-gham-cuoi.sheet-o-chon {
  box-shadow: inset 0 0 0 9999px rgba(90, 200, 140, .16),
              inset 0 0 0 1px rgba(90, 200, 140, .45),
              2px 0 0 var(--muc, var(--vien-ro, var(--vien)));
}

/* ⛔ Trong lúc kéo phải TẮT bôi đen chữ. Không tắt thì trình duyệt vừa bôi đen văn
   bản vừa chọn ô, hai màu chồng lên nhau, nhìn như bảng hỏng. */
.sheet-moi.sheet-dang-chon { user-select: none; -webkit-user-select: none; }

/* Lời nhắn ngắn ở góc — chỉ dùng khi app không có sẵn hộp báo nào. */
.sheet-bao {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%) translateY(8px);
  z-index: 9500;
  max-width: min(92vw, 420px);
  padding: 9px 14px;
  border-radius: 999px;
  border: 1px solid var(--vien);
  background: var(--the);
  color: var(--chu);
  font-size: 13px;
  line-height: 1.45;
  box-shadow: 0 6px 20px rgba(0, 0, 0, .16);
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease, transform .2s ease;
}
.sheet-bao.hien { opacity: 1; transform: translateX(-50%) translateY(0); }

/* Hộp hỏi xác nhận trước khi xoá/dán */
.sheet-hoi {
  position: fixed;
  inset: 0;
  z-index: 9600;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(0, 0, 0, .38);
}
.sheet-hoi-hop {
  width: min(100%, 380px);
  padding: 18px;
  border-radius: var(--r-md, 4px);
  border: 1px solid var(--vien);
  background: var(--the);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .24);
}
.sheet-hoi-tieu {
  font-size: 15px;
  font-weight: 600;
  /* ⛔ 1.45 — `line-height:1` cắt chân chữ tiếng Việt. */
  line-height: 1.45;
  color: var(--chu);
}
.sheet-hoi-dan {
  margin-top: 6px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--chu-mo);
}
.sheet-hoi-nut {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 16px;
}
.sheet-hoi-nut > button {
  min-height: 36px;
  padding: 0 16px;
  border-radius: var(--r-md, 4px);
  border: 1px solid var(--vien);
  background: var(--the);
  color: var(--chu);
  font-size: 13px;
  line-height: 1.45;
  cursor: pointer;
}
.sheet-hoi-nut > .sheet-hoi-ok {
  border-color: var(--xanh, #00793A);
  background: var(--xanh, #00793A);
  color: #fff;
  font-weight: 600;
}
.sheet-hoi-nut > button:hover { filter: brightness(1.06); }

/* ══════════════════════════════════════════════════════════════════════════════
   ③ LƯỚI KIỂU GOOGLE SHEETS — Boss chốt 10/09/2026
   *"phải sửa lại giao diện của các công cụ có dạng sheet thành y hệt như sheet…
     màu trắng và mọi thứ y hệt chỉ riêng cái tiêu đề để màu cũ thôi"*

   Bốn thứ làm nên "cảm giác Sheets", đo từ mẫu Excel-Style Table (21st.dev
   #8778) và từ ảnh Excel thật Boss gửi:
     ① kẻ MỌI ô — cả ô rỗng. Đây là thứ khác biệt lớn nhất: bảng cũ chỉ kẻ
        ngang, nên vùng trống bên phải nhìn như tờ giấy trắng chứ không như sổ.
     ② nền trắng thuần, chữ đen nhỏ, không thẻ màu, không chữ đậm.
     ③ ô đang chọn viền ĐẬM 2px — Sheets dùng xanh dương, mình dùng xanh trung tâm.
     ④ hàng tiêu đề GIỮ MÀU CŨ (Boss dặn thẳng), không đổi sang xám như Sheets.

   ⛔ ĐỪNG đổi `border-collapse` ở đây. Bảng app đang `table-layout: fixed`, và
      nhiều màn tự vẽ viền riêng; đổi kiểu gộp viền là bề rộng cột nhảy một pixel
      ở mọi bảng. Kẻ bằng `border` một phía (phải + dưới) thì không đụng gì cả.
   ══════════════════════════════════════════════════════════════════════════════ */

.sheet-moi {
  /* ⛔ 18/09 — ĐƯỜNG KẺ NÀY CỐ Ý KHÔNG MƯỢN `--vien` NỮA.
     Boss dặn: *"ko được cả app có viền đậm vậy chỉ bảng sheet thôi, các cột
     trong bảng sheet mới có viền đậm chứ tôi có bảo cả app đâu"*. Lần trước tôi
     đổi thẳng `--vien` cho đậm — nó ăn lan sang thẻ, hộp thoại, ô nhập, tức cả
     app, ngoài phạm vi Boss cho. `--sheet-ke` chỉ áp cho `.sheet-moi tbody td`
     và `.sheet-moi thead th`, đúng "các cột trong bảng sheet".
     ⛔ Đừng trả nó về `var(--vien, …)` cho gọn — làm thế là dựng lại đúng lỗi ấy. */
  --sheet-ke: #9A948B;
  --sheet-chon-vien: #00793A;

  /* ⛔ CỘT GHIM GIỮ XÁM — Boss chốt HAI LẦN, lần sau là 18/09/2026:
     *"nhưng mà mấy cái cột cố định thì phải có màu xám sửa lại cho tôi"*.
     ĐÃ THỬ TRẮNG TINH RỒI BỊ TRẢ LẠI trong cùng một phiên — đừng đi lại đường đó.
     Câu *"trong cột phải trắng xóa như tờ giấy mới"* nói về CỘT THƯỜNG (vùng trôi),
     không phải dải ghim: dải ghim phải khác màu thì mới thấy đâu là phần đứng yên.
     Vùng trôi ăn `--nen` (#FFFFFF) nên đã trắng sẵn; hai biến dưới chỉ lo dải ghim.
     ⛔ Nút công cụ ăn `--nen2` (#F3F3F3) — việc khác, không đụng. */
  --sheet-nen-th: #F0EEEA;
  --sheet-nen-td2: #F0EEEA;
}
body.toi .sheet-moi {
  /* Nền tối rõ hơn một bậc cho cân với bản sáng, nhưng dịu tay hơn: nền tối
     chói mắt nhanh hơn nền sáng. Vẫn chỉ trong bảng sheet. */
  --sheet-ke: rgba(255,255,255,.26);
  --sheet-chon-vien: #5AC88C;
  --sheet-nen-th: #2A3138;
  --sheet-nen-td2: #242A30;
}

/* ① Kẻ mọi ô. Chỉ vẽ hai phía (phải + dưới) nên không cộng thêm bề rộng vào ô
   nào — mép trái và mép trên đã là viền của ô liền kề. */
.sheet-moi tbody td {
  border-right: 1px solid var(--sheet-ke);
  border-bottom: 1px solid var(--sheet-ke);
}
.sheet-moi thead th {
  border-right: 1px solid var(--sheet-ke);
}

/* ② Chữ trong ô: cỡ đều, canh trái, KHÔNG đậm — đúng kiểu bảng tính.
   ⛔ Không đụng tới `thead th`: Boss dặn tiêu đề giữ nguyên màu và kiểu cũ. */
.sheet-moi tbody td {
  font-weight: 400;
  vertical-align: middle;
}

/* ③ Ô đang chọn: viền đậm 2px kiểu Sheets, vẽ bằng `box-shadow: inset` chứ
   KHÔNG bằng `border`.
   ⛔ Dùng `border` là bề rộng ô nhảy 2px ngay lúc bấm vào, cả cột giật một cái.
   ⛔ Và tuyệt đối không dùng `position: relative` + lớp phủ: ở bảng có cột ghăm
      `sticky`, `relative` trên `<td>` đẩy ô kế bên lệch đi 518px — đã đo được
      đúng con số ấy hôm 10/09. */
.sheet-moi tbody td.sheet-o-chon {
  box-shadow: inset 0 0 0 9999px rgba(0, 121, 58, .10),
              inset 0 0 0 2px var(--sheet-chon-vien);
}
body.toi .sheet-moi tbody td.sheet-o-chon {
  box-shadow: inset 0 0 0 9999px rgba(90, 200, 140, .13),
              inset 0 0 0 2px var(--sheet-chon-vien);
}
/* Ô ghăm phải gộp cả vạch ranh giới vào cùng một khai báo — hai luật cùng dùng
   `box-shadow` thì luật sau đè hẳn luật trước, và cột Tên HS (cột người ta bôi
   nhiều nhất) sẽ không hiện màu chọn nào cả. */
.sheet-moi.sheet-gham tbody td.sheet-cot-gham-cuoi.sheet-o-chon {
  box-shadow: inset 0 0 0 9999px rgba(0, 121, 58, .10),
              inset 0 0 0 2px var(--sheet-chon-vien),
              2px 0 0 var(--muc, var(--vien-ro, var(--vien)));
}
body.toi .sheet-moi.sheet-gham tbody td.sheet-cot-gham-cuoi.sheet-o-chon {
  box-shadow: inset 0 0 0 9999px rgba(90, 200, 140, .13),
              inset 0 0 0 2px var(--sheet-chon-vien),
              2px 0 0 var(--muc, var(--vien-ro, var(--vien)));
}

/* ══════════════════════════════════════════════════════════════════════════════
   ④ DẢI SỐ DÒNG 1, 2, 3… — Boss chốt 10/09/2026: *"Có, và gộp nút thùng rác vào đó"*

   Bình thường dải hiện SỐ; rê chuột vào dòng thì số nhường chỗ cho nút thùng rác.
   Hai thứ hoán đổi bề rộng cho nhau nên chữ trong ô KHÔNG xê dịch một pixel nào.

   ⛔⛔ KHÔNG `position: absolute` cho số. Ô cột đầu nằm trong dải ghăm
      (`position: sticky`), chồng thêm một lớp định vị nữa là số trôi khỏi ô lúc
      kéo ngang — đúng bẫy đã ghi ở `.cts-xoa`.
   ⛔ Nền dải vẽ bằng `background-image` của chính ô, không bằng `::before`: chỉ
      nền của ô mới phủ TRỌN chiều cao, còn `::before` là chữ inline nên chỉ cao
      bằng một dòng, dải sẽ hụt ở ô có nội dung hai dòng.
   ══════════════════════════════════════════════════════════════════════════════ */

.sheet-moi.sheet-so-dong tbody { counter-reset: sheet-dong; }
/* ⛔ CHỈ dòng dữ liệu mới được tăng số. Dòng đệm của cuộn ảo và dòng gộp
   nhóm cũng là <tr>; đếm cả chúng thì số lệch một bậc ngay từ dòng đầu.
   JS đánh dấu dòng thật bằng .sheet-hang — xem sheetCotSoDong. */
.sheet-moi.sheet-so-dong tbody tr.sheet-hang { counter-increment: sheet-dong; }

/* ══════════════════════════════════════════════════════════════════════════════
   DẢI SỐ DÒNG PHẢI LÀ LỚP NỔI, KHÔNG PHẢI MỘT MẢNH NẰM TRONG DÒNG CHỮ
   ⛔⛔ VÁ 10/09/2026 — bản trước để `::before` là một mảnh `inline-block` nằm
      chung dòng với nội dung, rồi hoán bề rộng với nút xoá lúc rê chuột. Ba chỗ
      hỏng, đều do CÙNG một nguyên nhân là "mảnh nằm trong dòng":
      ① Ô đầu của Follow HS · Dự giờ · Chăm sóc · Phụ đạo là hộp co giãn có
         `flex-wrap` (khối ⑫). `::before` chỉ chiếm chỗ trên DÒNG ĐẦU; mọi thứ
         rơi xuống dòng hai bắt đầu ngay mép chữ, tức x = mép ô + 8px — nằm gọn
         trong dải xám. Kênh Phá đo được "Lớp 3A1" ở x=84 trong lúc mép phải dải
         là x=124, và đường kẻ dọc của dải cắt ngang chữ.
      ② Nút xoá mang `order:-1` nên trong hộp co giãn nó đứng TRƯỚC `::before` —
         tức là nằm luôn trong dải, chồng lên chỗ của con số.
      ③ Cú hoán bề rộng (số co về 0, nút nở ra 40px) chỉ đúng khi ô có đủ CẢ HAI;
         mỗi bảng một kiểu nên đã phải chắp thêm `:has()` để chữa.
   ⇒ Tách hẳn hai tầng: dải số là LỚP NỔI (`position:absolute`) chiếm đúng 40px
     bên trái ô, còn nội dung được đẩy sang bằng `padding-left`. Nội dung nằm
     một dòng hay năm dòng, là chữ hay là khối, xếp xuôi hay ngược — cũng không
     bao giờ bò vào dải được nữa, vì chỗ ấy không còn nằm trên đường chữ chảy.
   ⛔ `position: relative` trên `<td>` (kể cả `display:table-cell`) là hợp lệ và
      mọi trình duyệt hiện đại đều neo đúng — đã đo lại trên cả sáu màn.
   ⛔ ĐỪNG bỏ nút xoá đi cho gọn: xoá hàng là việc thật, và máy cảm ứng không có
      rê chuột. Khối `@media (hover:none)` bên dưới bày sẵn cả hai.
   ══════════════════════════════════════════════════════════════════════════════ */

/* Nền dải xám + vạch ngăn, phủ trọn chiều cao ô.
   ⛔ Ô ghăm đã có `background` màu do JS đo — `background-image` chồng lên
      `background-color` ấy chứ không xoá nó, nên hai luật sống chung được. */
/* ⛔⛔ LUẬT ĐÁNH SỐ DÒNG TỪNG THÁO MẤT GHIM CỦA CỘT TÊN — vá 11/09/2026.
   Boss gọi đúng tên trước cả hai chúng tôi: *"cột bị lỗi đi theo màn hình kéo sang"*.
   ĐO THẬT lúc ĐANG CUỘN (đứng yên thì mọi cột đều đúng chỗ, số nào cũng đẹp):
       Follow up : cot0=relative · cot1=sticky left:190px · cot2=sticky left:310px
       Dự giờ    : cot0=relative · cot1=sticky left:190px · cot2=static
       cuộn 120px → cột tên trôi khỏi màn, elementFromPoint trả về DIV.noi-dung rồi
       "trống"; ở Dự giờ cột 1 đứng yên còn cột 2 trôi qua ⇒ HAI CỘT CHỒNG NHAU,
       chữ cụt mất ĐẦU (không phải cắt gọn ở mép).
   ⛔ CHỖ QUYẾT ĐỊNH: cột 1 ghim ở `left: 190px` = ĐÚNG bề rộng cột 0. Bố cục đã
      giả định cột 0 ghim chiếm 0–190px — tức có người viết ĐÚNG, rồi dòng
      `position: relative` dưới đây THÁO MẤT ghim ấy. Không lỗi, không ai báo.
   ⛔ Nó thắng bằng ĐỘ ĐẶC HIỆU chứ không phải thứ tự: (0,4,3) so với luật ghim
      `.sheet-moi.sheet-gham tbody td.sheet-cot-gham` (0,3,2).
   ⇒ Bọc `:where()` quanh hai lớp đầu: còn (0,2,3), thua luật ghim (0,3,2) ở hạng
     lớp, nên ô GHĂM thì ghim thắng, ô KHÔNG ghăm vẫn `relative` như cũ (không luật
     nào cạnh tranh). ⛔ KHÔNG siết luật ghim lên và KHÔNG dùng `!important` —
     siết lên là đẻ ra ngoại lệ chết câm cho lượt sau.
   ⛔ `position: sticky` CŨNG là gốc định vị cho `position: absolute`, nên `::before`
      vẽ số dòng vẫn nằm đúng chỗ. Đừng đổi sang cách khác.
   ⛔ Số `left` của cột 1 và 2 do JS đặt theo bề rộng THẬT — đừng gõ tay số nào vào
      đây. Đổi kiểu ghim thì phải rà lại mọi con số đi kèm (bệnh `left: 72px` đổi
      nghĩa khi `relative → sticky`). */
/* ⛔⛔ TACH LAM HAI KHOI — va 11/09/2026, chua HOI QUY DO CHINH TOI GAY RA.
   Cu truoc bao ca selector nay trong `:where()` de nhuong `position` cho luat ghim.
   Nhung `:where()` ha do dac hieu CUA CA KHOI, nen no nhuong luon `padding-left: 48px`
   — cho chua cho SO DONG. Do that: padding 48px -> 4px, trong khi so dong chiem 40px
   ⇒ SO DONG VE DE LEN CHU DAU CUA TEN. Boss thay va tuong loi phong chu.
   ⛔ BAI HOC: `:where()` khong phai dao mo — no ha CA KHOI. Muon nhuong DUNG MOT
      thuoc tinh thi phai TACH KHOI, de nhung thuoc tinh con lai o do dac hieu cu.
   Khoi 1 (do dac hieu CU, (0,4,3)): giu cho cho so dong va vach ke.
   Khoi 2 (`:where`, (0,2,3)): chi nhuong `position` cho luat ghim cot ten. */
.sheet-moi.sheet-so-dong tbody tr.sheet-hang td:first-child {
  padding-left: 48px;
  background-image:
    linear-gradient(to right,
      var(--sheet-so-nen, rgba(0, 0, 0, .035)) 0 40px,
      transparent 40px),
    linear-gradient(to right,
      transparent 0 40px,
      var(--sheet-ke) 40px 41px,
      transparent 41px);
  background-repeat: no-repeat;
}
:where(.sheet-moi.sheet-so-dong) tbody tr.sheet-hang td:first-child {
  position: relative;
}
body.toi .sheet-moi.sheet-so-dong tbody tr.sheet-hang td:first-child {
  --sheet-so-nen: rgba(255, 255, 255, .06);
}

/* Con số. `counter()` để trình duyệt tự đếm — không cần JS ghi số nào vào DOM.
   ⛔ `pointer-events:none` để lớp nổi này không nuốt cú bấm vào ô bên dưới. */
.sheet-moi.sheet-so-dong tbody tr.sheet-hang td:first-child::before {
  content: counter(sheet-dong);
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  color: var(--chu-mo, #6B6660);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}

/* Nút xoá cũng dọn vào đúng dải ấy, chồng lên chỗ con số.
   ⛔ PHẢI KỂ CẢ `.nv-b.xoa` VÀ `.fhs-xoa`, KHÔNG CHỈ `.cts-xoa` — mỗi màn gọi nút
      xoá hàng một tên: Sổ tuyển sinh `.cts-xoa`, Follow up · Chăm sóc · Dự giờ
      `.nv-b.xoa`, Follow HS còn thêm `.fhs-xoa`. Khai thiếu một tên là màn ấy
      giữ nguyên nút trong dòng chữ và ăn mất 35px của cột tên. */
.sheet-moi.sheet-so-dong tbody tr.sheet-hang td:first-child .cts-xoa,
.sheet-moi.sheet-so-dong tbody tr.sheet-hang td:first-child > .nv-b.xoa,
.sheet-moi.sheet-so-dong tbody tr.sheet-hang td:first-child > .fhs-xoa {
  position: absolute;
  left: 8px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  margin: 0;
  padding: 0;
  /* 24px là sàn đích bấm. Trước đây phải bóp xuống 22px vì nút nằm
     trong dòng chữ và mỗi pixel là một pixel cướp của tên học viên. Nay nó
     nằm trong dải nổi rộng 40px, không ăn của ai một pixel nào nữa. */
  width: 24px;
  min-width: 24px;
  height: 24px;
  min-height: 24px;
}

@media (hover: hover) {
  /* Lúc thường thấy SỐ; rê vào dòng thì số mờ đi, thùng rác hiện ra đúng chỗ ấy.
     ⛔ Dùng `opacity`, ĐỪNG `display:none` — bỏ hẳn phần tử thì đích bấm biến
        mất trong lúc con trỏ đang bay tới, bấm hụt liên tục. */
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang td:first-child .cts-xoa,
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang td:first-child > .nv-b.xoa,
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang td:first-child > .fhs-xoa {
    opacity: 0;
    pointer-events: none;
  }
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang:hover td:first-child .cts-xoa,
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang:hover td:first-child > .nv-b.xoa,
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang:hover td:first-child > .fhs-xoa {
    opacity: .55;
    pointer-events: auto;
  }
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang:hover td:first-child .cts-xoa:hover,
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang:hover td:first-child > .nv-b.xoa:hover,
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang:hover td:first-child > .fhs-xoa:hover {
    opacity: 1;
  }
  /* Số nhường chỗ — chỉ khi ô THẬT SỰ có nút xoá để lấp vào, không thì rê chuột
     qua bảng nào không có nút là dải trống trơn. */
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang:hover td:first-child:has(> .nv-b.xoa)::before,
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang:hover td:first-child:has(> .fhs-xoa)::before,
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang:hover td:first-child:has(.cts-xoa)::before {
    opacity: 0;
  }
}

/* ⛔ MÁY CẢM ỨNG KHÔNG BAO GIỜ CÓ `:hover`. Giấu nút sau cú rê chuột là trên điện
   thoại KHÔNG CÒN CÁCH NÀO xoá hàng — tính năng chết mà bài kiểm vẫn xanh.
   ⇒ Ở đó bày cả hai: dải rộng hơn, số bên trái, nút bên phải. */
@media (hover: none) {
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang td:first-child {
    padding-left: 70px;
    background-image:
      linear-gradient(to right,
        var(--sheet-so-nen, rgba(0, 0, 0, .035)) 0 62px,
        transparent 62px),
      linear-gradient(to right,
        transparent 0 62px,
        var(--sheet-ke) 62px 63px,
        transparent 63px);
  }
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang td:first-child::before {
    width: 26px;
  }
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang td:first-child .cts-xoa,
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang td:first-child > .nv-b.xoa,
  .sheet-moi.sheet-so-dong tbody tr.sheet-hang td:first-child > .fhs-xoa {
    left: 32px;
  }
}

/* ══════════════════════════════════════════════════════════════════════════════
   ⑤ Ô CÓ LỰA CHỌN — MẶC NHƯ Ô CHỮ THƯỜNG, ĐÚNG KIỂU GOOGLE SHEETS
   Boss chốt 10/09/2026: *"Y hệt Google Sheets: chữ thường, mũi tên hiện khi bấm"*
   và *"chức năng ô nào có lựa chọn thì thiết kế hợp với kiểu mới chứ không giữ
   lại kiểu cũ này nữa nó xấu và không dễ dùng"*.

   Ô chọn nhiều mục của app là `<details class="dg-chipbox"><summary>` — mặc sẵn
   một cái hộp có viền, bo góc và nền riêng. Trong một bảng tính thì cái hộp ấy
   là thứ phá vỡ ảo giác "đây là bảng": 40 ô thành 40 cái nút.

   ⛔ CHỈ ĐỔI KHI Ô NẰM TRONG BẢNG (`.sheet-moi td …`). Cùng lớp `dg-chipbox` ấy
      còn dùng ở FORM dự giờ, nơi cái hộp là đúng — gỡ viền ở đó là mất hẳn dấu
      hiệu "chỗ này bấm được".
   ══════════════════════════════════════════════════════════════════════════════ */

/* ① Cởi bỏ vỏ hộp: không viền, không bo góc, không nền riêng, không đệm. */
.sheet-moi td .dg-chipbox > summary {
  border: 0;
  border-radius: 0;
  background: transparent;
  padding: 0;
  min-height: 0;
  /* ⛔ Khe ngang PHẢI bằng 0. Dấu phẩy ngăn cách vẽ bằng ::before của thẻ sau;
     còn khe thì trình duyệt chèn thêm một dấu cách nữa, ra thành "Lười học ,
     Mất tập trung" — phẩy đứng lửng lơ cách chữ một quãng. */
  gap: 0;
}
.sheet-moi td .dg-chipbox[open] > summary {
  border: 0;
  border-radius: 0;
}

/* ② Giá trị đang chọn hiện thành CHỮ THƯỜNG, không phải thẻ màu.
   Nhiều giá trị thì ngăn bằng dấu phẩy, y như một ô Sheets nhiều dòng. */
/* ⭐ MỖI ĐÁP ÁN MỘT VIÊN CÓ NỀN — Boss chốt bằng nút bấm 12/09/2026, sau khi
   xem ảnh chụp ô 5 mục và 8 mục ở 390 và 2320.
   ⛔ KHÔNG DỰNG HỆ MỚI: hệ viên đã có sẵn từ đầu (`.dg-tom-tag` ở khối màn
      Dự giờ: nền #159F8B, chữ trắng, có đệm và bo góc). Chính khối này đã GỠ
      nền đi (`background: transparent; padding: 0`) khi khoác áo Sheets, rồi bù lại
      bằng dấu phẩy ngăn. Nay trả nền về, đổi sang XÁM NHẠT theo ý Boss.
   ⛔ DẤU PHẨY NGĂN Bỏ HẰN (luật `::before` ngay dưới đã xoá). Hai lý do đo được:
      ① viên xuống dòng thì dấu phẩy rơi xuống ĐẦU DÒNG (ảnh 2320 ô 5 mục:
        ", Lười học , Khá"), không ngôn ngữ nào viết thế;
      ② chính tên đáp án đã chứa dấu phẩy ("Kém, cần theo dõi") nên không ai
        phân biệt được ranh giới giữa hai lựa chọn. Nền làm việc ấy tốt hơn.
   ⛔ VIỀN VẼ BẰNG `box-shadow: inset`, ĐỪNG DÙNG `border`: `border` ăn thêm 2px
      bề ngang MỖI VIÊN, mà ở khổ 390 ô chỉ có chỗ cho hai viên — tốn bề ngang là
      đổi thẳng thành mất chữ. `inset` vẽ đè lên trong, không tốn một pixel bố cục.
   ⛔ KHÔNG `font-weight` đậm, KHÔNG CHỮ IN HOA — đúng hai thứ Boss đã chê "lộ ra
      là máy làm" năm lần.
   Màu lấy trong bảng đã chốt: `--nen2` (#F0EEEA sáng / #22272C tối) — bảng ghi
   đúng vai "chip · nút phụ · nhãn", và `--vien` (#D6D2CB) cho nét viền. */
.sheet-moi td .dg-tom-tag {
  /* ⭐ XANH LÁ THAY CHO XÁM — Boss chốt 16/09/2026: *"nó đang để dạng block bé và
     màu xám thì tôi muốn bạn sửa cho tôi màu nó thành màu xanh lá cây để chữ bên
     trong nhìn thật dễ"*. Hỏi bằng nút, Boss chọn **#00793A** (xanh lá của dấu đã
     xong) và **nền xanh nhạt, chữ xanh đậm**.
     ⛔ `--xanh` CHÍNH LÀ #00793A — đã tra bảng màu trước khi sửa, không thêm màu
        thứ bảy nào ngoài sáu màu thương hiệu đã chốt.
     ⛔ VẪN KHÔNG `font-weight` đậm, VẪN KHÔNG chữ in hoa — hai thứ Boss đã chê
        "lộ ra là máy làm" năm lần. Đổi màu thôi, đừng nhân thể "làm cho nổi". */
  /* ⛔⛔ MÀU CỨNG, KHÔNG DÙNG `--xanh` — đã đo và trả giá 16/09: `--xanh` của app là
     XANH NGỌC (#4FD1C5 bản tối, teal bản sáng), KHÔNG phải xanh lá. Viết
     `var(--xanh, #00793A)` thì phần dự phòng không bao giờ được dùng, và viên ra
     rgb(20,160,160) — vẫn đúng cái màu Boss vừa bảo đổi. Dòng
     `border-color: var(--xanh, #00793A)` ở chỗ khác trong file này là thứ đã làm
     tôi đọc nhầm; đừng đọc phần dự phòng rồi tưởng đó là giá trị thật của biến.
     ⛔ Bản tối lấy đúng bộ xanh lá app đã chốt (`--tt-chay-*`, dòng ~414) — xem
        luật `body.toi` ngay dưới. Đừng để bản tối dùng chung màu bản sáng: #00793A
        trên nền #22272C đọc không ra. */
  background: #E6F3EA;
  box-shadow: inset 0 0 0 1px #9CCFB0;
  color: #00793A;
  /* ⛔⛔ ĐỆM 4px, KHÔNG 6px — và `line-height` PHẢI KHAI, vá 12/09/2026.
     Boss chốt "không cắt chữ, hạ xuống 2 viên cho mọi cột". Đo ra thì 2 viên
     vẫn tràn 5px ở cột hẹp nhất (260px) trên hàng cao 48px, vì ba thứ cộng lại:
     đệm 6px×2 mỗi viên, `row-gap` 2px, và dòng chữ ăn theo `line-height` mặc
     định của trình duyệt (~1,45 với 12px = 17,4px) — ba dòng là 52px, quá trần.
     4px + `line-height:1.2` (14,4px/dòng) kéo về vừa khít MÀ KHÔNG ĐỤNG VÀO CHỮ.
     ⛔ Đừng chữa bằng cách hạ `font-size`: 12px là số đã chốt trong bảng màu. */
  padding: 0 4px;
  line-height: 1.2;
  /* Bo góc 3px là NGOẠI LỆ CÓ CHỦ Ý so với `--r-lg: 0` của app (app cố ý vuông).
     ⛔ Đừng dùng 999px: viên chứa cả câu ("Kém, cần theo dõi") mà bo tròn hẳn
     thì thành nhãn quảng cáo. Huy hiệu "+N" mới giữ 999px vì nó chỉ hai ba ký tự. */
  border-radius: 3px;
  font-size: 12px;
}

/* Bản tối: lấy đúng bộ xanh lá app đã chốt cho dấu "đang chạy" (dòng ~414) nên
   không đẻ thêm màu mới, và vẫn đọc được trên nền sẫm. */
body.toi .sheet-moi td .dg-tom-tag {
  background: #16291D;
  box-shadow: inset 0 0 0 1px #2B4634;
  color: #7FD6A0;
}
/* ⛔ LUẬT "DẤU PHẨY TRƯỚC MỖI THẺ" ĐÃ BỎ — 12/09/2026, Boss chốt viên có nền.
   Đừng khôi phục: tên đáp án có sẵn dấu phẩy bên trong ("Kém, cần theo dõi")
   nên dấu ngăn bằng phẩy không phân biệt được ranh giới; và khi viên xuống
   dòng thì dấu phẩy rơi xuống đầu dòng. Cả hai đều có ảnh chụp làm bằng. */

/* ②b HUY HIỆU "+N" — Boss chốt 10/09/2026, làm giống ô TVTS ở Sổ tuyển sinh.
   Ô hẹp mà xếp hết mục ra thì chữ cụt giữa chừng, không đọc nổi mục nào ra mục
   nào (Boss chụp cột "Thái độ phụ huynh"). Nay bày mục đầu rồi đếm phần còn lại.
   ⛔ PHẢI `flex: none`. Ô trong bảng là hộp co giãn; không ghim thì chính con số
      này bị bóp lại thành "+" cụt, mất hẳn phần đáng giá nhất.
   Rê chuột vào thì `title` bày ra đủ các mục còn lại — không giấu mất dữ liệu. */
.sheet-moi td .dg-tom-them {
  flex: none;
  font-size: 10.5px;
  font-weight: 600;
  line-height: 1;
  padding: 2px 5px;
  margin-left: 4px;
  border-radius: 999px;
  background: var(--xanh-nhat, #E4F2EF);
  color: var(--xanh-dam, #00793A);
  cursor: default;
}

/* ③ Ô chưa chọn gì thì TRỐNG TRƠN — Sheets không viết chữ mời gọi vào ô rỗng.
   ⛔ Đừng `display:none`: bỏ hẳn phần tử là summary co lại 0px và không còn gì
      để bấm, ô chọn thành ngõ cụt. Chỉ làm chữ trong suốt, chỗ bấm vẫn nguyên. */
.sheet-moi td .dg-tom-trong {
  color: transparent;
  font-size: 12px;
}

/* ④ Mũi tên ▾ — LUÔN HIỆN, RÕ NÉT.
   ⛔⛔ BẢN ĐẦU TÔI GIẤU NÓ ĐI, BOSS BÁC NGAY 10/09/2026: *"nút chọn ở các ô
      trong của app có giao diện sheet nó rõ ràng hơn nhìn thấy dễ ấn vào dễ
      hơn"*. Giấu dấu hiệu bấm được là bắt người dùng đi mò từng ô — trợ giảng
      đang vội giữa buổi học không có thời gian mò.
   Google Sheets cũng vẽ mũi tên thường trực cho ô có danh sách; thứ Sheets
   giấu là cái VỎ HỘP, không phải mũi tên. */
.sheet-moi td .dg-tom-mui {
  opacity: .75;
  font-size: 11px;
  transition: opacity .12s;
}
.sheet-moi td .dg-chipbox > summary:hover .dg-tom-mui,
.sheet-moi td:hover .dg-tom-mui,
.sheet-moi td .dg-chipbox[open] > summary .dg-tom-mui,
.sheet-moi td .dg-chipbox > summary:focus-visible .dg-tom-mui { opacity: 1; }

/* ⑤ Danh sách thả xuống: nổi LÊN TRÊN bảng chứ không chèn vào trong ô.
   Chèn vào ô là cả dòng phình cao gấp mấy lần — đúng thứ Boss chê.
   ⛔ Neo `relative` đặt trên chính `<details>`, TUYỆT ĐỐI không đặt lên `<td>`:
      ô của bảng này có thể đang là ô ghăm `position: sticky`, chồng thêm một lớp
      định vị lên `<td>` thì ô kế bên lệch đi 518px — đã đo được đúng con số ấy. */
.sheet-moi td .dg-chipbox { position: relative; }
.sheet-moi td .dg-chipbox[open] > .dg-chips {
  position: absolute;
  z-index: 40;
  top: 100%;
  left: -6px;
  min-width: calc(100% + 12px);
  max-width: 320px;
  max-height: 260px;
  overflow-y: auto;
  border: 1px solid var(--vien);
  border-radius: var(--r-md);
  background: var(--the);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .14);
}

/* ⑥ HỘP THẢ XUỐNG SAU KHI ĐƯỢC BÊ RA THẲNG BODY — xem sheetGanThaXuong().
   ⛔ MỌI LUẬT CŨ ĐỀU BÁM ".dg-chipbox > .dg-chips", tức CON TRỰC TIẾP. Bê hộp ra
      ngoài body là chúng rụng sạch: hết viền, hết nền, hết đệm — hộp thành một
      mớ chữ trôi nổi trên màn. Phải khai lại đủ ở đây. */
.dg-chips.sheet-tha-xuong {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 8px;
  margin: 0;
  max-width: 340px;
  overflow-y: auto;
  /* KHONG_LAN_CUON — xem khoi ly do o `.ont-than`. */
  overscroll-behavior: contain;
  /* 🎞 10/09/2026 — Boss: *"Các ô chọn ko đucợ để vuông mà để nó bo tròn xíu và
     có kết nối với ô tôi vừa ấn."* Góc vuông + trôi lơ lửng giữa màn thì người
     dùng không biết hộp này vừa bung ra từ ô nào — nhất là bảng nhiều cột hẹp,
     mở xong nhìn quanh mất phương hướng. */
  border: 1px solid var(--vien);
  border-radius: 10px;
  background: var(--the);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .18);
}

/* ⑥b DÂY NỐI GIỮA HỘP VÀ Ô VỪA BẤM — hai đầu, phải có ĐỦ CẢ HAI mới thành "nối":
   ① ô nguồn sáng viền lên như ô đang chọn ở Sheets;
   ② hộp mọc một mũi nhọn chỉ về phía ô ấy.
   ⛔ MŨI NHỌN PHẢI NẰM TRONG `::before` CỦA HỘP, ĐỪNG VẼ BẰNG PHẦN TỬ RIÊNG. Hộp
      này được bê ra thẳng `body` (xem `sheetGanThaXuong`), thêm một phần tử nữa là
      thêm một thứ phải tự tay dọn khi đóng — quên dọn thì mũi nhọn ở lại giữa màn.
   ⛔ `left` do JS đặt theo vị trí ô, vì hộp có thể bị đẩy lệch khi sát mép màn. */
.dg-chips.sheet-tha-xuong::before {
  content: "";
  position: absolute;
  top: -6px;
  left: var(--mui-trai, 18px);
  width: 11px;
  height: 11px;
  background: var(--the);
  border-left: 1px solid var(--vien);
  border-top: 1px solid var(--vien);
  transform: rotate(45deg);
  border-radius: 2px 0 0 0;
}
/* Hộp phải bật LÊN TRÊN ô (thiếu chỗ phía dưới) thì mũi nhọn lộn xuống đáy. */
.dg-chips.sheet-tha-xuong.mui-duoi::before {
  top: auto;
  bottom: -6px;
  transform: rotate(225deg);
}
/* Ô đang mở hộp: viền xanh như ô đang chọn, để mắt nối được hai thứ với nhau. */
.sheet-moi tbody td.dang-mo-tha {
  box-shadow: inset 0 0 0 2px var(--sheet-chon-vien, #00793A);
  position: relative;
  z-index: 1;
}

/* ══════════════════════════════════════════════════════════════════════════════
   ⑦ Ô XỔ VÀ Ô GÕ TRONG BẢNG CŨNG PHẢI MẶC NHƯ Ô CHỮ THƯỜNG
   Boss chốt 10/09/2026: *"ô nào có lựa chọn thì thiết kế hợp với kiểu mới chứ
   không giữ lại kiểu cũ này nữa nó xấu và không dễ dùng"*.

   Trong ảnh Boss gửi, cột "Phụ trách" là một hộp `<select>` viền xám có mũi tên
   riêng, cạnh một nút ＋ nền cam viền đứt. Hai thứ ấy hét lên "đây là biểu mẫu",
   trong khi Sheets thì ô nào cũng phẳng như nhau cho tới lúc bạn bấm vào.

   ⛔ CHỈ ÁP TRONG BẢNG (`.sheet-moi td …`). Cùng những lớp ấy còn dùng ở form
      thêm học sinh và ở thanh công cụ, nơi cái hộp là đúng.
   ⛔ ĐỪNG `appearance: none` RỒI THÔI. Bỏ vẻ mặc định của trình duyệt là mất
      luôn mũi tên ▾, và ô xổ trông y hệt ô chữ — không ai biết nó bấm ra danh
      sách được. Phải tự vẽ lại mũi tên bằng `background-image`.
   ══════════════════════════════════════════════════════════════════════════════ */

.sheet-moi td select,
.sheet-moi td input[type="text"],
.sheet-moi td input:not([type]),
.sheet-moi td input[type="date"] {
  border: 0;
  border-radius: 0;
  background-color: transparent;
  box-shadow: none;
  padding: 0 2px;
  height: auto;
  min-height: 0;
  font: inherit;
  color: inherit;
  width: 100%;
}

/* Mũi tên ▾ tự vẽ, mờ sẵn — bấm hay rê chuột thì rõ lên. Cùng cách cư xử với ô
   chọn nhiều mục ở khối ⑤, để hai loại ô không mỗi cái một kiểu. */
.sheet-moi td select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 14px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%236B6660' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 4.5L6 8l3.5-3.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1px center;
  background-size: 10px 10px;
  opacity: .92;
}
/* ⛔⛔ ĐỪNG GIẤU MŨI TÊN CỦA Ô XỔ SAU CÚ RÊ CHUỘT. Bản đầu tôi làm thế và Boss
   bác ngay: nút chọn phải *"rõ ràng hơn nhìn thấy dễ ấn vào dễ hơn"*. Ô xổ mà
   trông y hệt ô chữ thì không ai biết nó bấm ra danh sách được — mà `padding`
   đổi theo `:hover` còn tệ hơn: chữ trong ô nhảy một cái mỗi lần rê qua.
   ⇒ Mũi tên và chỗ chừa cho nó GIỮ NGUYÊN ở mọi lúc, chỉ đậm thêm khi rê vào. */
.sheet-moi td:hover select,
.sheet-moi td select:focus { opacity: 1; }

/* ⛔⛔ NGOẠI LỆ DUY NHẤT: Ô CỘT LỚP Ở DỰ GIỜ — Boss chốt 12/09/2026.
   *"cột lớp bỏ cái kí hiệu kéo xuống đi cho tôi… Để lại cái dạng ấn vào giữa để
    gõ và chọn chứ ko ấn cái mũi tên đấy nữa"*
   Ô này KHÔNG phải ô xổ thường: một cú bấm vào nó là đổi thẳng sang ô gõ-để-tìm
   (`sheetOChonMotO`, và cú trao con trỏ nằm ở `dgGanKhoi` bên man-hinh/du-gio.js).
   Mũi tên ▾ ở đây hứa một danh sách xổ mà cú bấm KHÔNG bao giờ mở ra nữa — bày
   một lối đi đã bịt thì thà đừng bày.
   ⛔ CHỈ ô này (`td.dg-lopcell`), ⛔ ĐỪNG nới ra cho `.sheet-moi td select`: mọi ô
      xổ khác vẫn phải giữ mũi tên, Boss đã bác chuyện giấu nó đi ngày 10/09
      (*"nút chọn phải rõ ràng hơn nhìn thấy dễ ấn vào dễ hơn"*).
   ⛔ Trả luôn `padding-right` về mức thường: chừa 14px cho một mũi tên không còn
      ở đó thì tên lớp bị cắt sớm 12px mà chẳng để làm gì. */
.sheet-moi td.dg-lopcell select {
  background-image: none;
  padding-right: 2px;
}

/* ⛔⛔ Ô TRẠNG THÁI CÓ NỀN MÀU THÌ MẤT SẠCH MŨI TÊN — đo thật 10/09/2026 ở lưới
   Điểm danh: `background-image` tính ra `none`, đúng cảnh Boss chụp (ô "Đủ" xanh
   và "Nghỉ" đỏ trơ trọi, không dấu hiệu nào cho biết bấm được).
   Thủ phạm là `.o select.gt-tot { background: … }` của app: nó dùng dạng VIẾT
   GỌN, mà dạng gọn thì đặt lại TOÀN BỘ nhóm `background-*`, kể cả `-image`. Và
   nó hai lớp + một thẻ (0,2,1), thắng luật mũi tên ở trên vốn một lớp + hai thẻ
   (0,1,2). Chữa bằng cách nâng riêng phần ẢNH lên (0,2,2) — nền màu vẫn của app,
   vì màu ấy mang NGHĨA (xanh = có mặt, đỏ = nghỉ), tuyệt đối đừng bôi trắng đi.
   ⛔ Mũi tên phải TRẮNG: mấy ô này chữ trắng trên nền đậm, dùng mũi tên xám của
      khối trên là chìm nghỉm, coi như vẫn không có. */
.sheet-moi td select[class*="gt-"] {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%23FFFFFF' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 4.5L6 8l3.5-3.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 2px center;
  background-size: 10px 10px;
  padding-right: 15px;
}
/* Ô "Thiếu" nền vàng nhạt, chữ nâu sẫm — mũi tên trắng ở đó lại tàng hình. */
.sheet-moi td select.gt-thieu {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%233A2A00' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 4.5L6 8l3.5-3.5'/%3E%3C/svg%3E");
}

/* Ô đang gõ thì phải thấy rõ mình đang ở đâu — Sheets viền xanh đậm quanh ô. */
.sheet-moi td select:focus,
.sheet-moi td input:focus {
  outline: 2px solid var(--sheet-chon-vien, #00793A);
  outline-offset: -2px;
}

/* Nút ＋ "thêm nhân viên" bên cạnh ô xổ: bỏ nền cam và viền đứt, chỉ còn một dấu
   cộng mờ. Vẫn bấm được, vẫn đủ 24px cho ngón tay.
   ⛔ Đừng ẩn hẳn nó sau `:hover` — trên điện thoại không có rê chuột, ẩn là mất
      hẳn đường thêm người, mà đó là việc người dùng thật cần làm. */
.sheet-moi td .fhs-them-o,
.sheet-moi td .fhs-pt-them {
  background: transparent;
  border: 0;
  box-shadow: none;
  padding: 0;
  min-width: 24px;
  min-height: 24px;
  opacity: .4;
  transition: opacity .12s;
}
.sheet-moi td .fhs-them-o:hover,
.sheet-moi td .fhs-pt-them:hover,
.sheet-moi td .fhs-them-o:focus-visible,
.sheet-moi td .fhs-pt-them:focus-visible { opacity: 1; }

/* ══════════════════════════════════════════════════════════════════════════════
   ⑧ CHIỀU CAO DÒNG ĐỀU TĂM TẮP — Boss chốt 10/09/2026
   *"Đều tăm tắp như Excel, bấm vào mới xem đủ"*

   Trong ảnh Boss gửi, một dòng có nhiều lần liên hệ cao gấp tám lần dòng bên
   cạnh. Đó là thứ làm bảng nhìn gồ ghề chứ không phẳng như bảng tính.

   ⛔⛔ KHÔNG CẮT ĐƯỢC CHIỀU CAO Ô BẢNG BẰNG `overflow` hay `max-height`. Trình
      duyệt bỏ qua cả hai trên `display: table-cell` — thử rồi, không nhúc nhích.
   ⇒ Cách duy nhất không phải đụng vào DOM của 16 màn: ép nội dung Ở LẠI MỘT
     DÒNG. Không xuống dòng thì ô cao đúng một dòng chữ, và mọi dòng bằng nhau.
     Phần thừa cắt bằng dấu ba chấm — `overflow` theo chiều NGANG thì `table-cell`
     có nghe, app đã dùng sẵn ở `.bang-keo-cot td`.

   ⛔ PHẢI CÓ ĐƯỜNG XEM LẠI PHẦN BỊ CẮT, không thì đây là xoá dữ liệu trước mắt
      người dùng chứ không phải làm gọn. Bấm vào ô (ô được chọn, ô đang sửa, hay
      con trỏ đang nằm trong ô) thì ô bung ra đủ — đúng cách Excel và Sheets làm.
   ══════════════════════════════════════════════════════════════════════════════ */

.sheet-moi tbody tr.sheet-hang td {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ⛔⛔ ĐỪNG CHO Ô "BUNG RA" KHI CHỌN HAY KHI CON TRỎ VÀO. Boss bác thẳng
   10/09/2026: *"tôi KO cần trong các ô sheet khi di chuột vào cột tên lại phóng
   to ra như này không chọn được, tôi chỉ cần nó để bình thường"* —
   *"nhiều công cụ đều bị lỗi ở cột tên lắm"*.

   Bản đầu tôi cho `.sheet-o-chon` và `:focus-within` mở `overflow: visible` +
   `white-space: normal` để xem lại phần bị cắt. Nhìn thì hợp lý, dùng thì hỏng:
   ô nở ra đè lên ô bên cạnh, chữ chồng nhau, và đúng lúc người ta đang định bấm
   thì nó nhảy — bấm trượt. Bảng tính thật KHÔNG làm thế: Excel giữ ô y nguyên,
   chỉ thanh công thức phía trên mới bày đủ nội dung.

   ⇒ CHỈ ô ĐANG SỬA mới bung. Lúc ấy ô đã thành ô gõ chữ, người dùng chủ động mở
     nó ra, không phải vô tình rê chuột qua. Xem thêm `.dang-sua` do màn tự gắn. */
/* ⛔⛔ PHẢI CÓ `tr.sheet-hang` Ở ĐÂY, KHÔNG ĐƯỢC BỚT. Luật ép-một-dòng phía dưới
   nhắm `.sheet-moi tbody tr.sheet-hang td` — hai tên lớp và ba tên thẻ. Câu này
   mà chỉ có hai tên lớp với hai tên thẻ thì NHẸ HƠN, và ô đang gõ không bung ra
   được nữa: người dùng mở ô ra sửa mà vẫn chỉ thấy đúng một dòng cụt.
   Đo thật 10/09/2026 — bài quét 16 màn bắt được ở ba màn cùng lúc, ngay sau khi
   tôi siết luật ép thành `tr.sheet-hang` mà quên nâng câu này lên theo.
   ⇒ Đổi bề nặng của luật ép thì PHẢI đổi cả câu này. Hai câu đi thành một cặp. */
.sheet-moi tbody tr.sheet-hang td.dang-sua,
.sheet-moi tbody td.dang-sua {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

/* Ô chọn nhiều mục: các thẻ giá trị phải nằm CÙNG một dòng, không quấn xuống.
   ⛔ `.dg-chipbox > summary` đang `flex-wrap: wrap` — để nguyên thì hai giá trị
      là ô cao gấp đôi, và cả dòng cao theo. */
.sheet-moi tbody td .dg-chipbox > summary {
  flex-wrap: nowrap;
  overflow: hidden;
}
/* ⛔⛔ KHÔNG CẮT ĐUÔI VIÊN — Boss chốt 12/09/2026: *"Không cắt chữ — hạ xuống 2
   viên cho mọi cột"*. Ba dòng `white-space:nowrap` + `overflow:hidden` +
   `text-overflow:ellipsis` ĐÃ BỎ, đừng khôi phục: chúng biến "Giáo viên đã có sự
   quan sát và hỗ trợ học sinh khi cần (đi từng bàn trả lời học sinh)" thành
   "Giáo viên đã…", tức người dùng mất đúng phần phân biệt đáp án này với đáp án
   kia. Boss đã bác thẳng cách ấy.
   ⛔ `min-width: 0` thì GIỮ — nó không cắt chữ, nó chỉ cho viên co lại dưới bề
      rộng nội dung để chữ QUẤN XUỐNG DÒNG thay vì đẩy ô rộng ra. Bỏ dòng này là
      viên ưỡn ngang làm cột phình, đúng thứ Boss cấm. */
.sheet-moi tbody td .dg-tom-tag {
  min-width: 0;
}
/* Ô đang mở danh sách thì cho quấn lại như cũ — lúc ấy người ta đang đọc kỹ. */
.sheet-moi tbody td .dg-chipbox[open] > summary { flex-wrap: wrap; }

/* Ép mọi thứ trong ô về CHUNG MỘT DÒNG.
   Đo được hai thủ phạm đẩy dòng lên 70px ở màn Follow up: nút "Thêm lần" cao
   33px, và ở cột Học viên thì thẻ tên với nút xoá đều là khối nên xếp chồng
   lên nhau. Cho chúng nằm ngang và hạ trần chiều cao là dòng về đúng một dòng.
   ⛔ Đừng hạ trần bằng thuộc tính "height" — nút nào vốn cao hơn sẽ bị bóp méo
      hình. Trần "max-height" chỉ chặn phần thừa, không kéo giãn thứ gì. */
.sheet-moi tbody tr.sheet-hang td { line-height: 20px; }
.sheet-moi tbody tr.sheet-hang td > * {
  max-height: 22px;
  vertical-align: middle;
}
.sheet-moi tbody tr.sheet-hang td > b,
.sheet-moi tbody tr.sheet-hang td > i,
.sheet-moi tbody tr.sheet-hang td > p,
.sheet-moi tbody tr.sheet-hang td > div,
.sheet-moi tbody tr.sheet-hang td > span {
  display: inline-flex;
  align-items: center;
  /* ⛔ ĐỪNG ĐẶT max-width: 100% Ở ĐÂY. Thẻ tên học viên sẽ chiếm trọn bề ngang ô
     và đẩy nút xoá đứng cạnh nó xuống dòng dưới — dòng lại cao gấp đôi, đúng
     thứ vừa đi chữa. Phần thừa đã có nowrap + overflow của ô lo cắt rồi. */
  min-width: 0;
  margin-top: 0;
  margin-bottom: 0;
}
/* ⛔⛔ THỨ NGƯỜI TA BẤM VÀO THÌ ĐỪNG BÓP. Trần 22px ở trên quét cả `<select>` và
   `<input>`, nên ô "Đủ" / "Nghỉ" ở lưới Điểm danh co còn 20px nằm lửng giữa một
   hàng cao 32px — trông như miếng dán đè lên ô chứ không phải ô của bảng, và
   đích bấm 20px thì dưới chuẩn 24px, bấm dễ trượt. Boss báo 10/09/2026:
   *"Trong đimẻ dnah cũng bị như vậy"*, và trước đó đã dặn nút chọn phải
   *"rõ ràng hơn nhìn thấy dễ ấn vào dễ hơn"*.
   ⇒ Cho chúng cao ít nhất 24px. Hàng đang 32px nên dòng KHÔNG cao thêm — phần
     nới này nằm gọn trong chỗ trống sẵn có, không phá "dòng đều tăm tắp".
   ⛔ Vẫn để `max-height: none` chứ đừng đặt `height` cứng: nút nào vốn cao hơn
     sẽ bị bóp méo hình. */
.sheet-moi tbody tr.sheet-hang td > select,
.sheet-moi tbody tr.sheet-hang td > input {
  max-height: none;
  min-height: 24px;
}
/* ⛔⛔ CẶP CỘT TRỢ GIẢNG CỐ Ý CAO HAI DÒNG — nhả kẹp 16/09/2026.
   Hai luật ngay trên đầu khối này quét mọi con trực tiếp của ô:
     · `td > * { max-height: 22px }`   — xén mất dòng thứ hai;
     · `td > div { display: inline-flex }` — biến hai dòng thành hai khối NẰM CẠNH
       NHAU, nên đo ra hai dòng cùng một toạ độ `top`, chữ tràn đè sang hàng trên.
   Đo thật trước khi nhả (sân 4 phiếu, khổ 1500): `tgTop` = [218, 218] và ảnh chụp
   thấy ô Trợ giảng cụt ngang giữa tên. Đây là ô CỐ Ý hai dòng — mỗi dòng một
   người — nên phải nhả, y như cột Giáo viên đã phải nhả ở khối ㉟.
   ⛔ NHẢ ĐÚNG HAI Ô NÀY, đừng nhả ở tầng chung: trần 22px là thứ giữ cho mọi bảng
      "phẳng như Excel" (Boss chốt 10/09), nhả chung là bảng nào cũng gồ ghề trở lại.
   ⛔ VẪN KẸP TỪNG DÒNG 24px. Nhả trần cho cả ô mà không kẹp dòng thì ô nhận xét có
      nhiều thẻ sẽ nở tuỳ nội dung, hàng cao vọt — đúng lỗi đã phải vá ở ô "Kết quả"
      màn Phụ đạo. 24px là đích bấm tối thiểu, đủ ngón tay, không dư. */
.sheet-moi tbody tr.sheet-hang td.dg-tgcell > .dg-tg-dong,
.sheet-moi tbody tr.sheet-hang td.dg-nxtgcell > .dg-nxtg-dong {
  display: flex;
  max-height: none;
}
/* ⛔ CANH MÉP TRÊN, KHÔNG CANH GIỮA. `.sheet-moi tbody td { vertical-align:middle }`
   (0,1,2) đè mất `vertical-align:top` tôi khai ở `.dg-tgcell` (0,1,0) — đo ra hai
   cột lệch nhau 2px ngay dòng đầu, vì nội dung hai ô chênh nhau vài pixel rồi cả
   hai cùng bị dồn về giữa, mỗi bên một nửa. Canh mép trên thì hai cột bắt đầu cùng
   một chỗ, BẤT KỂ ô nào cao hơn — không phải đi đo cho hai bên cao bằng nhau nữa. */
.sheet-moi tbody td.dg-tgcell,
.sheet-moi tbody td.dg-nxtgcell { vertical-align: top; }
.sheet-moi tbody tr.sheet-hang td.dg-nxtgcell > .dg-nxtg-dong > .dg-o-tich {
  min-height: 24px;
  max-height: 24px;
}
/* ⛔⛔ Ô TÊN THÌ KẸP HAI DÒNG, KHÔNG KẸP MỘT. Lượt đầu tôi kẹp cả `.ont` ở 24px cho
   "phẳng như Excel" — ảnh chụp ra tên cụt ngang: *"Nguyen Thi / Thanh Huong"* mất
   nửa dưới, *"Nguoi Moi Vua Go"* mất chữ cuối. Đó là VI PHẠM luật Boss ra ngày
   11/09: *"trong tất cả cột tên thì tên của nhân viên hay tên của học sinh đều
   phải NHÌN THẤY ĐƯỢC, không được ẩn"*.
   `.ont-xem` vốn cho 3 dòng; ở đây hạ xuống 2 và nới cột ra (xem `.dg-tgcell`) —
   tên thật ở trung tâm dài quanh 26 ký tự, cột ~200px là vừa một dòng, tên dài hơn
   mới xuống dòng thứ hai.
   ⛔ `max-height` là TRẦN chứ không phải chiều cao cố định: hàng nào tên ngắn thì
      ô vẫn 24px và hàng vẫn phẳng. Chỉ hàng có tên dài mới cao thêm — đúng cách
      cột Người dự giờ và cột Giáo viên đang làm. */
.sheet-moi tbody tr.sheet-hang td.dg-tgcell .ont {
  min-height: 24px;
  max-height: 40px;
}
.sheet-moi td.dg-tgcell .ont > .ont-xem { -webkit-line-clamp: 2; }
/* ⛔⛔ NÚT VÀ Ô GÕ NHIỀU DÒNG PHẢI CHẶN CẢ HAI ĐẦU, KHÔNG CHỈ NỚI ĐÁY.
   · `<button>` — thả trần là nút "Thêm lần" ở màn Follow up cao lại 33px và đẩy
     dòng lên 48px; bài quét bắt được ngay lượt đầu.
   · `<textarea>` — TỆ HƠN NHIỀU, và Boss bắt được tận mắt 10/09/2026. Ô "Kết quả"
     ở màn Phụ đạo chứa cả một bài nhận xét dài; thả trần là nó nở hết cỡ, hàng
     cao vọt hơn 150px, bảng gồ ghề hẳn — đúng thứ vừa đi chữa cả buổi.
     Tôi xếp nó chung nhóm với `select`/`input` vì "đều là chỗ người ta gõ", mà
     quên rằng ô NHIỀU DÒNG thì cao theo NỘI DUNG chứ không theo khuôn.
   ⇒ Ghim đúng 24px cho cả hai: đủ ngón tay bấm, dòng vẫn phẳng như Excel. Muốn
     xem trọn nội dung thì bấm vào ô — `.dang-sua` mới gỡ trần. */
.sheet-moi tbody tr.sheet-hang td > button,
.sheet-moi tbody tr.sheet-hang td > textarea {
  min-height: 24px;
  max-height: 24px;
}

/* ══════════════════════════════════════════════════════════════════════════════
   ㊱ Ô NHIỀU CHỮ: BỐN DÒNG RỒI DẤU BA CHẤM — Boss 11/09/2026
   ──────────────────────────────────────────────────────────────────────────────
   Boss: *"lúc bình thường ô có nhiều chữ phải tự xuống dòng, mặc định tối đa 4
   DÒNG, dài hơn thì cắt và hiện dấu ba chấm. Kéo rộng cột ra thì chữ phải fill đủ
   bề rộng mới, nhưng vẫn chỉ 4 dòng. Bấm vào ô thì hiện đủ chữ, và phải bỏ dấu ba
   chấm đi — đã show đủ chữ rồi chứ ko được đè lên dấu …"*

   Cái kẹp 24px ngay trên là lệnh 10/09 (*"giữ hàng phẳng như Excel"*). Nay Boss
   nới chính lệnh ấy cho ô CHỮ: một dòng → tối đa bốn dòng. ⛔ Chỉ nới cho
   `<textarea>` (ô chữ tự do); `<button>` vẫn 24px như cũ.

   ⛔ `-webkit-line-clamp` KHÔNG ăn với `<textarea>`. Nên dấu ba chấm phải do JS đo
      rồi khoác lớp `.o-cut` (xem `sheetSoiCatChu` trong js/tinh-nang.js).
   ⛔ Ô RẤT DÀI vẫn giữ trần 220px + cuộn trong lòng ô lúc đang sửa (khối ㉖/㉞),
      chỗ này KHÔNG đụng tới.
   ══════════════════════════════════════════════════════════════════════════════ */
.sheet-moi tbody tr.sheet-hang td > textarea {
  max-height: 80px;          /* ĐÚNG 4 dòng × line-height 20px, không dư một pixel:
                                dư ra là lộ vệt chữ dòng thứ năm bị cắt ngang thân */
  white-space: pre-wrap;
  overflow: hidden;          /* cắt GỌN ở dòng 4, không dấu gì — Boss 21/09 (khối ㊲) */
}
/* Ô một dòng: cắt gọn ở mép, KHÔNG "…" — Boss 21/09 (khối ㊲). */
.sheet-moi tbody tr.sheet-hang td > input:not([type="checkbox"]):not([type="radio"]) {
  text-overflow: clip;
}
/* ⛔ 21/09/2026 — ĐÃ GỠ dấu "…" vẽ ở góc ô bị cắt (`td.o-cut::after`). Boss bấm nút
   "Không giữ — bỏ hết": ô nhiều dòng cắt gọn ở dòng 4, không dấu, không chừa trống.
   `sheetSoiCatChu` vẫn gắn `.o-cut` — nay chỉ là cờ "ô đang giấu chữ", CSS không vẽ gì.
   GIỮ `position: relative` như cũ: gỡ ra là đổi gốc định vị cho con `absolute` của
   những ô đang mang lớp này — không đáng liều trong một việc chỉ là bỏ dấu. */
.sheet-moi tbody tr.sheet-hang td.o-cut { position: relative; }


/* ⑨ CỘT TÊN: CHỮ THƯỜNG, XUỐNG DÒNG, HÀNG CAO LÊN — Boss bấm nút chọn 11/09/2026.
   ⛔ RANH GIỚI PHẢI HẸP ĐÚNG MỘT CỘT. Hai lệnh của Boss chạm nhau ở đây:
     · 10/09 — *"giữ hàng phẳng như Excel"*, lệnh CHUNG cho mọi cột (cái kẹp 24px ở trên);
     · 11/09 — *"xuống dòng, hàng cao lên"*, lệnh RIÊNG cho cột tên.
   Mới hơn VÀ hẹp hơn thì thắng — nhưng chỉ thắng TRONG PHẠM VI CỦA NÓ.
   ⇒ Nhả kẹp cho đúng `td.dg-ten-cell`, KHÔNG nhả ở tầng chung: nhả luật chung là
     bảy màn kia cao lên theo, ta đã có nguyên một sổ lỗi về chuyện đó.
   ⛔ KẸP TRÊN 2 DÒNG. Tên 29 ký tự thành 2 dòng là đúng ý Boss; nhưng một cái tên
      60 ký tự mà đứng 5 dòng thì nó đẩy cả hàng, mất hết số hàng lọt màn.
      `-webkit-line-clamp` cắt đúng 2 dòng VÀ tự vẽ "…" — khác `text-overflow`,
      thứ chỉ ăn với ô một dòng và đã câm hai lần trong ngày hôm nay. */
.sheet-moi tbody tr.sheet-hang td.dg-ten-cell > .dg-ten-o { max-height: none; }
.dg-ten-o { display: block; width: 100%; }
.dg-ten-o > .dg-ten-xem {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  white-space: normal;
  overflow-wrap: anywhere;
  min-height: 24px;
  padding: 3px 5px;
  line-height: 1.35;
  font-size: 12.5px;
  cursor: text;
  /* Viền trong suốt giữ sẵn chỗ — rê chuột vào chỉ đổi MÀU viền, không xê dịch
     một pixel nào. Boss 10/09: *"di chuột vào cột tên đừng phóng to ra"*. */
  border: 1px solid transparent;
  border-radius: var(--r-o, 8px);
}
.dg-ten-o > .dg-ten-xem:hover { border-color: var(--vien); }
.dg-ten-o > .dg-ten-xem:focus { outline: 2px solid var(--xanh, #0B7A6E); outline-offset: -2px; }
.dg-ten-o > input.dg-ten-in { display: none; }
.dg-ten-o.dang-sua > .dg-ten-xem { display: none; }
.dg-ten-o.dang-sua > input.dg-ten-in { display: block; width: 100%; }

/* ⑧c (11/09 → GỠ 21/09/2026) — DẤU "…" VẼ BẰNG ẢNH NỀN Ở GÓC Ô CHỮ + ĐỆM 18px.
   Boss bấm nút "Không giữ — bỏ hết" (21/09): ô nhiều dòng cắt gọn ở dòng 4, không
   dấu, KHÔNG chừa trống. Nên gỡ hẳn luật vẽ dấu — cả ở lưới Điểm danh (Boss duyệt
   riêng cho Điểm danh cùng tối). Gỡ luôn đệm 18px: ô đang XEM và đang VIẾT nay xếp
   chữ y hệt nhau, bấm vào không còn cảnh chữ chảy lại, con trỏ lệch chữ vừa bấm.
   `sheetODayDu` vẫn gắn `.sheet-o-them` — nay chỉ là cờ "ô đang giấu chữ".
   ⛔ Đừng vẽ lại dấu ở đây: bài `thu-bo-dau-ba-cham-21-09.js` canh đúng chỗ này. */

/* ══════════════════════════════════════════════════════════════════════════════
   ⑧b BẤM VÀO Ô NHIỀU CHỮ THÌ PHẢI HIỆN TRỌN — Boss 10/09/2026
   *"ấn vào ô có viết nhiều chữ thì phải hiện đầy đủ ra như excel chứ???"*

   Đây KHÔNG mâu thuẫn với lệnh sáng nay *"di chuột vào cột tên đừng phóng to ra"*.
   Hai chuyện khác hẳn nhau, và chỗ tôi làm sai là gộp chúng làm một:
     · RÊ CHUỘT ngang qua bảng  → ô phải ĐỨNG YÊN. Rê là vô tình, mà ô nhảy đúng
       lúc người ta định bấm thì bấm trượt.
     · BẤM VÀO ô để sửa        → ô phải BUNG RA. Chủ động mở thì phải thấy đủ chữ,
       không thì gõ mù. Excel cũng vậy — ô đang gõ nổi lên trên các ô bên cạnh.
   Sáng nay tôi gỡ `:focus-within` cùng lúc với `.sheet-o-chon` vì tưởng cả hai
   đều là "chạm vào là nở". Sai: `.sheet-o-chon` mới là cái bám theo con trỏ;
   `:focus-within` chỉ xảy ra khi người ta THẬT SỰ bấm hoặc Tab vào ô.

   ⛔ PHẢI CÓ `z-index` + NỀN ĐỤC. Ô bung ra mà trong suốt thì chữ nó chồng lên
      chữ ô bên dưới, đọc thành một mớ. Nổi hẳn lên trên mới ra hình ô Excel.
   ⛔ `position: relative` là bắt buộc để `z-index` có hiệu lực trên ô bảng. */
.sheet-moi tbody tr.sheet-hang td:focus-within {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  /* ⛔⛔ `sticky` CHỨ KHÔNG PHẢI `relative` — vá 11/09/2026, ĐÚNG CÙNG MỘT Ổ với
     khối `.sheet-o-dang` ở css:14020 (đã vá sáng nay). Bỏ sót khối này là bỏ sót
     "luật gỡ": hai luật cùng nâng ô lên trên, vá một cái thì cái kia vẫn hỏng.
     Boss 11/09: *"nút ✕ ấn tích thì nhảy loạn"* + *"✕ không ăn"*. Đo ở Chăm sóc
     2320: `td.sheet-cot-gham` mang `position:sticky; left:190px` (JS đặt inline cho
     dải ghăm). Bấm vào nút tick → `:focus-within` khớp → `position` thành `relative`
     → chính `left:190px` ấy đổi nghĩa từ *mốc ghăm* thành *dịch phải thật 190px*
     ⇒ ô bay 190px ngay giữa cú bấm (đo được: nút 302px → 492px).
     Nút chạy khỏi ngón tay nên `mouseup` rơi ra ngoài nút ⇒ sự kiện `click` KHÔNG
     nổ ⇒ tích không ăn. HAI lời than của Boss là MỘT lỗi.
     `sticky` vẫn là thẻ CÓ ĐỊNH VỊ nên `z-index: 5` và `box-shadow` bên dưới giữ
     nguyên hiệu lực; ô THƯỜNG không khai `left` nên `sticky` nằm y chỗ cũ.
     ⛔ LUẬT GỠ: đổi kiểu định vị thì rà lại MỊI số đi kèm: left/top/right/bottom/z-index. */
  position: sticky;
  z-index: 5;
  background-color: var(--the, #fff);
  /* ⛔⛔ `inset` — VẼ VÀO TRONG, KHÔNG VẼ RA NGOÀI. Vá 10/09/2026.
     Boss: *"tôi chỉ muốn có 1 khung vuông như trên sheet"* kèm ảnh ô có hai viền
     và bị lòi ra. `box-shadow` không `inset` với `spread: 2px` vẽ TRỌN 2px RA
     NGOÀI cả bốn phía: đo cột "Giáo viên" thấy `<td>` l=366→464 mà quầng
     l=364→466, trong khi ô bên cạnh bắt đầu đúng ở 464 ⇒ chồng 2px, lại thêm
     `z-index: 5` nên nó vẽ đè lên ô hàng xóm.
     Vẽ vào trong thì hết lòi, hết chồng, và vẫn đúng nếp Excel (Excel cũng vẽ
     khung ô đang chọn nằm gọn trong lòng ô).
     ⛔ Bóng đổ phía dưới thì GIỮ ngoài (không `inset`) — nó là bóng, không phải
        viền, và bóng vốn phải toả ra ngoài mới ra hình nổi lên.
     ⛔ App đã có tiền lệ `inset` ở khối ⑧; giữ cho thống nhất, đừng để hai kiểu
        khung trong cùng một bảng. */
  box-shadow: inset 0 0 0 2px var(--sheet-chon-vien, #00793A), 0 6px 18px rgba(0, 0, 0, .14);
}
/* ⭐ 02/10/2026 — Boss câu 15–16 (ảnh iPhone, Điểm danh): khung xanh ô đang gõ phải trượt DƯỚI
   hàng tiêu đề (`.h-day` / `.h-cot`, z5) và DƯỚI cột mã + tên (`.c-ma` / `.c-ten`, z6) khi kéo bảng.
   Luật trên đặt z5 — BẰNG tiêu đề, mà thân bảng đứng sau thead trong mã nên ô thắng: kéo bảng
   lên là khung xanh đè lên chữ tiêu đề. Hạ còn 4: vẫn nổi trên ô thường (không z) và ô đang
   đứng (`.sheet-o-dang`, z2), nằm dưới mọi thứ đang ghim.
   ⛔ Chừa chính ô mã / ô tên: hạ chúng là ô tên ấy chui dưới các ô tên khác khi cuộn.
   ⛔ Chỉ bảng Điểm danh (`.luoi`) — Boss cho sửa đúng màn này (câu 1–2). */
.luoi.sheet-moi tbody tr.sheet-hang td:focus-within:not(.c-ma):not(.c-ten) { z-index: 4; }

/* ⛔⛔ `:not(select)` — Ô CHỌN SẴN KHÔNG ĐƯỢC BUNG. Boss 13/09/2026, nói riêng một câu:
   *"các ô lựa chọn có sẵn ko được để dạng mở rộng ô khi ấn vào nó gây lỗi"*.
   `max-height: none` làm `<select>` cao hết cỡ nội dung của nó, và một `<select>` cao
   hơn một dòng thì Chrome KHÔNG vẽ thành ô thả xuống nữa mà vẽ thành DANH SÁCH
   nhiều dòng — mọi lựa chọn hiện cùng lúc, dính liền nhau. Ảnh Boss gửi ở cột BTVN
   đọc ra "ĐủThiếuChưa hoàn thànhQuên phiếu" chính là bốn lựa chọn ấy chồng lên nhau.
   ⛔ ĐỪNG chữa bằng cách đặt một con số `max-height` cứng cho select — cỡ chữ của app
      đổi được (100/110/125%) và bảng còn zoom riêng, số cứng sẽ cắt cụt chữ ở mức lớn.
      Loại nó ra khỏi luật nới trần thì nó giữ đúng trần chung của `td > *` như mọi ô. */
/* ⛔⛔ LUẬT NỚI TRẦN Ở ĐÂY ĐÃ BỊ GỠ — 13/09/2026, và đừng chép nó về.
   Bản cũ: `td:focus-within > * { max-height: none }` cộng với khối `> textarea`
   (min-height 24 · max-height 220 · height auto) cho ruột ô cao lên NGAY TRONG LÒNG
   BẢNG. Hậu quả đo được: bấm vào một ô ở Nhắc phụ đạo thì cả hàng cao từ 89px
   lên 229px — đúng thứ Boss chê 13/09: *"lúc tôi chuyển qua viết ô đó thì cả hàng
   lại mở rộng ra... ô đó chỉ mở rộng đúng ô đó ko đc mở rộng hàng và cột đó"*.
   ⛔ VÀ ĐÂY MỚI LÀ ĐIỂM CHẾT: luật CSS ăn NGAY khi ô nhận tiêu điểm, SỚM HƠN mọi
      dòng JS (tay nghe `focusin` chạy sau). Nên dù JS có nhấc ruột ô đi ngay sau đó,
      hàng VẪN kịp giãn một nhịp và JS đo phải chiều cao đã giãn — giữ chỗ sai theo.
   ⇒ Nay ô đang gõ được đưa HẴN ra `body` (`sheetNoiRuotO`), nên không còn thứ gì
     cần nới trần trong lòng bảng nữa. Ô chọn sẵn thì vốn đã không được bung.
   ⛔ KHỐI HÌNH Ở TRÊN (`td:focus-within` — viền xanh, nền đục, z-index, sticky) THÌ
      GIỮ: đó là khung ô đang chọn kiểu Excel, Boss không chê, và nó không đổi kích
      thước ô nên không giãn hàng. */
/* Ô gõ nhiều dòng: cao theo nội dung, nhưng có trần để một bài văn dài không phủ
   kín màn hình — quá trần thì tự cuộn trong lòng ô. */
/* (khối `td:focus-within > textarea` đã gỡ cùng lúc — xem lời dặn ngay trên) */

/* ═══════════════════════════════════════════════════════════════════════════
   Ô ĐANG VIẾT NỔI HẴN LÊN — nửa CSS của `sheetNoiRuotO` (js/tinh-nang.js)
   ───────────────────────────────────────────────────────────────────────────
   Boss 13/09: *"sửa ô viết thì ô đó chỉ mở rộng đúng ô đó ko đc mở rộng hàng và
   cột đó"* — và phải mở ra *"y hệt như ô ấn vào mở ra xem"*, tức giống khung
   `.sheet-khung-xem`. Toạ độ và bề rộng do JS đặt; ở đây chỉ lo NÉT Vẽ.

   ⛔ KHÔNG PHẢI ĐUA ĐỘ NẶNG VỚI AI — và đây là chỗ bản đầu tiên làm sai, ghi lại để
      người sau khỏi đi lại: bản đầu nâng ruột ô TẠI CHỖ (vẫn trong `<td>`) nên phải
      đánh nhau với `.sheet-moi tbody tr.sheet-hang td > *` (`max-height: 22px`, độ
      nặng (0,3,4)), và tệ hơn nhiều: `div.dg-cuon` mang `contain: paint` nên `fixed`
      bị GIỮ LẠI trong khung cuộn (đo: đặt left 92px thì ô rơi ở 170px) và phần tràn
      ra ngoài bị XÉN. Nay ruột ô được đưa HẴN ra `body`, thính thế một lớp là đủ.

   ⛔ `resize: none`: tay kéo góc của trình duyệt đặt `height` inline — đúng cái JS đang
      dùng để đo. Kéo một cái là hai bên giành nhau và ô giật. Ô nổi đã tự vừa chữ.
   ⛔ `z-index` cao hơn `.sheet-khung-xem` (60): hai thứ không bao giờ cùng hiện, nhưng
      nếu có lúc giao nhau thì ô ĐANG GÕ phải ở trên — nó là thứ người ta đang làm.
   ⛔ NềN ĐỤC là bắt buộc: ô nổi tràn sang ô bên cạnh, trong suốt thì hai lớp chữ
      chồng nhau thành một mớ không đọc được. */
/* ═══════════════════════════════════════════════════════════════════════════
   Ô NỞ RA TẠI CHỖ — nửa CSS của `sheetNoO` (js/tinh-nang.js)
   ───────────────────────────────────────────────────────────────────────────
   ⛔⛔ `overflow: visible` LÀ DÒNG QUAN TRỌNG NHẤT KHỐI NÀY. Ô bảng vốn
      `overflow: hidden` (đo được: `td.o-cut` → hidden). Quên dòng này thì ruột ô
      nở ra bị chính ô của nó xén — nhìn như không nở gì cả, và không một lỗi nào báo.
   ⛔ `position: sticky` chứ KHÔNG `relative` — cùng một ổ với lỗi 11/09 (ô ghăm mang
      `left` inline, đổi sang `relative` là `left` đổi nghĩa từ *mốc ghăm* thành *dịch
      phải thật*, ô bay 190px ngay giữa cú bấm). `sticky` không khai `left` thì nằm y
      chỗ cũ, mà vẫn là thẻ ĐÃ ĐỊNH VỊ nên làm gốc cho `absolute` của ruột ô.
   ⛔ ĐỘ NẶNG: `td.sheet-o-no > .sheet-ruot-no` đạt (0,4,3), hơn `td > *` (0,3,4) đang
      ghim `max-height: 22px`. Viết thiếu một lớp là ô nở ra bị kẹp 22px, ra một vệt
      mỏng dính và không ai hiểu vì sao. */
.sheet-moi tbody tr.sheet-hang td.sheet-o-no {
  overflow: visible;
  position: sticky;
  z-index: 11;
}
.sheet-moi tbody tr.sheet-hang td.sheet-o-no > .sheet-ruot-no {
  box-sizing: border-box;
  max-height: none;
  /* ⭐ 18/09/2026 — HẾT ĐƯỜNG KẺ CẮT ĐÔI Ô.
     Boss: *"khi tôi ấn double click nhanh vào 1 ô điền chữ thì nó chia cắt ô ra
     làm 2 ... vẫn viết các thứ bình thường được nhưng nó hơi xấu"*, chốt bằng nút:
     **vẫn sửa được, chỉ bỏ đường kẻ ngăn**.
     Đo thật trước khi sửa: ô cha cao 94px, ruột `.dg-ta` chỉ cao 40px (sàn
     `min-height:40px` của chính nó) — nên viền DƯỚI của ruột rơi lứng giữa ô và
     vẽ ra đúng cái vạch ngăn đôi Boss chụp được.
     ⛔ Đừng chữa bằng cách Bỏ VIỀN ruột: viền xanh là thứ báo đang ở ô nào.
     ⛔ Đừng hạ `min-height` của `.dg-ta`: ô CHƯA nở của màn Dự giờ ăn chung sàn ấy.
     `100%` đây là chiều cao Ô CHA — `td.sheet-o-no` mang `position:sticky` nên nó
     chính là gốc toạ độ của ruột. Ruột phủ kín ô, viền dưới trùng mép ô, hết vạch.
     Ruột dài hơn ô vẫn nở bình thường — `min-height` chỉ đẩy LÊN, không kẹp xuống. */
  min-height: 100%;
  /* ⛔⛔ `max-width: none` KHÔNG PHẢI THỪA — thiếu nó là cả cơ chế nở chết câm.
     Đo thật 13/09/2026: đặt `style.width = "45ch"` (~300px) mà `getBoundingClientRect`
     vẫn trả 119px, đúng bằng bề rộng cột. Thủ phạm là
       `.bang-keo-cot td > textarea { max-width: 100% }`
     — `100%` ở đây là của Ô CHA, nên mọi bề rộng JS đặt vào đều bị kẹp về bề rộng cột.
     KHÔNG có lỗi, KHÔNG có cảnh báo, và phép đo trả thẳng con số ĐÃ BỊ KẸP nên nhìn
     y như JS tính sai. Hậu quả: ô nở thành sợi mì cao 540px × rộng 119px, và cả khối
     nới ngang nhị phân bên JS chưa bao giờ có hiệu lực.
     ⛔ BÀI HỌC: gỡ trần chiều CAO thì phải gỡ trần chiều NGANG cùng lượt. Trần còn lại
        ở chiều nào thì lỗi rơi hết sang chiều ấy, và phép canh chiều kia vẫn xanh. */
  max-width: none;
  resize: none;          /* tay kéo góc đặt `height` inline — giành với JS, ô giật */
  background: var(--the, #fff);
  color: var(--chu, #141F1E);
  border: 1px solid var(--sheet-chon-vien, #00793A);
  border-radius: 3px;
  box-shadow: 0 4px 14px rgba(16, 24, 32, .16);
  white-space: pre-wrap;
  overflow-wrap: break-word;
  text-align: left;
}
/* ĐANG SỬA thì viền ĐẬM hơn — Boss chọn 13/09 (xem thì viền mảnh).
   ⛔ ĐỔI BỀ DÀY VIỀN THÌ Ô PHẢI KHÔNG ĐỔI KÍCH THƯỚC: đã có `box-sizing: border-box`
      ở trên nên viền ăn vào trong, ô không nhảy một li giữa lúc xem và lúc sửa —
      đúng câu Boss: *"ô xem và ô điền làm giống nhau"*. */
.sheet-moi tbody tr.sheet-hang td.sheet-o-no-sua > .sheet-ruot-no {
  border-width: 2px;
}

/* Chỉ ô ĐANG SỬA mới trả lại nguyên trạng — xem lời dặn dài ở khối trên.
   ⛔ Bỏ `.sheet-o-chon` và `:focus-within` khỏi đây: chúng bung trần chiều cao
      ngay khi con trỏ vào ô, làm ô xổ "Trạng thái" cao vọt lên rồi chữ chồng
      lên nhau — Boss chụp được đúng cảnh ấy 10/09. */
/* Cùng chuyện bề nặng như câu bung ở trên — luật hạ trần nhắm `tr.sheet-hang`
   nên câu gỡ trần cũng phải nặng bằng, không thì ô đang gõ vẫn bị chặn 22px. */
.sheet-moi tbody tr.sheet-hang td.dang-sua > *,
.sheet-moi tbody td.dang-sua > * { max-height: none; }

/* ⛔⛔ ĐỘ ĐẶC HIỆU: luật chung theo tên thẻ THUA luật của app theo tên lớp.
   Ô cột Học viên có một nhãn báo trạng thái lưu; app khai nó là khối bằng
   .dg-dinh .dg-luutt (hai lớp), còn luật ép-một-dòng ở trên chỉ có một lớp và
   ba tên thẻ — thua. Một khối chen giữa hai thứ nằm ngang thì ngắt dòng, và
   nút xoá rơi xuống dòng dưới: đo được ô cao 58px thay vì 30px.
   ⇒ Nhắm thẳng bằng tên lớp cho đủ nặng. Nhãn đang rỗng thì bỏ hẳn khỏi bố cục
     — nó chỉ có chữ trong đúng khoảnh khắc đang lưu. */
/* ⛔⛔ GOC ⑥ 11/09/2026 — CHAM BAO DA LUU TRONG BANG: BO HAN.
   Boss: *"bo chấm xanh báo đã lưu — tôi ko cần cái đấy đâu nó sẽ gây loạn vị trí
   nếu tên dài hơn bình thường"*. Da qua hai doi: ban dau la chu, roi thanh cham
   8px nam ngoai dong chay (632b7fb). Ca hai deu khong phai thu Boss can — app da
   tu luu that, va con so "da luu" thi doc o kho chu khong doc o mot cham mau.
   ⛔ `display:none` chu khong phai `visibility:hidden` hay `opacity:0`: hai thu
      kia VAN CHIEM CHO, va dung cai "loan vi tri" Boss vua keu.
   ⛔ CHI trong bang. Dong chu "✓ tự lưu khi bạn gõ" o FORM (`#dgLuuTT`, `#ttTT`)
      la chu that trong hop, Boss khong keu — dung gom vao mot luat.
   ⛔ Giu nguyen phan JS dat chu vao the: no vo hai, va go di la dong den 6 file
      cua 6 man trong mot cu von chi de bo mot cham. Neu sau nay don sach thi don
      ca cum, co phep canh rieng. */
.sheet-moi tbody td .dg-luutt { display: none; }

/* ⑨ NÚT XOÁ HÀNG: nằm im cho tới lúc rê chuột vào dòng.
   Boss chốt gộp nút thùng rác vào dải số dòng. Ở Sổ tuyển sinh nút đứng ngay
   đầu ô nên thay chỗ số được (khối ④). Ở màn Follow up nó nằm SAU tên học
   viên, không dời về đầu ô được nếu không sửa DOM — nhưng cái đích Boss muốn
   là bảng đừng có một nút đỏ nhấp nháy ở mọi dòng, và cái đó thì làm được.
   ⛔ Trên máy cảm ứng KHÔNG có rê chuột. Ẩn ở đó là mất hẳn đường xoá hàng.
      Bên dưới cho nó hiện mờ thường trực. */
@media (hover: hover) {
  .sheet-moi tbody td .nv-b.xoa { opacity: 0; transition: opacity .12s; }
  .sheet-moi tbody tr:hover td .nv-b.xoa { opacity: .75; }
  .sheet-moi tbody td .nv-b.xoa:hover,
  .sheet-moi tbody td .nv-b.xoa:focus-visible { opacity: 1; }
}
@media (hover: none) {
  .sheet-moi tbody td .nv-b.xoa { opacity: .55; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   ⑩ NHỮNG THỨ KHÔNG ĐƯỢC ÉP VỀ MỘT DÒNG — Boss bác 10/09/2026
   *"ô chọn lớp phải rõ nét của 2 phần tìm kiếm và chọn lựa chọn tên ra chứ nó
    như tàng hình ý"*

   Luật ép-một-dòng ở khối ⑧ nhắm vào NỘI DUNG của ô. Nhưng nó quét cả những
   thứ là CÔNG CỤ chứ không phải nội dung: ô tìm kiếm gắn vào ô chọn là một
   thẻ div con, nên nó bị bóp còn 22px và bị ép thành inline-flex — ô gõ bên
   trong co lại gần bằng 0, dòng đếm "79 người trong danh sách" bị cắt cụt.
   Nhìn ra đúng như Boss tả: tàng hình.

   ⛔ Thêm công cụ mới vào ô bảng thì NHỚ khai vào đây, không thì nó cũng bị
      bóp y như vậy mà chẳng có lỗi nào báo. */
.sheet-moi tbody td .oc-tim,
.sheet-moi tbody td .oc-goiy,
.sheet-moi tbody td .oc-dem {
  display: block;
  max-height: none;
  white-space: normal;
  overflow: visible;
}
.sheet-moi tbody td .oc-tim > input.oc-o {
  /* Ô gõ trong danh sách PHẢI thấy được viền — đây là chỗ người ta gõ tên lớp.
     Khối ⑦ gỡ viền cho mọi input trong bảng, nhưng chỗ này là ngoại lệ: nó
     không nằm trong lưới bảng, nó nằm trong hộp danh sách thả xuống. */
  border: 1px solid var(--vien);
  border-radius: var(--r-o, 8px);
  background-color: var(--the);
  padding: 5px 8px;
}

/* ══════════════════════════════════════════════════════════════════════════════
   ⑪ Ô TÌM TRONG Ô CHỌN: NẰM IM CHO TỚI LÚC NGƯỜI TA VÀO Ô — Boss 10/09/2026
   *"Tôi di chuột vào mấy cái ô có thanh tìm kiếm xong tôi di chuột ra khỏi ô đó
     thì nó phải bỏ cái tìm kiếm luôn để lại như cũ cho đẹp."*
   *"Cái thanh tìm kiếm trong ô nó cứ bị dài ý để gọn lại."*

   Trước bản này ô tìm bày thường trực TRÊN ô chọn, nên mỗi hàng có thêm một ô gõ
   dài ngoẵng đè lên giá trị thật — Boss chụp cả cột "Lớp" toàn chữ "Tìm k" cụt.

   ⛔⛔ TUYỆT ĐỐI KHÔNG CHO NÓ CHIẾM THÊM CHỖ KHI HIỆN RA. Cách hiển nhiên —
      `display:none` rồi `display:block` lúc `:hover` — làm Ô CAO LÊN đúng lúc con
      trỏ chạm vào, tức dựng lại chính lỗi Boss vừa bác sáng nay: *"di chuột vào
      cột tên lại phóng to ra như này ko chọn được"*. Ô nhảy là bấm trượt.
   ⇒ Ô tìm ĐÈ LÊN ô chọn (`position:absolute; inset:0`), không đẩy gì cả. Bề cao
     bảng đứng yên tuyệt đối dù đang hiện hay đang ẩn.

   ⛔ VÀ HIỆN THEO CÚ BẤM, KHÔNG THEO CON TRỎ. Rê chuột ngang qua bảng là quét
      qua mấy chục ô; hiện theo con trỏ thì ô tìm nhấp nháy liên tục suốt đường
      chuột đi. `:focus-within` mới đúng: người ta chủ động vào ô thì mới cần tìm,
      và rời ô là nó tự biến mất — đúng câu Boss dặn.

   ⛔⛔ VÁ CÚ PHÁP 10/09/2026 — DÒNG NÀY TRƯỚC ĐÂY ĐÓNG CHÚ THÍCH SỚM MỘT NHỊP.
      Cả đoạn văn bên dưới rơi ra NGOÀI chú thích, thành rác cú pháp. Trình duyệt
      chữa cháy bằng cách nuốt từ chỗ rác cho tới dấu `{` gần nhất — tức là nuốt
      LUÔN câu chọn của luật ngay sau đó. Kết quả: luật `display:none` giấu ô tìm
      BIẾN MẤT KHỎI CSSOM, ô tìm bày thường trực trở lại ở mọi ô chọn, đúng cảnh
      Boss chê "Tìm lớp t" đè lên tên lớp. Đo bằng `document.styleSheets` chứ
      không grep — grep vẫn thấy đủ chữ, chỉ trình duyệt mới biết luật đã chết.
   ⛔ BÀI HỌC: thêm đoạn văn vào giữa khối chú thích thì soi lại CẶP `/*` … `*/`.

   ⛔⛔ VÀ ĐỪNG CHO NÓ ĐÈ LÊN Ô CHỌN. Bản đầu tôi làm thế (`position:absolute;
      inset:0`) để ô khỏi cao lên — hỏng ngay: chọn lớp xong, con trỏ vẫn còn
      trong ô nên ô tìm phủ kín, che mất chính cái lớp vừa chọn. Boss chụp được
      đúng cảnh ấy 10/09: hàng "Nguyễn Thị Thanh" hiện chữ "Tìm lớp t" thay vì
      tên lớp.
   ⇒ Ô tìm nằm ĐÚNG CHỖ CŨ (trên ô chọn), chỉ `display:none` khi không dùng tới.
     Lúc người ta bấm vào ô thì ô ấy đã NỔI LÊN TRÊN và bung ra rồi (khối ⑧b),
     nên ô tìm hiện thêm cũng không đè lên hàng nào — nó nằm trong phần ô đang
     nổi, đúng như Excel bung ô đang gõ. */
.sheet-moi tbody td .oc-tim > input.oc-o,
.sheet-moi tbody td .oc-tim > .oc-xoa {
  display: none;
}
.sheet-moi tbody td:focus-within .oc-tim > input.oc-o,
.sheet-moi tbody td.sheet-giu-bam .oc-tim > input.oc-o,
.sheet-moi tbody td.dang-sua .oc-tim > input.oc-o {
  display: block;
  position: static;
  width: 100%;
  height: auto;
  margin: 0 0 4px;
}
.sheet-moi tbody td:focus-within .oc-tim.co-chu > .oc-xoa,
.sheet-moi tbody td.sheet-giu-bam .oc-tim.co-chu > .oc-xoa,
.sheet-moi tbody td.dang-sua .oc-tim.co-chu > .oc-xoa {
  display: block;
}
/* Dòng đếm "79 người trong danh sách" cũng chỉ cần lúc đang tìm. */
.sheet-moi tbody td .oc-dem { display: none; }
.sheet-moi tbody td.sheet-giu-bam .oc-dem,
.sheet-moi tbody td:focus-within .oc-dem,
.sheet-moi tbody td.dang-sua .oc-dem { display: block; }

/* ══════════════════════════════════════════════════════════════════════════════
   ⑫ THÙNG RÁC ĐỨNG TRƯỚC TÊN — Boss 10/09/2026
   *"cái nút thùng rác trước tên cho tôi và cách ra xíu để đỡ gây khó nhìn."*
   Kèm ảnh Sổ tuyển sinh làm mẫu: thùng rác đỏ đứng đầu ô, rồi mới tới tên.

   Sổ tuyển sinh vốn đã dựng nút ở đầu ô nên đúng sẵn. Các màn khác (Follow up,
   Dự giờ, Chăm sóc…) đặt nút SAU tên trong cùng một `<td class="dg-dinh">`.
   ⛔ ĐỪNG ĐI SỬA HTML TỪNG MÀN. Boss nói *"nhiều công cụ đều bị"* — sửa tay từng
      file thì màn nào viết sau lại quên, mà mỗi lần sửa là một lần đụng file của
      kênh khác. Đảo chỗ bằng `order` thì mọi bảng ăn cùng một lượt.
   ⛔ PHẢI ĐẶT `display:flex` LÊN CHÍNH Ô. `order` chỉ có nghĩa trong hộp co giãn;
      ô bảng mặc định là `table-cell` nên không hộp nào để mà xếp lại thứ tự.
      Bảng này có `<colgroup>` ghim bề rộng (xem `gaKeoCot`) nên đổi cách bày bên
      trong ô KHÔNG làm lệch cột — đã đo lại sau khi đổi. */
.sheet-moi tbody td.dg-dinh {
  /* ⛔⛔ O_TEN_CAO_BANG_HANG 11/09/2026 — Boss: *"o ten da to ra nhung o khong to
     ra, ten o 1 goc trong khi hang da mo rong khi mo cot lich su lien he."*
     GOC: o nay tung khai `display:flex`. `flex` bien `<td>` thanh hop co gian, tuc
     no ROI KHOI bo cuc bang: trinh duyet boc no vao mot o bang VO DANH, o vo danh
     ay cao theo hang con cai hop thi chi cao bang noi dung. Do o 2320, san Follow
     up 8-3-1-0: hang 134px ma o ten 63px — hut 71px; hang bung het 422px thi hut
     359px. Dung canh Boss chup.
     ⛔ DA THU VA LOAI BON CACH giu nguyen `flex`: `height:100%`, `align-self:
        stretch`, `tr{height:1px}`+`height:100%`, `height:inherit` — CA BON deu do
        hut Y NGUYEN 71px. Phan tram chieu cao khong bam duoc vao o bang vo danh.
     ⇒ Tra `<td>` ve dung `table-cell`, no lai tu cao bang hang nhu moi o khac.
     ⛔ BO `flex` KHONG LAM MAT THU TU NUT THUNG RAC: trong bang `sheet-so-dong`,
        nut xoa da `position:absolute; left:8px` tu truoc (khoi ~11810), khong con
        nho `order:-1` nua. Do lai sau khi doi: nut van dung truoc ten 10/10 hang.
     ⛔ Va kiem chieu kia: the ten van cao 40px (hai dong), ten bi cat 0/10, cot
        dau van rong 190px, hang thap nhat con 43 -> 33px (gon hon, khong xau di). */
  display: table-cell;
  /* ⛔ Boss chot 11/09/2026: *"da chot la no phai nam o GIUA hang khi mo rong —
     luon luon phai o giua chu khong phai o tit tren cung."* Ban dau toi de `top`,
     Boss xem anh va che ngay. `middle` la mac dinh cua o bang, nen cot ten an
     cung mot luat voi moi cot khac — khong con cot nao canh kieu rieng. */
  vertical-align: middle;
  gap: 6px;                     /* "cách ra xíu" — Boss dặn đúng chữ này */
  /* ⛔⛔ NGOẠI LỆ "ĐƯỢC XUỐNG DÒNG" CỦA CỘT NÀY ĐÃ HẾT HIỆU LỰC — Boss 10/09/2026.
     Sáng 10/09 Boss xin cho ô này tự xuống dòng (*"cái này sao lại nhồi hết vào 1
     dòng????"*) nên khối này từng là ngoại lệ có chủ ý của luật "đều tăm tắp" ở
     khối ⑧. Chiều 10/09, sau khi nhìn ảnh chụp cả bảng, Boss CHỌN LẠI:
        *"Một dòng, bấm vào bung ra."*
     Lý do Boss đổi ý nằm ở chính con số: cho xuống dòng thì hàng có tên dài cao
     45–75px trong khi hàng bên cạnh 32px, và cái Boss đang dựng là BẢNG TÍNH —
     bảng tính thì mọi hàng phải cao bằng nhau, chỗ nào thiếu thì bấm vào xem.
     ⇒ Nay cột này ép một dòng y hệt mọi cột khác; phần bị cắt xem bằng cách BẤM
       VÀO Ô (khối ⑧b `.sheet-o-bung` bung ra).
     ⛔ ĐỪNG dựng lại `flex-wrap: wrap` / `max-height: none` ở đây vì đọc thấy câu
        Boss nói buổi sáng — câu buổi chiều mới là câu còn hiệu lực. Hai dòng
        `max-height: none` cũ đã gỡ hẳn: để lại là ô tự cao lên, đúng thứ vừa bỏ. */
  /* ⛔⛔ ĐẢO LẠI LẦN THỨ BA — Boss BẤM NÚT CHỌN 11/09/2026: *"Xuống dòng,
     hàng cao lên"* (ba lựa chọn: xuống dòng hàng cao lên · một dòng rê chuột
     hiện đủ · ô tự nới rộng). Câu chiều 10/09 ở trên ĐÃ HẾT HIỆU LỰC.
     ⛔ NHƯNG LÝ DO BOSS ĐỔI Ý LẦN TRƯỚC VẪN ĐÚNG, nên lần này phải khác:
        hồi ấy thả tự do nên hàng có tên dài cao 45–75px cạnh hàng 32px, bảng
        so le. NAY KẸP Ở HAI DÒNG bằng `-webkit-line-clamp: 2` + `max-height:
        42px` ở thẻ `<b>` — hàng cao đều và CÓ TRẦN, không phải thả nổi.
        Đo trước khi kẹp: hàng ở 390 phình tới 93px — bảng cuộn mãi.
     ⛔ Đừng gỡ `flex-wrap` này vì đọc thấy câu chiều 10/09 ngay trên: câu
        11/09 mới còn hiệu lực, và nó đi kèm trần hai dòng. */
  flex-wrap: wrap;
  white-space: normal;
}
/* ⛔⛔ NÚT XOÁ PHẢI HẸP LẠI TRONG BẢNG SHEET — vá 10/09/2026 sau khi đo.
   Nút `.nv-b` mặc rộng 35px vì nó vốn là nút của biểu mẫu. Trong ô "Học viên"
   rộng 118px thì 35px ấy là gần một phần ba ô: đo được 10/09, chính nó đẩy tên
   học viên xuống dòng dưới và làm hàng cao 75px.
   ⇒ Trong bảng thì 22px — vẫn trên mức 20px của một đích bấm phụ, mà trả lại
     13px cho cái tên. ⛔ ĐỪNG hạ dưới 22px và đừng ẩn hẳn: xoá hàng là việc thật,
     máy cảm ứng không có rê chuột để làm nút hiện ra. */
/* ⛔⛔ HAI CÁCH ĐÃ THỬ VÀ ĐÃ LOẠI cho chuyện hàng cao ở 390 — 11/09/2026.
   Sau khi cho ô tên xuống dòng, thẻ `<b>` chiếm trọn một dòng nên hàng xếp
   thành BA TẦNG: nút xoá → tên (2 dòng) → chấm “đã lưu” dưới cùng.
   Đo ở 390: Follow up 93px, Phụ đạo 75px. Mốc muốn đạt là ≤75px.
   ⛔ CÁCH 1 — bóp bề rộng thẻ tên (`flex: 1 1 calc(100% - 46px)`) để hai viên
      nhỏ ngồi chung dòng: HỒNG. Thẻ tên còn 71px, 6/6 ô ẩn chữ trở lại.
   ⛔ CÁCH 2 — cho chấm `order: -1` đứng cạnh nút xoá: LỢI MỘT MÀN, HẠI BA.
      Follow up 390 93→80px, nhưng Phụ đạo 390 75→89px, Phụ đạo 1280 55→69px,
      Follow up 1280 43→52px. Net âm nên đã gỡ.
   ⛔ ĐÃ ĐO: chấm là `.dg-luutt`, có BA trạng thái `dang`/`xong`/`loi` — nó báo
      đã lưu hay lưu lỗi, CÓ NGHĨA, ⛔ đừng bỏ đi cho gọn. Nút xoá cũng có
      `title` riêng từng màn. Cả hai đều phải ở lại.
   ⇒ Việc còn nợ: hàng Follow up @390 vẫn 93px. */
.sheet-moi tbody td.dg-dinh > .nv-b.xoa,
.sheet-moi tbody td.dg-dinh > .fhs-xoa {
  order: -1;
  flex: none;
  margin: 0;
  width: 22px;
  min-width: 22px;
  height: 22px;
  min-height: 22px;
  padding: 0;
}
/* ⛔⛔ TÊN PHẢI TỰ XUỐNG DÒNG, ĐỪNG CẮT BẰNG BA CHẤM — Boss 10/09/2026 lượt 2.
   Bản trước để `white-space: nowrap` + `text-overflow: ellipsis` ở đây, tức là
   NGƯỢC HẲN với `flex-wrap: wrap` vừa đặt lên ô ở trên: ô thì cho xuống dòng, mà
   thứ duy nhất cần xuống dòng (cái tên) lại bị cấm. Kết quả đo được: tên không
   bao giờ ngắt giữa chừng, nên cả thẻ `<b>` nhảy nguyên xuống DÒNG THỨ HAI, để
   lại dòng đầu chỉ có mỗi con số thứ tự — mọi hàng cao 55px trong khi nội dung
   chỉ đáng 32px. Đúng cảnh Boss chụp.

   ⛔ `flex: 1 1 0` chứ KHÔNG phải `flex: 1 1 auto`. Trong hộp co giãn nhiều dòng,
      trình duyệt xếp món vào dòng theo BỀ RỘNG GỐC của nó trước rồi mới co. Bề
      rộng gốc `auto` của tên dài hơn chỗ còn lại → nó bị đẩy xuống dòng dưới
      NGUYÊN CẢ THẺ, y như lỗi cũ. Bề rộng gốc 0 thì nó ở lại dòng đầu và chữ
      bên trong tự ngắt — đúng thứ Boss xin. */
/* ⛔⛔ BỀ RỘNG GỐC PHẢI LÀ MỘT CON SỐ THẬT, ĐỪNG ĐỂ `0`. Đo 10/09/2026 sau lượt
   đầu: cột này rộng 118px, mà dải số chiếm 48px và nút xoá 35px — chỗ còn lại
   cho tên đúng 10px. Với bề rộng gốc 0 thì tên KHÔNG bị đẩy xuống dòng (0 thì
   chỗ nào chẳng đủ), nó ở lại dòng đầu trong 10px và ngắt mỗi dòng MỘT CHỮ CÁI:
   thẻ `<b>` cao 340px, cột nhìn như trống trơn vì ô cắt mất phần thừa. Boss sẽ
   thấy cột "Học viên" rỗng không.
   ⇒ Bề rộng gốc ~6em: chỗ còn lại hẹp hơn thế thì tên xuống hẳn dòng dưới và
     dùng trọn bề ngang ô (đúng thứ Boss xin); cột rộng ra thì nó ở lại dòng đầu
     cạnh con số và giãn ra hết chỗ. Một luật lo cả hai cảnh, không cần đo tay. */
/* ⛔⛔ CHẶN Ở ĐÚNG MỘT DÒNG — Boss chốt chiều 10/09/2026 ("Một dòng, bấm vào bung
   ra"). Trước đó chặn ở hai dòng; con số đo được khi ấy: hàng có tên dài cao
   45–75px cạnh hàng 32px, tức bảng vẫn so le. Một dòng thì mọi hàng bằng nhau.
   ⛔ VẪN GIỮ `-webkit-line-clamp` chứ đừng đổi sang `white-space: nowrap`: ô này
      là hộp co giãn nhiều mảnh, `nowrap` làm cả thẻ `<b>` không chịu co lại nên
      nó đẩy huy hiệu "lần 1/2" văng khỏi ô. Clamp 1 dòng cắt CHỮ bên trong thẻ,
      không đụng tới cách xếp các mảnh. */
.sheet-moi tbody td.dg-dinh > b {
  /* ⛔⛔ TÊN CHIẾM TRỌN MỘT DÒNG RIÊNG — Boss bấm nút chọn 11/09/2026:
     *"Xuống dòng, hàng cao lên"* (trong ba lựa chọn: xuống dòng · rê chuột hiện
     đủ · ô tự nới rộng). Lệnh cũ *"Một dòng, bấm vào bung ra"* (10/09) HẾT HẠN.
     Đo ở 390 với tên 46 và 52 ký tự: Follow up 6/6 ô, Chăm sóc 5/5, Phụ đạo
     10/10 đều bị xén — thẻ tên chỉ được 41–53px vì phải đứng chung một hàng
     với viên tên lớp và nút xoá.
     ⛔ `flex: 1 1 100%` + `flex-wrap: wrap` ở ô cha: tên tự xuống hẳn dòng dưới
        và dùng TRỌN bề ngang ô. Đây KHÔNG phải nới bề ngang cột — cột giữ
        nguyên, chỉ chia lại chỗ BÊN TRONG ô.
     ⛔ KẸP Ở HAI DÒNG bằng `line-clamp` + `max-height`, đừng thả tự do: thả ra
        thì hàng ở 390 phình tới 93px, bảng cuộn mãi. Hai dòng đủ cho tên 52 ký tự.
     ⛔ TRẦN CHIỀU CAO PHẢI NỚI THEO: `.sheet-moi tbody tr.sheet-hang td > *`
        (css:12180) chặn `max-height: 22px` — vừa đủ MỘT dòng 20px. Chỉ đổi clamp
        mà quên trần thì dòng thứ hai vẫn bị xén. Hai luật NGANG CƠ (0,2,3), luật
        này thắng nhờ ĐỨNG SAU — ⛔ đừng dời khối này lên trước css:12180.
     ⛔ VẪN GIỮ `-webkit-line-clamp` chứ đừng đổi sang `white-space: nowrap`: ô này
        là hộp co giãn nhiều mảnh, `nowrap` làm thẻ `<b>` không chịu co nên nó đẩy
        huy hiệu "lần 1/2" văng khỏi ô. */
  flex: 1 1 100%;
  min-width: 0;
  max-height: 42px;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: normal;
  overflow-wrap: break-word;
}
/* Bấm vào ô thì bỏ chặn, xem trọn tên.
   ⛔⛔ PHẢI CÓ `.sheet-o-bung` TRONG DANH SÁCH NÀY, và nó mới là đường thật.
      `:focus-within` chỉ nổ khi trong ô có thứ NHẬN ĐƯỢC TIÊU ĐIỂM. Ô "Học viên"
      chứa mỗi thẻ `<b>` và một nút xoá — bấm vào cái tên thì tiêu điểm rơi về
      `BODY`, `:focus-within` không bao giờ đúng, và cái tên không bao giờ bung.
      Đo 10/09/2026. Nay `sheetDatODang` gắn `.sheet-o-bung` lên ô khi thấy ruột
      bị cắt, nên bấm phát nào bung phát ấy. Hai vế cũ giữ lại cho ô có ô nhập.
   ⚠️ NÓI THẬT CHO NGƯỜI ĐỌC SAU: rút riêng dòng `.sheet-o-bung > b` này ra thì
      bài thử vẫn XANH — vì khối ⑧b đã đặt `overflow: visible` lên `> *`, mà
      `-webkit-line-clamp` phải có `overflow: hidden` mới cắt được, nên nó đã tự
      hết tác dụng. Giữ dòng này là CỐ Ý làm việc ấy cho tường minh: dựa vào
      chuyện "overflow:visible vô hiệu hoá line-clamp" là dựa vào một tác dụng
      phụ, ai đó chỉnh khối ⑧b là gãy câm. ⛔ Đừng ghi nó vào báo cáo như một
      thứ đã được bài kiểm chứng minh — bài kiểm KHÔNG phân biệt được nó. */
/* ⛔⛔ COT_HS_XEP_DOC 11/09/2026 — Boss: *"ten hoc sinh, xong o ben duoi se la
   lop va so lan goi — chu khong phai ca 3 cai de chung 1 hang, trong kha xau va kho
   nhin, phai mo to cot ra moi nhin duoc het."*
   GOC do bang CSSOM (hoi xem THE `<b>` dang `display` gi, va luat nao dat no):
     `.dg-dinh b`                                  => block      (0,1,1)
     `.sheet-moi tbody tr.sheet-hang td > b, ...`   => inline-flex (0,2,4)  <= THANG
     `.sheet-moi tbody td.dg-dinh > b`              => -webkit-box (0,2,3)
   Luat gom (0,2,4) nang nhat nen ten thanh `inline-flex` — tuc no NAM CHUNG DONG
   voi `Lop 4C1` va `lan 1/2`. Do duoc: 5/5 hang. Va no cung nuot luon cai kep hai
   dong (`-webkit-box`) cua cot ten, nen luat 2-dong bay gio dang chet cam.
   ⇒ Khai lai voi be nang du (0,3,4) de thang luat gom: ten la `-webkit-box` (giu
     duoc kep 2 dong) VA rong tron dong, nen lop/lan bi day xuong dong duoi.
   ⛔ Chi dat `width:100%`, KHONG dat `display:block`: bo `-webkit-box` la mat luon
      `-webkit-line-clamp`, ten dai lai tran vo han. */
/* ⛔ NHAN "da luu" DANG RONG THI DUNG CHIEM CHO. No la `inline-block` rong 8px,
   va tu luc cot Hoc sinh xep doc thi no thanh MOT DONG RONG thu ba trong o — khoi
   chu bi day len, do duoc lech 6px so voi tam hang o Follow up va Cham soc.
   ⛔ CHI an khi RONG: ba trang thai `dang`/`xong`/`loi` co chu that thi phai hien,
      do la cach nguoi dung biet da luu duoc hay chua. */
.sheet-moi tbody tr.sheet-hang td.dg-dinh > .dg-luutt:empty {
  display: none;
}

/* ⭐⭐ CHẤM BÁO LƯU RA KHỎI DÒNG CHẢY — coordinator quyết 11/09/2026, không hỏi Boss.
   ĐÍNH CHÍNH NGAY ĐẦU, để lần sau đừng đọc nhầm: nhãn `.dg-luutt` trong bảng sheet
   KHÔNG hiện chữ. Khối ㉝ (css:14398) đã thu nó thành MỘT CHẤM TRÒN 8px với
   `font-size: 0` từ 10/09. Nên lý do tôi và coordinator lo ban đầu — *"nhãn che
   đuôi tên dài"* — KHÔNG CÓ THẬT. Đo ra mới biết, không đoán được từ lời than.
   VẬY THÌ CÁI GÌ LÀM HÀNG CAO THÊM? Chính cú `63c2809` của tôi: nó cho
   `td.dg-dinh > b { display:-webkit-box; width:100% }` để xếp cột Học sinh theo
   chiều dọc — tên chiếm trọn bề ngang, nên cái chấm `inline-block` vốn đứng CÙNG
   DÒNG với tên bị đẩy xuống một DÒNG THỨ BA. Khối ㉝ vá đúng bệnh cho bố cục CŨ,
   tôi đổi bố cục mà quên rà lại nó. Đo ở Chăm sóc 2320: mỗi cú tích thành công thì
   bảng cao 550 → 566 → 582 → 598 (16px một hàng).
   ⇒ Chấm ra khỏi dòng chảy, neo mép phải ô, canh giữa chiều cao. Hàng đứng im
     tuyệt đối: NUT_DUNG_YEN 0px · HANG_XOM_DUNG_YEN 0px · bảng 550 → 550.
   ⛔ `position: sticky` cho ô, KHÔNG PHẢI `relative`. Khối ㉝ dặn đúng: ô này là
      cột đầu, nằm trong dải ghăm và mang `left` do JS đặt inline, nên `relative`
      biến `left` thành dịch ngang thật và ô bay khỏi chỗ (đúng lỗi vừa vá ở
      `b37f069`, đo được 190px). Nhưng lời dặn ấy dừng sớm một bước: `sticky` vẫn
      là thẻ CÓ ĐỊNH VỊ nên neo được con `absolute`, mà ô thường (không khai `left`)
      thì nằm y trong dòng chảy. Đó là đường đi được mà khối ㉝ chưa thấy.
   ⛔ ĐỪNG thêm nền/viền/padding vào đây: đây là CHẤM 8px `background: currentColor`,
      không phải chữ. Tôi đã thử bản có nền đục + viền và đo ra một viên thuốc trắng
      10×8px — xấu và sai nghĩa.
   ⛔ Chấm KHÔNG được nuốt cú bấm vào ô tên nằm dưới nó ⇒ `pointer-events: none`. */
.sheet-moi tbody tr.sheet-hang td.dg-dinh {
  position: sticky;
}
.sheet-moi tbody tr.sheet-hang td.dg-dinh > .dg-luutt {
  position: absolute;
  right: 5px;
  top: 50%;
  transform: translateY(-50%);
  margin: 0;
  z-index: 4;
  pointer-events: none;
  transition: opacity .25s ease;
}
/* Tự mờ sau 1,5 giây — `dgLuuTTNhip` trong js/tinh-nang.js gắn lớp này.
   ⛔ MẶC ĐỊNH LÀ HIỆN: lớp này là thứ được THÊM VÀO để ẩn, nên mã kia chết thì chấm
      vẫn hiện như cũ, chứ không biến mất im lặng. */
.sheet-moi tbody tr.sheet-hang td.dg-dinh > .dg-luutt.dg-luutt-an {
  opacity: 0;
}
.sheet-moi tbody tr.sheet-hang td.dg-dinh > b {
  display: -webkit-box;
  width: 100%;
}
/* `Lop X` va `lan n/m` dung chung dong thu hai, co dau cham giua cho de doc.
   ⛔ Dung `+` (ke ngay sau): thieu mot trong hai thi khong co dau cham lac long. */
.sheet-moi tbody tr.sheet-hang td.dg-dinh > .pd-dinh-lop + .pd-lan::before {
  /* ⛔⛔ DẤU CHẤM GIỮA VIẾT THẲNG BẰNG KÝ TỰ THẬT `·`, KHÔNG VIẾT BẰNG MÃ THOÁT.
     Boss 11/09: *"cột tên học sinh trong công cụ nhắc phụ đạo có cái chữ ?b7 trong
     các ô ở giữa lớp và lần 1/2, bỏ cái chữ ở giữa đi nó không có ý nghĩa gì cả"*.
     ĐÂY LÀ LỖI CỦA CHÍNH TÔI ở cú `63c2809`: tôi dựng khối CSS trong một chuỗi
     Python rồi ghi ra file, mà `"\00b7"` trong chuỗi Python là MÃ THOÁT BÁT PHÂN —
     `\00` thành một byte NUL (U+0000), còn `b7` rơi lại thành chữ thường. Trình
     duyệt vẽ NUL ra ô vuông tofu ⇒ đúng cái "◆b7" Boss chụp được.
     ⛔ Nhìn file bằng mắt thì NUL VÔ HÌNH — phải đổ codePoint ra mới thấy. Đó là
        lý do nó sống sót qua cả `node --check`, qua mắt tôi, và tới tận màn Boss.
     ⛔ LUẬT CHO LẦN SAU, đã trả giá hai lần trong một buổi: vá file bằng script thì
        CHỨA MÃ THOÁT PHỨC TẠP RA — viết thẳng ký tự thật. Ký tự thật không có cách
        nào bị diễn dịch sai thêm lần nữa.
     ⛔ VÀ QUÉT LẠI CẢ KHO sau mỗi đợt vá bằng script: đếm byte NUL. Quét hôm nay ra
        4 file, 3 file là CỐ Ý và phải giữ nguyên (khoá ghép `cs + NUL + id` ở
        man-hinh/thong-tin-hoc-sinh.js · chữ ký `SQLite format 3` + NUL ở bài kiểm kho chung · lớp
        ký tự điều khiển ở server/cts.js), chỉ chỗ này là hỏng. */
  content: "·";
  margin: 0 4px 0 2px;
  color: var(--mo);
}
.sheet-moi tbody tr.sheet-hang td.dg-dinh.sheet-o-bung > b,
.sheet-moi tbody tr.sheet-hang td.dg-dinh:focus-within > b,
.sheet-moi tbody td.dg-dinh.dang-sua > b {
  -webkit-line-clamp: unset;
  line-clamp: unset;
  overflow: visible;
}
/* Bung ra thì ô phải được xuống dòng lại, không thì gỡ clamp cũng vô nghĩa. */
.sheet-moi tbody tr.sheet-hang td.dg-dinh.sheet-o-bung {
  flex-wrap: wrap;
  row-gap: 2px;
}
/* Con số thứ tự (`::before` của khối ④) cũng là một món trong hộp co giãn. Không
   ghim `flex: none` thì nó bị co lại còn vài pixel và con số cụt mất. */
.sheet-moi tbody tr.sheet-hang td.dg-dinh::before { flex: none; }

/* ══════════════════════════════════════════════════════════════════════════════
   ⑬ THẲNG HÀNG — Boss 10/09/2026: *"sao dấu lôn xọn thế này bạn làm ăn chán quá"*
   (ảnh cột "Phụ trách": mũi tên ▾ và dấu ＋ mỗi hàng một chỗ)

   GỐC — không phải lỗi của mũi tên, mà là lỗi của cái hộp chứa nó. `.dg-tom-mui`
   đã có `margin-left: auto` từ đầu, tức là "đẩy tôi ra mép phải". Nhưng mép phải
   của CÁI GÌ? `<details class="dg-chipbox">` nằm trong `.fhs-o-hang` (hộp co
   giãn) mà không khai `flex`, nên nó chỉ rộng bằng đúng nội dung — mép phải của
   nó bám theo độ dài chữ, mỗi hàng một chỗ. Đo 10/09: bốn ô cùng một hàng cho ra
   mũi tên ở 874 · 1130 · 1370 · 1574; hàng dưới lại khác.
   ⇒ Cho hộp nở kín ô thì `margin-left: auto` mới có mép để bám, và mọi mũi tên
     của một cột xếp thành một đường thẳng — đúng cách Google Sheets vẽ.

   ⛔ ĐỪNG "chữa" bằng `position: absolute; right: 0` cho mũi tên. Ô chọn có thể
      đang là ô ghăm `sticky`; chồng thêm định vị lên nó thì cột kế bên lệch đi
      (đã trả giá ở khối ⑤).
   ══════════════════════════════════════════════════════════════════════════════ */
.sheet-moi tbody td .dg-chipbox {
  flex: 1 1 auto;
  min-width: 0;
}
.sheet-moi tbody td .dg-chipbox > summary { width: 100%; }
/* Mũi tên: neo mép phải, không bị bóp. */
.sheet-moi tbody td .dg-tom-mui {
  flex: none;
  margin-left: auto;
  padding-left: 6px;
}
/* Thẻ giá trị co được, huy hiệu "+N" thì không — số đếm mà cụt thì vô nghĩa.
   ⛔⛔ `flex: 0 1 auto` chứ ĐỪNG `1 1 auto` — vá 10/09/2026 sau khi đo.
      Bản trước để `1 1 auto`, tức thẻ chữ NỞ RA CHIẾM HẾT chỗ trống của ô. Chữ
      thì vẫn nằm bên trái thẻ, nên huy hiệu "+1" bị đẩy theo mép phải của cái
      thẻ đã nở: đo được ở Follow up ngày 10/09 là huy hiệu đứng cách chữ 131px,
      trên kho thật của Boss là 184px. Nhìn ra màn hình thì "+1" trôi lơ lửng
      giữa ô, không ai biết nó đếm cho cái gì.
      `0 1 auto` = KHÔNG nở, vẫn co được: thẻ ôm sát chữ nên "+1" bám ngay sau
      chữ, mà chữ dài quá thì vẫn cắt bằng ba chấm như cũ (luật ở dòng 12163).
   ⚠️ MŨI TÊN ▾ THÌ CỐ Ý KHÔNG BÁM CHỮ — đừng "sửa nốt cho đều". Nó giữ
      `margin-left: auto` ở ngay trên, tức luôn neo mép phải ô, vì Boss đã bác
      đúng kiểu bám chữ ấy: *"sao dấu lôn xọn thế này bạn làm ăn chán quá"* (ảnh
      cột Phụ trách, mũi tên mỗi hàng một chỗ). Chữ mỗi hàng một độ dài nên dấu
      bám chữ là dấu so le. Huy hiệu "+1" bám chữ vì nó THUỘC VỀ chữ; mũi tên
      neo mép phải vì nó thuộc về Ô. Hai dấu, hai luật, cả hai đều do Boss chốt. */
.sheet-moi tbody td .dg-tom-tag { flex: 0 1 auto; }
.sheet-moi tbody td .dg-tom-them { flex: none; }

/* ══════════════════════════════════════════════════════════════════════════════
   ⑬bis BÀY MẤY VIÊN LÀ TUỲ KHỔ MÀN — Boss chốt 12/09/2026
   *"ô đó phải hiển thị đủ đáp án trong đó trên màn hình bên ngoài và tối đa 4
    đáp án được hiển thị, nó mà nhiều hơn 4 đáp án thì đáp án thứ 5 trở đi là +1"*
   rồi chốt thêm bằng nút bấm: **"Màn to bày 4, điện thoại bày ít hơn"**.

   ⛔⛔ NGƯỠNG KHỔ DO CSS QUYẾT, KHÔNG PHẢI JS. `dgChipTom` chạy LÚC VẼ; nếu nó đọc
      `innerWidth` rồi ghim con số vào chữ thì Boss kéo cửa sổ hẹp lại là "+N" nói
      dối ngay, mà chẳng ai vẽ lại bảng. Nên JS dựng SẴN CẢ HAI huy hiệu và CSS ở
      đây chọn cái nào hiện — kéo cửa sổ là đổi tức thì, không cần vẽ lại.
   ⛔ 820px là mốc "điện thoại / máy tính" app đang dùng sẵn (thanh bên đổi kiểu ở
      821px, mười khối khác cũng lấy mốc này). Đừng đẻ thêm mốc mới.
   ⛔ GIẤU bằng `display:none` chứ đừng bỏ khỏi HTML — cùng một khối chữ phải chạy
      đúng ở CẢ HAI khổ mà không phải vẽ lại.
   ══════════════════════════════════════════════════════════════════════════════ */
/* Cụm viên tự xuống dòng để bày đủ tới 4 — Boss đòi "hiển thị ĐỦ đáp án".
   ⛔ QUẤN Ở ĐÂY, ĐỪNG QUẤN Ở `summary`: mũi tên ▾ là con của `summary` và phải
      neo mép phải trên MỘT dòng (luật ⑬ ngay trên — Boss đã chê dấu so le). Cho
      `summary` quấn thì mũi tên rơi xuống dòng riêng, dựng lại đúng lỗi ấy. */
/* DẤU "đang tải" NGẦM — 12/09/2026. Xem `dauDangTai` trong js/tinh-nang.js: màn nào
   chờ lâu thì cắm dấu này thay vì xoá trắng vùng nội dung. Dấu phải VÔ HÌNH:
   thứ người dùng thấy là màn chờ sẵn có của app, còn đây chỉ là cái cờ cho
   `ttTheoDoiDangTai` bắt.
   ⛔ Đừng dùng `display:none`: `ttTheoDoiDangTai` chỉ hỏi `querySelector` nên vẫn
      chạy, nhưng luật ẩn kiểu ấy hay bị luật khác đè lại thành lộ ra một dòng
      chữ giữa màn. Giữ kiểu "chỉ trình đọc màn hình thấy", 1px, cắt sạch.
   ⛔ `position:absolute` để nó không chiếm một dòng trong bố cục — chiếm chỗ là
      màn cũ bị đẩy một nhịp, đúng cái nháy đang đi chữa. */
.dang-tai-ngam {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

.sheet-moi tbody td .dg-tom-ds {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* Viên có nền thì phải có khe thấy được giữa hai viên, không thì hai nền
     xám dính nhau thành một mảng. 3px đủ tách mà không ăn bề ngang — số viên
     bày được ở 390 là con số phải ĐO LẠI mỗi lần đụng vào đây. */
  /* ══════════════════════════════════════════════════════════════════════════
     GIÃN VIÊN RA 6px — Boss 17/09/2026, THAY luật `column-gap:3px / row-gap:0`
     ──────────────────────────────────────────────────────────────────────────
     Boss: *"nó đã có block màu xanh nhưng tôi muốn nó phải cách nhau ra chứ tôi
     nhìn vào ô hiển thị ở ngoài nó ríu rít lại trông rất khó nhìn"* — chốt 6px.

     ⛔⛔ LUẬT CŨ `row-gap: 0` (vá 12/09) CÓ LÝ DO THẬT: mỗi ly khe dọc nhân lên theo
        số dòng viên, và đó là thứ từng đẩy ô tràn khỏi hàng 48px. Nay Boss chốt giãn,
        nên khe dọc để 4px chứ KHÔNG 6px — vừa đủ tách, vừa đỡ nhân lên.
        ⭐ NẾU Ô LẠI TRÀN KHỎ HÀNG thì đây là chỗ đầu tiên phải soi, và phải ĐO rồi báo
        Boss chứ đừng lặng lẽ trả về 0 — đó là lệnh Boss vừa đổi.
     ══════════════════════════════════════════════════════════════════════════ */
  column-gap: 6px;
  row-gap: 4px;
  flex: 1 1 auto;
  min-width: 0;
}
/* ⛔⛔ HAI VIÊN Ở MỌI CỘT MỌI KHỔ — Boss ĐỔI Ý 12/09/2026, thay hẳn luật 4/2 cũ.
   *"Không cắt chữ — hạ xuống 2 viên cho mọi cột"*. Boss biết và chấp nhận cái
   giá: màn 2320 cũng chỉ bày 2 viên rồi "+N", dù thừa chỗ.
   ⛔ ĐỪNG TIẾC CON SỐ 4 và đừng khôi phục mốc 820px cho khối này: bốn viên chỉ
      vừa khi được phép cắt đuôi bằng ba chấm, mà cắt chữ thì Boss đã bác.
   ⛔ Ca thử phá `hienca` của lượt trước HẾT HẠN theo luật này — phải viết lại,
      "bày hết mọi viên" nay là ca sai ở CẢ NĂM khổ chứ không riêng khổ hẹp.
   ⛔ Huy hiệu "phần còn lại sau 4" (`dg-tom-them-rong`) nay không bao giờ dùng
      tới. GIỮ trong HTML, chỉ ẩn — JS vẫn dựng sẵn cả hai để đổi luật bằng CSS
      mà không phải vẽ lại bảng (lý do ở khối ⑬bis ngay trên). */
/* ⛔⛔ LUẬT CHẶN CỨNG 2 VIÊN ĐÃ GỠ — Boss chốt 16/09/2026, thay lệnh 12/09.
   Bốn dòng cũ ở đây giấu viên thứ 3–4 (`.i3`, `.i4`) rồi chọn sẵn huy hiệu "+N"
   theo khổ màn. Nay `dgTomNhetVua` trong js/tinh-nang.js ĐO CHỖ THẬT của từng ô mà
   quyết, nên không còn con số nào để ghim vào CSS.
   ⛔ ĐỪNG TRẢ LẠI mấy dòng ấy vì thấy hàng nào đó bày ít viên: bày ít là ĐÚNG khi
      ô hẹp. Muốn biết có hỏng không thì đo `.dg-tom-tag` nào đang `display:none`
      trong một ô RỘNG, đừng đếm ở ô hẹp.
   ⛔ Lớp `.i1 .i2 .i3…` VẪN GIỮ trong HTML — bài kiểm và phép soi đang dựa vào nó
      để gọi tên từng viên. Đừng bỏ đi cho gọn. */
/* Lưới an toàn: nhỡ JS không chạy thì viên thừa bị CẮT chứ hàng không cao vống.
   `max-height` ở đây chỉ là trần phòng thân — `dgTomNhetVua` đặt lại theo ô thật. */
.sheet-moi tbody td .dg-tom-ds { overflow: hidden; max-height: 3.6em; }

/* Ô xổ đi kèm nút ＋ (Phụ trách · Đánh giá): ô xổ nở kín, nút ＋ neo mép phải.
   ⛔ PHẢI KHAI `width: 100%` CHO CHÍNH HÀNG. `.fhs-o-hang` là `<div>` trong ô
      bảng — ô bảng không phải hộp co giãn nên div đã rộng kín; nhưng ở màn nào
      ô ấy là hộp co giãn (`td.dg-dinh`) thì thiếu dòng này là hàng lại co. */
.sheet-moi tbody td .fhs-o-hang {
  display: flex;
  align-items: center;
  gap: 4px;
  width: 100%;
}
.sheet-moi tbody td .fhs-o-hang > select,
.sheet-moi tbody td .fhs-o-hang > .dg-chipbox {
  flex: 1 1 auto;
  min-width: 0;
}
.sheet-moi tbody td .fhs-them-o,
.sheet-moi tbody td .fhs-pt-them { flex: none; }

/* ══════════════════════════════════════════════════════════════════════════════
   ⑭ Ô RỖNG PHẢI CÓ NGHĨA — Boss 10/09/2026 (ảnh màn Dự giờ: ba cột "Phong cách",
   "Tương tác HS", "Kiến thức GV" chỉ hiện đúng một dấu chấm nhỏ)

   ⛔⛔ LUẬT CŨ Ở KHỐI ⑤③ ĐÃ HẾT HIỆU LỰC, ĐỪNG KHÔI PHỤC. Sáng nay tôi viết
      *"Sheets không viết chữ mời gọi vào ô rỗng"* rồi cho `.dg-tom-trong` màu
      trong suốt. Nghe thì đúng, nhìn thì hỏng: chữ tàng hình mà mũi tên ▾ vẫn
      còn, nên ô rỗng còn trơ lại MỘT DẤU CỤT không ai hiểu là gì. Google Sheets
      không gặp cảnh này vì ô rỗng của nó rỗng THẬT — không mũi tên. Mình thì
      Boss đã chốt phải luôn có mũi tên ("nhìn thấy dễ ấn vào dễ hơn").
   ⇒ Có mũi tên thì phải có chữ đi kèm, không thì mũi tên đứng một mình vô nghĩa.
     Chữ mờ, cỡ nhỏ — đủ đọc, không tranh chỗ với dữ liệu thật. */
.sheet-moi td .dg-tom-trong {
  color: var(--mo, #6B6660);
  opacity: .62;
  font-size: 12px;
  font-style: italic;
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sheet-moi td .dg-chipbox > summary:hover .dg-tom-trong,
.sheet-moi td .dg-chipbox[open] > summary .dg-tom-trong { opacity: 1; }

/* ══════════════════════════════════════════════════════════════════════════════
   ⑮ BA MỨC CỠ Ô — Boss chốt bằng nút bấm 10/09/2026: Thoáng 32 · Vừa 28 · Chật 24
   Người dùng chọn ở thanh chức năng; JS gắn `sheet-cao-vua` / `sheet-cao-chat`
   lên chính thẻ bảng và nhớ theo tài khoản (`load`/`save`).

   ⛔⛔ ĐÍCH BẤM KHÔNG ĐƯỢC XUỐNG DƯỚI 24px KỂ CẢ Ở MỨC CHẬT. Boss dặn nút chọn
      phải *"dễ ấn vào"*; bóp ô xuống 24 mà bóp luôn ô xổ bên trong thì mức Chật
      thành mức không bấm được. ⇒ Ô hẹp lại bằng cách bỏ ĐỆM, còn thứ người ta
      bấm vẫn giữ nguyên 24px và chiếm trọn bề cao ô.
   ⛔ Đây là "bóp NGANG" theo đúng luật đã chốt: chiều cao chỉ hạ tới đúng bằng
      đích bấm rồi dừng, không hạ tiếp. */
.sheet-moi {
  --sheet-o-cao: 32px;
  --sheet-o-dem: 4px;
}
.sheet-moi.sheet-cao-vua  { --sheet-o-cao: 28px; --sheet-o-dem: 2px; }
.sheet-moi.sheet-cao-chat { --sheet-o-cao: 24px; --sheet-o-dem: 0px; }
.sheet-moi tbody tr.sheet-hang td {
  height: var(--sheet-o-cao);
  padding-top: var(--sheet-o-dem);
  padding-bottom: var(--sheet-o-dem);
}

/* ⛔⛔ Ô ĐÃ ĐỔI SANG HỘP CO GIÃN THÌ `height` LÀ BỀ CAO CHỐT, KHÔNG PHẢI SÀN.
   Trên `display: table-cell`, `height` chỉ là mức tối thiểu — ô vẫn nở ra được.
   Nhưng hai ô dưới đây đã bị khối ⑫ và ⑰ đổi sang `display: flex` để xếp lại thứ
   tự, và với hộp co giãn thì `height: 32px` là CHỐT CỨNG: phần xuống dòng thứ hai
   bị `overflow: hidden` cắt sạch. Đo thật 10/09/2026: cột "Học viên" hiện ra
   TRỐNG TRƠN — còn mỗi con số thứ tự, tên học viên nằm ở dòng hai đã bị cắt mất.
   Nhìn ảnh thì tưởng app nuốt dữ liệu, mà không có một lỗi nào báo.
   ⇒ Hai ô ấy dùng `min-height`: vẫn cao tối thiểu đúng mức Boss chọn, mà tên dài
     thì nở ra được — chính là thứ Boss xin ở lệnh "cho nó tự xuống dòng trong ô".
   ⛔ Thêm ô nào khác sang `display:flex` thì NHỚ khai vào đây, không thì nó cũng
      bị cắt y như vậy mà chẳng có dấu vết nào. */
.sheet-moi tbody tr.sheet-hang td.dg-dinh,
.sheet-moi tbody tr.sheet-hang td.fhs-lhcell {
  height: auto;
  min-height: var(--sheet-o-cao);
}

/* ⛔⛔ Ô CHỌN TRONG BẢNG PHẢI VỪA LÒNG Ô, ĐỪNG MANG BỀ RỘNG CỦA BIỂU MẪU.
   Vá 10/09/2026 sau khi đo màn Phụ đạo: MỌI hàng cao 51px trong khi Boss chốt
   32px — cao gấp rưỡi, và đều tăm tắp nên nhìn không ra là lỗi.

   Thủ phạm: `.dg-bang .pd-tt-sel { min-width: 94px }` (css:6962). Con số 94px
   ấy sinh ra cho ô chọn nằm trong BIỂU MẪU, nơi có cả trăm pixel bề ngang.
   Nhét nguyên nó vào ô bảng rộng 98px (lòng ô 81px) thì ô chọn RỘNG HƠN CHỖ
   CHỨA NÓ: nó chèn ngang ra, đẩy ô cao lên, và tràn đè ô bên cạnh.
   Đây cũng chính là con đã bắt được ở lỗi "vùng chết 82/98px" — cùng một ô
   chọn, hai triệu chứng khác nhau.

   ⛔ ĐỘ ĐẶC HIỆU: luật cũ là (0,2,0). Câu gỡ ở đây phải NẶNG HƠN mới đè nổi —
      `.sheet-moi tbody td .pd-tt-sel` là (0,2,2). Viết nhẹ hơn là nó thua âm
      thầm, ô vẫn 51px mà chẳng có lỗi nào để lần ra. Đây là lần thứ NĂM trong
      ngày phải đếm điểm trước khi viết một luật cho `.sheet-moi`.
   ⛔ CHỈ GỠ TRONG BẢNG SHEET. Ô chọn ngoài biểu mẫu vẫn cần 94px để đọc được
      chữ "Chưa thực hiện"; gỡ toàn cục là hỏng chỗ đang chạy đúng.
   ⛔ `width: 100%` để ĐÍCH BẤM PHỦ TRỌN Ô. Boss đã chê chuyện bấm vào giữa ô
      mà không ăn; ô chọn hẹp hơn ô là tự đẻ ra vùng chết. */
.sheet-moi tbody td .pd-tt-sel,
.sheet-moi tbody td .pd-done-sel {
  min-width: 0;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}

/* ══════════════════════════════════════════════════════════════════════════════
   ⑯ MÀU TIÊU ĐỀ CỘT CHỈNH ĐƯỢC, MẶC ĐỊNH TRẮNG — Boss 10/09/2026
   *"Sửa lại màu cột thành dạng giống sheet thật hơn đi, không để mặc định 1 màu
     nữa, mà cho nhân viên có quyền được chỉnh màu tiêu đề cột nha, mặc định là
     màu trắng"*

   ⛔⛔ ĐỪNG ĐI GHI ĐÈ TỪNG LUẬT `thead th`. App có ít nhất năm luật cùng tô nền
      tiêu đề (`.dg-bang thead th`, `.dg-bang thead .dg-dinh`, `.cts-bang …`,
      bản nền tối…), mỗi luật một bề nặng khác nhau; đè tay là chắc chắn sót một
      chỗ, và chỗ sót ấy vẫn xanh lè giữa một bảng trắng.
   ⇒ ĐỔI CHÍNH BIẾN mà cả năm luật ấy đang gọi. Khai lại `--dau-bang-*` ngay trên
     thẻ bảng thì mọi luật con thừa hưởng giá trị mới, không phải tranh bề nặng
     với ai. JS chỉ cần đặt `--sheet-dau-nen` lên thẻ bảng là xong.

   ⛔ Bảng KHÔNG mang `.sheet-moi` (phiếu in, bảng cũ) vẫn giữ nguyên màu xanh —
      khối này không với tới chúng, đúng ý.
   ⛔ Nền trắng thì phải có viền THẬT, không thì hàng tiêu đề trôi lẫn vào ô đầu.
   ══════════════════════════════════════════════════════════════════════════════ */
.sheet-moi {
  --dau-bang-nen: var(--sheet-dau-nen, #FFFFFF);
  /* ⛔ MẶC ĐỊNH LÀ XÁM MỜ, KHÔNG PHẢI MÀU CHỮ THÂN BÀI — bám mẫu 21st.dev
     (tiêu đề cột xám 12px, không đậm). Trước đây rơi về `--chu` nên tiêu đề
     ĐEN ĐÚNG BẰNG chữ trong ô: đo được rgb(31,29,26) ở cả 6 màn, tức là hàng
     tiêu đề không tách khỏi thân bảng chút nào.
   ⛔ `--sheet-dau-chu` vẫn đứng TRƯỚC: đó là màu nhân viên tự chọn ở bảng màu
      (khối ⑯), và lựa chọn của người dùng luôn thắng mặc định của mẫu. Đổi
      thứ tự hai cái này là bảng màu bấm vào không thấy gì đổi. */
  --dau-bang-chu: var(--sheet-dau-chu, var(--chu-mo, #6B6660));
  --dau-bang-vien: var(--sheet-dau-vien, var(--vien-ro, #B9B3AA));
}
body.toi .sheet-moi {
  --dau-bang-nen: var(--sheet-dau-nen, #22262B);
  /* nền tối: cũng hạ xuống tông mờ cho khớp — xem lời dẫn ở khối sáng. */
  --dau-bang-chu: var(--sheet-dau-chu, var(--chu-mo, #9A948C));
  --dau-bang-vien: var(--sheet-dau-vien, var(--vien, rgba(255,255,255,.18)));
}
/* Tiêu đề trắng thì chữ đen 700 nhìn nặng như tờ rơi. 600 là đủ tách khỏi thân
   bảng — và đúng luật "đừng để lộ ra là máy làm" (cấm 800 + IN HOA). */
.sheet-moi thead th {
  font-weight: 600;
  border-bottom: 1px solid var(--dau-bang-vien);
}

/* ══════════════════════════════════════════════════════════════════════════════
   ⑰ Ô "LỊCH SỬ LIÊN HỆ" — Boss 10/09/2026
   *"Lịch sử liên hệ cái ô của nó có dấu + ấn vào bị lỗi khó dùng, thiết kế sao
     cho nó đồng đều thẳng hàng nhau đi"*

   ĐO ĐƯỢC THỦ PHẠM (10/09, bài `bisect`): ẩn riêng cột này đi thì hàng tụt từ
   39px xuống 32px — tức MỘT MÌNH nó kéo cao CẢ BẢNG, kể cả những hàng chưa có
   lần liên hệ nào. Vì ô này xếp DỌC: danh sách các lần ở trên, nút "Thêm lần"
   nằm DƯỚI nó. Hai khối chồng nhau thì ô cao gấp đôi, mà nút thì mỗi hàng một
   độ cao khác nhau — đúng chữ "không thẳng hàng" của Boss.

   ⇒ Xếp NGANG: danh sách bên trái (một dòng, cắt bằng ba chấm), nút "Thêm lần"
     neo mép phải. Thế là nút của mọi hàng rơi vào đúng một đường dọc, y như dấu
     ＋ của cột "Phụ trách" sau khối ⑬.
   ⛔ KHÔNG ĐƯỢC GIẤU MẤT DỮ LIỆU. Bấm vào ô là khối ⑧b cho nó nổi lên và bung
      hết — nhưng phải NỚI TRẦN cho cả danh sách bên trong, không thì ô nổi lên
      mà ruột vẫn bị cắt còn một dòng.
   ⛔ Sửa bằng CSS, KHÔNG sửa HTML của `man-hinh/follow-hoc-sinh.js`: cùng kiểu ô ấy còn ở
      màn Chăm sóc, mà file màn là chỗ kênh khác đang viết.
   ══════════════════════════════════════════════════════════════════════════════ */
.sheet-moi tbody td.fhs-lhcell {
  display: flex;
  align-items: center;
  /* 8px là khe tối thiểu giữa hai thứ bấm được. 6px cũ làm nút "Thêm lần" dính
     sát ô kết quả — cặp cuối cùng còn dưới chuẩn sau khi đã chữa mấy chỗ kia. */
  gap: 8px;
  /* ⛔⛔ `flex-wrap: wrap` PHẢI CÓ MẶT Ở ĐÂY — thiếu suốt từ 11/09 tới 17/09/2026.
     Khối chú thích ngay dưới viết từ 11/09 nói rõ *"⇒ Cho `wrap`"* và giải thích cả
     trang vì sao cần, nhưng LUẬT THẬT thì chưa bao giờ có dòng ấy. Chú thích nói một
     đằng, mã chạy một nẻo — và vì phần lý do trông đã đầy đủ nên đọc lại bao nhiêu
     lần cũng không sinh nghi.
     ⭐ ĐO THẬT 17/09: `.fhs-them-boc` khai `flex: 0 0 100%` để nằm riêng một dòng,
     nhưng thiếu `wrap` thì nó KHÔNG BAO GIỜ xuống dòng — nó ở lại cuối dòng cũ, bị
     đúng cái `gap: 8px` trên đẩy sang phải 8px, rồi tràn khỏi mép phải ô 3px. Nút ＋
     lệch tâm ô đúng 8px, dù bản thân nút vẫn nằm chính giữa cái bọc của nó.
     ⛔ Nên sửa ở nút hay ở bọc đều là chữa sai chỗ: cả hai đã đúng sẵn. */
  flex-wrap: wrap;
}
/* ⛔⛔ CHO XUỐNG DÒNG, ĐỪNG CẮT — vá 11/09/2026. Boss: *"nút cứ ríu rít vào nhau"*
   (cột Lịch sử liên hệ).

   ĐO THẬT, sau khi nạp 3 lần liên hệ như kho thật: 16 thứ bấm được nhồi trong một
   ô 340px, 9 thứ NẰM HẲN NGOÀI ô (bị `overflow: hidden` cắt), khe giữa các thứ chỉ
   6px, và ở khổ 390 có 15 đích bấm dưới 44px.

   ⛔ VÀ ĐÂY MỚI LÀ CON SỐ QUYẾT ĐỊNH: MỘT lần liên hệ cần ~293px
      (ngày 118 + nút lịch 37 + ô kết quả 90 + nút ✕ 24 + khe), trong khi ô chỉ còn
      ~236px sau khi trừ nút "Thêm lần" (104px). Tức hàng ngang KHÔNG ĐỦ CHỖ cho
      dù CHỈ MỘT lần — đây không phải "hơi chật", mà là bố cục bất khả thi về hình học.
      Nới khe thêm vài pixel không cứu được gì.

   ⇒ Cho `wrap`: lần nào không đủ chỗ thì xuống dòng, hàng cao lên — đúng câu trả
     lời Boss đã bấm nút chọn cho cột tên ("Xuống dòng, hàng cao lên"). Giữ
     `row` chứ không đổi thành `column`: cột được kéo rộng ra thì hai lần lại tự xếp
     chung một dòng, không phí chỗ.
   ⛔ Bỏ `overflow: hidden`: cắt là GIẤU MẤT thứ bấm được, mà thứ bị cắt VẪN nhận cú
      bấm — đúng kiểu "bấm trượt" Boss kêu. Ẩn thì phải ẩn cả đích bấm, còn đã bày
      ra thì phải bấm được.
   ⚠ CÁI GIÁ: hàng cao lên khi có nhiều lần liên hệ. Đó là chỉ số phải báo Boss,
     không phải thứ tự quyết — xem con số trong lời commit. */
.sheet-moi tbody td.fhs-lhcell > .fhs-lhs {
  flex: 1 1 auto;
  min-width: 0;
  /* ⛔⛔ NỚI TRẦN CHIỀU CAO — KHÔNG CÓ DÒNG NÀY THÌ `wrap` Ở TRÊN LÀ VÔ NGHĨA.
     `.sheet-moi tbody tr.sheet-hang td > *` (css:12180) ghim `max-height: 22px`
     cho mọi con trực tiếp của ô — vừa đúng MỘT dòng 20px. Đo thật 11/09/2026 sau
     khi cho xuống dòng: ruột ô cần 236px mà chỉ được 22px, ô cao 33px ⇒ chữ bị
     CẮT NGANG THÂN (nhìn ảnh thấy `Da goi, phu` và dòng ngày cụt nửa dưới) — tệ
     hơn hẳn lúc chưa vá.
     ⛔ ĐÂY LÀ BỆNH "siết luật phải siết cả luật gỡ" LẦN NỮA: ô này đã được cho
        `height:auto; min-height:…` (css:12693) để nở ra được, nhưng trần 22px của ruột
        thì không ai gỡ — nên ô có quyền cao mà ruột không có quyền cao.
        Khối `:focus-within` ngay dưới cũng phải khai `max-height: none` vì chính
        lý do đó — chỉ khác là nó chỉ nới lúc đang gõ.
     ⛔ VÀ ĐÂY LÀ BÀI HỌC VỀ PHÉP CANH: `canh-nut-riu-rit.js` báo ĐẠT vì nó chỉ đo
        khe và tràn theo chiều NGANG. Nới chiều nào thì phải kiểm chiều kia — nay
        phép canh đã thêm `HONG_CAT_DOC` so `scrollHeight` với `clientHeight`. */
  max-height: none;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 8px;
  overflow: visible;
}
/* ⛔⛔ NÚT ＋ NAY NẰM TRONG `.fhs-them-boc`, KHÔNG CÒN LÀ CON TRỰC TIẾP CỦA Ô.
   Luật cũ nhắm `td.fhs-lhcell > .fhs-them-lh` nên từ 17/09 là KHÔNG KHỚP NỮA — trông
   vẫn đúng nhưng chết câm, không luật nào báo. Chuyển sang cái bọc.
   `flex: 0 0 100%` để bọc chiếm trọn một dòng riêng — có thế nút mới nằm GIỮA Ô và
   DƯỚI danh sách đúng như Boss chốt (câu hỏi 9), chứ không chèn ngang vào cuối dòng. */
.sheet-moi tbody td.fhs-lhcell > .fhs-them-boc {
  flex: 0 0 100%;
  order: 1;
  margin: 6px 0 0;
  display: flex;
  justify-content: center;
}
/* Mỗi lần liên hệ: ngày · kết quả · nút xoá nằm ngang, canh giữa theo chiều dọc.
   `align-items: flex-start` của luật cũ làm nút ✕ dính lên mép trên ô. */
.sheet-moi tbody td.fhs-lhcell .fhs-lh {
  align-items: center;
  /* ĐỦ chỗ thì nằm một dòng, thiếu thì chiếm trọn dòng riêng. `flex: none` của
     bản cũ khiến nó giữ nguyên bề rộng tự nhiên rồi tràn ra ngoài ô. */
  flex: 1 1 auto;
  min-width: 0;
  max-width: 100%;
  /* ⛔ PHẢI CHO XUỐNG DÒNG CẢ BÊN TRONG MỘT LẦN LIÊN HỆ. Ô ngày rộng cứng 118px,
     ô kết quả tối thiểu 90px, nút ✕ 24px — cộng khe là ~269px, trong khi dòng chỉ
     còn ~236px. Không cho `wrap` thì nó tràn ra khỏi dòng và nút ✕ ĐÈ LÊN nút
     "Thêm lần" — đo được khe 0px, đúng nguồn "bấm trượt" Boss kêu. */
  flex-wrap: wrap;
  gap: 8px;
}
/* Khe trong chính ô ngày cũng phải đủ 8px — đo được 6px giữa ô chữ và nút lịch.
   ⛔ CHỈ SIẾT TRONG Ô BẢNG: `.nv-datevn` là thứ dùng chung khắp app, đổi toàn cục là
      đổi bố cục của những màn không ai yêu cầu. */
.sheet-moi tbody td.fhs-lhcell .nv-datevn { gap: 8px; }
.sheet-moi tbody td.fhs-lhcell .fhs-lh-kq {
  min-width: 90px;
}
/* CHU GOI Y BI CAT THI PHAI CO DAU BA CHAM — va 11/09/2026.
   Boss nhin anh thay o Phu dao hien "Ket qua (dien sau" — cut dung dau dong ngoac,
   5 hang deu the. Doc len trong nhu app go sai chinh ta, te hon han cat nhieu.
   Cung ho voi vu "Quen phie" da va o 7e32d8b.
   Phep canh canh-chu-cut.js TUNG MU voi ca nay vi no chi doc `value`: o rong thi
   chuoi rong nen ca hong roi vao ro "bo qua" — tu bien mat khoi mau so. Vá phep canh
   xong thi so that la 25/118 o chu khong phai 3/80.
   ⛔ CHI AP KHI DANG HIEN CHU GOI Y VA CHUA GO (`:placeholder-shown:not(:focus)`):
      doi `white-space` cho chu THAT la doi bo cuc o nhieu dong, khong ai yeu cau.
   ⛔ Day la LUOI CHUNG, khong thay cho viec rut chu goi y cho vua o. Chu goi y 28 ky
      tu trong o 111px thi co dau ba cham van la mat nua cau — phai rut chu (xem
      man-hinh/phu-dao.js va man-hinh/cham-soc.js cung luot). */
/* ⛔ CHI `input`, KHONG CO `textarea` — da DO, khong phai doan.
   Dat `text-overflow: ellipsis` len textarea thi computed style nhan du, nhung CHUP
   ANH RA thi chu VAN CUT GIUA CHU, khong co dau ba cham nao: `text-overflow` khong ap
   cho chu goi y cua textarea. Voi `input` thi CO an — anh thay ro dau "..".
   ⇒ De lai ve textarea la de lai mot LUAT CHET CAM, lam nguoi sau tuong da co luoi.
   Anh doi chung: scratchpad/anh/bacham/co-luat.png (textarea, KHONG co dau ba cham)
   va input-co-luat.png (input, CO dau ba cham). */
.sheet-moi tbody td input.o-bang:placeholder-shown:not(:focus) {
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* ⛔⛔ THU GỌN LỊCH SỬ LIÊN HỆ — Boss bấm nút chọn 11/09/2026.
   Phần ĐẾM và phần vẽ nhãn nằm ở `man-hinh/follow-hoc-sinh.js` (`fhsSoLanHien`,
   `fhsNhanConLai`, `FHS_MO_LH`) — ⛔ ĐỪNG thử làm lại bằng CSS: bản thử dùng
   `counter-increment` + `::after` in ra "còn 0 lần", vì counter KHÔNG chạy trên
   phần tử `display:none`. CSS ở đây CHỈ lo giấu và kẻ nhãn.
   ⛔ Giấu bằng `display:none` chứ không cắt: thứ bị cắt vẫn nhận cú bấm.
   ⛔ Hai luật dưới NGANG CƠ nhau (0,3,2) — luật "mở" thắng nhờ ĐỨNG SAU, đừng
      đảo thứ tự hai khối này. */
.fhs-lhcell .fhs-lh.fhs-an { display: none; }
.fhs-lhcell .fhs-lhs.fhs-mo .fhs-lh.fhs-an { display: flex; }
/* 🖱 16/09/2026 — VỆT NHOÈ KHI LĂN QUA LẦN LIÊN HỆ CŨ. Boss chốt bằng nút bấm:
   **"nhẹ, chỉ thoáng thấy"**. Cơ chế lăn ở `fhsLanQua` trong `man-hinh/follow-hoc-sinh.js`.
   ⛔ 0,6px chứ đừng hơn: đây là CHỮ, không phải ảnh. Nhoè 2px là chữ thành vệt xám
      không đọc được, và người ta sẽ tưởng màn hình hỏng chứ không nghĩ là hiệu ứng.
   ⛔ Chỉ nhoè phần chữ, ĐỪNG nhoè cả ô: nút ✕ và ô ngày nhoè theo thì trông như
      bấm không được — mà chúng vẫn bấm được, tức là nói dối người dùng.
   ⛔ `will-change` để trình duyệt dựng sẵn lớp vẽ: dựng giữa chừng là khựng đúng
      lúc người ta đang lăn, và cú khựng ấy còn dễ thấy hơn chính vệt nhoè. */
.fhs-lhcell .fhs-lhs .fhs-lh-kq,
.fhs-lhcell .fhs-lhs .nv-datevn {
  transition: filter .12s ease-out;
  will-change: filter;
}
.fhs-lhcell .fhs-lhs.fhs-nhoe .fhs-lh-kq,
.fhs-lhcell .fhs-lhs.fhs-nhoe .nv-datevn {
  filter: blur(.6px);
}
@media (prefers-reduced-motion: reduce) {
  .fhs-lhcell .fhs-lhs.fhs-nhoe .fhs-lh-kq,
  .fhs-lhcell .fhs-lhs.fhs-nhoe .nv-datevn { filter: none; transition: none; }
}

.fhs-lhcell .fhs-con-lai {
  flex: 1 1 100%;
  /* đích bấm: chừa 28px chiều cao. Hàng chật nhất của Boss là 24px, nên đây là
     chỗ cao hơn hàng một chút — cố ý, vì nó là thứ phải bấm được. */
  min-height: 28px;
  padding: 3px 0;
  border: 0;
  background: none;
  text-align: left;
  font: inherit;
  font-size: 12.5px;
  color: var(--mo);
  cursor: pointer;
}
.fhs-lhcell .fhs-con-lai:hover { color: var(--chu); text-decoration: underline; }
@media (min-width: 1200px) {
  .dg-bang td.fhs-lhcell { min-width: 560px; }
}
/* Bấm vào ô thì bung trọn — nới trần cho cả ruột, không chỉ cho ô. */
/* `.sheet-giu-bam` đi kèm ở cả hai luật dưới đây: lật hàng thành cột làm nút
   "còn N lần" tụt 44px và nở 112px NGAY GIỮA một cú bấm (đo được ở Follow up,
   1366: mousedown trên `button.fhs-con-lai` rect [788,506,439,26] → mouseup rơi
   vào `textarea.fhs-lh-kq` rect [788,550,551,26]). Giữ dáng cho tới khi chuột
   nhả hẳn thì `click` mới về đúng nút. */
.sheet-moi tbody tr.sheet-hang td.fhs-lhcell:focus-within,
.sheet-moi tbody tr.sheet-hang td.fhs-lhcell.sheet-giu-bam {
  flex-wrap: wrap;
}
.sheet-moi tbody tr.sheet-hang td.fhs-lhcell:focus-within > .fhs-lhs,
.sheet-moi tbody tr.sheet-hang td.fhs-lhcell.sheet-giu-bam > .fhs-lhs {
  flex-direction: column;
  align-items: stretch;
  overflow: visible;
  max-height: none;
  flex-basis: 100%;
}

/* ══════════════════════════════════════════════════════════════════════════════
   ⑱ THANH CHỨC NĂNG CỦA BẢNG — làm theo ĐÚNG mẫu Boss gửi
   https://21st.dev/@preetsuthar17/components/toolbar  (id 3033)

   ⛔⛔ BẢN ĐẦU CỦA TÔI ĐÃ BỊ BOSS BÁC: *"thiết kế phải giống hệt của 21st dev tôi
      gửi nha, thiết kế thế này sai rồi"*. Bốn chỗ sai, ghi lại để lượt sau đừng
      lặp lại:
        ① tôi làm một DẢI chạy hết bề ngang màn — mẫu là một VIÊN THUỐC gọn, nổi
           lên, chỉ rộng đúng bằng số nút;
        ② tôi in chữ tiếng Việt ra thanh ("Tô nền", "Cỡ ô"…) — mẫu KHÔNG một chữ
           nào, toàn icon, tên nằm trong mách nhỏ (tooltip);
        ③ tôi bày sẵn 12 ô màu ra thanh — mẫu gom vào MỘT nút, bấm mới xổ ra;
        ④ tôi không có mách nhỏ — mẫu có, nền đen, hiện phía TRÊN nút.

   Số đo bê thẳng từ mã gốc, đừng làm tròn lại:
     vỏ  · bo góc 8px · đệm 4px · khe giữa nút 4px · viền 1px nhạt · bóng đậm
     nút · 32×32px · bo góc 6px · icon 16×16 nét 2
     vạch· 1×32px
     mách· cách nút 40px, nền #1F2937, chữ trắng 12px, bo 6px, đệm 4px 8px

   ⛔ MÀU THÌ DÙNG BIẾN CỦA APP, đừng bê bảng màu Tailwind vào — Boss đã chê "lộ
      ui AI" năm lần. Hình dáng và số đo giống mẫu, màu là của MyPAS.
   ══════════════════════════════════════════════════════════════════════════════ */

/* Cái neo. ⛔⛔ PHẢI CAO 0px. Thanh này hiện/ẩn theo con trỏ; nếu nó chiếm chỗ
   thật thì mỗi lần hiện ra là cả bảng bị đẩy xuống rồi lại nhảy lên — Boss dặn
   thẳng "không được đẩy bảng xuống". Neo cao 0 thì thanh nổi đè lên, bảng đứng im
   tuyệt đối. */
.sheet-tcn-vo {
  position: relative;
  height: 0;
  z-index: 60;
}
.sheet-tcn {
  position: absolute;
  top: 2px;
  left: 0;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px;
  border: 1px solid var(--vien);
  border-radius: 8px;
  background: var(--nen2, #F0EEEA);
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -4px rgba(0, 0, 0, .1);
  /* Bật lên nhẹ: mờ→rõ, trượt lên 10px, phóng 0.9→1. Mẫu dùng lò xo của
     framer-motion; app không có React nên đi bằng transition thường.
     ⛔ Đừng nhại kiểu nảy quá đà — thanh công cụ văn phòng không nảy. */
  opacity: 0;
  transform: translateY(6px);
  transform-origin: top left;
  pointer-events: none;
  /* ⛔⛔ ĐƯỜNG CHUYỂN KHAI Ở ĐÂY VÀ CHỈ Ở ĐÂY — vá 10/09/2026.
     Trước đó có HAI khai báo `transition` cho cùng `.sheet-tcn`: một ở khối này
     (.16s ease) và một ở khối ㉙ cuối file (.18s cubic-bezier). Cái sau thắng vì
     đứng sau, nhưng đọc mã thì chỗ nào cũng tưởng mình đang đúng — và sửa nhịp ở
     đây thì không thấy gì đổi, đúng kiểu "sửa mà màn hình không nhúc nhích".
     Boss chê *"đang mở lại ngưng lại, trông đơ đơ lắm"* nên phải chắc chắn chỉ có
     MỘT đường chuyển, một nhịp, một đường cong.
     ⛔ Muốn đổi nhịp thì đổi ở ĐÂY. Khối ㉙ nay chỉ còn `will-change` và luật
        giảm-chuyển-động. */
  transition: opacity .22s cubic-bezier(.22, 1, .36, 1),
              transform .22s cubic-bezier(.22, 1, .36, 1);
  white-space: nowrap;
}
.sheet-tcn.mo-nhat { opacity: .15; }
.sheet-tcn.hien {
  opacity: 1;
  transform: none;
}
.sheet-tcn.hien.ro { pointer-events: auto; }
.sheet-tcn .sheet-tcn-vach {
  width: 1px;
  height: 32px;
  background: var(--vien);
  flex: none;
}
.sheet-tcn .sheet-tcn-nut {
  position: relative;
  width: 32px;
  height: 32px;
  min-width: 32px;
  padding: 0;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--chu);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.sheet-tcn .sheet-tcn-nut svg {
  width: 16px;
  height: 16px;
  display: block;
}
/* Nút đang bật và nút đang rê chuột dùng CHUNG một nền: màu thương hiệu ở 10%.
   ⛔ Không viền, không đổi màu chữ — mẫu chỉ đổi nền, thêm viền là ra vẻ khác. */
.sheet-tcn .sheet-tcn-nut:hover,
.sheet-tcn .sheet-tcn-nut.dang-chon {
  background: var(--sheet-tcn-bat, rgba(20, 160, 160, .10));
}
.sheet-tcn .sheet-tcn-nut:focus-visible {
  outline: 2px solid var(--muc, #0D8081);
  outline-offset: -2px;
}
body.toi .sheet-tcn { --sheet-tcn-bat: rgba(90, 208, 198, .16); }

/* Mách nhỏ. ⛔ CHỈ Ở MÁY CÓ CON TRỎ. Máy cảm ứng không có hover; ở đó mách nhỏ
   hoặc không bao giờ hiện, hoặc dính lại sau cú chạm và che mất nút. */
@media (hover: hover) {
  .sheet-tcn .sheet-tcn-nut::after {
    content: attr(data-mach);
    position: absolute;
    bottom: 40px;
    left: 50%;
    transform: translateX(-50%);
    padding: 4px 8px;
    border-radius: 6px;
    background: #1F2937;
    color: #FFFFFF;
    font-size: 12px;
    line-height: 1.35;
    white-space: nowrap;
    box-shadow: 0 4px 10px rgba(0, 0, 0, .22);
    opacity: 0;
    pointer-events: none;
    transition: opacity .12s ease;
    z-index: 3;
  }
  .sheet-tcn .sheet-tcn-nut:hover::after,
  .sheet-tcn .sheet-tcn-nut:focus-visible::after { opacity: 1; }
}

/* Bảng xổ ra từ một nút (bảng màu · ba mức cỡ ô).
   ⛔ NẰM TRONG chính nút thì position:absolute neo được vào nút, khỏi phải đo
      toạ độ bằng JS. Thanh không có overflow:hidden nên bảng tràn ra ngoài được. */
.sheet-tcn .sheet-tcn-xo {
  position: absolute;
  top: 36px;
  left: 0;
  padding: 6px;
  border: 1px solid var(--vien);
  border-radius: 8px;
  background: var(--the);
  box-shadow: 0 10px 24px rgba(0, 0, 0, .18);
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  width: max-content;
  max-width: 168px;
  z-index: 5;
}
.sheet-tcn .sheet-tcn-xo.xo-doc { flex-direction: column; flex-wrap: nowrap; max-width: none; }
.sheet-tcn .sheet-tcn-o {
  width: 22px;
  height: 22px;
  min-width: 22px;
  padding: 0;
  border: 1px solid var(--vien-ro, #B9B3AA);
  border-radius: 4px;
  cursor: pointer;
}
.sheet-tcn .sheet-tcn-o.dang-chon {
  outline: 2px solid var(--muc, #0D8081);
  outline-offset: 1px;
}
.sheet-tcn .sheet-tcn-dong {
  border: 0;
  border-radius: 5px;
  background: transparent;
  color: var(--chu);
  font: inherit;
  font-size: 12.5px;
  text-align: left;
  padding: 5px 10px;
  min-height: 26px;
  cursor: pointer;
  white-space: nowrap;
}
.sheet-tcn .sheet-tcn-dong:hover { background: var(--nen2); }
.sheet-tcn .sheet-tcn-dong.dang-chon { background: var(--xanh-nhat); }

/* Nút bật/tắt thanh, cắm vào chính thanh nút của công cụ.
   ⛔⛔ BẮT BUỘC PHẢI CÓ. Boss dặn thanh hiện theo con trỏ; mà điện thoại không có
      con trỏ — chỉ làm hover là người dùng điện thoại KHÔNG BAO GIỜ mở được thanh
      này, đúng kiểu "tính năng chết mà bài kiểm vẫn xanh". */
.sheet-tcn-bat {
  width: 30px;
  height: 30px;
  min-width: 30px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 7px;
  background: transparent;
  color: var(--chu);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.sheet-tcn-bat svg { width: 16px; height: 16px; display: block; }
.sheet-tcn-bat:hover { background: var(--nen2); }
.sheet-tcn-bat.dang-chon {
  background: var(--sheet-tcn-bat, rgba(20, 160, 160, .10));
  border-color: var(--muc, #0D8081);
}

/* Dấu định dạng do người dùng đặt lên ô.
   ⛔ Ô bảng có thể đang là hộp co giãn (`td.dg-dinh`, `td.fhs-lhcell`) — ở đó
      `text-align` không có tác dụng, phải xếp bằng `justify-content`. Khai cả
      hai thì ô nào cũng nghe. */
.sheet-moi tbody td.sheet-dd-dam { font-weight: 600; }
.sheet-moi tbody td.sheet-dd-ngh { font-style: italic; }
/* ⛔ `background-color` chứ đừng `background` viết gọn: ô số dòng và ô ghăm đang
   dùng `background-image` để vẽ dải xám, dạng gọn xoá sạch nó. */
.sheet-moi tbody td.sheet-dd-to { background-color: var(--sheet-dd-nen, #FFF3C4); }

/* ══════════════════════════════════════════════════════════════════════════════
   ⑲ Ô ĐỊNH DANH: MÓN CHÍNH NỞ KÍN, MÓN PHỤ ĐỨNG YÊN — vá 10/09/2026
   Khối ⑫ mới ghim đúng hai món (nút xoá và thẻ `<b>`), nên ở màn nào ô định danh
   chứa một CÔNG CỤ thay vì một cái tên thì công cụ ấy không được ghim: đo ở màn
   Dự giờ, ô "Người dự giờ" là `<div class="ont">` (ô gõ có tìm kiếm) — nó rộng
   theo nội dung, chen với dải số 48px nên bị đẩy xuống dòng dưới, hàng cao gấp
   đôi và con số nằm chơ vơ một mình ở dòng trên.
   ⛔ Liệt kê món PHỤ rồi loại trừ, đừng liệt kê món CHÍNH: món chính mỗi màn một
      tên (`b` · `.ont` · `.oc-boc`…), đếm không xuể; món phụ thì chỉ có hai loại
      (nút xoá hàng, nhãn báo đã lưu) và chúng dùng chung tên lớp ở mọi màn.
   ══════════════════════════════════════════════════════════════════════════════ */
/* ⛔⛔ LOẠI `b` RA — vá 11/09/2026, vụ THỨ TÁM cùng một kiểu đè nhau.
   Mỗi `:not(.x)` cộng MỘT bậc lớp, nên chọn tử này nặng (0,6,3) và nghiền luật
   riêng của thẻ tên `.sheet-moi tbody td.dg-dinh > b` (0,2,3) ở dưới: khai gì
   ở đó cũng vô hiệu, CSSOM vẫn trả về giá trị của luật này.
   ⛔ ĐỪNG chữa bằng cách nhét thêm `:not()` cho luật kia nặng hơn — đó là chạy
      đua trọng số, mai có luật thứ ba lại đè tiếp. Loại hẳn `b` ra thì quyền
      quyết định về đúng một chỗ.
   ⛔ `:not(b)` là bậc KIỂU (0,0,1), nên luật chỉ nhích lên (0,6,4) — vẫn đè
      đúng những thẻ nó vốn đè, không đổi gì khác. */
.sheet-moi tbody td.dg-dinh > *:not(b):not(.nv-b):not(.dg-luutt):not(.cts-xoa):not(.fhs-xoa) {
  flex: 1 1 6em;
  min-width: 0;
}

/* ══════════════════════════════════════════════════════════════════════════════
   ⑳ Ô GÕ NHIỀU DÒNG CŨNG PHẢI PHẲNG NHƯ Ô CHỮ — Boss 10/09/2026
   *"ô nào có lựa chọn thì thiết kế hợp với kiểu mới chứ không giữ lại kiểu cũ này
     nữa nó xấu và không dễ dùng"*
   Khối ⑦ gỡ vỏ hộp cho `select` và `input`, nhưng BỎ SÓT `textarea` — mà cột
   "Nhận xét chung" ở Dự giờ và cột "Kết quả" ở Phụ đạo đều là `textarea`. Nên
   giữa một bảng phẳng lại có mấy cái khung viền xám nổi lên, đúng thứ Boss chê.
   ⛔ Ô đang gõ vẫn phải thấy rõ — viền xanh lúc `:focus` giữ nguyên như khối ⑦.
   ══════════════════════════════════════════════════════════════════════════════ */
.sheet-moi tbody td textarea {
  border: 0;
  border-radius: 0;
  background-color: transparent;
  box-shadow: none;
  padding: 0 2px;
  font: inherit;
  color: inherit;
  width: 100%;
  resize: none;
}
.sheet-moi tbody td textarea:focus {
  outline: 2px solid var(--sheet-chon-vien, #00793A);
  outline-offset: -2px;
}

/* ══════════════════════════════════════════════════════════════════════════════
   ㉑ GIAO DIỆN SHEET LÀM THEO ĐÚNG MẪU — Boss chốt luật đứng 10/09/2026
   *"từ giờ tôi gửi gì của 21st.dev nghĩa là tôi muốn làm giống hẳn, không được
     đoán nha, check thật kĩ để làm cho chuẩn vào"* — *"cả giao diện sheet cũng thế"*
   Mẫu chính: 21st.dev "xlsx-viewer" (ảnh gốc 1038px, đo tỉ lệ 1:1).

   Số đo bê từ ảnh mẫu:
     hàng dữ liệu ~26px · hàng tiêu đề ~24px nền xám rất nhạt, chữ XÁM 12px CĂN GIỮA
     KHÔNG in đậm · dải số bên trái nền xám nhạt, số xám 11px căn giữa · lưới 1px
     xám rất nhạt kẻ CẢ NGANG LẪN DỌC kể cả ô rỗng · chữ trong ô đen 13px căn trái
     đệm trái 8px · chữ dài CẮT CỤT THẲNG không ba chấm không xuống dòng · vỏ bảng
     KHÔNG bo góc KHÔNG đổ bóng.

   ⛔⛔ HAI CHỖ CỐ Ý KHÁC MẪU — Boss dặn thẳng, đừng "sửa" theo mẫu:
     ① tiêu đề giữ TÊN CỘT THẬT của app, không đổi thành A/B/C/D:
        *"phần A B C D ở trên tiêu đề thì vẫn để là tên cột đang có của app sẵn rồi"*
     ② bảng màu là biến màu của app, không bê màu Tailwind của mẫu vào.

   ⛔ MỘT CHỖ KHÁC MẪU VÌ KHÔNG THỂ GIỐNG: mẫu để số dòng ở một CỘT RIÊNG ngoài lưới
      (rộng 50px); app nhét số vào chính ô đầu (dải 40px, xem khối ④) vì mọi màn đã
      dựng bảng theo cách ấy — tách ra thành cột riêng là phải sửa HTML của 16 màn,
      tức đụng file của kênh khác. Giữ 40px, đã ghi lại để lượt sau biết là cố ý.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ① Chữ trong ô: 13px, đen, căn trái, đệm ngang 8px (mẫu).

   ⛔⛔ `text-align` PHẢI TÁCH RA MỘT LUẬT NHẸ HƠN — vá 10/09/2026 sau khi trả giá.
      Bản trước gộp chung ở bề nặng (0,2,3). Mà app có hàng chục cột CỐ Ý canh
      giữa hoặc canh phải, khai ở bề nhẹ hơn:
        · `.dg-bang td.cs-tickcell`   (0,2,1) — ô tích ✕/✓ của Chăm sóc
        · `.tk-tl td`                 (0,1,1) — bảng thống kê canh phải
        · `.luoi td.o`                (0,2,1) — ô điểm danh
        · `.qlh-stt`, `.tl-stt`, `.tl-bo`, `.pq-o`, `.lt-nho`, `.lt-datetxt`…
      Tất cả đều THUA và bị kéo về canh trái. Boss nhìn thấy: ô tích rộng 98px,
      nút ✕ 30px dạt sang trái, chừa 60px trắng bên phải — và tưởng ô bị mất.
      Đây đúng cái bẫy đã ghi ở khối ⑬: *siết một luật thì phải rà cả luật bị nó
      đè*. Lần này tôi dẫm lại chính nó.
   ⇒ `text-align` khai riêng ở `.sheet-moi tbody td` (0,1,2) — ĐỦ để đặt nếp mặc
     định cho bảng nào không nói gì, mà THUA mọi luật của app có kèm tên lớp.
   ⛔ ĐỪNG gộp nó về lại cho "gọn": gọn ở đây đúng bằng phá canh lề của 8 màn.
   ⛔ Cỡ chữ và đệm thì GIỮ ở bề nặng — hai thứ ấy là hình dáng chung của bảng
      sheet, đúng ra phải thắng; chỉ canh lề mới là chuyện riêng của từng cột. */
.sheet-moi tbody td { text-align: left; }
.sheet-moi tbody tr.sheet-hang td {
  font-size: 13px;
  padding-left: 4px;
  padding-right: 4px;
}

/* ② Chữ dài CẮT CỤT THẲNG. Mẫu để ô "Gross profi" cắt ngang giữa chữ, không ba
   chấm — vì ba chấm ăn mất hai ký tự nữa của một ô vốn đã hẹp.
   ⛔ Đây là ĐỔI Ý so với khối ⑧ (viết sáng nay dùng `ellipsis`). Giữ lại dòng này
      chứ đừng xoá khối ⑧: nó còn giữ `nowrap` + `overflow:hidden`, là hai thứ làm
      nên "đều tăm tắp". */
.sheet-moi tbody tr.sheet-hang td { text-overflow: clip; }

/* ②c CỘT TÊN Ở ĐIỂM DANH PHẢI XUỐNG DÒNG — vá 11/09/2026, VỤ THỨ CHÍN cùng kiểu.
   `.luoi .c-ten` tự khai `white-space: normal` từ lâu, nhưng nó chỉ (0,2,0) nên
   THUA `.sheet-moi tbody tr.sheet-hang td { white-space: nowrap }` (0,2,3) ở trên.
   Mà `sheetGan` GẮN THÊM `sheet-moi` cho `<table class="luoi">` lúc chạy, nên luật
   dùng chung với tới được bảng Điểm danh — ô tên bị ép một dòng, CSSOM trả về
   `nowrap` dù luật riêng nói `normal`.
   Đo ở 390 trước khi vá: 4/13 ô tên giấu chữ ("Nguyễn Minh…", "Trần Thị Bích …").
   Boss chốt: *"mọi cột tên đều PHẢI nhìn thấy được, không được ẩn"* — có dấu
   “…” chỉ là mức tối thiểu, chưa phải thứ Boss xin.
   ⛔ ĐỘ ĐẶC HIỆU: bộ này (0,3,2) — ba lớp so với hai — nên đè được (0,2,3) mà
      KHÔNG cần `!important`. ⛔ Đừng rút bớt `.sheet-moi` hay `.luoi` cho gọn:
      bớt một lớp là tụt xuống ngang cơ và thua ngay, không ai báo lỗi.
   ⛔ KHÔNG bóp và cũng không nới bề rộng cột — cột giữ nguyên 112px ở 390.
   ⛔ KHÔNG kẹp bằng `-webkit-line-clamp`: ĐÃ ĐO, phải đổi `display` của ô bảng
      sang `-webkit-box`, và khi ấy HÀNG KHÔNG CAO LÊN được nữa (đứng nguyên
      33px) nên nó kẹp thành MỘT dòng — số ô giấu chữ TĂNG từ 4 lên 5.
   KẾT QUẢ đo ở 390, theo độ dài tên:
      ≤27 ký tự → 1–2 dòng, hàng 32–49px (đạt mốc ≤55px)
      55 và 61 ký tự → 8 dòng, hàng 111 và 131px — đó là hai chuỗi CỐ TÍNH cực
      đoan của sân đo, không phải tên thật. Tên dài thật thì hàng cao thật —
      đúng thứ Boss bấm nút chọn: “Xuống dòng, hàng cao lên”. */
/* ②d Ô NGÀY Ở ĐIỂM DANH BỊ NUỐT HAI KÝ TỰ CUỐI — vá 11/09/2026.
   Ở 390 mọi hàng đều hiện “11/09/…”. Đo ra: ô 78px, đệm 8px mỗi bên nên lòng
   còn 62px, thẻ `.gt-ngay` được 58px — mà chuỗi “11/09/26” ở 11,5px cần 60px.
   Thiếu ĐÚNG 2px, và 2px ấy nuốt mất phần năm.
   ⇒ Hạ đệm ngang của riêng cột ngày xuống 4px: lòng thành 70px, dư sức.
   ⛔ ĐỘ ĐẶC HIỆU — đã vấp: bản đầu tôi viết `.luoi tbody td.o-ngay` (0,2,2),
      thua `.sheet-moi tbody tr.sheet-hang td { padding: 8px }` (0,2,3) nên đệm
      KHÔNG HỀ GIẢM và tôi suýt kết luận “nới đệm không ăn thua”. Phải đủ ba
      lớp `.luoi.sheet-moi … td.o-ngay` (0,3,2) mới thắng.
   ⛔ ĐÂY KHÔNG PHẢI “mất năm”. App có SẴN hai bản `.ngay-dai` (“11/09/2026”)
      và `.ngay-ngan` (“11/09/26”); ở 390 nó CỐ Ý dùng bản ngắn. Muốn năm bốn
      chữ số ở 390 thì phải nới cột (cần ~85px, đang 78px) — đổi bố cục bảng,
      phải hỏi Boss. Ở đây chỉ chữa đúng cái hỏng: bản ngắn bị cắt cụt.
   ⛔ KHÔNG có nút lịch nào trong ô này — đã liệt kê toàn bộ thẻ con, chỉ có
      hai thẻ ngày. Đừng đi gỡ nút lịch để “lấy chỗ”. */
/* ⛔⛔ Ô MÀ TOÀN BỘ NỘI DUNG LÀ MỘT THẺ ĐIỀU KHIỂN THÌ KHÔNG ĐỆM NGANG — vá 11/09/2026.
   Boss nhìn ra trên ảnh: ô Điểm danh hiện "Quên phiế" (mất chữ "u") và
   "Chưa hoàn thàn" (mất "h"). Cụt ĐÚNG MỘT HAI KÝ TỰ CUỐI nên trông như app gõ
   sai chính tả — tệ hơn cắt nhiều, vì người đọc không nhận ra là bị cắt.

   ⛔ MŨI TÊN KHÔNG PHẢI THỦ PHẠM — tôi đã nghi nó và ĐO THÌ SAI: ở mốc `1c7e19e`,
      lúc mũi tên đã MẤT SẠCH, chữ vẫn cụt y nguyên 15/36 ô.
   GỐC đo được: `.sheet-moi tbody tr.sheet-hang td` thêm 4px đệm MỖI BÊN, đè
   `.luoi th, .luoi td { padding: 0 }`. Thẻ chọn hẹp đi 8px: cột 4 từ 88 → 80px,
   chỗ cho chữ từ 71 → 63px, trong khi "Quên phiếu" rộng đúng 71px.
   Mốc gốc `fa444a1` vốn ĐÃ SÁT MÉP (71 trên 71) — 8px đệm đẩy nó qua.

   ⇒ Ô nào có đúng MỘT thẻ điều khiển làm con thì bỏ đệm ngang của Ô: thẻ đó đã
     có đệm riêng (2px trái, 15px phải chừa cho mũi tên), nên đệm của ô chỉ bóp
     thẻ lại chứ không thêm khoảng thở nào mắt thấy.
   ⛔ ĐỪNG bỏ đệm cho MỌI ô: ô chứa CHỮ vẫn cần 4px, không thì chữ dính sát viền
      — đúng nếp bảng tính và đúng ý đồ của khối trên.
   ⛔ ĐỪNG chữa bằng cách thu chữ hay cắt bớt mũi tên: cả hai đều là đổi thiết kế
      Boss đã chốt. Chỗ thừa duy nhất là đệm thừa này.
   ⚠ VẪN CÒN SÁT MÉP cho giá trị dài hơn: cột do người dùng khai nên nhãn có thể dài
     bất kỳ. Đường lùi thật là kéo rộng cột (`bang-keo-cot`), không phải luật này.
     Chạy `canh-chu-cut.js` sau mọi thay đổi bề rộng — đừng tin trí nhớ. */
.sheet-moi tbody tr.sheet-hang td:has(> select:only-child),
.sheet-moi tbody tr.sheet-hang td:has(> input:only-child) {
  padding-left: 0;
  padding-right: 0;
}
.luoi.sheet-moi tbody td.o-ngay {
  padding-left: 4px;
  padding-right: 4px;
}

.luoi.sheet-moi tbody td.c-ten {
  white-space: normal;
  overflow-wrap: break-word;
}

/* ②b NGỢI LỆ CHO CỘT TÊN: cắt thì PHẢI có dấu “…” — Boss chốt 11/09/2026.
   Câu ② ngay trên (cắt phẳng, không ba chấm, theo mẫu Google Sheets) VẪN ĐÚNG
   cho mọi cột số và cột ngắn — ⛔ ĐỪNG đi gỡ nó.
   Nhưng cột TÊN thì khác: tên người cắt ngang giữa chữ mà không dấu hiệu gì thì
   trợ giảng đọc ra MỘT CÁI TÊN KHÁC, chứ không biết là còn chữ. Đo được 10 thẻ
   cắt phẳng: 2 ô `.c-ten` ở Điểm danh @390 (19 ký tự, thừa 43px), 2 ô
   `.lt2-c-lt` ở Lộ trình (56 ký tự, thừa 17px), 2 ô `.cts-g3` ở Tuyển sinh
   (32 ký tự, thừa 21px), và 4 ô gõ `.nv-in.dg-o` ở Dự giờ (28–29 ký tự,
   thừa 78–110px — nặng nhất ở đây).
   ⛔ CHỈ BỐN CỘT NÀY. Mở rộng ra cả bảng là xóa nguyên nếp Sheets Boss đã chọn.
   ⛔ ĐỘ ĐẶC HIỆU: ba bộ đầu (0,3,3) đè được câu ② (0,2,3). Bộ `.luoi tbody
      td.c-ten` chỉ NGANG CƠ (0,2,3) nên nó thắng nhờ ĐỨNG SAU — ⛔ đừng dời khối
      này lên trên câu ②, là thua ngay và không ai báo lỗi.
   ⛔ Ô GÕ `<input>`: ba chấm chỉ hiện lúc KHÔNG đứng trong ô; bấm vào thì trình
      duyệt tự cuộn theo con trỏ. Đúng thứ ta cần: lúc chỉ nhìn thì biết là còn
      chữ, lúc sửa thì đọc được hết. */
.sheet-moi tbody tr.sheet-hang td.c-ten,
.sheet-moi tbody tr.sheet-hang td.lt2-c-lt,
.sheet-moi tbody tr.sheet-hang td.cts-g3,
.luoi tbody td.c-ten,
.sheet-moi tbody td .nv-in.dg-o {
  text-overflow: ellipsis;
}

/* ③ Hàng tiêu đề theo mẫu: thấp, chữ xám nhỏ, CĂN GIỮA, KHÔNG in đậm.
   ⛔ Bề nặng phải đủ đè `.dg-bang thead th` (0,2,1) — `.sheet-moi[class]` cho ra
      (0,2,0) rồi cộng `thead th` thành (0,2,2). Nhắm bằng `.sheet-moi thead th`
      không đủ nặng, luật sẽ chết câm mà không báo gì. */
/* ⛔⛔ HÀNG TIÊU ĐỀ BÁM MẪU 21st.dev — vá 10/09/2026 sau khi người soi đo
   LỆCH 5/5 MỤC Ở MỌI MÀN. Đây là thứ đập vào mắt đầu tiên, và sửa một khối
   là ăn cả app.

        mục        app (cũ)     mẫu 21st.dev    nay
        căn lề     center       TRÁI            trái  ✔ sửa
        độ đậm     500          400             400   ✔ sửa
        màu chữ    đen          xám             xám   ✔ sửa
        nền        trắng        xám nhạt        TRẮNG ✘ CỐ Ý GIỮ — xem dưới
        chiều cao  40–42px      ~24px           ~24px nếu tên cột một dòng

   ⛔⛔ KHÔNG ĐỔI MÀU NỀN SANG XÁM, DÙ MẪU LÀ XÁM. Boss đã chốt riêng chuyện
      này ở khối ⑯: *"cho nhân viên có quyền được chỉnh màu tiêu đề cột nha,
      mặc định là màu trắng"*. Nền tiêu đề nay là thứ NGƯỜI DÙNG TỰ CHỌN
      (`--dau-bang-nen`), không phải hằng số của mẫu. Ghi đè bằng xám ở đây là
      vừa cãi lệnh Boss vừa làm bảng màu kia bấm vào không thấy gì đổi — đúng
      kiểu "bày ra một lựa chọn không dùng được". Mẫu thua ở ĐÚNG mục này.
   ⛔ Màu chữ vẫn đi qua `--dau-bang-chu` để bảng màu còn điều khiển được;
      chỉ hạ GIÁ TRỊ MẶC ĐỊNH xuống tông xám của mẫu.

   ⚠️ CHIỀU CAO 40–42px CHƯA SỬA ĐƯỢC Ở ĐÂY, và KHÔNG ĐƯỢC TỰ SỬA:
      4+4 đệm + 12px×1,3 = ~24px cho MỘT dòng — tức là luật này vốn đã đúng
      mẫu. Sở dĩ đo ra 40–42px là vì rất nhiều TÊN CỘT đang xuống HAI dòng
      (đo được: Lộ trình 65 ô, Tuyển sinh 28, Lịch thi 21), mà hai dòng thì
      2×15,6 + 8 = ~39px — khớp đúng con số đo được.
      Mà "cho tên cột xuống 2 dòng" LÀ LỆNH CỦA BOSS (khối ①bis, 10/09:
      *"Cho xuống 2 dòng"*, sau khi 15/41 tên cột bị cắt cụt). Ép về một dòng
      ở đây là lặng lẽ huỷ một quyết định của Boss — đúng cái bẫy vừa mắc ở
      cột Học viên. ⇒ ĐÃ BÁO ĐIỀU PHỐI, chờ Boss chốt như đã chốt cột kia.
   ⛔ Đừng ai đọc dòng "mẫu 24px" ở trên rồi tự đi bịt `white-space: normal`
      của khối ①bis. Hai chỗ ấy là một cặp.

   ⛔ ĐỘ ĐẶC HIỆU: `[class]` cộng một bậc lớp mà không cần `!important` — cần
      thế để đè luật riêng của từng bảng (0,2,0)+`thead th`. Đừng rút gọn
      thành `.sheet-moi thead th`, nó tụt xuống (0,1,2) và thua âm thầm. */
/* ⛔⛔ MÀU CHỮ ĐẦU BẢNG PHẢI ĐỨNG RIÊNG VÀ ĐỘ NẶNG 0 — vá 11/09/2026.
   Boss: *"lỗi màu bị trắng xoá ở cột, các chữ trắng xoá hết"* (màn Điểm danh).
   Đo được: `SPAN.ngay` chữ #6B6660 trên nền navy #1F2A5A = **2.40 : 1**, và trên
   nền nâu = 1.53 : 1. Dưới 3:1 là không đọc nổi — nhìn ra đúng như cột trống.

   GỐC: bảng điểm danh khai `<table class="luoi">`, KHÔNG có `sheet-moi` trong
   HTML — nhưng `sheetGan` KHOÁC THÊM `sheet-moi` lúc chạy (đo lại: đúng là có).
   Từ đó luật dưới đây, nhờ `[class]` cộng thêm một bậc, thành (0,2,2) và đè
   `.luoi .h-day { color:#fff }` ở css:742 vốn chỉ (0,2,0). Chữ đáng lẽ TRẮNG
   hoá thành xám nhạt nằm trên nền đậm.
   Đây là vụ thứ SÁU trong ngày luật mới của tôi âm thầm đè luật riêng của bảng
   khác — đúng bài học "luật ngang cơ đứng sau thì thắng".

   ⇒ Tách riêng `color` ra một luật bọc `:where(...)`, độ nặng **0**: bảng nào có
     màu riêng thì màu riêng luôn thắng, còn bảng không khai gì vẫn nhận màu chung.
   ⛔ ĐỪNG hạ cả khối dưới xuống `:where` — mấy dòng cỡ chữ/căn lề/đệm vẫn CẦN
      thắng luật cũ của từng bảng, hạ hết là vỡ đầu bảng ở mọi màn.
   ⛔ ĐỪNG chữa bằng `!important` cho `.luoi .h-day` — thế là chạy đua độ nặng,
      mai có luật thứ ba lại đè tiếp. */
:where(.sheet-moi) :where(thead th) {
  color: var(--dau-bang-chu, #6B6660);
  /* ⛔⛔ `text-align` PHẢI Ở ĐÂY, KHÔNG ĐƯỢC Ở KHỐI `[class]` DƯỚI — vá 11/09/2026.
     Boss: *"chữ day ở dưới tiêu đề nó bị đẩy sang bên trái"* (dải buổi ĐANG MỞ,
     nền nâu, màn Điểm danh).
     Đo được: dải rộng 615px, viên `DAY 3 (17/07)` (`input.o-ten-day`, 96px) nằm
     cách mép trái đúng 11px — lệch tâm 497px. `.o-ten-day` tự nó `text-align:
     center`, nhưng nó là thẻ inline-block nên chỗ đứng do Ô CHA quyết; ô cha là
     `.luoi .h-day { text-align:center }` (css:742, độ nặng 0,2,0) lại thua
     `.sheet-moi[class] thead th { text-align:left }` (0,2,2) của tôi.
     Đây là VỤ THỨ BẢY trong ngày luật mới của tôi âm thầm đè luật riêng của bảng
     khác, và là vụ thứ hai của ĐÚNG khối này — lượt trước tôi mới gỡ `color` ra
     mà quên rà nốt các dòng còn lại trong cùng khối. Đúng lỗi "siết luật thì
     phải siết cả luật gỡ".
     ⛔ Bảng nào muốn tiêu đề căn giữa thì nay tự quyết được; bảng không khai gì
        vẫn nhận căn trái như Boss chốt. */
  text-align: left;
  /* ⛔ `line-height` NẰM Ở ĐÂY, KHÔNG ĐƯỢC Ở KHỐI `[class]` — rà 11/09/2026.
     Rà hết sáu dòng của khối `.sheet-moi[class] thead th` bằng CSSOM (hỏi từng
     `thead th` đang hiện xem luật nào khớp, ai đứng thứ nhì), rồi ĐO thật bằng
     cách dời từng dòng xuống `:where` và quét lại 8 màn. Kết quả:
       · font-size 12px  — PHẢI thắng: nhả ra thì Lịch thi tụt 11.5px
                           (`.lt-bang th`), Điểm danh vỡ thành 11.5/12.5px.
       · font-weight 400 — PHẢI thắng: kẻ đứng nhì là 700 ở SÁU bảng
                           (`.dg-bang` `.lt2-bang` `.fss-bang` `.cts-bang`
                           `.luoi .h-day` `.luoi .h-cot`). Nhả ra là đầu bảng
                           đậm hết — đúng cái "lộ ra là máy làm" Boss đã chê.
       · padding 4px     — PHẢI thắng: nhả ra thì Tuyển sinh + Nhân viên về
                           đệm 0 (`.cts-bang th,td`), hàng tụt 25px→17px, chữ
                           dính viền; Lộ trình còn 2px.
       · height auto     — PHẢI thắng: gỡ `.lt2-bang thead th{42px}` (0,1,2)
                           VÀ `.lt2-bang/.cts-bang th,td{height:30px}` (0,2,2,
                           ngang cơ nên thắng nhờ đứng sau). Nhả ra: Lộ trình
                           30px, Tuyển sinh 17px.
       · line-height 1.3 — DÒNG DUY NHẤT KHÔNG CẦN THẮNG. Kẻ đứng nhì chỉ lệch
                           chút (1.15–1.35) và đều là ý đồ riêng của bảng:
                           `.lt2-bang thead .lt2-c-tuan{1.15}`, `.luoi .h-cot
                           {1.35}`, `.luoi .c-ten{1.15}`. Nhả xuống `:where` thì
                           Lộ trình 38→34px (gọn hơn), Điểm danh 65→66px, sáu
                           màn còn lại KHÔNG đổi, và phép canh cắt chữ vẫn xanh
                           0/224 ô (thử phá: ép `display:block;height:8px` →
                           đỏ 224/224). Trả quyền cao dòng về cho từng bảng,
                           nhất là cột tên `.luoi .c-ten` sắp cho xuống dòng.
     ⛔ ĐỪNG gộp năm dòng kia xuống đây cho "gọn" — đã đo, gộp là hỏng 4 màn. */
  line-height: 1.3;
}

.sheet-moi[class] thead th {
  font-size: 12px;
  /* ⭐ 18/09/2026 — 400 → 500. Boss chốt bằng nút bấm: *đậm vừa*, mức 500, sau câu
     *"cho chữ in đậm nhẹ nhàng sẵn cho tôi"* áp cho **toàn bộ công cụ**.
     ⛔ Lời dặn *"KHÔNG ĐƯỢC SỪA CON SỐ 400"* ở css:~16476 viết 12/09, khi Boss
        đang chê đầu bảng ĐẬM QUÁ (700–800 + IN HOA = “lộ ra là máy làm”). Nay
        Boss tự xét và chọn 500 — đậm hơn thân bảng đủ để tách ra, nhưng còn xa
        mức bị chê. Luật cũ HẾT HIỆU LỰC ở đúng con số này, phần còn lại giữ.
     ⛔ ĐÂY LÀ LUẬT THẬT quyết định nét đầu bảng của CẢ APP (Lộ trình · Tuyển sinh
        · Dự giờ · Chăm sóc · Follow up · Lịch thi · Quản lý học · Nhân viên). Viết
        `.sheet-moi thead th` ở chỗ khác là (0,1,2), thua khối này — đã thử, đo ra
        14/14 cột vẫn 400 mà không một lỗi nào báo.
     ⛔ Màn Điểm danh giữ 600 riêng (khối `.luoi` css:~16490) — Boss chốt riêng
        12/09 vì tên cột ở đó *"nhạt quá"*. Không hạ xuống theo. */
  font-weight: 500;
  padding-top: 4px;
  padding-bottom: 4px;
  /* ⛔⛔ GỠ CHIỀU CAO GHIM CỨNG CỦA TỪNG BẢNG — vá 10/09/2026.
     Màn Lộ trình đo ra hàng tiêu đề 42px dù CHỈ MỘT TẦNG và mọi tên cột đều
     ngắn ("Lớp" · "Cơ sở" · "Tầng"), không ô nào có con xếp dọc. Truy ra:
     `.lt2-bang thead th { height: 42px }` (css:10579) ghim cứng con số ấy từ
     thời bảng còn kiểu cũ. Nội dung chỉ cần ~24px, 18px còn lại là trống không.
     ⛔ `height: auto` chứ ĐỪNG ghim một con số mới. Ghim số là lặp lại đúng cái
        lỗi đang chữa, và bảng hai/ba tầng (Lịch thi) sẽ vỡ.
     ⛔ ĐỘ ĐẶC HIỆU: luật cũ (0,1,2); câu gỡ này (0,2,2) nhờ `[class]` nên đè
        được. Rút gọn thành `.sheet-moi thead th` là tụt về (0,1,2) — ngang cơ,
        và luật nào đứng sau thắng, tức là thua tuỳ chỗ ngồi. Lần thứ SÁU trong
        ngày phải đếm điểm trước khi viết luật cho `.sheet-moi`.
     ⛔ Chỉ gỡ TRONG bảng dạng Sheet. Bảng cũ không mang `.sheet-moi` vẫn giữ
        42px như trước — đừng đụng tới chúng. */
  height: auto;
}

/* ⛔⛔ `visibility: hidden` VẪN CHIẾM CHỖ — vá 10/09/2026.
   Cụm nút cột `.lt-cot-nut` được ẩn bằng `visibility:hidden` (css:6011) cho tới
   khi rê chuột vào. Nhưng `visibility` chỉ làm thứ ấy TÀNG HÌNH, nó VẪN GIỮ
   NGUYÊN 21px trong dòng. Đo thật (có bật `hover:hover` đàng hoàng): tầng 2 của
   Lịch thi cao 50px, trong đó 21px là chỗ trống của một cụm nút đang tàng hình.
   Ẩn mà không trả lại chỗ thì chưa phải là ẩn.

   ⛔⛔ ĐỪNG CHỮA BẰNG `display: none`. Người viết luật cũ chọn `visibility` là CÓ
      LÝ DO: `display:none` thì lúc rê chuột vào, cụm nút hiện ra và ĐẨY cả bố
      cục nhảy một cái. Đổi một lỗi thừa chỗ lấy một lỗi bảng giật — tệ hơn.
   ⇒ Cho cụm nút NỔI ĐÈ (`position: absolute`) thay vì chiếm một dòng riêng.
     Thẻ đã ra khỏi dòng chảy nên KHÔNG chiếm chỗ lúc ẩn, và cũng KHÔNG đẩy gì
     lúc hiện — bảng đứng yên ở cả hai trạng thái. Đây đúng cách app đã dùng cho
     nút ba chấm `.sheet-nut-menu` ngay trong file này; giữ cho thống nhất.
   ⛔ `right: 20px` để chừa chỗ cho nút ba chấm vốn đã ngồi ở `right: 3px` —
      hai thứ cùng nổi đè một góc thì phải chia chỗ, không là chồng lên nhau.
   ⛔ Chỉ áp trong bảng dạng Sheet. Bảng cũ ngoài `.sheet-moi` giữ nguyên nếp cũ. */
.sheet-moi thead th .lt-cot-nut {
  position: absolute;
  right: 20px;
  top: 50%;
  transform: translateY(-50%);
  margin: 0;
  z-index: 2;
}

/* ④ Vỏ bảng: không bo góc, không đổ bóng, tràn sát mép (mẫu).
   ⛔ Chỉ áp cho khung có bảng dạng sheet bên trong — `:has` lo việc đó. Bỏ `:has`
      là mọi khung cuộn trong app mất bo góc, kể cả những khung không phải bảng. */
.dg-cuon:has(> table.sheet-moi),
.keo-duoc:has(> table.sheet-moi),
.lt-fullw:has(table.sheet-moi) > .dg-cuon {
  border-radius: 0;
  box-shadow: none;
}

/* ⑤ Mặc định là mức "Vừa" (28px) — gần nhất với 26px của mẫu trong ba mức Boss đã
   chốt bằng nút bấm (Thoáng 32 · Vừa 28 · Chật 24). Không tự đẻ thêm mức 26px:
   ba mức ấy là con số Boss chọn, đổi sau lưng là lượt sau không ai hiểu vì sao. */

/* ⑥ ĐÍCH BẤM ≥ 24px KỂ CẢ Ô NẰM LỒNG TRONG MỘT LỚP VỎ.
   ⛔⛔ Khối ⑧ chỉ nhắm CON TRỰC TIẾP (`td > select`). Đo thật 10/09/2026 ở mức
      Chật: ô xổ "Phụ trách" chỉ cao 20px — vì nó nằm trong `<div class="fhs-o-hang">`
      nên không phải con trực tiếp, luật kia không với tới. Bấm hụt là chuyện xảy ra
      hằng ngày với trợ giảng đang vội.
   ⛔ Chừa ô tick và ô tròn: ép chúng cao 24px là hình méo, mà đích bấm của chúng
      vốn đã do trình duyệt lo. */
.sheet-moi tbody tr.sheet-hang td select,
.sheet-moi tbody tr.sheet-hang td input:not([type="checkbox"]):not([type="radio"]) {
  min-height: 24px;
}

/* ══════════════════════════════════════════════════════════════════════════════
   ㉒ BẢNG QUẢN LÝ TÀI KHOẢN — Boss bắt lỗi 10/09/2026
   *"phần quản lí tài khoản… bạn đang để sai… sao sắp xếp đang bị lỗi vậy lộn xộn quá"*

   THỦ PHẠM (hỏi CSSOM sống, không grep): thẻ hàng là tr.hang-tk, mà `.hang-tk` là
   luật CŨ từ thời danh sách này còn vẽ bằng div — nó gán `display: flex`. Trên một
   tr thì `display:flex` biến hàng thành hộp co giãn và mọi td thành khối `block`:
   ô không còn thuộc cột nào cả. Đo được 10/09/2026: thead chia 739 · 150 · 216 · 74
   px, còn tbody dồn hết vào 191 · 82 · 214 · 44 px sát mép trái — hai cột cuối
   trống trơn, badge so le kiểu bậc thang. Đúng ảnh Boss gửi.

   ⛔ ĐÂY LÀ LỖI CÓ TỪ TRƯỚC, không phải do lớp sheet sinh ra. Nhưng lớp sheet làm
      nó lộ hẳn ra, vì `gaKeoCot` đặt `table-layout: fixed` + bề rộng cứng cho thead,
      nên hai bên lệch nhau nhìn thấy rõ.
   ⛔ ĐỪNG "chữa" bằng cách bỏ class `hang-tk` khỏi mã: sáu tay nghe và ba bộ lọc
      của màn ấy tìm hàng bằng đúng tên lớp này (`tr.hang-tk`), bỏ đi là lọc chết câm.
   ⇒ Trả tr về `table-row` và td về `table-cell`. Luật `.hang-tk` giữ nguyên cho chỗ
     nào còn dùng nó trên div.
   ══════════════════════════════════════════════════════════════════════════════ */
tr.hang-tk {
  display: table-row;
  align-items: initial;
  gap: 0;
  padding: 0;
  flex-wrap: nowrap;
}
tr.hang-tk > td { display: table-cell; }

/* Tên lớp phụ trách: được phép xuống dòng (ngoại lệ giống cột định danh) — một trợ
   giảng có thể gánh 14 lớp, ép một dòng là cắt cụt ngay từ tên thứ ba. */
.mtb-lop { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.mtb-lop-ten {
  font-size: 12px;
  color: var(--chu);
  line-height: 1.45;
  overflow-wrap: anywhere;
  flex: 1 1 100%;
}
.mtb-lop-ten .dg-tom-them {
  display: inline-block;
  font-size: 10.5px;
  font-weight: 600;
  line-height: 1;
  padding: 2px 5px;
  border-radius: 999px;
  background: var(--xanh-nhat, #E4F2EF);
  color: var(--xanh-dam, #0D8081);
}

/* ══════════════════════════════════════════════════════════════════════════════
   ㉓ HÀNG NÚT CÔNG CỤ ÔM LUÔN TIÊU ĐỀ · DÒNG ĐẾM · CỤM ZOOM — Boss 10/09/2026
   *"càng sát càng tốt hoặc ghép vào luôn cũng được… tiết kiệm được từng pixel"*
   Phần dời thẻ nằm ở `sheetGomDauBang` trong js/tinh-nang.js; ở đây chỉ lo xếp chỗ.
   ⛔ `flex-wrap: wrap` là bắt buộc — màn hẹp mà không cho xuống dòng thì tiêu đề
      bị đẩy ra khỏi màn, đúng thứ vừa đi chữa ở chỗ khác.
   ⛔ Cụm zoom đẩy sang PHẢI (`margin-left:auto`) đúng như mẫu 21st.dev: ở đó
      "− 100% + │ 🔍 │ ⋯" nằm bên phải, trên lưới.
   ══════════════════════════════════════════════════════════════════════════════ */
.sheet-hang-nut {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 4px;
}
.sheet-hang-nut > .sheet-dau-gom.nv-h {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
.sheet-hang-nut > .sheet-dau-gom.bl-thanh {
  margin: 0;
  font-size: 12px;
  color: var(--mo);
  display: flex;
  align-items: center;
  gap: 6px;
}
.sheet-hang-nut > .sheet-dau-gom.zoom-nut {
  margin: 0 0 0 auto;
}
/* Khung bảng bám sát ngay bên dưới hàng ấy. */
.sheet-hang-nut + .lt-fullw,
.sheet-hang-nut + .dg-cuon,
.sheet-hang-nut + div > .dg-cuon { margin-top: 0; }

@media (max-width: 700px) {
  .sheet-hang-nut { gap: 6px; }
  .sheet-hang-nut > .sheet-dau-gom.zoom-nut { margin-left: auto; }
}

/* Badge chức vụ ở bảng tài khoản phải ôm sát chữ, đừng kéo hết bề ngang ô —
   ô rộng 233px mà badge trải hết 233px thì nhìn như một cái nút khổng lồ. */
.mtb-bang tbody td > .mtb-badge { display: inline-flex; width: auto; }

/* Siết nốt phần hở còn lại: đo được 11px sau lượt ghép, Boss xin ≤8px.
   ⛔ Đừng dùng `!important`: màn nào cần lề riêng sẽ không đè lại được, và lượt
      sau người ta đi tìm mãi không hiểu vì sao. Nhắm đủ nặng là được.
   ⛔ Và đừng bóp bằng `margin âm` — bảng sẽ trườn lên đè lên hàng nút lúc màn hẹp. */
#noiDung > .sheet-hang-nut { margin-bottom: 2px; }
#noiDung > .sheet-hang-nut + * { margin-top: 2px; }

/* ⛔⛔ [hidden] THUA display:flex — vá 10/09/2026, đo được ngay lượt đầu.
   Bảng xổ khai display:flex, mà thuộc tính [hidden] chỉ mạnh bằng display:none của
   luật mặc định trình duyệt. Luật của mình thắng, nên CẢ BA bảng xổ (12 ô màu + 3
   mức cỡ ô) hiện thường trực: viên thuốc phình từ ~300px lên 854px, đúng cái dải
   ngang mà Boss vừa bác. Và vì chúng nổi đè lên nút nên bấm nút nào cũng trượt —
   bốn phép canh đỏ cùng lúc mà không có lỗi JS nào.
   ⇒ Khai lại display:none cho [hidden] ở đúng chỗ này. Đây là cái bẫy kinh điển
     mỗi khi gán display cho một phần tử có lúc bị ẩn bằng [hidden]. */
.sheet-tcn .sheet-tcn-xo[hidden] { display: none; }

/* Vỏ [nút + bảng xổ]. Bảng xổ KHÔNG được nằm trong <button> (xem khối ⛔ ở
   js/tinh-nang.js), nên nó là em ruột của nút và neo vào cái vỏ này. */
.sheet-tcn .sheet-tcn-cum { position: relative; display: inline-flex; flex: none; }

/* ══════════════════════════════════════════════════════════════════════════════
   ㉔ DẤU ĐỊNH DẠNG PHẢI NẶNG HƠN LUẬT NỀN — vá 10/09/2026 sau khi đo
   Bốn phép canh đỏ mà không có lỗi JS nào: bấm "căn giữa" thì text-align vẫn là
   left, bấm ô màu thì nền vẫn trắng. Nguyên do là BỀ NẶNG, đúng cái bẫy đã trả
   giá hai lần trong file này:
     · luật nền   khối ㉑① ".sheet-moi tbody tr.sheet-hang td"      = (0,2,3)
     · dấu căn lề khối ⑱  ".sheet-moi tbody td.sheet-dd-giua"      = (0,2,2) THUA
     · ô ghăm             ".sheet-moi.sheet-gham tbody td.sheet-cot-gham" = (0,4,2)
   Dấu do NGƯỜI DÙNG đặt thì phải thắng mọi luật nền — nếu không, người ta bấm nút
   mà màn hình không đổi, và sẽ kết luận nút hỏng.
   ⇒ Nâng lên (0,4,3) bằng "[class]" — một bộ chọn thuộc tính nặng ngang một lớp,
     mà mọi bảng sheet đều có class nên không loại trừ ai.
   ⛔ Không dùng "!important": lượt sau muốn đè lại sẽ không còn đường nào.
   ⛔ Sửa cỡ nền/căn lề ở khối ㉑ thì phải rà lại khối này — siết luật nền mà quên
     siết luật gỡ là ngoại lệ chết câm, đúng bài học đã ghi.
   ══════════════════════════════════════════════════════════════════════════════ */
/* ⚠ BA LUẬT `.sheet-dd-trai/giua/phai` ĐÃ GỠ HẲN 11/09/2026 — Boss:
     *"Công cụ căn lề tôi bảo ko dùng nữa rồi mà chỉ giữ lại màu, viết in đậm,
       viết nghiêng, highlight"*
   Khối chú thích ngay trên còn lấy "căn giữa" làm ví dụ — ví dụ đó nay là BIÊN BẢN,
   không phải luật còn sống. Bài học về độ nặng thì không đổi một chữ, và vẫn đúng
   cho hai dấu còn lại (đậm · nghiêng) và cho dấu tô nền ngay dưới.
   ⛔ ĐỪNG dựng lại ba luật này nếu thấy dữ liệu cũ còn khóa `al`: khóa ấy đã được
      `sheetDDApDung` bỏ qua một cách có chủ đích. */
.sheet-moi[class] tbody tr.sheet-hang td.sheet-dd-dam { font-weight: 600; }
.sheet-moi[class] tbody tr.sheet-hang td.sheet-dd-ngh { font-style: italic; }
.sheet-moi[class] tbody tr.sheet-hang td.sheet-dd-to { background-color: var(--sheet-dd-nen, #FFF3C4); }

/* ══════════════════════════════════════════════════════════════════════════════
   ㉕ ĐÍCH BẤM TRONG Ô KHÔNG ĐƯỢC DƯỚI 24px — vá 10/09/2026 sau khi đo
   Kênh Phá đếm được: Chăm sóc 45/70 ô · Dự giờ 48/96 · Lịch thi 55/90 (nhỏ nhất
   18px) · Follow HS 12/24. Đo lại ở đây ra đúng bốn thủ phạm, và cả bốn đều là
   thứ bảng sheet vừa làm cho "phẳng" đi: `.nv-lich` 37×23 · `.ont-mui` 18×24 ·
   `.dg-chiptom` 81×20 · `.lt-lich` 27×18.
   ⛔ 24px là SÀN, không phải con số cho đẹp: ngón tay người lớn chạm trung bình
      rộng hơn thế, dưới sàn ấy là bấm mười lần hụt ba.
   ⛔⛔ CHỈ NỚI THEO CHIỀU NGANG VÀ DÙNG `min-`, ĐỪNG ĐẶT `height`. Luật đã chốt:
      *"làm gọn thì bóp NGANG"* — mà ngược lại, nới ra cũng phải nới ngang trước.
      `min-height:24px` không đội hàng lên: mức Thoáng ô đã cao 32px, mức Chật
      24px vừa khít, đã đo cả ba mức sau khi vá.
   ⛔ TRỪ ô tích và nút chọn: chúng có cỡ riêng do trình duyệt vẽ, ép rộng 24px là
      cái khung tích to đùng lệch hẳn khỏi dòng chữ.
   ══════════════════════════════════════════════════════════════════════════════ */
.sheet-moi tbody tr.sheet-hang td button:not(.sheet-tcn-nut):not(.sheet-tcn-o),
.sheet-moi tbody tr.sheet-hang td summary,
.sheet-moi tbody tr.sheet-hang td [role="button"] {
  min-height: 24px;
  min-width: 24px;
  box-sizing: border-box;
  /* ⛔⛔ `vertical-align: middle` LÀ BẮT BUỘC Ở ĐÂY, không phải cho đẹp.
     Một hộp inline cao 24px đặt trên đường chữ thì trình duyệt còn chừa thêm chỗ cho
     phần đuôi chữ thòng xuống (g, y, p) bên dưới — hộp dòng thành 27px. Đo thật:
     vừa thêm `min-height` xong là cả ba mức cỡ ô đội lên đúng 3px (32→35 · 28→31 ·
     24→27), ba phép canh đỏ cùng lúc. Đó là HẠ CHIỀU CAO kiểu ngược — trái hẳn
     luật đã chốt *"làm gọn thì bóp NGANG"*: nới đích bấm thì cũng phải nới ngang,
     không được đẩy hàng cao lên. Canh giữa thì phần thừa ấy biến mất. */
  vertical-align: middle;
}
/* ⛔ PHẢI CANH GIỮA CẢ THẺ BỌ — không chỉ thẻ bấm được bên trong.
   Ô chọn nhiều mục là `<details class="dg-chipbox">` bọc `<summary>`. Nới `summary`
   lên 24px thì chính cái `<details>` cao 24px, mà NÓ mới là thứ nằm trên đường chữ
   của ô — canh giữa mỗi `summary` thì phần thừa vẫn còn nguyên ở tầng ngoài. Đo thật:
   vá mỗi `summary` xong hàng vẫn 27px, vá cả thẻ bọ mới về 25px. */
/* ⛔⛔ `top` CHỨ KHÔNG PHẢI `middle` — đo rồi mới chọn.
   Một hộp inline cao 24px canh `middle` thì trình duyệt đặt nó quanh điểm giữa chữ
   rồi VẪN chừa thêm chỗ cho phần đuôi chữ thòng xuống của dòng chữ nền — hộp dòng
   phồng từ 24px lên 27px. Canh `top` thì hộp dòng chỉ còn bằng hộp cao nhất.
   ĐO THẬT (Follow HS, mức Chật): `.dg-chipbox` 20→24px sau khi nới đích bấm ⇒
   hàng 25→27px — ba phép canh cỡ ô đỏ cùng lúc. Đổi sang `top` thì hàng về đúng
   mức cũ mà đích bấm vẫn 24px — đạt cả hai, không phải đánh đổi cái nào.
   ⛔ Nội dung bên trong mỗi hộp vẫn tự canh giữa (`align-items:center`), nên chữ
      không hề bị đẩy lên trên — đã xem ảnh chụp, không chỉ xem số. */
.sheet-moi tbody tr.sheet-hang td > * { vertical-align: top; }
/* Nút đã được neo tuyệt đối trong dải số thì giữ đúng 24×24 của nó, đừng để luật
   trên nở thêm. (Luật trên nhẹ hơn nên vốn đã thua, ghi ra đây cho lượt sau biết
   là CỐ Ý chứ không phải quên.) */

/* Hộp chọn nhiều mục: phần bấm được là chính cái `summary`.
   ⛔ GIỮ `inline-flex` của khối ⑤, ĐỪNG đổi sang `flex`: hộp khối chiếm trọn một
      dòng riêng trong ô và đẩy hàng cao thêm. Chỉ cần canh giữa theo chiều dọc. */
.sheet-moi tbody tr.sheet-hang td .dg-chipbox > summary {
  align-items: center;
}

/* ══════════════════════════════════════════════════════════════════════════════
   ㉖ Ô ĐANG GÕ PHẢI NỞ RA THEO CHIỀU NGANG — Boss 10/09/2026
   *"ấn vào ô có viết nhiều chữ thì phải hiện đầy đủ ra như excel chứ???"*

   ĐO TRƯỚC KHI SỬA (màn Phụ đạo, cột "Kết quả", nạp 300 ký tự thật):
     ô rộng 97px · `<textarea>` rộng 81px · scrollHeight 500px · trần 220px
     ⇒ 280px chữ không có đường nào xem tới.
   Khối trên đã cho ô đang gõ `overflow: visible`, nền đục, `z-index: 5` — tức là
   ĐÃ nổi lên trên như Excel. Thứ còn thiếu là BỀ NGANG: hộp gõ vẫn bó trong 81px
   nên 300 chữ phải xếp thành mười lăm dòng, cao gấp đôi trần.

   ⇒ Cho hộp gõ một bề ngang tối thiểu 320px. Bảng đang `table-layout: fixed` nên
     con số này KHÔNG kéo cột nào rộng ra — nó chỉ tràn ra vẽ đè lên ô bên cạnh,
     đúng cảnh Excel: ô đang sửa phủ lên hàng xóm, rời ô là hàng xóm hiện lại.
   ⛔ `max()` chứ không phải số cứng: cột vốn rộng hơn 320px thì giữ nguyên bề
      rộng thật của nó, đừng bóp lại.
   ⛔ ĐỪNG nới bằng cách sửa `<col>`: đó là bề rộng CỘT, nới là cả bảng xô ngang
      mỗi lần bấm vào một ô — và bề rộng ấy là thứ người dùng tự kéo, ghi đè lên
      là cướp mất lựa chọn của họ.
   ══════════════════════════════════════════════════════════════════════════════ */
/* `.sheet-giu-bam` — ô vừa nhả tiêu điểm GIỮA một cú bấm. Giữ nguyên bề rộng cho
   tới khi chuột nhả hẳn, không thì mọi cột bên phải dịch trái ngay giữa
   `mousedown` và `mouseup` và cú bấm rơi sang cột khác (gốc ②, xem
   `sheetGanGiuBamKhiRoi` trong js/tinh-nang.js). */
/* ⛔⛔ 13/09/2026 — GO BE RONG 320px. DO THAT BAC BO CHU THICH O TREN.
   Chu thich khoi ㉖ khang dinh: *"Bang dang table-layout: fixed nen con so nay
   KHONG keo cot nao rong ra"*. Do lai sang 13/09 tren man Diem danh, o cot
   "Nhan xet": bam vao o thi RUOT o 251 -> 320px, O 260 -> 329px, CA COT theo
   (bon hang deu 329), va CA BANG 846 -> 915px. Hoi CDP
   CSS.getMatchedStylesForNode thi chinh luat nay la luat thang.
   Do la dung canh Boss che 13/09: *"app hien gio dang mo 1 o trong cot do thi
   toan bo cot tu dong mo ra dieu do tao ra hinh toan bo cot mo ra het khung
   chop nhay 1 luc ngan"*.
   ⇒ Viec "xem du chu" nay do KHUNG NOI lo (sheetMoKhungXem trong js/tinh-nang.js):
     khung ve ngoai bang, position:fixed, nen bang dung yen tuyet doi.
   ⛔ DUNG TRA LUAT NAY VE. Muon o rong hon luc GO thi phai cho ruot thoat khoi
      dong tinh be rong cot (vi du position:absolute), chu khong phai dat width
      lon len ruot — ruot con nam trong luong tinh cot thi cot van no theo.
   Hai lop `sheet-giu-bam` va `dang-sua` giu lai o day CHI de nguoi doc sau biet
   chung tung di chung duong: `dang-sua` la o NGUOI KHAC dang dung (veNguoiDangSua,
   dong ~25238), khong phai o minh dang go. */
/* Ô một dòng cũng vậy, nhưng nới vừa phải: chữ trong `<input>` vốn cuộn ngang
   được, nó không giấu mất chữ như `<textarea>`. */
/* (O mot dong: go not be rong 220px, cung mot ly do nhu tren.) */
/* Nở sang phải thì mép phải phải còn đường thoát. Ô ở cột cuối nở ra sẽ đụng mép
   bảng; cho nó nở ngược sang TRÁI để không bị khung cuộn cắt mất. */
.sheet-moi tbody tr.sheet-hang td:last-child:focus-within > textarea,
.sheet-moi tbody tr.sheet-hang td:last-child:focus-within > input:not([type="checkbox"]):not([type="radio"]) {
  position: relative;
  right: 0;
  margin-left: auto;
  display: block;
}

/* ══════════════════════════════════════════════════════════════════════════════
   ㉗ THỨ CHEN GIỮA HÀNG NÚT VÀ BẢNG THÌ BÓP LỀ — Boss 10/09/2026
   *"càng sát càng tốt… tiết kiệm được từng pixel từng milimét"*
   `sheetGomDauBang` dời được tiêu đề · dòng đếm · cụm zoom lên hàng nút. Còn bộ
   lọc, chú giải, thẻ số liệu thì KHÔNG dời được — chúng rộng cả màn và là việc
   thật. Cái dôi ra ở đó không phải nội dung mà là LỀ:
     Khối lớp   201px hở / 130px nội dung → 71px lề
     Thống kê TS 208px hở / 125px nội dung → 83px lề
   ⛔ Bóp lề, KHÔNG bóp nội dung, KHÔNG giấu đi. Bộ lọc mất là màn hỏng.
   ⛔ `#noiDung` trong bộ chọn không phải để trang trí: lề của các khối này do luật
      riêng của từng màn đặt (`.kl-loc`, `.bd-o`…), một bộ chọn theo lớp thường
      thua chúng. Mượn `id` là nặng hơn hẳn mà vẫn còn đường đè lại sau này —
      hơn `!important`, thứ khoá luôn cửa của lượt sau.
   ══════════════════════════════════════════════════════════════════════════════ */
#noiDung .sheet-giua-gon {
  margin-top: 2px;
  margin-bottom: 2px;
}
#noiDung .sheet-hang-nut + .sheet-giua-gon { margin-top: 0; }

/* Hàng nút công cụ nằm thẳng trong `#noiDung` thì lề dưới 2px, không phải 10px.
   ⛔ ĐẶT Ở ĐÂY CHỨ ĐỪNG CHỚ `sheetGomDauBang` gắn lớp: hàm ấy chạy sau khi bảng
      vẽ xong, màn nào vẽ chậm thì có lượt kịp có lượt không — đo hai lượt liên tiếp ra
      181px và 189px cho cùng một màn, chênh đúng 8px của cái lề này. Luật CSS thì
      đúng ngay từ nhịp vẽ đầu tiên, không phụ thuộc vào ai chạy trước ai. */
#noiDung > .nv-thanh { margin-bottom: 2px; }

/* ══════════════════════════════════════════════════════════════════════════════
   ㉘ Ô CHƯA ĐIỀN GÌ THÌ TRẮNG TRƠN — Boss chốt 10/09/2026
   *"Tôi muốn các ô chưa chọn hoặc chưa điền gì thì để màu trắng, không đừng để
     chữ 'chọn' hay gì cả, vì excel sheet không như thế."*

   ⛔⛔ KHỐI ⑭ ĐÃ BỊ HUỶ. Đừng khôi phục, và đừng lý luận lại như tôi đã lý luận
      ở đó ("có mũi tên thì phải có chữ đi kèm"). Boss trả lời thẳng cho cái lý
      luận ấy: bỏ luôn cả mũi tên đi. Ô rỗng của Excel rỗng thật — không chữ,
      không gạch, không mũi tên. Đây là lượt ĐỔI Ý THỨ HAI ở đúng chỗ này, nên
      lượt sau nhìn thấy ô rỗng trơ trọi thì đó là ĐÚNG Ý, không phải sót việc.

   Mũi tên vẫn nằm trong mã (để rê chuột vào là thấy ô này bấm được), nhưng chỉ
   hiện ở ba lúc người dùng đang thật sự để ý tới ô:
     · con trỏ đang rê trên ô          `td:hover`
     · con trỏ đang ở trong ô          `td:focus-within`
     · ô đang được bôi chọn            `td.sheet-o-chon`
   ⛔ Dùng `opacity`, ĐỪNG `display:none`: bày ra rồi giấu bằng `display` thì ô
      co giật một cái mỗi lần rê chuột qua, cả bảng nhấp nháy.
   ══════════════════════════════════════════════════════════════════════════════ */
.sheet-moi td .dg-tom-mui {
  opacity: 0;
  transition: opacity .12s;
}
.sheet-moi td:hover .dg-tom-mui,
.sheet-moi td:focus-within .dg-tom-mui,
.sheet-moi td.sheet-o-chon .dg-tom-mui,
.sheet-moi td .dg-chipbox[open] > summary .dg-tom-mui,
.sheet-moi td .dg-chipbox > summary:focus-visible .dg-tom-mui {
  opacity: .85;
}
/* Chữ gợi ý (nếu màn nào còn dựng ra) thì giấu hẳn — không chiếm chỗ, không đọc
   thành nội dung thật. `display:none` ở đây thì đúng: nó không bao giờ hiện lại. */
.sheet-moi td .dg-tom-trong { display: none; }

/* ══════════════════════════════════════════════════════════════════════════════
   ㉙ Ô ĐANG ĐỨNG · NÚT MỜ KHI CHƯA CÓ Ô · THANH MỞ RA CHO MƯỢT
   Boss chốt 10/09/2026 ba câu, gộp vào một khối cho khỏi tản mát.

   ① *"Con trỏ đang ở ô nào thì bấm phát tô luôn ô đó — không bắt bôi xanh."*
      ⇒ Phải có DẤU cho biết mình đang đứng ở ô nào, không thì bấm xong không
        đoán được vừa tô vào đâu. Excel vẽ một khung đậm quanh ô đang đứng.
      ⛔ Khung vẽ bằng `box-shadow` LỒNG VÀO TRONG (`inset`), đừng dùng `border`:
        thêm viền là ô rộng thêm 2px và cả cột xô sang — bảng giật một cái mỗi
        lần bấm sang ô khác. `outline` cũng không được: nó vẽ TRÙM RA NGOÀI mép
        ô nên bị ô ghăm (`position: sticky`) bên cạnh đè mất một nửa.
      ⛔ Nhạt hơn hẳn màu vùng bôi xanh: hai thứ khác nghĩa, nhìn phải khác nhau.

   ② *"Chưa đứng ở ô nào mà bấm thì đừng làm gì… chỉ để nút ở trạng thái mờ."*
      `sheetSoiThanh` gắn lớp `khong-o` lên thanh khi chưa có ô nào để làm.
      ⛔ CHỈ mờ nhóm định dạng Ô. Nút "màu tiêu đề" và "cỡ ô" ăn vào CẢ BẢNG nên
        lúc nào cũng dùng được — mờ luôn cả chúng là cướp mất hai chức năng.
      ⛔ `pointer-events: none` để bấm vào thật sự không ăn, chứ không chỉ nhìn mờ.

   ③ *"khi lia chuột qua thì nó… mở ra dần dần luôn chứ không phải đang mở lại
        ngưng lại, trông đơ đơ lắm."*
      Đơ là vì hai thứ đá nhau: `transition` chạy dở thì `transform` bị đặt lại.
      ⇒ Khai một đường chuyển DUY NHẤT cho cả ba tính chất, cùng một nhịp, cùng
        một đường cong; và `will-change` để trình duyệt dựng sẵn lớp vẽ, không
        phải dựng giữa chừng (chính chỗ dựng giữa chừng gây khựng).
      ⛔ ĐỪNG dùng `animation`: chạy lại từ đầu mỗi lần đổi lớp, nên rê ra rồi rê
        vào là giật về vị trí đầu. `transition` thì quay ngược từ CHỖ ĐANG Ở.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ① Ô đang đứng */
.sheet-moi tbody td.sheet-o-dang {
  box-shadow: inset 0 0 0 2px var(--sheet-chon-vien, #00793A);
  /* ⛔⛔ `sticky` CHỨ KHÔNG PHẢI `relative` — vá 11/09/2026.
     Luật này (0,3,2) đè `.luoi .c-ten { position:sticky; left:72px }` (css:837,
     0,2,0). Đổi sang `relative` thì chính dòng `left:72px` ấy đổi NGHĨA: từ
     *mốc ghăm cách mép 72px* thành *dịch sang phải thật 72px*. Đo được: bấm
     vào ô tên học sinh thì ô nhảy 91px → 163px ở 1280, 301px → 373px ở 1920,
     đè trùm cột "Ngày điểm danh" và chỗ cũ để lại một lỗ trắng.
     Nặng hơn: ô hết ghăm nên cuộn ngang là trôi mất — trợ giảng đang điền
     điểm cho em nào thì mất luôn tên em ấy.
     ⛔ Vì sao `sticky` là đúng chứ không phải thêm `left:auto`:
       · ô THƯỜNG không khai `left` ⇒ `sticky` không có mốc nào để dính, nằm
         y nguyên trong dòng chảy — giống hệt `relative`, mà vẫn là thẻ CÓ
         ĐỊNH VỊ nên `z-index` vẫn ăn.
       · ô GHĂM giữ nguyên `left:72px` của nó ⇒ vẫn dính đúng chỗ.
       Đặt `left:auto` thì chữa được cú nhảy 72px nhưng GIẾT luôn cái ghăm,
       tức là vẫn còn nguyên lỗi "cuộn ngang là mất tên". Đã cân nhắc và loại.
     ⛔ LUẬT GỠ: đổi kiểu định vị thì phải rà lại MỌI con số đi kèm —
        `left` `top` `right` `bottom` `z-index`. Chính vì bỏ qua bước này mà
        một dòng `position` đứng đây làm hỏng một cột ở file khác. */
  position: sticky;
  z-index: 2;
}
/* Ô vừa đang đứng vừa nằm trong vùng bôi xanh thì vùng nói to hơn — người ta
   đang nhìn cả vùng, không nhìn một ô. */
.sheet-moi tbody td.sheet-o-dang.sheet-o-chon {
  box-shadow: none;
}

/* ② Nút mờ khi chưa có ô nào để làm */
.sheet-tcn.khong-o .sheet-tcn-nut[data-v="dam"],
.sheet-tcn.khong-o .sheet-tcn-nut[data-v="ngh"],
.sheet-tcn.khong-o .sheet-tcn-nut[data-v="mo-to"],
.sheet-tcn.khong-o .sheet-tcn-nut[data-v="trai"],
.sheet-tcn.khong-o .sheet-tcn-nut[data-v="giua"],
.sheet-tcn.khong-o .sheet-tcn-nut[data-v="phai"] {
  opacity: .38;
  /* ⛔⛔ ĐỪNG ĐẶT LẠI `pointer-events: none` — gỡ 16/09/2026 (tối).
     Bản cũ chặn hẳn cú bấm cho “nói đủ câu” bằng mờ + con trỏ thường. Đo thật
     16/09 thì KHÔNG đủ: Boss báo *"cái thanh định dạng highlight in đậm.. vẫn bị
     ko ấn được và nút mờ ko ấn được ở các công cụ"*. Quyền không thiếu
     (`SHEET_DD_SUA_DUOC = true`), bấm sau khi chọn ô thì ăn ngay
     (`{"id:DG1|0":{"dam":1}}`) — chỉ là không ai nói cho Boss biết phải chọn ô trước.

     `pointer-events: none` cắt luôn CẢ HAI đường giải thích: không nhận cú bấm
     (nên không hiện được lời nhắc) và không nhận cả `hover` (nên `title` cũng
     không bung ra). Nút mờ câm là nút hỏng, theo đúng chặng ② của skill
     `cong-cu-cho-nguoi-that`.
     ⇒ Giữ mờ (báo chưa dùng được) + giữ con trỏ thường (không hứa hẹn), nhưng
       để nút NHẬN được cú bấm để còn chỉ đường — xem `sheetGanThanh` trong
       js/tinh-nang.js, nhánh `khong-o` hiện lời nhắc “Hãy bấm chọn ô trước”. */
  /* ⛔ Con trỏ bàn tay là LỜI HỨA "bấm được". Nút đang tắt mà vẫn để bàn tay thì
     người dùng bấm, không có gì xảy ra, và kết luận app hỏng — chứ không đoán ra
     là "phải vào một ô trước". Mờ + con trỏ thường mới nói đủ câu.
     (`pointer-events:none` làm con trỏ ăn theo thẻ cha, nên phải khai ở cha nữa
      thì mới chắc — xem luật ngay dưới.) */
  cursor: default;
}
.sheet-tcn.khong-o .sheet-tcn-cum:has(> .sheet-tcn-nut[data-v="mo-to"]) {
  cursor: default;
}

/* ③ Mở ra cho mượt */
/* Đường chuyển khai ở khối ⑱ (chỗ dựng hình viên thuốc) — ĐỪNG khai lại ở đây,
   hai khai báo cho cùng một thứ là lượt sau sửa nhầm chỗ. Ở đây chỉ dặn trình
   duyệt dựng sẵn lớp vẽ, để nó khỏi phải dựng giữa chừng lúc đang chạy.
   ⛔ `will-change` không phải bùa: khai lên thứ KHÔNG bao giờ đổi là tốn bộ nhớ
      vẽ vô ích. Ở đây đúng vì cả hai tính chất này đổi mỗi lần bật/tắt thanh. */
.sheet-tcn {
  will-change: opacity, transform;
}
/* ⛔ Máy nào người dùng đã xin "giảm chuyển động" thì bỏ hẳn hiệu ứng — với một
   số người, thứ trượt vào trượt ra gây chóng mặt thật. Vẫn hiện ra bình thường,
   chỉ là hiện ngay. */
@media (prefers-reduced-motion: reduce) {
  .sheet-tcn { transition: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   ㉚ TRONG Ô BẢNG: MỘT KHUNG VUÔNG, MỘT Ô GÕ — Boss chốt 10/09/2026
   Ba câu Boss chê, cùng một gốc là "trong ô có quá nhiều thứ chồng lên nhau":
     ① *"lia chuột đến đâu là lại hiện cái thanh tìm kiếm bé bé ra… nó bị chiếm
        diện tích"*  → gộp còn MỘT ô, xem `sheetOChonMotO` bên js/tinh-nang.js.
     ② danh sách lớp xổ ra ĐÈ LÊN chính ô nguồn, chọn không được.
     ③ *"tôi chỉ muốn có 1 khung vuông như trên sheet"* → ô nhập đang có viền
        riêng, cộng với quầng của `<td>` thành hai khung lồng nhau.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ① MỘT Ô: giấu `<select>`, nút ×, dòng đếm. Chỉ còn ô gõ, trải hết bề ngang ô.
   ⛔ Giấu `<select>` bằng cách bóp về 0 chứ ĐỪNG `display:none`: thẻ ẩn hẳn thì
      trình duyệt bỏ nó khỏi biểu mẫu và một số trình đọc màn hình mất luôn nhãn.
      Bóp về 0 + `position:absolute` thì nó vẫn sống, vẫn nhận `sel.value`, chỉ là
      không chiếm chỗ. */
.sheet-moi tbody td .oc-tim.oc-mot-o {
  display: block;
  position: relative;
  width: 100%;
  min-width: 0;
}
.sheet-moi tbody td .oc-tim.oc-mot-o > select {
  position: absolute;
  left: 0;
  top: 0;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.sheet-moi tbody td .oc-tim.oc-mot-o > .oc-xoa,
.sheet-moi tbody td .oc-tim.oc-mot-o > .oc-dem,
.sheet-moi tbody td .oc-tim.oc-mot-o > .oc-goiy-d {
  display: none;
}
/* ⛔ Ô gõ phải THẤY ĐƯỢC MỌI LÚC ở đây — khối ⑫ có luật giấu `input.oc-o` cho tới
   khi vào ô, luật ấy dành cho kiểu CŨ (ô tìm phụ nằm cạnh ô chọn). Ở kiểu một-ô
   thì giấu nó đi là ô trống trơn, không đọc được đang chọn lớp nào.
   Bề nặng phải hơn luật giấu kia — nó là (0,3,3), đây là (0,4,3). */
.sheet-moi tbody td .oc-tim.oc-mot-o > input.oc-o,
.sheet-moi tbody td:focus-within .oc-tim.oc-mot-o > input.oc-o,
.sheet-moi tbody td.sheet-giu-bam .oc-tim.oc-mot-o > input.oc-o,
.sheet-moi tbody td.dang-sua .oc-tim.oc-mot-o > input.oc-o {
  display: block;
  position: static;
  width: 100%;
  height: auto;
  margin: 0;
  min-height: 24px;
}

/* ② Danh sách xổ ra không được đè lên chính ô nguồn.
   Danh sách neo `top: 100%` của `<details>`, mà `<details>` chỉ cao bằng dòng chữ
   tóm tắt — trong khi Ô thì cao hơn (có đệm). Nên mép trên danh sách rơi vào
   giữa ô, đè lên đúng chữ mình vừa bấm.
   ⇒ Neo theo ĐÁY Ô: cho `<details>` cao bằng ô (`height: 100%`) thì `top: 100%`
     mới rơi đúng dưới mép ô.
   ⛔ Đừng đẩy bằng `margin-top` một con số đoán: ô cao 25px hay 47px là tuỳ mức
      cỡ ô và tuỳ nội dung — số cứng thì mức này đúng, mức kia hở hoặc đè. */
.sheet-moi tbody td .dg-chipbox {
  height: 100%;
  display: flex;
  align-items: center;
}
.sheet-moi tbody td .dg-chipbox[open] > .dg-chips {
  top: calc(100% + 2px);
}

/* ③ MỘT khung vuông duy nhất.
   `<td>` khi đang gõ đã có quầng 2px (khối ⑧). Ô nhập bên trong lại còn viền
   riêng + bo góc + nền riêng ⇒ hai khung lồng nhau, và vì ô nhập rộng bằng đúng
   ô nên viền của nó nằm ngay sát viền kia, trông như bị lòi ra.
   ⇒ Ô nhập trong bảng KHÔNG có viền, KHÔNG bo góc, nền trong suốt. Khung duy
     nhất là quầng của `<td>` — đúng nếp Google Sheets: khung thuộc về Ô.
   ⛔ Đây là luật CHỈ trong bảng. Ngoài biểu mẫu, ô nhập vẫn phải có viền của nó,
      không thì chẳng ai biết chỗ nào gõ được. */
.sheet-moi tbody tr.sheet-hang td input:not([type="checkbox"]):not([type="radio"]),
.sheet-moi tbody tr.sheet-hang td textarea,
.sheet-moi tbody tr.sheet-hang td select {
  border: 0;
  border-radius: 0;
  box-shadow: none;
  outline: 0;
}
/* ⛔⛔ NỀN TRONG SUỐT PHẢI CHỪA Ô MANG MÀU NGHĨA — vá 11/09/2026. Boss báo:
     *"màu cũ đâu hết rồi sao tự tay xóa sạch"* (lưới Điểm danh trắng bong).
   Đo ở mốc `1c7e19e`, 5/5 loại ô hỏng: "Đủ" chữ trắng trên nền trắng 1,11:1 ·
   "Nghỉ" 1,29:1 · "Quên phiếu" 1,11:1 — nhìn ra đúng là một cột trống.

   GỐC — hỏi CDP `getMatchedStylesForNode`, không đọc file: dòng
   `background: transparent` của khối ngay trên đứng (0,2,4), đè
   `.o select.gt-tot { background: var(--o-tot) }` vốn chỉ (0,2,1). Và vì là
   dạng VIẾT GỌN, nó đặt lại CẢ nhóm `background-*` nên nuốt luôn
   `background-image` — mũi tên ô xổ (0,2,2) mất theo. Một dòng, ba thứ hỏng:
   nền màu, chữ đọc được, và dấu hiệu cho biết ô bấm được.

   Đây là vụ thứ MƯỜI cùng một cơ chế: bảng Điểm danh khai `<table class="luoi">`,
   KHÔNG có `sheet-moi` trong HTML — `sheetGan` khoác thêm lúc chạy. Nên luật
   thẩm mỹ dùng chung với tới một bảng mà ở đó NỀN Ô MANG NGHĨA (xanh = có mặt ·
   đỏ = nghỉ · vàng = thiếu). Đọc file CSS không bao giờ thấy điều đó.

   ⇒ Tách riêng ĐÚNG MỘT dòng `background` và chừa ô mang lớp `gt-*`. Phần còn
     lại của khối (viền, bo góc, bóng, quầng) vẫn áp cho mọi ô như cũ — đó mới
     là thứ khối ③ sinh ra để làm.
   ⛔ ĐỪNG chữa bằng `!important` cho `.o select.gt-tot`: thế là chạy đua độ nặng,
      mai có luật thứ ba lại đè tiếp và lúc ấy không ai gỡ được nữa.
   ⛔ ĐỪNG bỏ hẳn dòng `background: transparent`: ô nhập KHÔNG mang màu nghĩa vẫn
      phải trong suốt, không thì mỗi ô gõ lại thành một khung trắng lồng trong ô
      — đúng lỗi "hai khung lồng nhau" mà khối ③ sinh ra để chữa.
   ⛔⛔ VÀ PHẢI LÀ `background-color`, KHÔNG ĐƯỢC DÙNG DẠNG VIẾT GỌN `background`.
      Dạng gọn đặt lại CẢ nhóm `background-*` nên nó nuốt luôn `background-image`
      — tức MŨI TÊN của ô xổ. Đo đối chứng với mốc `fa444a1` (trước cả đêm 10/09):
      Dự giờ 8 mũi tên → 0 · Follow up 6 → 0 · Phụ đạo 15 → 0 · Chăm sóc 10 → 0.
      Bốn màn mất sạch dấu hiệu "ô này bấm ra danh sách được", trong khi chẳng ai
      đụng tới bốn màn ấy. Đúng lời Boss: *"sửa 1 bên là công cụ khác và các nút
      khác đều bị lỗi"*. Khối ③ sinh ra để bỏ VIỀN, BO GÓC và NỀN — chưa bao giờ
      có ý bỏ mũi tên; css:12047 còn ghi rõ *"ĐỪNG GIẤU MŨI TÊN CỦA Ô XỔ"*.
      Dùng longhand là nói đúng điều mình muốn nói.
   ⛔⛔ DANH SÁCH NÀY SẼ SÓT — và lưới an toàn KHÔNG phải là trí nhớ của ai.
      Sau khi vá lần đầu (chỉ chừa `gt-*` của Điểm danh), bộ rà toàn bộ tìm ra
      ngay một ca nữa cùng họ ở màn Phụ đạo: `.pd-tt-sel.tt-pending` (css:6963) cho
      ô trạng thái nền hổ phách "đang chờ", cùng hai anh em `.tt-done` (xanh) và
      `.tt-cancelled` (đỏ). Ba màu ấy MANG NGHĨA y như xanh/đỏ của Điểm danh.
      Đo đối chứng với mốc `fa444a1`: Phụ đạo 1 luật bị nuốt → 2 luật. Đúng một
      vụ MỚI do đêm 10/09 gây ra; sáu chỗ còn lại thì giống hệt mốc gốc.
      ⇒ Lưới an toàn là PHÉP CANH `canh-mau-nghia.js`: nó hỏi CSSOM xem phần tử
        nào CÓ luật cho nền màu đặc mà nền TÍNH RA lại trong suốt — bắt được mọi
        ca cùng họ mà không cần biết tên lớp. Thêm lớp trạng thái mới ở bất cứ
        màn nào thì chạy lại nó, đừng tin vào danh sách dưới đây.
   ⛔ ĐỪNG đổi `[class*="gt-"]` thành liệt kê bốn lớp: `lopMau()` trong
      `js/tinh-nang.js` có thể thêm bậc màu mới, liệt kê tay là sót âm thầm. */
.sheet-moi tbody tr.sheet-hang td input:not([type="checkbox"]):not([type="radio"]),
.sheet-moi tbody tr.sheet-hang td textarea,
.sheet-moi tbody tr.sheet-hang td select:not([class*="gt-"]):not(.tt-pending):not(.tt-done):not(.tt-cancelled) {
  background-color: transparent;
}
/* Lúc đang gõ thì `<td>` lo phần khung; ô nhập tuyệt đối không vẽ thêm gì.
   ⛔ Vẫn phải CÓ MỘT dấu hiệu: người dùng phải biết mình đang gõ ở đâu. Dấu ấy là
      quầng của `<td>` (khối ⑧) — nên ĐỪNG gỡ nốt cái ấy cho "sạch". */
.sheet-moi tbody tr.sheet-hang td input:focus,
.sheet-moi tbody tr.sheet-hang td textarea:focus,
.sheet-moi tbody tr.sheet-hang td select:focus {
  border: 0;
  box-shadow: none;
  outline: 0;
}
/* Ô nhập không được tràn khỏi ô của nó. */
.sheet-moi tbody tr.sheet-hang td input:not([type="checkbox"]):not([type="radio"]),
.sheet-moi tbody tr.sheet-hang td textarea {
  max-width: 100%;
  box-sizing: border-box;
}

/* ══════════════════════════════════════════════════════════════════════════════
   ㉛ DÒNG "ĐANG CHỜ · ĐÃ XỬ LÝ" KHÔNG ĐƯỢC ĐẨY CỤM NÚT RA RÌA — Boss 10/09/2026
   *"'Yêu cầu giáo viên': thanh nút chức năng bị đẩy ra tận rìa phải, khó dùng
     khó kéo qua lại."*

   ĐO Ở MÀN 390px (kênh Phá dựng lại được, `man-hinh/yeu-cau-giao-vien.js:152`):
     `<span class="ts-tong">` ăn 255 / 366px · viên nút còn 103px
     bên trong viên: scrollWidth 389 vs clientWidth 101 ⇒ 288px nút nằm ngoài
     tầm nhìn, mà trang KHÔNG cuộn ngang nên chỉ kéo được trong lòng viên.

   GỐC: thẻ ấy không có một luật CSS nào cả, nên nhận mặc định `flex: 0 1 auto`
   — mà nội dung là một câu dài không có chỗ ngắt hợp lý, nên bề rộng "tự nhiên"
   của nó gần bằng cả câu. Nó không co, cụm nút phải chịu.

   ⇒ Cho nó CO ĐƯỢC (`min-width: 0`) và cho XUỐNG DÒNG ở màn hẹp.
   ⛔ ĐỪNG giấu con số đi cho gọn: đó là thứ Boss nhìn để biết còn bao nhiêu yêu
      cầu chưa xử lý. Bóp chỗ, không bóp nội dung.
   ⛔ ĐỪNG cho cụm nút `flex: 1` để giành lại chỗ: hai bên cùng giành thì màn rộng
      lại thừa một khoảng trắng giữa. Chỉ cần bên kia CHỊU CO là đủ.
   ══════════════════════════════════════════════════════════════════════════════ */
.ts-tong {
  flex: 0 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}
@media (max-width: 700px) {
  /* Màn hẹp: câu đếm xuống hẳn dòng riêng, trả trọn bề ngang cho cụm nút. */
  .ts-tong {
    flex: 1 1 100%;
    order: 9;
    font-size: 12px;
    line-height: 1.4;
  }
}

/* ══════════════════════════════════════════════════════════════════════════════
   ㉛b ĐIỆN THOẠI: TRẢ TRỌN BỀ NGANG CHO CỤM NÚT — Boss 20/09/2026
   *"nút đang bị khá là khuất và có mấy cái dòng chữ chiếm diện tích, hãy để nút
     hiển thị ra nó dài ra, vẫn có thể kéo sang 2 bên được, và cái chữ đấy ẩn đi"*.

   ĐO Ở MÀN 390px (Chrome thật, 20/09):
     .nv-thanh.tnn  366px · nowrap · sw 366 = cw 366 → thanh ngoài KHÔNG kéo được
       ├ .ts-tong   169px  (câu "Đang chờ: 0 · đã xử lý: 1 · tất cả 1 yêu cầu")
       └ .nv-gon    189px · sw 389 / cw 187 → 202px nút nằm ngoài ô cửa sổ 187px
   Người dùng phải kéo một thanh 389px qua khe hở 187px. Đó là "khuất".

   ⛔ BẢN VÁ ㉛ Ở NGAY TRÊN KHÔNG CÒN VỚI TỚI. Nó cho `.ts-tong{flex:1 1 100%}` để
      câu đếm xuống dòng riêng — nhưng thanh nay được gom thành viên `.tnn`, mà
      `.tnn{flex-wrap:nowrap}` thì `flex-basis:100%` không xuống dòng nổi, nó chỉ
      giành chỗ rồi bị bóp. Giữ nguyên khối ㉛: nó vẫn đúng cho thanh chưa gom.

   ⛔ KHỐI ㉛ CÓ CÂU "ĐỪNG giấu con số đi cho gọn" — câu ấy chốt 10/09/2026, nay
      Boss ra lệnh ngược lại 20/09/2026 và lệnh mới hơn thì thắng. Con số không mất
      hẳn: hai nút ngăn vẫn in số ngay trên mặt nút (`.yc-ngan-so`).

   ⛔ CHỈ MÀN YÊU CẦU GV. Boss chốt bằng nút. Nên bám `.yc-thanh` —
      dấu do `man-hinh/yeu-cau-giao-vien.js` gắn — chứ đừng bám `.tnn`, vì `.tnn` là của
      cả 12 thanh công cụ trong app.
   ══════════════════════════════════════════════════════════════════════════════ */
@media (max-width: 700px) {
  .yc-thanh > .ts-tong { display: none; }

  /* Chữ trong nút ẩn đi, TRỪ nút ngăn ĐANG MỞ — để luôn còn đúng một chữ nói rõ
     mình đang đứng ở ngăn nào. Icon thì nút nào cũng giữ.

     ⛔⛔ HAI BỘ CHỌN, KHÔNG PHẢI MỘT — đừng gộp lại cho "gọn".
     Hai nút ngăn nằm trong `<div class="yc-ngan-hang">`, một thẻ RIÊNG, không phải
     con của `.yc-thanh`. Phép gom (`gonMotThanh`) gom cả hai hàng, nhưng GOM VÀO
     ĐÂU thì tuỳ bề ngang màn và tuỳ số yêu cầu đang có: có lượt hai nút ngăn về
     chung viên với "Làm mới" trong `.yc-thanh`, có lượt chúng ở lại viên riêng của
     `.yc-ngan-hang`.
     Bản đầu của tôi (20/09) chỉ viết `.yc-thanh .nv-gon …` — chạy đúng trên kho
     của Boss (có yêu cầu) và SAI trên kho rỗng: hai nút ngăn vẫn phơi cả chữ, viên
     nút vẫn giấu mất 131px. Bài `thu-giao-dien-dien-thoai-20-09` bắt được.
     ⇒ Nút ngăn thì bám thẳng `.yc-ngan` — lớp ấy CHỈ màn Yêu cầu GV mới có, nên
       vẫn đúng phạm vi Boss chốt mà không phụ thuộc gom vào đâu. */
  .nv-gon button.yc-ngan:not(.chon) > .nvg-chu { display: none; }
  .nv-gon button.yc-ngan:not(.chon) > i { margin-right: 0; }

  /* Các nút còn lại của chính thanh này (Làm mới · Tải kho về Excel · Xoá…).
     ⛔⛔ BÁM VÀO NÚT (`.yc-nut`), ĐỪNG BÁM VÀO THANH. Bản 20/09 đầu tiên viết
     `.yc-thanh .nv-gon button:not(.yc-ngan)` — đòi viên nút phải nằm trong
     `.yc-thanh`. Nhưng `gonMotThanh` đặt viên ở đâu là tuỳ bề ngang màn VÀ tuỳ
     lượng dữ liệu: kho nhiều yêu cầu thì viên nằm trong thanh (luật trúng), kho ít
     thì nó gom ra ngoài (luật trượt). Đo 20/09 ở màn 320px: nút "Làm mới" vẫn rộng
     99px vì chữ chưa ẩn, cụm nút giấu mất 54px. Dấu `yc-nut` do
     `man-hinh/yeu-cau-giao-vien.js` gắn thẳng lên nút nên bê đi đâu cũng trúng — và vẫn chỉ
     riêng màn này, đúng ý Boss "chỉ màn Yêu cầu GV".
     ⛔⛔ TÊN PHẢI LÀ `yc-nut-thanh`, ĐỪNG RÚT GỌN VỀ `yc-nut`. Dòng 5211 đã có
     một `.yc-nut` KHÁC HẲN: hàng ba nút hành động bên trong mỗi thẻ yêu cầu,
     `display:grid; grid-template-columns:1fr 1fr 1fr auto; margin-top:2px`. Bản
     đầu của tôi (20/09) dùng đúng tên ấy, thế là ba nút thanh công cụ lặng lẽ nhận
     lưới 4 cột — mà BÀI KIỂM VẪN XANH 78/78, vì lưới chỉ có một icon thì ba cột
     `1fr` co về 0 và bề rộng đo ra vẫn đúng 38px. Xanh do MAY. */
  .nv-gon button.yc-nut-thanh > .nvg-chu { display: none; }
  .nv-gon button.yc-nut-thanh > i { margin-right: 0; }

  /* ⛔⛔ NÚT NGĂN ĐANG CHỌN VẪN PHẢI ĐỌC ĐƯỢC — 20/09/2026.
     Luật ngay trên chỉ giấu `.nvg-chu` của nút KHÔNG chọn, cốt để nút đang chọn
     còn một chữ nói rõ mình đứng ở ngăn nào. Nhưng chữ ấy vẫn câm, vì cụm gom
     `.nv-gon button` ghim `font-size:0 !important` cho MỌI nút bên trong (khối
     "CHỪA SẴN CHỖ", Boss chốt 12/09). Giấu bằng `display:none` và câm vì
     `font-size:0` là hai đường khác nhau — chặn một đường không đủ.
     Trả cỡ chữ riêng cho đúng nút đang chọn, không đụng nút nào khác. */
  .nv-gon button.yc-ngan.chon { font-size: 12.5px !important; padding: 0 10px !important; }
  .nv-gon button.yc-ngan.chon > .nvg-chu { max-width: 200px; opacity: 1; margin-left: 0; }
  /* ⛔ Luật `> i { margin-right: 0 }` ngay trên chỉ đúng cho nút KHÔNG chọn — nút
     ấy chỉ còn mỗi icon nên lề thừa làm nó lệch tâm. Nút đang chọn thì chữ vừa phơi
     ra, không trả lề lại là icon dính liền vào chữ. Nhìn tận mắt ở 390px mới thấy. */
  .nv-gon button.yc-ngan.chon > i { margin-right: 5px; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   ㉛c MÀN RỘNG THÌ THANH YÊU CẦU GV PHƠI CHỮ RA — Boss chốt 20/09/2026
   ──────────────────────────────────────────────────────────────────────────────
   Boss nhìn ảnh chụp thanh ở màn 1280 rồi chốt bằng nút bấm: *"Cho hiện chữ lại
   — trên máy tính hiện đủ: Tìm · Làm mới · Đang chờ 0 · Kho đã xử lý 1"*.

   VÌ SAO TRƯỚC ĐÓ MẤT CHỮ, dù khối ㉛b ở trên chỉ áp dưới 700px:
   `gonMotThanh` gom thanh này vào cụm `.nv-gon`, và cụm ấy ghim
   `font-size:0 !important` cho mọi nút con ở MỌI khổ màn — đó là cái "thu cụm
   lại cho gọn" Boss chốt 12/09, chữ chỉ nở ra khi rê chuột. Với nút hành động
   (Làm mới, Tải về) thì đúng: icon thay lời, rê chuột là biết. Nhưng hai nút
   NGĂN không phải nút hành động — chúng là chỗ báo mình đang đứng ở ngăn nào,
   mà cái đó thì không rê chuột từng nút để đoán được. Đo 20/09 ở màn 1280: cả
   thanh còn đúng bốn hình, nút ngăn rộng 56px, không một chữ nào.

   ⛔ ĐỪNG SỬA `.nv-gon button` — nó là cụm dùng chung của 12 thanh công cụ
      trong app. Đổi ở đó là đổi cả 12 màn, trái đúng hai điều: Boss chốt "chỉ
      màn Yêu cầu GV", và luật 13/09 cấm tự sửa thứ không được yêu cầu.
   ⇒ Bám hai dấu riêng của màn này (`yc-ngan` do `man-hinh/yeu-cau-giao-vien.js` gắn cho nút
     ngăn, `yc-nut-thanh` cho nút của thanh), y như khối ㉛b ngay trên.
   ⛔ ĐẶT SAU khối ㉛b, không đặt trước: hai luật ngang bề nặng nhau thì cái
      đứng sau thắng. Đặt trước là viết xong vẫn không ăn.
   ⛔ `min-width:701px` cho khít với `max-width:700px` của ㉛b — chừa hở một px
      là có đúng một bề ngang màn mà không luật nào áp.
   ══════════════════════════════════════════════════════════════════════════════ */
@media (min-width: 701px) {
  /* Cỡ chữ và đệm LẤY ĐÚNG SỐ CỦA LUẬT MỞ (`.nv-gon:hover button`), không tự
     chọn số mới: nút này phơi chữ sẵn, các nút bên cạnh nở ra khi rê chuột —
     hai bên lệch cỡ chữ thì cụm nhấp nháy đổi cao mỗi lần con trỏ đi qua. */
  .nv-gon button.yc-ngan,
  .nv-gon button.yc-nut-thanh { font-size: 12.5px !important; padding: 0 10px !important; }
  .nv-gon button.yc-ngan > .nvg-chu,
  .nv-gon button.yc-nut-thanh > .nvg-chu { max-width: 200px; opacity: 1; margin-left: 0; }
  /* Chữ đã phơi thì icon phải có lề, không thì ra «🕐Đang chờ» dính liền. */
  .nv-gon button.yc-ngan > i,
  .nv-gon button.yc-nut-thanh > i { margin-right: 5px; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   ㉜ DANH SÁCH CHỌN TỰ VẼ — thay cho phần xổ ra do hệ điều hành vẽ
   Đi kèm `sheetOChonMotO` bên js/tinh-nang.js. Lý do phải tự vẽ nằm ở khối chú thích
   của hàm ấy: phần xổ của `<select>` không nằm trong trang nên không đặt được chỗ,
   không tô được màu, và không đo được.

   ⛔ `position: fixed` — KHÔNG phải `absolute`. Bảng nằm trong khung cuộn có
      `overflow`; con `absolute` bị khung ấy cắt cụt, danh sách của hàng cuối chỉ
      hiện được vài dòng. Toạ độ do JS tính theo đáy Ô, xem `datCho()`.
   ⛔ Màu lấy từ biến của app, không gõ mã màu lạ vào đây: Boss đã chê "lộ ui AI"
      năm lần, mà nguồn gốc luôn là một bảng màu đi mượn ở đâu đó.
   ══════════════════════════════════════════════════════════════════════════════ */
.oc-xo {
  position: fixed;
  z-index: 90;
  max-height: 260px;
  overflow-y: auto;
  padding: 4px;
  border: 1px solid var(--vien-ro, #B9B3AA);
  border-radius: 8px;
  background: var(--the, #FFF);
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, .12), 0 4px 6px -4px rgba(0, 0, 0, .1);
}
.oc-xo[hidden] { display: none !important; }
.oc-xo-dong {
  display: block;
  width: 100%;
  min-height: 28px;
  padding: 4px 8px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--chu, #1F1D1A);
  font: inherit;
  font-size: 13px;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}
/* `nam-tren` = dòng đang được phím mũi tên trỏ tới. Phải nhìn giống hệt lúc rê
   chuột, không thì đi bằng phím với đi bằng chuột thành hai giao diện khác nhau. */
.oc-xo-dong:hover,
.oc-xo-dong.nam-tren { background: var(--nen2, #F0EEEA); }
.oc-xo-dong.dang-chon { font-weight: 600; }
.oc-xo-trong {
  padding: 8px;
  color: var(--mo, #6B6660);
  font-size: 12px;
}

/* ══════════════════════════════════════════════════════════════════════════════
   ㉝ BÁO "ĐÃ LƯU" KHÔNG ĐƯỢC LÀM HÀNG CAO LÊN — vá 10/09/2026
   Boss bấm ✕ ở Chăm sóc thì thấy "ô trắng hẳn". Kênh Phá dựng lại được: dữ liệu
   KHÔNG mất, `<td>` vẫn còn, nút vẫn đúng — cái làm Boss tưởng mất là BỐ CỤC NHẢY.
     `man-hinh/cham-soc.js:443` đổ chữ "✓ đã lưu" vào nhãn `.dg-luutt` vốn `:empty` nên
     đang `display:none`, cao 0. Có chữ là nhãn thành 20px, HÀNG 29px → 45px, đáy
     bảng tụt 16px — ngay dưới ngón tay vừa bấm.

   ⛔ Bố cục KHÔNG được nhúc nhích lúc người ta vừa bấm. Đây là luật chung, không
      riêng màn này: cú bấm kế tiếp luôn trượt, và người dùng kết luận app hỏng.
   ⇒ Trong bảng dạng sheet, nhãn ấy thu thành MỘT CHẤM TRÒN 8px nằm cùng dòng.
     Chấm xanh = đã lưu · chấm xám = đang lưu · chấm đỏ = lỗi. Màu đã có sẵn ở
     `.dg-luutt.xong/.dang/.loi`, chỉ mượn lại bằng `currentColor`.
   ⛔ `font-size: 0` chứ ĐỪNG xoá chữ đi: chữ vẫn nằm trong cây trợ năng nên trình
      đọc màn hình vẫn đọc được "✓ đã lưu" — người khiếm thị không mất lời báo.
   ⛔ ĐỪNG dùng `position:absolute` để né chỗ: ô bảng có thể đang là ô ghăm
      (`position: sticky`); đặt `position:relative` lên `<td>` để làm neo là GIẾT
      luôn cái ghăm ấy. Đã có lời dặn đúng chỗ này ở khối ⑤.
   ⛔ ĐỪNG bỏ hẳn lời báo cho gọn: người dùng cần biết cú bấm đã tới máy chủ chưa.
   ══════════════════════════════════════════════════════════════════════════════ */
.sheet-moi tbody td .dg-luutt {
  /* ⛔⛔ GOC ⑥ 11/09/2026 — BO HAN CAI CHAM. Boss: *"bo chấm xanh báo đã lưu —
     tôi ko cần cái đấy đâu nó sẽ gây loạn vị trí nếu tên dài hơn bình thường"*.
     Khoi nay la CHO VE ra cai cham; luat "display:none" dat o tren (khoi ⑧b) bi
     chinh khoi nay de len vi NGANG CO MA DUNG SAU. Do duoc: van con 8x8 o 3/4 man.
     Loi dan cu ngay duoi day ("ĐỪNG bỏ hẳn lời báo cho gọn") nay HET HIEU LUC —
     Boss da quyet nguoc lai, va Boss la nguoi dung. */
  display: none;
  flex: none;
  align-self: center;
  width: 8px;
  height: 8px;
  min-width: 8px;
  margin: 0 0 0 4px;
  padding: 0;
  border-radius: 50%;
  background: currentColor;
  font-size: 0;
  line-height: 0;
  overflow: hidden;
  /* ⛔ `top` chứ không phải `middle`: một hộp inline canh giữa thì trình duyệt còn
     chừa thêm chỗ bên dưới đường chữ, hộp dòng phồng thêm 2px và HÀNG cao lên 2px
     đúng lúc người ta vừa bấm. Đo thật: 29→31px. Nhỏ, nhưng đã là nhúc nhích —
     và chỗ này chính là chỗ Boss báo "bấm ✕ thành ô trắng".
     Canh `top` thì chấm nằm gọn trong hộp dòng sẵn có, hàng đứng im. */
  vertical-align: top;
  margin-top: 4px;
}
/* Nhãn rỗng thì không có gì để báo — giấu hẳn, khỏi chừa một chấm vô nghĩa. */
.sheet-moi tbody td .dg-luutt:empty { display: none; }
/* ⛔ Luật cũ `.dg-dinh .dg-luutt { display:block; margin:2px 0 }` (css:4146) bắt
   nhãn chiếm trọn một dòng riêng — chính nó cộng thêm 16px. Trong bảng thì phải
   thua luật trên; bề nặng ở đây là (0,3,3) so với (0,2,1) của nó. */
.sheet-moi tbody td.dg-dinh .dg-luutt {
  display: none;            /* GOC ⑥ — xem khoi ngay tren */
  margin: 0 0 0 4px;
}

/* ⛔⛔ NÚT TÍCH TRONG BẢNG PHẢI CAO CỐ ĐỊNH — phần hai của khối ㉝, vá 10/09/2026.
   Sau khi chữa cái nhãn "đã lưu", hàng VẪN cao thêm 2px mỗi lần bấm ✕. Bisect ra
   thủ phạm thứ hai, khác hẳn: chính CÁI NÚT đổi cỡ.
     `button.lt-done { height: 26px }` (css:6043) — nhưng lúc chưa bấm nó đang bị
     trần chiều cao của khối ⑧ ép về 24px. Bấm một cái là hàng nở ra, trần nới
     theo, nút bung về 26px, hàng lại nở thêm — hai thứ đẩy nhau.
   ⇒ Trong bảng thì ép cứng 24px cho cả hai trạng thái. Nút không đổi cỡ thì không
     có gì để đẩy nhau nữa.
   ⛔ 24px là SÀN ĐÍCH BẤM, đừng hạ thêm.
   ⛔ ĐỪNG chữa bằng cách nới trần của khối ⑧: trần ấy là thứ giữ cho mọi hàng
      "đều tăm tắp", nới ra là mất luôn cái đều — đổi một lỗi 2px lấy một lỗi to
      hơn nhiều.
   ⛔ Bố cục không được nhúc nhích lúc người ta vừa bấm. Đây là luật chung; chỗ
      nào có nút đổi hình theo trạng thái thì rà đúng cách này. */
.sheet-moi tbody td button.lt-done,
.sheet-moi tbody td button.cs-tick {
  height: 24px;
  min-height: 24px;
  max-height: 24px;
  box-sizing: border-box;
  line-height: 1;
  padding-top: 0;
  padding-bottom: 0;
}

/* ══════════════════════════════════════════════════════════════════════════════
   ㉞ BẤM VÀO Ô ĐANG BỊ CẮT CHỮ THÌ PHẢI BUNG RA — Boss chốt 10/09/2026
   ──────────────────────────────────────────────────────────────────────────────
   Boss: *"ấn vào 2 cột tên và lớp phải show full chữ ra như mấy cột khác ý"* —
   ảnh màn Dự giờ: cột "Người dự giờ" hiện `Nguyễn Th`, cột "Lớp" hiện `3A1` kèm
   một chip `GV:Đỗ Thị Thuý Qu…`. Bấm vào hai cột ấy không có gì xảy ra, trong
   khi các cột khác bấm vào là bung.

   GỐC (đã kiểm chứng, không phải đoán): luật bung ở khối ⑧b neo vào
   `td:focus-within`. `:focus-within` CHỈ nổ khi trong ô có thứ NHẬN ĐƯỢC TIÊU
   ĐIỂM. Hai cột ấy là CHỮ TRẦN — không `<input>`, không `<button>` — nên không
   bao giờ khớp. Đo thật: bấm giữa ô, `document.activeElement` là `BODY`.

   ⇒ Thêm một đường thứ hai, KHÔNG qua tiêu điểm: JS gắn `.sheet-o-bung` lên ô
     vừa bấm KHI VÀ CHỈ KHI ô ấy đang thật sự bị cắt (`sheetDatODang`).

   ⛔⛔ SIẾT LUẬT ÉP THÌ PHẢI SIẾT CẢ LUẬT GỠ. Luật cắt chữ là
      `.sheet-moi tbody tr.sheet-hang td` (0,3,3). Luật bung phải NẶNG BẰNG mới
      đè nổi — viết thiếu `tbody tr.sheet-hang` là (0,2,2), thua, và ô vẫn cụt y
      như cũ mà không một lỗi nào để lần ra. Đây đúng cái bẫy đã dẫm phải sáng
      nay ở luật căn lề.
   ⛔⛔ Ô GHĂM (`position: sticky`) THÌ CHỈ ĐƯỢC NÂNG `z-index`, TUYỆT ĐỐI KHÔNG
      ĐỔI `position`. Luật `:focus-within` ở khối ⑧b đặt `position: relative` —
      trên ô ghăm thì đó là GỠ GHĂM ngay giữa lúc người ta đang cuộn ngang: cột
      "Người dự giờ" trôi đi mất. Ở đây `position` để NGUYÊN, chỉ nâng `z-index`.
      `z-index` có hiệu lực trên `sticky` mà không cần `relative`.
   ⛔ `z-index` phải CAO HƠN ô ghăm thường (khối ghăm dùng 3–4) nhưng THẤP HƠN
      hộp thả xuống (3000), không thì danh sách lựa chọn chui xuống dưới ô.
   ⛔ Nền phải ĐỤC. Ô bung mà trong suốt thì chữ chồng lên chữ ô dưới, đọc thành
      một mớ — tệ hơn lúc còn cụt.
   ⛔ Bung theo CHIỀU NGANG là chính (`min-width`), đừng cho nở tự do cả hai
      chiều: bảng 41 cột mà ô nở ngang không giới hạn là nó phủ kín mấy cột bên
      cạnh. Kẹp bằng `max-width` theo bề ngang màn hình.
   ══════════════════════════════════════════════════════════════════════════════ */

/* Trần chiều cao của khối ⑧ cũng phải gỡ, không thì ô bung ngang mà chữ dòng
   thứ hai vẫn bị cắt ngang bụng. Nặng bằng đúng luật hạ trần. */
/* ⛔⛔ MOT_KIEU_MO_O 11/09/2026 — HAI DUONG MO O PHAI RA CUNG MOT HINH.
   Boss gui HAI anh cua CUNG MOT COT: mot anh o mo thanh khung vuong gon co thanh
   cuon ben phai; anh kia o keo dai xuong tan day man, day moi hang duoi di mat.
   *"luc thi no mo theo kieu khung hinh chu nhat day du chu va khong bi dai, luc
   thi no mo va xuong dong lien tuc khien o do dai chiem het man hinh."*
   GOC: co HAI duong mo chay song song, va chung khac nhau dung mot cho — cai tran:
     A. `td:focus-within > textarea` — `max-height: 220px; overflow-y: auto`
        ⇒ khung vuong gon. Chay cho o CO the nhan tieu diem (textarea/input).
     B. `td.sheet-o-bung > *`        — `max-height: NONE`
        ⇒ cao het co chu. Chay cho o CHU TRAN (khong co gi nhan tieu diem duoc).
   Cung mot cot co the di duong nao tuy o do dang la chu tran hay dang la o go —
   nen nguoi dung thay "luc the nay luc the kia" ma khong hieu vi sao.
   Do bang CSSOM: duong A tran 220px, duong B tran `none`.
   ⇒ Cho duong B DUNG CAI TRAN CUA DUONG A. Mot kieu duy nhat: cao toi 220px roi
     cuon trong long o.
   ⛔ Van giu `max-height: none` cho THE BEN TRONG neu no la o go — khong, khong
      can: duong A da lo phan textarea roi, va o day dat tran cho MOI con.
   ⛔ Cot TEN khong he bi thiet: hai dong ten cao ~40px, cach tran 220px rat xa. */

/* Ô ghăm bung ra phải nổi HẲN trên phần đang cuộn, không thì phần cuộn trườn
   qua che mất đúng cái chữ vừa bung. Vẫn KHÔNG đụng `position`. */
/* ⛔⛔ 13/09/2026 — GO CO CHE "O BUNG TRONG LONG BANG". Hai luat duoi day (o bung
   va ruot cua o bung) truoc gio lo viec "bam vao o thi o do mo ra xem du chu".
   Boss che thang cach lam nay 13/09 va mo ta dung cai minh muon:
     *"khi an vao 1 o trong cot thi chi rieng o do mo ra hien thi day du... o co
      the vua tran xuong o ben duoi va o o cot ben canh. Va neu o duoi day bang ko
      con cho ben duoi thi o se mo sang ben phai"*
   O bung trong long bang KHONG lam duoc dieu do: no chi cao len trong o cua minh,
   day hang xuong, va con keo cot rong ra (do that: bang 846 -> 915px).
   ⇒ Nay thay bang KHUNG NOI `.sheet-khung-xem` (sheetMoKhungXem trong js/tinh-nang.js):
     ve ngoai bang, position:fixed, nen BANG DUNG YEN TUYET DOI va khung tran duoc
     xuong duoi lan sang phai dung y Boss.
   ⛔ CON MOT LY DO KY THUAT NUA, quan trong voi nguoi sua sau: luat bung nay nam
      tren duong POINTERDOWN (sheetDatODang), ma pointerdown LUON chay TRUOC
      mousedown. Ruot bung cao len xong thi phep do "o nay co bi cat chu khong" o
      tay nghe mousedown nhin vao mot cai ruot da noi va khai "chu vua roi" —
      khung khong bao gio mo. Tra luat nay ve la dung lai dung cai bay ay.
   ⛔ JS van gan lop `sheet-o-bung` (js/tinh-nang.js ~28909) — de nguyen, vo hai, va
      con dung de biet o nao dang bi cat chu.
   Ban cu giu lai trong lich su git, moc truoc luot nay. */
.sheet-moi tbody tr.sheet-hang td.sheet-cot-gham.sheet-o-bung {
  z-index: 8;
}
/* ⛔ Ô GHĂM ĐANG GÕ cũng phải ở bậc của dải ghăm. Luật `td:focus-within` ở khối
   ⑧b nặng (0,3,3), nặng hơn luật ghăm (0,3,2), nên khi bấm vào một ô GHĂM thì
   chính nó tụt xuống `z-index: 5` — thấp hơn mấy ô ghăm đứng cạnh, và ô trôi
   bung ra (6) trèo lên che nó. Luật này nhắm hẹp hơn hẳn (một lớp cụ thể trên
   một trạng thái cụ thể) nên nặng (0,4,3) là đúng phần việc của nó, không phải
   đua trọng số với luật chung. */
.sheet-moi tbody tr.sheet-hang td.sheet-cot-gham:focus-within {
  z-index: 7;
}

/* ⛔⛔ TẮT GẠCH CHÂN ĐỎ CHÍNH TẢ TRONG BẢNG — Boss chưa nhắc, nhưng ảnh 10/09
   lộ ra: mọi đoạn nhận xét tiếng Việt đều bị gạch chân răng cưa đỏ vì trình
   duyệt không biết tiếng Việt, nhìn như cả ô toàn lỗi.
   ⛔ CHỈ TẮT Ở Ô NHẬP TRONG BẢNG DỮ LIỆU. Ô soạn tin nhắn / thư cho phụ huynh
      thì PHẢI để nguyên — ở đó gõ sai một chữ là gửi thẳng tới khách hàng.
   ⚠ `spellcheck` là thuộc tính HTML, CSS không tắt được; luật này chỉ là chỗ
     ghi lại quyết định. Việc tắt thật làm ở JS (`sheetTatSoatChinhTa`). */

/* ══════════════════════════════════════════════════════════════════════════════
   🗓️ LỘ TRÌNH HỌC — CỘT TUẦN BÀY NHƯ MỘT QUYỂN LỊCH (Boss giao 10/09/2026)
   ──────────────────────────────────────────────────────────────────────────────
   Boss: *"các số đang để hơi khó nhìn nó hơi bé cho những người có màn hình bé…
   để dấu cậu hay là những ký hiệu hay là chữ khi điền thêm vào nó có màu khác hơn
   so với cả số… cái màu vàng là những cái cột nào mà là ngày có ngày lễ hoặc ngày
   nghỉ bạn để cho số ở trong mấy cái cột đó nó đậm hơn nó rõ hơn… thiết kế giao
   diện cho nó giống 1 cái quyển lịch 1 chút"*.

   Boss chốt bằng nút bấm: GIỮ NGUYÊN bề rộng cột 46px (để một màn vẫn nhìn được
   nhiều tuần), chỉ cho con số to lên · ký hiệu CAM, chữ ghi chú XÁM · ô ngày lễ
   thì số đậm + sẫm + vạch dọc hai bên · thêm BĂNG THÁNG gộp bên trên.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ⛔⛔ HAI CON SỐ NÀY KHAI ĐÚNG MỘT CHỖ — ở đây.
   `--lt2-rong-tuan` vừa là bề rộng một cột tuần, vừa là thứ băng tháng nhân lên
   để trùm đúng số cột nó gộp. Gõ 46px ở hai nơi thì sửa một nơi là băng tháng
   lệch khỏi cột, mà lệch kiểu ấy không có gì kêu lên cả.
   `--lt2-cao-thang` vừa là chiều cao băng tháng, vừa là khoảng phải tụt xuống
   của hàng tiêu đề tuần khi ghim (sticky) — sai một trong hai là hai hàng tiêu đề
   dán chồng lên nhau lúc cuộn. */
/* ⛔⛔ 46px LÀ SỐ KHAI, KHÔNG PHẢI BỀ RỘNG THẬT TRÊN MÀN — đo 10/09/2026.
   Bề rộng thật của một cột tuần là 56px: bộ kéo cột dùng chung (`gaKeoCot` trong
   js/tinh-nang.js) đặt một cái SÀN và chừa 13px đệm phải cho nút menu cột kiểu Sheet.
   Đo cả bản trước lẫn bản sau đợt này: bảng đúng 4214px, cột đúng 56px ở cả hai —
   tức đợt "quyển lịch" KHÔNG nới thêm một pixel nào, đúng lời Boss chốt là giữ
   nguyên bề rộng.
   ⛔ ĐỪNG "sửa" 46 thành 56 cho khớp. Số này còn là thứ băng tháng nhân lên ở
      `calc()`, và ở nhịp vẽ đầu tiên — trước khi `gaKeoCot` kịp dựng `<colgroup>`
      — thì CHÍNH nó là bề rộng cột. Đổi một bên là băng tháng lệch khỏi cột đúng
      nhịp ấy. Hai chỗ phải cùng một con số, và `<colgroup>` lo phần còn lại. */
.lt2-bang { --lt2-rong-tuan: 46px; --lt2-cao-thang: 24px; }
.lt2-bang .lt2-c-tuan { width: var(--lt2-rong-tuan); }

/* ── ① BĂNG THÁNG ─────────────────────────────────────────────────────────── */
.lt2-bang thead th.lt2-thang {
  box-sizing: border-box;
  width: calc(var(--lt2-rong-tuan) * var(--lt2-so-tuan, 1));
  height: var(--lt2-cao-thang);
  padding: 0 4px;
  line-height: calc(var(--lt2-cao-thang) - 1px);
  text-align: center;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: clip;
  /* Vạch trái đậm hơn viền thường — đây là chỗ sang tờ lịch mới. */
  border-left: 1px solid var(--vien-ro, var(--vien));
}
/* Sang một năm dương lịch mới thì vạch dày hơn: năm học vắt qua hai năm, chỗ đổi
   năm là mốc giáo vụ hay dò nhất. */
.lt2-bang thead th.lt2-thang-moi-nam { border-left-width: 2px; }

/* ⛔ HÀNG TIÊU ĐỀ TUẦN PHẢI TỤT XUỐNG ĐÚNG CHIỀU CAO BĂNG THÁNG.
   Luật cũ `.lt2-bang thead th { position:sticky; top:0 }` ghim MỌI ô tiêu đề vào
   mép trên. Có hai hàng rồi mà vẫn top:0 thì lúc cuộn, hàng tuần leo lên dán đè
   lên băng tháng — đúng kiểu hỏng nhìn thấy được nhưng không báo lỗi. */
/* ══════════════════════════════════════════════════════════════════════════════
   ⛔⛔ GIÀNH LẠI `position: sticky` CHO ĐẦU BẢNG — nó đã MẤT TỪ TRƯỚC ĐỢT NÀY
   ──────────────────────────────────────────────────────────────────────────────
   Đợt "bảng kiểu Sheet" (Boss giao sáng 10/09) thêm
       .sheet-moi thead th { position: relative; }        ← ~dòng 11257
   để làm chỗ neo cho nút menu ba chấm trên đầu cột. Dòng ấy có độ ưu tiên ĐÚNG
   BẰNG `.lt2-bang thead th { position: sticky }` (~dòng 10413) — cả hai đều
   (0,1,2) — mà nó đứng SAU trong file, nên nó thắng. Hậu quả: mọi ô tiêu đề mất
   ghim, TRỪ đúng ô "Lớp" (`.lt2-bang .lt2-g1` là (0,2,1), thắng cả hai).

   ĐO THẬT 10/09/2026 trên bản CHƯA có đợt "quyển lịch", cuộn xuống 209px:
       hàng tiêu đề trôi lên  -51px       ô "Lớp" đứng lại ở  158px
   Tức đầu bảng vỡ làm đôi — tên cột trôi mất trong khi cột Lớp còn dính. Ai cuộn
   xuống giữa bảng 54 cột thì không còn biết mình đang điền vào tuần nào.

   ⛔ ĐỪNG ĐI SỬA DÒNG 11257. Nó đang phục vụ MỌI bảng kiểu Sheet trong app, và
      `sticky` cũng là phần tử CÓ ĐỊNH VỊ nên nút menu `position:absolute` bên
      trong vẫn neo đúng — chỉ cần nhỉnh hơn một bậc và CHỈ cho bảng này.
   ⚠️ Các bảng kiểu Sheet KHÁC gần như chắc chắn đang dính đúng lỗi này. Đã báo
      Boss để kênh làm đợt Sheet rà lại; đây không phải chỗ chữa cho cả app.
   ══════════════════════════════════════════════════════════════════════════════ */
.lt2-bang thead tr th { position: sticky; }
.lt2-bang thead tr:first-child th { top: 0; }
.lt2-bang thead tr:last-child th  { top: var(--lt2-cao-thang); }

/* ── ② SỐ TO HƠN · KÝ HIỆU KHÁC MÀU ───────────────────────────────────────── */
/* ⛔ BỎ NỀN VIÊN THUỐC của `.lt2-chip`, KHÔNG PHẢI ĐỂ CHO ĐẸP.
   Cột giữ nguyên 46px theo lời Boss, mà một ô có thể chứa hai buổi ("9" và "10").
   Nền + đệm hai bên của viên thuốc ăn mất 8px mỗi số; bỏ nó đi mới đủ chỗ nâng
   con số từ 11px lên 13px — tức là chính chỗ ấy đổi thành cỡ chữ. */
.lt2-bang .lt2-chip {
  background: none;
  min-width: 0;
  padding: 0 2px;
  margin: 0;
  font-size: 13px;
  line-height: 19px;
  font-weight: 600;
  /* Chữ số cùng bề ngang thì hai dòng số thẳng cột với nhau, đọc lướt cả bảng
     54 cột mới không bị nhảy mắt. */
  font-variant-numeric: tabular-nums;
  color: var(--xanh-dam);
}
/* Ký hiệu người ta gõ thêm (+ ++ …) — CAM, và đậm hơn số một bậc. */
.lt2-bang .lt2-kh { color: var(--cam); font-weight: 700; }
/* Ngoặc chỉ là dấu tách số khỏi chữ, phải mờ hơn cả hai — nó không mang tin. */
.lt2-bang .lt2-ngoac { color: var(--mo); font-weight: 400; }

/* ── ③ Ô TUẦN NGHỈ LỄ: SỐ ĐẬM + SẪM + VẠCH DỌC ────────────────────────────── */
/* ⛔⛔ GÕ CỨNG MÀU CHỮ Ở ĐÂY, ĐỪNG LẤY var(). Nền ô nghỉ lễ là #FFF8E1 gõ cứng và
   GIỐNG NHAU ở cả chế độ sáng lẫn tối (xem chú thích ~dòng 10442). Lấy
   var(--xanh-dam) thì chế độ tối trả về một màu SÁNG, số lại chìm vào nền kem —
   đúng cái lỗi Boss đã báo hai lần, chỉ đổi chỗ. */
.lt2-bang td.lt2-nghi .lt2-chip  { color: #4A3B10; font-weight: 700; }
.lt2-bang td.lt2-nghi .lt2-kh    { color: #A34700; }
.lt2-bang td.lt2-nghi .lt2-ngoac { color: #7A6636; }

/* Vạch dọc hai bên cột nghỉ lễ — nhìn ra cả cột là tuần nghỉ ngay cả khi ô trống.
   ⛔ DÙNG box-shadow inset, ĐỪNG ĐỔI border-width. Bảng chạy
      `table-layout:fixed` + `border-collapse:separate`; nới viền 1px → 2px là
      đổi bề rộng cột, mà băng tháng bên trên tính theo 46px × số tuần nên nó
      lệch khỏi cột ngay. box-shadow không chiếm chỗ nào cả. */
.lt2-bang th.lt2-nghi, .lt2-bang td.lt2-nghi {
  box-shadow: inset 2px 0 0 #E8B93A, inset -2px 0 0 #E8B93A;
}
/* Băng tháng nằm trên cột nghỉ thì không kẻ vạch — một khối tháng thường trùm cả
   tuần nghỉ lẫn tuần thường, kẻ vào đó là chỉ sai chỗ. */

/* Màn hẹp: con số vẫn giữ 13px (đây chính là lời Boss — *"hơi bé cho những người
   có màn hình bé"*), chỉ băng tháng rút bớt chiều cao cho đỡ ăn chỗ. */
@media (max-width: 700px) {
  .lt2-bang { --lt2-cao-thang: 22px; }
  .lt2-bang thead th.lt2-thang { font-size: 10.5px; }
}

/* ════════════════════════════════════════════════════════════════════════════
   🗓️ Ô NHẬP LỘ TRÌNH: VỪA VỚI Ô, RỒI MỞ DẦN RA — Boss giao 12/09/2026
   ────────────────────────────────────────────────────────────────────────────
   Boss: *"ô nhập nó phải bé đi vừa với ô và ấn thì nó mở dần ra MÀ, và giao diện
   các cột tuần sửa thành giống lịch."*

   ĐO THẬT TRƯỚC KHI SỬA (khổ 1280, 110%, 18 lớp, ô đã có dữ liệu dài như thật):
     ô `<td>` tuần        81,9px
     hộp đang mở         102,1px  =  ô gõ 44  +  nút "Tự tạo" 49,3  +  đệm/gap 8,8
   ⇒ MỘT MÌNH cái nút đã chiếm 60% bề rộng ô. Nút KHÔNG neo sai và KHÔNG nằm ngoài
     luồng — nó là con thứ hai của một `display:flex` xếp NGANG. Nên mọi cách hạ
     sàn ô gõ đều không cứu được: hộp vẫn ≥ 49,3 + 44 + 8,8.

   ⇒ BÓP NGANG bằng cách XẾP DỌC: ô gõ ở TRÊN, nút "Tự tạo" ở DƯỚI. Bề ngang hộp
     nay chỉ bằng thứ rộng nhất trong hai, tức ~53px < 61,6px bề rộng ô.
   ⛔ BÓP NGANG, ĐỪNG HẠ CHIỀU CAO ô gõ: hạ là dựng lại đúng lỗi Boss chê 09/09
      (*"ô nhập số bé quá không nhập được số"*). Hộp cao lên thì nổi đè, còn HÀNG
      đứng yên — hộp neo giữa ô bằng `translate(-50%,-50%)` nên không đội hàng.
   ⛔ GIỮ NGUYÊN CHỮ "Tự tạo", không đổi thành icon: đổi chữ thành hình là đổi thứ
      người dùng đang đọc được, phải hỏi Boss — mà việc này Boss giao là "bé đi",
      không giao đổi nút.

   ⛔ "MỞ DẦN RA" CHỈ CHẠY TRÊN `transform` + `opacity`. Chạy trên `width` là
      trình duyệt tính lại bố cục mỗi khung hình, và bảng này 18 lớp × 54 tuần.
      `scale` làm `getBoundingClientRect().width` đổi dần thật, nên đo được — chứ
      không phải "có khai hiệu ứng" là xong (có vẽ ≠ số có đổi).
   ⛔⛔ VÀ `pointer-events` KHÔNG PHỤ THUỘC LỚP `lt2-vao`. Bài học đắt cùng ngày:
      thanh định dạng bảng gắn "đã rõ hẳn" bằng `transitionend`, nên máy bật
      "giảm chuyển động" (`transition:none` ⇒ sự kiện ấy không bao giờ nổ) là nút
      In đậm chết HẲN. Ở đây bấm được từ nhịp đầu, lớp kia chỉ đổi hình.
   ════════════════════════════════════════════════════════════════════════════ */

/* Bóp ngang: ô gõ trên, nút dưới. Luật này đứng SAU luật gốc (~10867) nên thắng —
   cố ý viết ở cuối file, không sửa một dòng nào của khối cũ. */
.lt2-bang td.lt2-o:focus-within .lt2-sua-boc {
  flex-direction: column;
  align-items: stretch;
  gap: 3px;
  /* ⛔ Sàn/trần bề rộng do `lt2CoORong` đo từ ô thật mà đặt lên chính ô gõ —
     ở đây KHÔNG gõ một con số nào, để hai nơi khỏi đá nhau. */
  /* ⛔⛔ DÙNG `@keyframes`, KHÔNG dùng `transition` + một lớp gắn sau.
     Ca thử phá B (12/09): chặn lớp `lt2-vao` bám vào — tức giả lập nhịp
     `requestAnimationFrame` không tới — thì hộp NẰM MÃI ở `opacity .4`,
     `scale .62`. Bấm vẫn được (đo ra `true`), nhưng mờ vĩnh viễn là một
     trạng thái kẹt, và đó đúng họ hàng với lỗi nút "In đậm" cùng ngày:
     trạng thái cuối treo vào một sự kiện có thể không bao giờ nổ.
     `@keyframes … both` tự chạy ngay khi thẻ vào DOM: không cần lớp, không
     cần rAF, không có đường nào kẹt. */
  /* ⛔⛔ KHÔNG CÓ HIỆU ỨNG MỞ — Boss chốt 20/09/2026.
     Bản 12/09 cho hộp nở dần ra bằng `animation: lt2MoDanRa .2s` (từ `scale .62`,
     `opacity .4`). Boss báo *"nó nháy 1 phát hiện rõ ra nút tự tạo"*; hỏi lại bằng
     nút bấm, đưa đúng hiệu ứng này ra, Boss chọn **"Đúng nó — bỏ hiệu ứng đi"**.
     Với một ô bảng cao 32px thì cú nở ấy đọc ra đúng là một cái nháy chứ không
     phải chuyển động mềm mắt.
     ⛔ ĐỪNG THÊM LẠI, kể cả dưới dạng `transition`. Lý do cũ (chống kẹt trạng thái
        vì `transitionend` có thể không bao giờ nổ) nay không còn chỗ bám: không có
        hiệu ứng thì không có trạng thái nào để kẹt — hộp vào DOM là hiện đủ, rõ,
        bấm được ngay từ nhịp đầu. */
}

/* ══════════════════════════════════════════════════════════════════════════════
   NUT "TU TAO" BI CAT KHOI HOP — do ra 19/09/2026
   ------------------------------------------------------------------------------
   Boss: *"toi thay nut tu tao ko the hien len duoc"*.
   SO DO (do-lt.js muc 4): nut CO that, 48x24px, display block, do mo 1, nam tron
   trong man — moi phep canh "co hien khong" deu XANH. Nhung `elementsFromPoint`
   ngay giua nut tra ve mot o tuan o HANG KHAC, va trong ca chong khong he co nut.
   Hinh hoc noi ro vi sao: hop `.lt2-sua-boc` do duoc **54x22px** (day o 286), con
   nut nam o **291-315** — tuc nut ROI RA NGOAI HOP roi bi xen mat.
   Hai luat dung chung cua bo Sheet gay ra:
     · `.sheet-moi tbody tr.sheet-hang td > * { max-height: 22px }` — dung 22px ay,
     · va `overflow:hidden` cua chinh cai boc.
   Chung viet cho o MOT DONG. Ngay 12/09 hop doi sang xep DOC (o go tren, nut duoi)
   de khoi trum qua bon cot tuan ben canh — tu do nut tut xuong duoi tran 22px va bi
   cat. Dung bai hoc da ghi ngay trong file nay: noi be ngang xong thi loi roi xuong
   chieu DOC, ma phep canh cu chi do chieu ngang nen van xanh.
   Cot chu (`lt2-c-lt`) da duoc mien `overflow` tu 11/09 (css:11883) — o so bi bo
   quen, dung nhu loi dan o day da noi truoc: *"o so cua Dot 2 giu nguyen nep cu"*.
   ⛔ SUA O DAY, DUNG NOI LONG HAI LUAT DUNG CHUNG: `max-height:22px` la thu giu cho
      54 cot tuan cao deu nhau; go no o goc la ca bang Diem danh va Cham soc gian ra.
   ⛔ PHEP CANH PHAI LA `elementsFromPoint`, dung `display`/`opacity`/`getBoundingRect`
      — ca ba deu dep trong khi nut da chet. Xem muc 4 cua `do-lt.js`. */
.lt2-bang td.lt2-o:focus-within > .lt2-sua-boc { max-height: none; overflow: visible; }

/* Nút trải hết bề ngang hộp cho dễ bấm — xếp dọc rồi thì không tốn chỗ ngang nữa. */
.lt2-bang td.lt2-o:focus-within .lt2-tutao { width: 100%; }
/* ⛔ Có TRẦN bề rộng thì phải cho cuộn ngang trong ô, không thì gõ quá trần là chữ
   cuối bị cắt mà không một dấu hiệu nào. */
.lt2-bang td.lt2-o:focus-within .lt2-sua { overflow-x: auto; }

/* (Khối `@media (prefers-reduced-motion: reduce)` đặt `animation: none` cho hộp gõ
   đã gỡ 20/09/2026 cùng lúc với hiệu ứng: không còn chuyển động nào thì không còn
   gì để tắt, và mọi máy nay đều hiện ngay như nhau.) */

/* ══════════════════════════════════════════════════════════════════════════════
   ⛔⛔ Ô THÂN CỘT "LỚP" PHẢI GIỮ `sticky` — vá 20/09/2026, đo trên dữ liệu thật
   ──────────────────────────────────────────────────────────────────────────────
   Boss: *"cột cố định phải đi theo hướng tôi kéo nhưng đây lại ở yên 1 chỗ ban đầu
   nên tạo ra khoảng trắng đó"*, và khi hỏi lại thì chỉ rõ: chỉ mỗi cột Lớp đứng
   yên còn ba cột kia trôi — hoá ra ngược lại, chính ô THÂN cột Lớp mới là cái trôi.

   SỐ ĐO THẬT (bản sao kho thật, 127 lớp, màn 1920, đã kéo ngang 900px):
       hàng tiêu đề  lt2-g1  position: sticky    thấy   66 →  278   đứng yên
       hàng thân     lt2-g1  position: relative  thấy -834 → -622   TRÔI RA NGOÀI
                     lt2-c-coso  sticky          thấy  278 →  366   đứng yên
   Ô tiêu đề "Lớp" đứng yên, ô thân trôi đi mất, để lại đúng mảng trắng Boss thấy —
   và cột "Buổi mỗi tuần" trôi qua thì hiện ra ngay trong chỗ trống ấy.

   HAI LUẬT TRANH NHAU:
       :where(.sheet-moi.sheet-so-dong) tbody tr.sheet-hang td:first-child
           { position: relative }             (0,2,3)  ← css:13284, THẮNG
       .lt2-bang .lt2-g1 { position: sticky }  (0,2,0)  ← css:11635
   `:where()` chỉ hạ độ đặc hiệu của PHẦN TRONG NGOẶC; phần còn lại
   `tbody tr.sheet-hang td:first-child` vẫn tính (0,2,3) nên nó vẫn thắng. Chú thích
   ở css:13265 tưởng `:where()` nhường được `position` cho luật ghim cột tên — đo ra
   thì không.

   ⛔⛔ VÌ SAO SÁU LƯỢT ĐO TRƯỚC ĐÓ ĐỀU XANH: luật kia chỉ áp khi bảng mang class
      `sheet-so-dong`, mà dải số dòng chỉ BẬT khi ô đầu rộng từ 150px
      (`sheetCotSoDong` trong js/tinh-nang.js). Sân đo giả để cột Lớp 126px → dải số
      TẮT → luật không bao giờ chạm tới. Màn Boss cột Lớp 212px → BẬT.
      Đây đúng là lý do Boss ra luật *"làm việc phải vào localhost thao tác ở trong
      để rõ bệnh có gì ở đâu"*.

   ⛔ ĐỪNG GỠ `position:relative` Ở GỐC (css:13284). Nó là chỗ neo của `::before` vẽ
      số dòng, và đang phục vụ MỌI bảng kiểu Sheet trong app. `sticky` cũng là thẻ
      CÓ ĐỊNH VỊ nên số dòng vẫn neo đúng — sửa ở đây, đúng một bảng.
   ⛔ Độ đặc hiệu phải ĐỦ (0,2,3) mới thắng; viết ngắn hơn là thua và lỗi quay lại
      mà bài kiểm vẫn xanh (vì bài kiểm đọc chữ, không đo thẻ thật).
   ══════════════════════════════════════════════════════════════════════════════ */
.lt2-bang tbody tr.sheet-hang td.lt2-g1 {
  position: sticky;
  left: 0;
}

/* ══════════════════════════════════════════════════════════════════════════════
   🧭 HƯỚNG MỞ CỦA HỘP GÕ — Designer soi ảnh bắt được 12/09/2026
   ──────────────────────────────────────────────────────────────────────────────
   Cú bóp ngang ở khối trên ĐÃ đúng, nhưng nó đẩy lỗi sang chiều DỌC: hộp xếp dọc
   cao 61–67px mà ô tuần chỉ cao 32–35px, lại neo `top:50%` + `translateY(-50%)`
   (căn giữa ô), nên hộp thò đều hai phía ~13–16px. Thò LÊN thì che mất chữ ngày
   ở đầu cột — Designer thấy «27/7» bị phủ gần hết trong ảnh. Đó không phải thò
   vào chỗ trống: mất chữ ngày là mất thông tin "mình đang gõ vào tuần nào".
   ⛔ Đúng bài `phep-canh-mot-chieu-chung-nhan-loi-chieu-kia`: nới ngang xong thì
      lỗi rơi xuống dọc, mà phép canh cũ chỉ đo ngang nên vẫn xanh.

   CÚ SỬA: thôi căn giữa ô — THẢ XUỐNG TỪ ĐÁY Ô. Dưới hết chỗ thì `lt2ChonHuongMo`
   gắn `data-lt2-len="1"` để bật lên trên.
   ⛔ MẶC ĐỊNH LÀ THẢ XUỐNG, cố ý: JS chưa chạy (hay chạy muộn) thì hộp vẫn ở
      hướng an toàn. Che một phần hàng dữ liệu bên dưới thì người ta vẫn đọc được
      dòng tiêu đề; che dòng tiêu đề là mất hẳn thông tin đang cần.
   ════════════════════════════════════════════════════════════════════════════ */
/* ⛔⛔ SỬA LẠI 20/09/2026 — `top:0`, KHÔNG PHẢI `top:100%`.
   Bản 12/09 thả hộp xuống từ ĐÁY ô (`top:100%`). Nó chữa được nửa bệnh (hết che
   chữ ngày ở đầu cột) nhưng đẻ ra nửa khác, và Boss bắt đúng nửa ấy:
   *"ấn vào các ô ở cột tháng tuần nó vẫn bị xung đột với giao diện tự tạo cũ"*.
   ẢNH CHỤP THẬT (`soi2.png`, sân 142 lớp, màn 1920): bấm ô ở HÀNG 2 mà chỗ gõ
   hiện ở HÀNG 3, nút "Tự tạo" rơi tận HÀNG 4 — lơ lửng giữa bảng, nền trắng của
   hộp che mất cả hai hàng dưới.
   Số đo khớp: ô 231→263 (cao 32) · hộp 264→325 (cao 61) ⇒ hộp nằm TRỌN bên dưới ô.
   ⛔ Bấm ô này mà chữ hiện ở ô khác thì đúng là "xung đột" theo nghĩa đen — chỗ gõ
      PHẢI nằm ngay trên ô mình vừa bấm.
   Nay mép TRÊN hộp trùng mép TRÊN ô: chỗ gõ phủ đúng ô, chỉ phần thừa (nút "Tự
   tạo") tràn xuống, che MỘT hàng thay vì hai, và vẫn không che chữ ngày đầu cột. */
.lt2-bang td.lt2-o:focus-within .lt2-sua-boc {
  top: 0;
  bottom: auto;
  /* ⛔ CHỈ còn translateX: chiều dọc nay do `top`/`bottom` lo. Để lại
     `translateY(-50%)` là hộp tụt lên nửa thân mình và che lại đúng chỗ vừa gỡ. */
  transform: translateX(-50%);
  transform-origin: top center;
  margin-top: 0;
}
/* Bật lên trên — chỉ khi `lt2ChonHuongMo` đo thấy dưới hết chỗ mà trên còn đủ.
   Mép DƯỚI hộp trùng mép DƯỚI ô, đối xứng với hướng thả xuống ở trên. */
.lt2-bang td.lt2-o[data-lt2-len="1"]:focus-within .lt2-sua-boc {
  top: auto;
  bottom: 0;
  transform-origin: bottom center;
  margin-top: 0;
  margin-bottom: 0;
}

/* ══════════════════════════════════════════════════════════════════════════════
   ⛔⛔ HỘP GÕ PHẢI NỔI KỂ CẢ KHI KHÔNG CÒN CON TRỎ — vá 20/09/2026
   ──────────────────────────────────────────────────────────────────────────────
   Boss tả đúng ca lỗi bằng nút bấm: *"lúc đầu ấn vào 1 ô bất kì không sao, ấn ô
   THỨ HAI lại bị, bất kì ô nào cũng có"* và *"cột có ô vừa ấn đó nó MỞ RỘNG RA cho
   cái nút cũ hiện ra trong chốc lát rồi biến mất, cột đó quay lại, tạo ra cảm giác
   giống chớp nháy"*.

   SỐ ĐO THẬT (bản sao kho thật 127 lớp, màn 1920, ghi từng khung hình):
       bấm ô A (lần đầu)      41ms   bảng 4462px   cột tuần [56]      hộp absolute
       bấm sang ô B           32ms   bảng 4510px   cột tuần [56,104]  hộp STATIC 95x22
                              74ms   bảng 4462px   cột tuần [56]      hộp biến mất
   Tức trong ~42ms hộp của ô CŨ nằm chen INLINE trong ô, đẩy cột tuần từ 56 lên
   104px và cả bảng nở thêm 48px, rồi bị xoá và bảng thu lại — đúng cú chớp nháy.

   VÌ SAO: mọi luật cho hộp "nổi" đều treo vào `:focus-within`. Bấm sang ô khác thì
   ô cũ MẤT CON TRỎ NGAY, `:focus-within` hết ăn tức thì, nhưng thẻ hộp còn sống
   thêm một nhịp cho tới khi `lt2DongSua` vẽ lại ruột ô. Một nhịp không luật ⇒ về
   `position: static` mặc định ⇒ chiếm chỗ thật trong ô.
   VÌ SAO LẦN ĐẦU KHÔNG SAO: chưa có ô nào đang mở nên chẳng có hộp cũ nào phải đóng.

   CỦA SỬA: lặp lại đúng các thuộc tính ĐỊNH VỊ + XẾP DỌC ở một bộ chọn KHÔNG cần
   `:focus-within`. Hộp `.lt2-sua-boc` trong `td.lt2-o` chỉ do `lt2MoSuaO` đẻ ra, nên
   nó có mặt nghĩa là ô đang mở — không cần hỏi con trỏ ở đâu nữa.

   ⛔ ĐỪNG GỠ CÁC LUẬT `:focus-within` Ở TRÊN. Chúng (0,4,1) cao hơn luật này
      (0,3,1) và mang giá trị Y HỆT, nên lúc có con trỏ không đổi gì; giữ nguyên để
      người đọc sau vẫn thấy mạch cũ, và để gỡ nhầm một bên không làm hỏng cả hai.
   ⛔ ĐỪNG chữa bằng cách đổi `lt2MoSuaO` sang xoá ruột ô cũ trước: nhịp vẽ nằm
      trong tay trình duyệt, mã không hẹn được nó. Chữa ở CSS thì dù hộp còn sót bao
      lâu cũng không chiếm một ly nào của bố cục.
   ══════════════════════════════════════════════════════════════════════════════ */
.lt2-bang td.lt2-o .lt2-sua-boc {
  position: absolute;
  left: 50%;
  top: 0;
  bottom: auto;
  transform: translateX(-50%);
  transform-origin: top center;
  margin: 0;
  width: auto;
  max-width: min(300px, 60vw);
  z-index: 7;
  padding: 3px;
  background: var(--the);
  border-radius: var(--r-sm, 4px);
  box-shadow: 0 2px 10px rgba(0,0,0,.18);
  flex-direction: column;
  align-items: stretch;
  gap: 3px;
  max-height: none;
  overflow: visible;
}
/* Hướng bật lên — bản không cần con trỏ, đối xứng với luật `:focus-within` ở trên. */
.lt2-bang td.lt2-o[data-lt2-len="1"] .lt2-sua-boc {
  top: auto;
  bottom: 0;
  transform-origin: bottom center;
}
/* Ruột hộp cũng phải giữ nguyên cỡ, không thì hộp đổi hình trong chính nhịp ấy. */
.lt2-bang td.lt2-o .lt2-sua { height: 28px; font-size: 13px; text-align: left;
  overflow-x: auto; }
.lt2-bang td.lt2-o .lt2-tutao { width: 100%; }

/* ══════════════════════════════════════════════════════════════════════════════
   ⛔⛔ SỔ TUYỂN SINH: BẢN ĐIỆN THOẠI ÁP NHẦM LÊN MÁY TÍNH ĐANG PHÓNG TO
   ── vá 20/09/2026, Boss báo và đo lại tái hiện được ──────────────────────────
   Boss: *"tôi chỉnh lại về 100% thì không sao, còn để dưới 100% hoặc trên 100%
   thì bị"*, và gửi ảnh so hai bên: trong Chrome có VẠCH ĐẬM ngay sau cột "Tên HS"
   rồi HỞ ra một mảng trắng, còn cửa sổ rộng hơn thì liền mạch.

   Vạch đậm sau "Tên HS" là DẤU VÂN TAY của bản điện thoại: khối
   `@media screen and (max-width:820px)` (css:8955) cố ý bỏ ghim bốn cột, chỉ giữ
   `.cts-g3` (Tên HS) làm neo, và dời vạch đậm sang nó. Thiết kế ấy ĐÚNG cho điện
   thoại — vùng ghim cộng lại 836px mà màn chỉ 390px thì bảng đứng im hoàn toàn.

   CHỖ SAI: ngưỡng `max-width` đếm theo LY CSS, mà phóng to trình duyệt làm số ly
   ấy NHỎ ĐI. Màn 1920 thật, phóng 250% ⇒ còn 768 ly CSS ⇒ lọt xuống dưới 820 ⇒
   máy tính để bàn lại chạy bản điện thoại. Người dùng không hề đổi máy, chỉ bấm
   Ctrl+cộng cho chữ to dễ đọc.

   ĐO LẠI TÁI HIỆN ĐƯỢC (bản sao dữ liệu thật 4.652 lượt, Chrome thật, cửa sổ 800):
       kéo sang  900px ⇒ HỞ  592px trước cột 2
       kéo sang 2000px ⇒ HỞ 1692px
       kéo sang 3500px ⇒ HỞ 3192px
   Cùng bài ấy ở cửa sổ 1400/1920/2179/2560 thì khít — đúng lời Boss: chỉ lệch khỏi
   100% mới bị.

   CỦA SỬA: phân biệt "màn hình THẬT nhỏ" với "màn to đang phóng" bằng thứ không
   đổi theo mức phóng — KIỂU CON TRỎ. Điện thoại và máy tính bảng có `hover: none`
   + `pointer: coarse`; máy tính có chuột thì `hover: hover` + `pointer: fine` dù
   phóng bao nhiêu. Nên chỗ nào là máy tính thì trả lại đủ năm cột ghim.

   ⛔ ĐỪNG SỬA TRONG KHỐI `max-width:820px` Ở TRÊN. Khối ấy dài 600 dòng và lo cho
      CẢ NĂM công cụ; đụng vào là đổi bố cục điện thoại của bốn màn không liên quan.
      Ở đây chỉ KHÔI PHỤC lại đúng những thuộc tính khối ấy đã đổi, cho riêng máy tính.
   ⛔ ĐỪNG nâng ngưỡng 820 lên cho "chắc": điện thoại ngang màn rộng tới 900+ ly CSS
      vẫn phải chạy bản điện thoại.
   ⛔ Boss chốt 20/09 bằng nút bấm: **"Năm cột đứng yên ở MỌI mức phóng"** — không
      được bớt cột ghim để né lỗi.
   ══════════════════════════════════════════════════════════════════════════════ */
@media screen and (max-width: 820px) and (hover: hover) and (pointer: fine) {
  /* Trả lại ghim cho bốn cột bị khối điện thoại đẩy về `static`. */
  .cts-bang tbody .cts-g1, .cts-bang tbody .cts-g2, .cts-bang tbody .cts-g4,
  .cts-bang tbody .cts-g5, .cts-bang tbody .cts-g6 { position: sticky; }
  /* Trả lại mốc `left` cho hàng tiêu đề (khối kia đặt `left:auto`), và trả z-index
     về đúng thang bậc của bộ Sheet. */
  /* ⛔ PHẢI ĐẶT `left` CHO CẢ THÂN BẢNG, KHÔNG CHỈ HÀNG TIÊU ĐỀ. Bản vá đầu chỉ
     đặt cho `thead` và đo ra: hàng tiêu đề khít, còn hàng thân HỞ đúng bằng quãng
     đã kéo (900 → 900px · 2000 → 2000px · 3500 → 3500px) — tức ô thân trôi theo
     tay. Đúng bài học của Lộ trình sáng nay: ô tiêu đề đứng yên tử tế trong khi ô
     thân trôi mất, và ô thân mới là thứ người dùng nhìn thấy. */
  .cts-bang .cts-g1, .cts-bang thead .cts-g1 { left: 0; }
  .cts-bang .cts-g2, .cts-bang thead .cts-g2 { left: var(--g2, 0px); }
  .cts-bang .cts-g4, .cts-bang thead .cts-g4 { left: var(--g4, 0px); }
  .cts-bang .cts-g5, .cts-bang thead .cts-g5 { left: var(--g5, 0px); }
  .cts-bang .cts-g6, .cts-bang thead .cts-g6 { left: var(--g6, 0px); }
  .cts-bang thead .cts-g1, .cts-bang thead .cts-g2, .cts-bang thead .cts-g4,
  .cts-bang thead .cts-g5, .cts-bang thead .cts-g6 { z-index: 6; }
  /* Cột neo của bản điện thoại bị ghim cứng `left:0`; trả nó về mốc thật. */
  .cts-bang .cts-g3       { left: var(--g3, 0px); }
  .cts-bang thead .cts-g3 { left: var(--g3, 0px); z-index: 6; }
  /* Vạch dày "bên trái đứng yên, bên phải trôi" trở lại cột ghim CUỐI (g5),
     và cột Tên HS thôi mang vạch dày. Số cột ghim và chỗ đặt vạch đi thành MỘT CẶP. */
  .cts-bang .cts-g3, .cts-bang thead .cts-g3 { border-right: 1px solid var(--vien); }
  .cts-bang .cts-g5, .cts-bang thead .cts-g5 { border-right: 2px solid var(--muc); }
  /* ⛔⛔ Ô THÂN CỘT ĐẦU BỊ DẢI SỐ DÒNG ĐẨY VỀ `relative` NÊN TRÔI — đo 20/09/2026:
         THÂN  cột TVTS  thấy -886 → -696  position: relative   TRÔI RA NGOÀI MÀN
               bốn cột kia                 position: sticky     đứng yên
     Thủ phạm là luật dùng chung của dải số dòng:
         :where(.sheet-moi.sheet-so-dong) tbody tr.sheet-hang td:first-child
             { position: relative }          (0,2,3)  ← thắng
     `:where()` chỉ hạ độ đặc hiệu của phần TRONG ngoặc; phần còn lại vẫn (0,2,3).
     Đúng con bệnh đã chữa cho Lộ trình sáng nay (commit 127e760).
     Ở màn từ 821px trở lên, luật css:8932 `.cts-bang tbody td.cts-tv.cts-g1` đã lo
     việc này rồi; khối ấy bọc trong `min-width:821px` nên dưới ngưỡng là hở ra.
     ⛔ ĐỪNG gỡ `position:relative` ở gốc: nó là chỗ neo của `::before` vẽ số dòng
        cho MỌI bảng kiểu Sheet. `sticky` cũng là thẻ có định vị nên số dòng vẫn neo đúng. */
  .cts-bang tbody tr.sheet-hang td.cts-g1 { position: sticky; left: 0; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   SỔ TUYỂN SINH Ở KHUNG HẸP — CHỈ GHIM TÊN HS (Boss chốt 08/10/2026)
   ──────────────────────────────────────────────────────────────────────────────
   Lớp `cts-hep` trên `#ctsCuon` do JS bật khi năm cột ghim nuốt quá 75% bề ngang khung
   (xem `ctsApHep`, man-hinh/tuyen-sinh.js). Bám KHUNG chứ không bám bề ngang màn hình:
   cửa sổ máy tính kéo hẹp, bảng thu 80%, điện thoại — đều cùng một phép đo.
   ⛔ Đứng NGOÀI mọi `@media`, và bám `#ctsCuon` (một id) để thắng cả ba nơi đang đặt ghim:
      man.css `.cts-bang .cts-gN` · khối điện thoại `max-width:820px` · khối vá 20/09 ngay
      trên (`.cts-bang tbody tr.sheet-hang td.cts-g1`, 0,3,3).
   ⛔ Cột TVTS giữ `relative` chứ không `static`: nó là ô đầu dòng, chỗ neo `::before` của
      dải số dòng dùng chung. `left:auto` để `relative` không dịch ô đi đâu cả. */
#ctsCuon.cts-hep .cts-bang tbody td.cts-g1 { position: relative; left: auto; }
#ctsCuon.cts-hep .cts-bang tbody td.cts-g2, #ctsCuon.cts-hep .cts-bang tbody td.cts-g4,
#ctsCuon.cts-hep .cts-bang tbody td.cts-g5, #ctsCuon.cts-hep .cts-bang tbody td.cts-g6 { position: static; }
#ctsCuon.cts-hep .cts-bang thead th.cts-g1, #ctsCuon.cts-hep .cts-bang thead th.cts-g2,
#ctsCuon.cts-hep .cts-bang thead th.cts-g4, #ctsCuon.cts-hep .cts-bang thead th.cts-g5,
#ctsCuon.cts-hep .cts-bang thead th.cts-g6 { left: auto; z-index: 9; }
#ctsCuon.cts-hep .cts-bang .cts-g3 { position: sticky; left: 0; border-right: 2px solid var(--muc); }
#ctsCuon.cts-hep .cts-bang thead th.cts-g3 { z-index: 10; }
#ctsCuon.cts-hep .cts-bang .cts-g5 { border-right: 1px solid var(--vien); }

/* ⚡ CUỘN MƯỢT 08/10/2026 — tắt chế độ TỰ GIỮ CHỖ ĐANG NHÌN của trình duyệt (scroll
   anchoring) cho khung sổ. Từ ngày ấy lăn lên chỉ CHÈN THÊM dòng phía trên (`ctsVeTiep`),
   dòng đang nhìn vẫn nằm nguyên trên trang ⇒ Chrome tự kéo scrollTop bù phần chèn, rồi
   `ctsDoTungDong` lại bù thêm một lần nữa ⇒ dòng nhảy 16–48px (bài thu-cts-du-ten-25-09 bắt
   được). Để MỘT bên lo: mã tự bù — chạy y hệt trên Chrome, Firefox, Safari (Safari không
   có scroll anchoring). */
#ctsCuon { overflow-anchor: none; }

/* ══════════════════════════════════════════════════════════════════════════════
   🧩 HAI NÚT «KIỂU BÀY SỔ» — Boss chốt 08/10/2026 (man-hinh/tuyen-sinh.js, khối 🧩 trên
   `ctsKieuSo`). Màu theo thiet-ke/BANG-MAU-VA-CHU.md: chip xám `--nen2` + viền `--vien`, bo
   `--r-sm` (4px — "ô nhỏ, nhãn, chip"), chữ 11px "chú thích nhỏ".
   ══════════════════════════════════════════════════════════════════════════════ */
/* ① Ô «Tổng học phí»: nút phủ cả ô, số ĐẬM sát mép PHẢI như Excel; «có hoàn» đứng trái và
      là thứ bị cắt trước khi ô hẹp — số tiền không bao giờ bị cắt. */
#ctsCuon .cts-tien-nut.cts-tien-tong { width: 100%; justify-content: flex-end; }
#ctsCuon .cts-tien-tong .cts-tien-mt { flex: none; }
#ctsCuon .cts-tien-tong .cts-tien-lan { flex: none; font-size: 11.5px; color: var(--mo);
  font-variant-numeric: tabular-nums; white-space: nowrap; }
#ctsCuon .cts-tien-tong .cts-tien-hoan { flex: 0 1 auto; min-width: 0; margin-right: auto;
  overflow: hidden; white-space: nowrap; font-size: 11px; color: var(--do); }
/* ② Chip mã dưới tên — bấm là chép mã.
      Dòng cao ĐÚNG ~40px (Boss chốt "~30 → ~40"): đệm 4 + dòng tên 20 − 2 + chip 13 + đệm 4 + kẻ 1.
      ⛔ Viền vẽ bằng `box-shadow` trong, KHÔNG `border` — viền thật cộng 2px vào chiều cao mọi dòng.
      ⛔ `margin-top:-2px` chỉ ăn vào khoảng trống dưới chân dòng tên (dòng 20px, chữ 13px); mã là
         chữ in + số, không có nét thò xuống nên không chạm tên. Đo Chrome thật: 48px → 40px. */
#ctsCuon .cts-ma-chip { display: block; width: fit-content; max-width: 100%; margin-top: -2px;
  padding: 0 5px; font-size: 11px; line-height: 13px; color: var(--mo); background: var(--nen2);
  box-shadow: inset 0 0 0 1px var(--vien); border-radius: var(--r-sm); white-space: nowrap;
  font-variant-numeric: tabular-nums; cursor: pointer; }
#ctsCuon .cts-ma-chip:hover { color: var(--chu); box-shadow: inset 0 0 0 1px var(--vien-ro); }
/* Hộp «Màu và cột»: hai nút bật/tắt. Trạng thái nói bằng CHỮ («Đang bật») chứ không chỉ bằng màu. */
.cts-kieu-hang { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px;
  padding: 7px 0; border-bottom: 1px solid var(--vien); }
.cts-kieu-nut[aria-pressed="true"] { background: var(--xanh); border-color: var(--xanh); color: #fff; }
body.toi .cts-kieu-nut[aria-pressed="true"] { color: #0F1A1C; }
.cts-kieu-tt { font-size: 12px; color: var(--mo); }
.cts-kieu-nut[aria-pressed="true"] + .cts-kieu-tt { color: var(--o-tot); font-weight: 600; }
.cts-kieu-ta { flex-basis: 100%; font-size: 12px; color: var(--mo); }
/* Hộp Tổng học phí: dòng «Đã đóng N lần». */
.cts-tien-dem { margin: 0 0 8px; font-weight: 600; }

/* ══════════════════════════════════════════════════════════════════════════════
   👪 BA Ô GOM THÀNH BLOCK — Boss chốt 09/10/2026 (man-hinh/tuyen-sinh.js, khối 👪 trên
   `ctsGomHSHtml`). Block cùng họ chip mã 08/10: nền `--nen2`, viền trong `--vien`, bo `--r-sm`,
   chữ 11px. Bố xanh nước biển, Mẹ hồng — Boss chốt; hai sắc có bản nền tối riêng.
   ⛔ Viền block vẽ bằng `box-shadow` trong, không `border` — viền thật cộng 2px cho mọi dòng.
   ⛔ Block mờ «+ …» ẨN bằng `visibility` (giữ chỗ) — xem khối 👪 bên JS: dòng phải giữ nguyên
      chiều cao khi rê chuột, cuộn ảo đo chiều cao từng dòng. Giữ chỗ thì phải đứng CUỐI hàng
      (`ctsNoiKhoi`); cây bút thì dính liền block và luôn hiện (`ctsKhoiCap`).
   ⛔ Chữ block mờ / nhãn link vẽ bằng `::before content:attr(data-nhan)` — không vào textContent,
      Ctrl+C chép ô không lẫn chữ mồi.
   ══════════════════════════════════════════════════════════════════════════════ */
/* Hai màu Bố (xanh nước biển) / Mẹ (hồng) — Boss chốt, bảng màu chung chưa có hai sắc này. Khai
   MỘT chỗ (sáng + tối), mọi luật khác chỉ dùng `var(--vai-bo)` / `var(--vai-me)`. Đặt đúng ba khung
   dùng chúng: bảng sổ · hộp nhỏ cạnh block (`#ctsKhoiHop`) · hộp thoại chung (`#htThan`, hộp Thêm học
   sinh). ⛔ Đừng khai trên thẻ trần `body` — đè cả app (thu-css-khong-de-len-nen-chung). */
#ctsCuon, #ctsKhoiHop, #htThan { --vai-bo: #1F6FD1; --vai-me: #D63F8C; }
body.toi #ctsCuon, body.toi #ctsKhoiHop, body.toi #htThan { --vai-bo: #6AA9F2; --vai-me: #F08DBE; }
/* Ô gom xuống dòng, chữ bám đỉnh ô. (0,2,4) — thắng `.sheet-moi tbody tr.sheet-hang td` (0,2,3). */
table.cts-bang>tbody>tr>td.cts-gom { white-space: normal; overflow-wrap: anywhere; vertical-align: top;
  padding-top: 4px; padding-bottom: 4px; line-height: 18px; }
#ctsCuon .cts-tach, #ctsCuon .cts-an-chep { display: none; }
/* ⛔ `max-height:none` + `overflow:visible`: cụm bảng Sheet ghim `td > * { max-height:22px }` (0,2,3)
      và `.bang-keo-cot td > span { overflow:hidden }` — hàng block xuống dòng thứ hai bị kẹp 22px,
      dòng sau TRÀN ra ngoài đáy ô và bị dòng dưới đè thành một vạch xén (đo ảnh Chrome 09/10). */
#ctsCuon .cts-khoi-dong, #ctsCuon .cts-ph-dong { display: flex; flex-wrap: wrap; align-items: center; gap: 3px 4px;
  max-height: none; overflow: visible; }
#ctsCuon .cts-bang td.cts-gom > * { max-height: none; }
#ctsCuon .cts-khoi-dong { margin-top: 2px; }
#ctsCuon .cts-ph-dong + .cts-ph-dong { margin-top: 2px; }
#ctsCuon .cts-khoi { display: inline-flex; align-items: center; max-width: 100%; min-height: 17px; box-sizing: border-box;
  padding: 1px 5px; margin: 0; border: 0; font: inherit; font-size: 11px; line-height: 15px; text-align: left;
  color: var(--mo); background: var(--nen2); box-shadow: inset 0 0 0 1px var(--vien); border-radius: var(--r-sm);
  white-space: normal; overflow-wrap: anywhere; font-variant-numeric: tabular-nums; text-decoration: none; cursor: pointer; }
#ctsCuon span.cts-khoi { cursor: default; }
#ctsCuon button.cts-khoi:hover, #ctsCuon a.cts-khoi:hover { color: var(--chu); box-shadow: inset 0 0 0 1px var(--vien-ro); }
#ctsCuon .cts-khoi:focus-visible, #ctsCuon .cts-khoi-but:focus-visible, #ctsCuon .cts-vai:focus-visible {
  outline: 2px solid var(--muc); outline-offset: 1px; }
/* ⛔ Block «bé bé» (Boss) cao 17px như chip mã HS 08/10. ĐỪNG nới chỗ bấm bằng lớp vô hình
      `::after` thò ra trên/dưới: nó làm ô TRÀN 1px ⇒ bảng dùng chung coi là «ô bị cắt chữ»
      (`sheetOBiCatChu`), bấm block là bật khung xem, cú bấm sau vào bút rơi vào khung và mở ô
      sửa Nguồn (đo Chrome 09/10, thu-cts-gom-cot-09-10 bắt được). */
/* Số điện thoại và link: chữ đậm hơn — đây là thứ người ta bấm nhiều nhất. */
#ctsCuon .cts-khoi-sdt, #ctsCuon .cts-khoi-link { color: var(--chu); white-space: nowrap; }
#ctsCuon .cts-khoi-link::before { content: attr(data-nhan); }
#ctsCuon .cts-khoi-link:hover { text-decoration: underline; }
/* Dòng chữ cũ trong ô link (không phải link): một dòng, rê chuột vào là hiện đủ. */
#ctsCuon .cts-khoi-chu { white-space: nowrap; overflow: hidden; text-overflow: clip; }
#ctsCuon .cts-khoi-chu:hover { white-space: normal; }
/* Tên phụ huynh thứ hai là TÊN, không phải chip. */
#ctsCuon .cts-khoi.cts-khoi-ten { padding: 0; background: transparent; box-shadow: none; font-size: inherit;
  line-height: 18px; color: var(--chu); }
#ctsCuon .cts-khoi.cts-khoi-ten:hover { box-shadow: none; text-decoration: underline; }
/* Block mờ «+ …»: viền đứt, chỉ hiện khi rê chuột vào dòng (điện thoại: khi chạm dòng). */
#ctsCuon .cts-khoi-them { visibility: hidden; background: transparent; box-shadow: none;
  outline: 1px dashed var(--vien-ro); outline-offset: -1px; color: var(--mo); white-space: nowrap; }
#ctsCuon .cts-khoi-them::before { content: attr(data-nhan); }
#ctsCuon .cts-khoi-them:hover { color: var(--muc); outline-color: var(--muc); box-shadow: none; }
/* Chip HAI NGĂN «SĐT | bút» · «Facebook | bút»: ngăn trái làm việc chính (chép số / mở link), ngăn
   phải là bút sửa. Bút luôn hiện, mờ — ẩn mà giữ chỗ là thành lỗ hổng giữa hàng (ảnh Chrome 09/10). */
#ctsCuon .cts-khoi-cap { display: inline-flex; align-items: stretch; max-width: 100%; }
#ctsCuon .cts-khoi-cap > .cts-khoi { min-width: 0; border-top-right-radius: 0; border-bottom-right-radius: 0; }
#ctsCuon .cts-khoi-but { flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 20px; min-width: 0; height: auto; min-height: 0; padding: 0; margin: 0 0 0 -1px; border: 0;
  background: var(--nen2); box-shadow: inset 0 0 0 1px var(--vien); border-radius: 0 var(--r-sm) var(--r-sm) 0;
  color: var(--mo); cursor: pointer; }
#ctsCuon .cts-khoi-but i { width: 11px; height: 11px; }
#ctsCuon .cts-khoi-but:hover { color: var(--chu); box-shadow: inset 0 0 0 1px var(--vien-ro); }
#ctsCuon .cts-bang tbody tr:hover .cts-khoi-them, #ctsCuon .cts-bang tbody tr.cts-cham .cts-khoi-them { visibility: visible; }
/* Hình người Bố / Mẹ / chưa chọn. */
/* 24×24 là sàn đích bấm của cụm bảng Sheet (luật ㉕) — hình 15px nằm giữa. */
#ctsCuon .cts-vai { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px;
  margin: 0 2px 0 -4px; padding: 0; vertical-align: middle; border: 0; background: transparent; border-radius: 50%;
  color: var(--mo); cursor: pointer; }
#ctsCuon span.cts-vai { cursor: default; }
#ctsCuon .cts-vai i { width: 15px; height: 15px; }
#ctsCuon button.cts-vai:hover { background: var(--nen2); }
#ctsCuon .cts-vai.bo { color: var(--vai-bo); }
#ctsCuon .cts-vai.me { color: var(--vai-me); }
/* Vạch dày «bên trái đứng yên» theo số cột ghim: gom học sinh thì chỉ ghim 3 cột (`ctsSoGhim`). */
#ctsCuon.cts-ghim3 .cts-bang .cts-g3, #ctsCuon.cts-ghim3 .cts-bang thead .cts-g3 { border-right: 2px solid var(--muc); }

/* Hộp sửa nhỏ cạnh block + menu Bố / Mẹ — cùng dáng hộp «+N» của cột TVTS (`.cts-hop-bu`). */
.cts-kh-hop { position: fixed; z-index: 120; box-sizing: border-box; width: min(300px, calc(100vw - 16px));
  display: flex; flex-direction: column; gap: 8px; padding: 10px; font-size: 13px; color: var(--chu);
  background: var(--the); border: 1px solid var(--vien); border-radius: var(--r-md); box-shadow: 0 6px 20px rgba(0,0,0,.14); }
.cts-kh-hop.cts-kh-menu { width: auto; min-width: 170px; padding: 6px; gap: 2px; }
.cts-kh-nhan { font-size: 12px; font-weight: 600; color: var(--chu); }
.cts-kh-menu .cts-kh-nhan { padding: 2px 8px 4px; color: var(--mo); font-weight: 400; }
.cts-kh-ghi { font-size: 11.5px; line-height: 1.45; color: var(--mo); }
.cts-kh-loi { font-size: 12px; color: var(--do); }
.cts-kh-loi:empty { display: none; }
.cts-kh-nut { display: flex; justify-content: flex-end; gap: 6px; }
.cts-kh-hop .nv-in { padding: 6px 9px; font-size: 13.5px; }
.cts-kh-mon { display: flex; align-items: center; gap: 8px; width: 100%; padding: 6px 8px; border: 0;
  background: transparent; border-radius: var(--r-sm); font: inherit; color: var(--chu); text-align: left; cursor: pointer; }
.cts-kh-mon:hover, .cts-kh-mon:focus-visible { background: var(--nen2); outline: none; }
.cts-kh-mon.chon { font-weight: 600; background: var(--xanh-nhat); }
.cts-kh-mon i, .cts-vai-nut i { width: 15px; height: 15px; }
.cts-kh-mon.bo i, .cts-vai-nut.bo i { color: var(--vai-bo); }
.cts-kh-mon.me i, .cts-vai-nut.me i { color: var(--vai-me); }
/* Hai nút Bố / Mẹ (hộp thêm phụ huynh thứ hai + hộp Thêm học sinh). Đang chọn: viền + nền theo màu vai,
   chữ vẫn màu chữ thường — trạng thái nói bằng cả nền lẫn `aria-pressed`, không chỉ bằng màu. */
.cts-vai-chon { display: flex; gap: 6px; }
.cts-vai-nut { display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px; font: inherit; font-size: 13px;
  color: var(--chu); background: var(--the); border: 1px solid var(--vien); border-radius: var(--r-md); cursor: pointer; }
.cts-vai-nut:hover { border-color: var(--vien-ro); }
.cts-vai-nut.chon { font-weight: 600; }
.cts-vai-nut.bo.chon { border-color: var(--vai-bo); box-shadow: inset 0 0 0 1px var(--vai-bo); }
.cts-vai-nut.me.chon { border-color: var(--vai-me); box-shadow: inset 0 0 0 1px var(--vai-me); }
.cts-vai-nhac { margin-top: 4px; font-size: 12px; color: var(--do); }
.cts-ht-them2 { margin: -4px 0 12px; }
/* Nút «Dò trùng rồi tạo hàng» mờ khi còn thiếu Bố/Mẹ — vẫn bấm được để ra chữ đỏ nói thiếu gì. */
#htOK.cts-ok-khoa { opacity: .45; cursor: not-allowed; }

/* ══════════════════════════════════════════════════════════════════════════════
   🗂 ĐỢT 3 — Boss chốt 11/10/2026 (khối ĐỢT 3 cuối man-hinh/tuyen-sinh.js). Ô «Cơ sở test» gom block
   lịch test, ô «Cơ sở học» gom Điểm test + Lớp đăng ký — dùng lại nguyên bộ block 👪 ở trên.
   Cột «Liên hệ» một dòng, chữ cắt bằng CSS. Chỉ dùng token màu chung ⇒ nền tối tự theo.
   ══════════════════════════════════════════════════════════════════════════════ */
/* Block mượn của Hồ sơ test: chữ nghiêng mờ như ô cũ `.cts-tu-test`, bấm ra hộp chỉ đọc. */
#ctsCuon .cts-khoi.cts-khoi-tutest { font-style: italic; }
/* Block + chấm cam «Hồ sơ test ghi khác» dính nhau, không tách dòng giữa hai thứ. */
#ctsCuon .cts-khoi-kem { display: inline-flex; align-items: center; max-width: 100%; }
#ctsCuon .cts-khoi-kem .cts-lech-test { margin-left: 3px; font-size: 13px; }
/* Ô Liên hệ: MỘT dòng như ô thường — «2 lần · 11/10: chữ» cắt GỌN ở mép ô, không dấu ba chấm
   (luật ㊲ 21/09 «bỏ dấu … toàn app», css/nen.css). */
table.cts-bang>tbody>tr>td.cts-lh { padding-top: 0; padding-bottom: 0; }
#ctsCuon .cts-lh-nut { display: flex; align-items: center; width: 100%; max-width: 100%; min-width: 0; height: 22px;
  padding: 0; margin: 0; border: 0; background: transparent; font: inherit; font-size: 12.5px; color: var(--chu);
  text-align: left; white-space: nowrap; overflow: hidden; cursor: pointer; }
#ctsCuon .cts-lh-so { flex: none; font-weight: 600; font-variant-numeric: tabular-nums; }
#ctsCuon .cts-lh-ngay { flex: none; color: var(--mo); font-variant-numeric: tabular-nums; white-space: pre; }
#ctsCuon .cts-lh-chu { flex: 1 1 auto; min-width: 0; overflow: hidden; }
#ctsCuon .cts-lh-nut:hover .cts-lh-chu { text-decoration: underline; }
#ctsCuon .cts-lh-nut:focus-visible { outline: 2px solid var(--muc); outline-offset: -2px; }
/* Ô trống: chữ mờ «+ Liên hệ» luôn hiện — «chưa liên hệ» cũng là một thông tin cần thấy. */
#ctsCuon .cts-lh-trong { color: var(--mo); opacity: .75; }
#ctsCuon .cts-lh-trong::before { content: attr(data-nhan); }
#ctsCuon .cts-lh-trong:hover { color: var(--muc); opacity: 1; }
/* Ô ngày + ô giờ cạnh nhau — hộp nhỏ lịch test và hộp Liên hệ dùng chung. */
.cts-kh-lich { display: flex; gap: 6px; align-items: stretch; }
.cts-kh-lich .nv-datevn { flex: 1 1 auto; min-width: 0; }
.cts-kh-lich .cts-kh-gio { flex: none; width: 74px; box-sizing: border-box; font-variant-numeric: tabular-nums; }
/* Hộp «Liên hệ — tên». */
#htThan .cts-lh-hop { display: flex; flex-direction: column; gap: 12px; }
#htThan .cts-lh-khung { display: flex; flex-direction: column; gap: 8px; }
#htThan .cts-lh-moi { padding: 10px; background: var(--nen2); border: 1px solid var(--vien); border-radius: var(--r-md); }
#htThan .cts-lh-o-hang { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
#htThan .cts-lh-o-hang .cts-kh-lich { flex: 0 1 260px; }
#htThan .cts-lh-nguoi { font-size: 12.5px; color: var(--mo); }
#htThan .cts-lh-nguoi b { color: var(--chu); font-weight: 600; }
#htThan .cts-lh-ghi { width: 100%; box-sizing: border-box; min-height: 52px; resize: vertical; font: inherit; font-size: 13.5px; }
#htThan .cts-lh-chan { display: flex; align-items: center; justify-content: flex-end; gap: 6px; }
#htThan .cts-lh-nhac { margin-right: auto; font-size: 12px; color: var(--mo); }
#htThan .cts-lh-luu[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }
#htThan .cts-lh-ds { max-height: min(48vh, 420px); overflow-y: auto; border-top: 1px solid var(--vien); }
#htThan .cts-lh-dong { padding: 8px 2px; border-bottom: 1px solid var(--vien); }
#htThan .cts-lh-dong.dang-sua { padding: 10px 2px; }
#htThan .cts-lh-dong.hoi { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
#htThan .cts-lh-hoi { flex: 1 1 220px; font-size: 13px; color: var(--do); }
#htThan .cts-lh-xoathat { color: var(--do); border-color: var(--do); }
#htThan .cts-lh-dau { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; font-size: 12.5px; }
#htThan .cts-lh-dau b { font-weight: 600; font-variant-numeric: tabular-nums; color: var(--chu); }
#htThan .cts-lh-ai { color: var(--chu); }
#htThan .cts-lh-dasua { color: var(--mo); font-size: 11.5px; }
#htThan .cts-lh-viec { display: flex; gap: 4px; margin-left: auto; }
#htThan .cts-lh-noi { margin-top: 3px; font-size: 13.5px; line-height: 1.5; color: var(--chu); white-space: pre-wrap; overflow-wrap: anywhere; }
#htThan .cts-lh-rong { margin: 8px 0 0; font-size: 13px; color: var(--mo); }

/* ══ [DESIGNER 12/09 · TÊN CỘT ĐIỂM DANH ĐẬM HƠN] ══
   Boss 12/09/2026 chê TÊN CỘT ở màn Điểm danh *"nhạt quá"*, đòi **nét 600** và
   **chữ đen hơn**.

   ⛔⛔ ĐỪNG ĐỌC `.luoi .h-cot { font-weight:700 }` (css:800) RỒI TƯỞNG ĐÃ ĐẬM.
      Hỏi CSSOM lúc chạy thì nét thật đo được là **400** ở CẢ SÁU khổ
      (390 · 1001 · 1280 · 1366 · 2320 · 2560@cỡ chữ 110%). Thủ phạm:

        .sheet-moi[class] thead th { font-weight: 400 }      (0,2,2)  css:14274
        .luoi        .h-cot        { font-weight: 700 }      (0,2,0)  css:800

      `sheetGan` khoác thêm `sheet-moi` cho `<table class="luoi">` lúc chạy
      (đo lại: đúng là có), nên luật 400 của khối kiểu-Sheet đè luật 700 của
      chính bảng điểm danh. Bảng đo được trước khi vá:

        ô tiêu đề          nét   màu             tương phản trên nền của nó
        .h-cot (7 cột)     400   #2C3742         11,1 : 1
        .h-cot.h-ngay      400   #1F2A5A         12,5 : 1
        thead .c-ma/.c-ten 400   #3D4854          8,5 : 1   ← nhạt nhất

   ⛔ KHÔNG ĐƯỢC SỬA CON SỐ 400 Ở KHỐI `.sheet-moi[class] thead th`. Khối ấy
      ăn CẢ APP: Lộ trình · Tuyển sinh · Dự giờ · Chăm sóc · Follow up · Lịch
      thi · Quản lý học · Nhân viên. Chú thích tại chỗ đã ghi rõ *"nhả ra là
      đầu bảng đậm hết — đúng cái lộ ra là máy làm Boss đã chê"*. Boss chỉ nói
      về màn ĐIỂM DANH ⇒ luật dưới đây bọc trong `.luoi`, và `table.luoi` chỉ
      được dựng ở MỘT chỗ duy nhất trong cả app (js/tinh-nang.js:26866, lưới điểm
      danh). Không màn nào khác đi nhờ.

   ⛔⛔ NÉT VÀ MÀU PHẢI TÁCH LÀM HAI LUẬT, VỚI HAI ĐỘ NẶNG KHÁC NHAU — đây là
      chỗ ăn tiền, đừng gộp lại cho gọn:

        css/nen.css NẠP TRƯỚC css/lop.css (index.html:49 vs :51)
        ⇒ NGANG ĐIỂM thì luật ở file này THẮNG nền tối. Muốn nền tối thắng thì
          phải CỐ Ý để điểm THẤP HƠN nó, chứ không phải bằng nó.

        · nét  — nền tối không khai `font-weight` ở đâu cả (đã grep cả file)
                 ⇒ tự do leo lên (0,3,2) để đè (0,2,2).
        · màu  — nền tối khai cứng:
                   body.toi .luoi .h-cot          { color:#C8D0D8 }  (0,3,1)
                   body.toi .luoi thead .c-ma/.c-ten { color:#C8D0D8 } (0,3,2)
                 ⇒ luật màu của tôi phải nằm DƯỚI hai số ấy: (0,3,0) và (0,2,2).

      ⚠️ HAI CA THỬ PHÁ ĐÃ CHẠY, VÀ CON SỐ KHÁC VỚI CÁI TÔI ĐOÁN BAN ĐẦU —
         ghi lại đúng số đo được, đừng ghi cái suy ra:
           · saiB (leo lên (0,4,2), VẪN đi qua `var(--chu)`):
               chữ đầu bảng nền tối hoá **#E4E1DB** (không phải #1F1D1A như tôi
               đoán) vì nền tối KHAI LẠI `--chu` = #E4E1DB ở tầng ③ của bảng
               điểm danh. Tương phản 9,93:1 — ĐỌC ĐƯỢC. Cái mất là app lặng
               lẽ thôi dùng màu #C8D0D8 mà nền tối đã cố ý chọn.
           · saiC (leo lên (0,4,2) VÀ ép mã cứng `#1F1D1A`):
               #1F1D1A trên nền #2B323A = **1,30:1** — mất chữ hẳn (phép
               canh đỏ đúng dòng tương phản, không phải dòng màu).
         ⇒ ĐI QUA BIẾN `var(--chu)` LÀ THỨ ĐỠ CHO CA saiB KHÔNG THÀNH THẢM HOẠ.
           Nhưng vẫn phải giữ độ nặng thấp, vì "đọc được" không có nghĩa là
           "đúng ý người đã chọn màu ấy".

   ⛔ `.h-ngay` (ô "Ngày điểm danh") ĐƯỢC MIỄN đổi màu: navy #1F2A5A là màu cố
      ý cho khớp dải buổi, và nó đã 12,5:1 — đen hơn cả cái Boss chê. Nó VẪN
      nhận nét 600 (nét không mang nghĩa màu). Nếu viết `.luoi .h-cot { color }`
      không có `:not(.h-ngay)` thì luật mới (đứng sau, ngang điểm) nuốt luôn
      navy mà không ai báo.

   ⛔ Màu lấy `var(--chu)` — **#1F1D1A, "Chữ chính" trong bộ màu thương hiệu**
      (thiet-ke/BANG-MAU-VA-CHU.md §"Màu nền và chữ"). Không đặt màu mới.
      Đi qua biến chứ đừng ép mã cứng: nền tối định nghĩa lại `--chu` thành
      #E4E1DB, nên nếu mai ai gỡ luật nền tối ở trên thì chữ vẫn tự sáng lên.
      Tương phản mới trên nền #F2F5F8: **15,4 : 1** (cũ 11,1 và 8,5).

   ⛔ 600 chứ KHÔNG 700, và KHÔNG `text-transform: uppercase`, KHÔNG
      `letter-spacing`. Nét 800 + IN HOA + giãn chữ là ba thứ Boss đã chê "lộ
      rõ UI do AI làm" NĂM LẦN (BANG-MAU-VA-CHU.md §3 "Nét chữ"). Đo lại sau
      khi vá: `text-transform` vẫn `none`, `letter-spacing` vẫn `normal`. */

/* ① NÉT 600 — đủ nặng để đè `.sheet-moi[class] thead th` (0,2,2).  (0,3,2) */
.luoi[class] thead th.h-cot,
.luoi[class] thead th.c-ma,
.luoi[class] thead th.c-ten {
  /* Dấu vân tay để phép canh tìm được ĐÚNG ba luật này trong CSSOM. Không vẽ gì. */
  --dsg-th-dam: net;
  /* ⭐ 18/09/2026 — 600 → 500. Boss: *"trong điểm danh thì các cột ko cần đậm đâu
     để lại như cũ nha"*, chốt bằng nút: **về 500 cho bằng các màn khác**.
     ⛔ Không hạ hẳn về 400: Boss chọn 500 chứ không chọn “không đậm gì” — 400 là
        dựng lại đúng cái bị chê *"nhạt quá"* hôm 12/09.
     ⛔ Khối này vẫn phải giữ `[class]`: nó đang để đè `.sheet-moi[class] thead th`
        (0,2,2) — `sheetGan` khoác `sheet-moi` cho `table.luoi` lúc chạy. Bỏ `[class]`
        là lưới điểm danh rơi về luật chung, không ai báo gì cả.
     ⛔ MÀU và `--dsg-th-dam` giữ nguyên — Boss chỉ nói về ĐẬM. */
  font-weight: 500;
}

/* ② CHỮ ĐEN HƠN — bảy ô tên cột, TRỪ ô Ngày.  (0,3,0)
   ⛔ Phải THẤP hơn `body.toi .luoi .h-cot` (0,3,1), xem lời dẫn trên. */
.luoi .h-cot:not(.h-ngay) {
  --dsg-th-dam: mau-cot;
  color: var(--chu, #1F1D1A);
}

/* ③ CHỮ ĐEN HƠN — hai ô tên cột nằm trong dải ghăm bên trái ("Mã HS", "Học sinh").
   (0,2,2)
   ⛔ Phải THẤP hơn `body.toi .luoi thead .c-ma/.c-ten` (0,3,2). */
.luoi thead th.c-ma,
.luoi thead th.c-ten {
  --dsg-th-dam: mau-ghim;
  color: var(--chu, #1F1D1A);
}

/* ④ BÙ LẠI 1px ĐỆM NGANG — ĐỪNG GỠ DÒNG NÀY, nó cứu MỘT HÀNG của bảng.
   ⛔⛔ ĐO ĐƯỢC, KHÔNG PHẢI PHÒNG XA: nét 600 làm CHỮ RỘNG RA, nên bề rộng
      nhỏ-nhất-có-thể của 7 ô tên cột tăng ~3px. Bảng đang `table-layout` tự
      động, nên 3px ấy bị LẤY TỪ cột Học sinh (`.c-ten`): 204px → 203px. Và
      203px thì đúng một tên học sinh 26 ký tự phải xuống DÒNG THỨ BA ⇒ hàng ấy
      cao thêm 16px ⇒ khổ 1280 tụt từ **19 hàng xuống 18 hàng** một màn.
      Số đo (sân 18 HS + 1 hàng tổng, tên dài 23-27 ký tự như thật):

        bản              1280: bảng · c-ten · tbody · HÀNG LỌT
        gốc              1241 · 204 · 642 · **19**
        vá trần (600)    1242 · 203 · 658 · **18**   ← mất một hàng
        vá + dòng ④      1242 · 204 · 642 · **19**   ← lấy lại

   ⛔ ĐÂY KHÔNG PHẢI "bảng vốn mong manh, 1px nào cũng vỡ". Đã thử phá ngược:
      nới `min-width` của `.h-cot` từ 70px lên 71px rồi 73px mà KHÔNG đổi nét —
      cả ba con số đứng y nguyên (1241 · 204 · 642 · 19). Tức thủ phạm đúng là
      bề rộng chữ đậm, không phải một nhiễu bất kỳ. ⇒ tôi gây ra thì tôi bù.

   ⛔ ĐÃ THỬ CÁCH KHÁC VÀ BỎ: nới `.c-ten { min-width: 158px → 168px }`. Nó
      cũng lấy lại 19 hàng ở 1280, nhưng làm bảng ở 1001 phình 1007→1020 và ở
      1366/2320 phình 1305→1307; tệ hơn là nó đụng vào chính cột mà việc "bóp
      cột tên ở khổ 390" đang phải sửa. Hạ đệm thì 1366/2320 về ĐÚNG số gốc
      (1305) và 1001 chỉ lệch 1px.

   ⛔ BỌC TRONG `@media (min-width: 821px)` — BẮT BUỘC. Khổ ≤820px có luật
      riêng `.luoi .h-cot { padding: 6px 4px }` (hỏi CSSOM: nó nằm trong
      `@media (max-width: 820px)`, điểm (0,2,0)). Luật của tôi (0,3,2) sẽ ĐÈ
      mất đệm 4px ấy và nới nó thành 6px — đúng kiểu "nới luật CSS thì phải xem
      ai đang đi nhờ". Bọc media lại thì khổ 390 giữ NGUYÊN từng con số của bản
      gốc (bảng 873 · c-ten 112 · tbody 1014 · 7 hàng lọt) — đã đo, khớp tuyệt đối. */
@media (min-width: 821px) {
  .luoi[class] thead th.h-cot {
    --dsg-th-dam: bu-dem;
    padding-left: 6px;
    padding-right: 6px;
  }
}
/* ══ [HẾT KHỐI DESIGNER 12/09 · TÊN CỘT ĐIỂM DANH] ══ */

/* ═══ DSG-V3 ═══ BÓP CỘT TÊN Ở KHỔ 390 (Boss 13/09/2026) ═══════════════════
   Boss: cột tên ở điện thoại chiếm ~100px, bóp lại còn ~60px và cố định.

   ⛔⛔ VIỆC NÀY ĐỤNG HAI QUYẾT ĐỊNH CŨ CỦA CHÍNH BOSS — khai ra ở đây để lượt
      sau đừng tưởng tôi không đọc:
      · 25/07/2026 (chú thích ở ~dòng 1401) Boss BỎ `nowrap` + `ellipsis` cho
        ĐÚNG cột này: *"tiếng Việt thì phần BỊ CẮT lại chính là TÊN, chỗ để phân
        biệt các em. Trợ giảng không biết đang điền cho ai."*
      · 112px không phải số bốc: chọn SAU KHI ĐO 505 học sinh thật — dài nhất 26
        ký tự, 99% dưới 23, giữa là 14; 2 dòng × 12px × 1.15 = 27,6px vẫn lọt
        trong hàng cao 32px nên hiện đủ tên mà không mất hàng nào.

   60px thì KHÔNG CÒN cách nào hiện đủ tên. ĐO THẬT ở khổ 390, sân 19 hàng,
   tên mẫu 23–27 ký tự (số hàng lọt một màn là số đếm được, không phải ước):
      ① 112px xuống dòng (ĐANG CÓ) → tên dài nhất xuống 3 dòng ·  7 hàng/màn
      ② 60px  xuống dòng            → tên dài nhất xuống 5 dòng ·  4 hàng/màn ⛔
      ③ 60px  + cắt (đầu hay đuôi)  → 1 dòng                    · 12 hàng/màn
      ④ 72px  xuống dòng            → 4 dòng                    ·  5 hàng/màn
      ⑤ 88px  xuống dòng            → 3 dòng                    ·  6 hàng/màn
   ⇒ ② là số XẤU: bóp ngang xong lỗi rơi xuống dọc, mất 3 trong 7 hàng.
   ⇒ ③ ngược lại: bóp ngang mà CÒN ĐƯỢC THÊM 5 hàng/màn (7 → 12), vì cột tên
     thôi kéo hàng cao lên. Nên chọn ③, và cắt từ ĐẦU để phần còn lại là TÊN
     RIÊNG — tôn trọng đúng lý do Boss bỏ ellipsis hồi 25/07.
   ⛔ NHƯNG PHẢI NÓI THẲNG, ĐÂY LÀ ĐÁNH ĐỔI THẬT, KHÔNG PHẢI THẮNG TRẮNG:
     ở 60px thì CẢ 19/19 ô tên đều bị cắt, và chỉ còn nhìn được 4–5 KÝ TỰ CUỐI
     ("…h Chi", "…uong"). Tên thật giữa là 14 ký tự nên gần như em nào cũng bị
     cắt. Đây là đổi CÁCH ĐỌC cột tên chứ không chỉ là bóp một cột — nhận hay
     không là quyết định của Boss, tôi chỉ đưa số.

   ⛔ BÓP NGANG THÔI — không hạ chiều cao hàng (hạ chiều cao là dựng lại một lỗi
      đã vá). Sau khi bóp đã đo lại chiều DỌC: số dòng, chiều cao hàng, số hàng
      lọt một màn, và ô có bị cắt chữ theo chiều dọc không.
   ⛔ Chỉ áp trong `@media (max-width: 820px)` — khổ 1001/1280/1366/2320 phải
      KHÔNG ĐỔI MỘT PIXEL (đã canh bằng mốc).
   ⛔⛔ HỎI CSSOM TRƯỚC KHI SỬA LUẬT NÀY, ĐỪNG GREP FILE RỒI TIN.
      Luật đang giữ cột tên cho xuống dòng là `.luoi.sheet-moi tbody td.c-ten`
      (0,3,2) — mà lớp `sheet-moi` do `sheetGan` khoác LÚC CHẠY, nên đọc file
      CSS không bao giờ thấy nó. Bản đầu của tôi viết `.luoi tbody .c-ten`
      (0,2,1) và THUA IM LẶNG: cả bốn ca thử phá ra kết quả y hệt nhau vì không
      ca nào ăn. `[class]` ở đây là để thắng bằng ĐIỂM (0,4,2), chứ không phải
      thắng nhờ đứng sau — ngang điểm mà thắng nhờ thứ tự file thì ai chèn thêm
      một luật `.sheet-moi` phía dưới là gãy, và gãy không báo lỗi.
   ⛔ ĐỪNG thêm luật đệm ngang cho ô này. Tôi đã thử `padding-left/right: 3px`
      và nó CHẾT CÂM: `.sheet-moi tbody tr.sheet-hang td` (0,2,3) đang giữ 4px.
      Mà đo ra đệm 4px · 3px · 2px đều cho ĐÚNG 5 ký tự, nên không đáng đổi.
   ⛔⛔ CÁCH CẮT ĐẦU — ĐÃ ĐO BỐN BIẾN THỂ, ĐỪNG ĐỔI BỪA (khổ 390, tên 27 ký tự
      "Duong Thi Nhat Le Quynh Chi"):
        `unicode-bidi: plaintext`      → nhìn thấy "Duon"  — CẮT ĐUÔI, HỎNG.
           (plaintext lấy hướng theo nội dung ⇒ chữ Latin thành ltr, chiều cắt
            quay về bên phải. Đây là cái tôi đoán đúng lúc đầu và ĐO RA LÀ SAI.)
        `unicode-bidi: bidi-override`  → nhìn thấy "Duon", và ĐẢO THỨ TỰ TỪ. HỎNG.
        `unicode-bidi: embed`          → nhìn thấy "h Chi" — CẮT ĐẦU, thứ tự từ
                                          NGUYÊN VẸN. ĐÚNG.
        `unicode-bidi: normal`         → y hệt `embed`.
      Mặc định của ô bảng là `isolate`, nên PHẢI khai đè; để trống là không ăn.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 820px) {
  /* ⭐⭐ BOSS CHOT 13/09/2026 — SO LOP PHAI DI CUNG HANG VOI O "Tat ca lop".
     Boss: *"so 127/127 lop de ngay canh o chon Tat ca lop, dang bi tach doi hang"*.

     DO TRUOC KHI SUA (bang phan lop, 20 lop):
       may tinh 1280 — o chon het o x=365, so bat dau o x=1206: CACH NHAU 841px.
       dien thoai 390 — so bi day HAN xuong dong duoi, lech doc 40px.
     Thu pham o may tinh: `.gtgb-dem { margin-left: auto }` day o dem ra tan mep
     phai. Da go (841px → 8px).

     ⛔⛔ HAI DIEU TOI DOAN SAI O KHO HEP — CDP BAC BO CA HAI, ghi lai de nguoi
        sau khoi di lai:
       ① "O tim chiem 230px nen phai day no xuong hang rieng" — KHONG. O kho hep
          o tim nam trong vien thu gon, va `.nv-gon .nvg-tim > input { width: 0;
          max-width: 0 }` (luat nang nhat, dung sau) bop no ve DUNG 0px. Day no
          xuong hang rieng chang giai phong duoc mot pixel nao — do lai: so van
          lech 40px y nguyen.
       ② "Cho o chon `flex: 1 1 auto` cho no gon" — chinh la TU GAY THEM. `.nv-in`
          co `width: 100%`, cong `flex-grow: 1` thi o chon NO ra tan 341px, va
          341 + 8 + 62 = 411 > 390 nen so bi be xuong hang.
     ⇒ Cho o chon CO LAI duoc va giu tran 200px: 200 + 8 + 62 = 270px tren 390px.

     ⛔ ĐẶT Ở ĐÂY, KHONG dat canh `.gtgb-dem` o dong ~9418: cho ay nam LONG trong
        mot @media khac, nen mot `@media (max-width: 820px)` viet o do khong bao
        gio khop. Da thu va do ra la vo hieu. Khoi nay thi da chung minh la an
        (chinh no dang giu cot ten 112px cua viec 7). */
  .gtgb-loc .gtgb-chon { flex: 0 1 auto; min-width: 0; max-width: 200px; }
  /* ⛔ VA THU BA — PHAI NHAM DUNG THE. Sau khi go `margin-left: auto` va cho o
     chon co lai, kho 390 VAN lech 40px. Do lai tung the: o chon het o x=341,
     man rong 390, con 41px ma so can 62px.
     Cai chiem cho la VIEN THU GON cua o tim — `div.bl-timhang` (~133px), CHU
     KHONG phai cai `input.gtgb-tim` ben trong no (input ay dung la 0px, nhu CDP
     da chi). Hai lan truoc toi nham vao input nen sua ma khong doi mot pixel.
     Cay DOM that: `.gtgb-loc > .bl-timhang > .nv-gon.co-tim > .nvg-tim > input`.
     ⇒ Day CA VIEN xuong mot hang rieng. Hang duoi con lai 200 + 8 + 62 = 270px. */
  .gtgb-loc > .bl-timhang { flex: 1 1 100%; }

  /* ⭐⭐ BOSS DAO LAI 13/09/2026 — NOI COT TEN 60 → 112px.
     Boss: *"noi cot rong ra cho ten du 1-2 dong"* va *"dau mic hien lai — cot
     rong roi thi du cho"*.
     Ban 60px truoc do la de danh cho cot diem, va cai gia la ten bi cat con
     4-6 ky tu (`…Thuy`, `…hi Mai`). Do that 13/09 o ca ba kho 390 · 360 · 320:
     6/6 hang deu bi cat chu, ke ca ten 10 ky tu.
     ⛔ KHONG ha co chu (van la quyet dinh 25/07 cua Boss) va KHONG ha chieu cao
        hang. Chi noi NGANG.
     ⛔ 112px la con so DA CO SAN trong khoi @media o dong ~1414 cua chinh file
        nay, kem phep do: *"Cot 104px chua ~15 ky tu MOI DONG → 2 dong thua suc
        chua ca ten dai nhat"* (505 hoc sinh that: dai nhat 26 ky tu, giua 14).
        Lay dung con so ay chu khong bia mot so moi. */
  .luoi[class] .c-ten, .luoi[class] thead .c-ten {
    min-width: 112px; max-width: 112px; width: 112px;
  }
  /* ⭐ 60px chứa ~5 ký tự: tên 27 ký tự mà cho XUỐNG DÒNG thì thành 5 dòng và
     hàng cao lên — đo được 7 hàng/màn tụt còn 4. Nên CẮT chứ không xuống dòng,
     và cắt từ ĐẦU để phần còn lại là TÊN RIÊNG.
     ⛔ CHỪA HÀNG TỔNG (`tr.tong`, dựng ở js/tinh-nang.js:26331): ô ấy ghi
        "Tổng (Đ/Đủ)" — chỗ có nghĩa nằm ở ĐẦU chuỗi, cắt đầu là mất chữ
        "Tổng" thành "…(Đ/Đủ)". Hàng ấy cắt ĐUÔI. */
  /* ⭐⭐ 13/09/2026 — XUONG DONG THAY VI CAT DAU.
     Ban cu cat dau bang `direction: rtl` + `unicode-bidi: embed` (mot meo da do
     ky, xem bang bon bien the o tren) — no dung cho o 60px, noi ma chi hien duoc
     mot dong. Nay cot 112px thi ten dai nhat 26 ky tu LOT TRON HAI DONG, khong
     con ly do gi de cat.
     ⛔ GO CA `direction` LAN `unicode-bidi`, dung go moi mot cai: de lai `rtl`
        thi dong cuoi bi day sang phai va dau … nhay ve dau chuoi.
     ⛔ `line-height: 1.15` la cho mau chot, khong phai trang tri: 2 dong x 12px
        x 1.15 = 27,6px, van LOT trong hang cao 32px san co — hien du ten ma
        KHONG an them mot pixel chieu cao nao, so hang mot man giu nguyen.
        (Chinh phep tinh nay da ghi o khoi @media dong ~1409.)
     ⛔ `overflow-wrap: break-word` de mot tu qua dai (ho ten viet lien khong dau)
        van xuong duoc dong, thay vi thoc ra ngoai o. */
  .luoi[class] tbody tr:not(.tong) .c-ten {
    white-space: normal;
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.15;
    word-break: normal;
    overflow-wrap: break-word;
    text-align: left;
  }
  .luoi[class] tbody tr.tong .c-ten {
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* ⭐⭐ BOSS DOI Y 13/09/2026 — HIEN LAI DAU MIC.
     Sang cung ngay Boss chon AN dau nay o kho dien thoai, vi o ten khi ay chi
     60px: dau chiem 15px + le 3px = 18px tren 52px long o (35%), nen ten chi
     con 2-4 ky tu. Nay cot noi len 112px thi 18px ay khong con dang ke, va Boss
     chot: *"hien lai — cot rong roi thi du cho"*.
     ⛔ GO HAN LUAT AN, dung doi thanh `visibility` hay `opacity`: dau nay la
        THONG TIN THAT (em nao da nop bai noi), an nua thi nguoi dung mat tin.
     ⛔ Luat cu giu lai trong lich su git, moc `50a9fb7`. */
}
/* ══════════════════════════════════════════════════════════════════════════════
   🃏 12/09/2026 — Ô CHỌN NHIỀU MỤC KIỂU "THẺ BAY" (Boss gửi mẫu 21st.dev)
   ──────────────────────────────────────────────────────────────────────────────
   Mẫu: https://21st.dev/@geekles007/components/multiple-select
   Mẫu ấy viết bằng React + framer-motion, cơ chế bay nằm ở `layout` +
   `layoutId={name}`. App này không có React, không framer-motion, không Tailwind
   — nên phần bay dịch sang kỹ thuật FLIP (đo rect trước/sau rồi translate về chỗ
   cũ, bỏ transform cho nó tự chạy về) ở `js/tinh-nang.js`, còn dáng thì ở đây.

   NĂM HÀNH VI CỦA MẪU, khối này lo ba (①③⑤), JS lo hai (②④):
     ① hai khu: trên = đã chọn · dưới = chưa chọn, mục đã chọn BIẾN khỏi khu dưới
     ② bấm thẻ khu dưới → bay lên khu trên; bấm ✕ → bay ngược (FLIP, xem JS)
     ③ thẻ đã chọn nền TRẮNG + đổ bóng · thẻ chưa chọn nền XÁM
     ④ khu trên cuộn ngang, cao 48px, thêm thẻ thì tự cuộn tới cuối (xem JS)
     ⑤ khu dưới tự tràn dòng, và ẨN HẲN khi đã chọn hết mọi mục

   ⛔ KHỐI NÀY ĐẶT Ở CUỐI TỆP LÀ CÓ CHỦ Ý — ba người khác đang gõ cùng tệp này.
      Nó KHÔNG sửa một dòng nào của `.ht-tich-hang` / `.ht-tich-o` (dòng ~7796),
      vì hai chỗ khác mượn `kieu:"tich"` làm nút bật/tắt MỘT mục:
      `js/tinh-nang.js` chỗ ô "Hoặc" của nhãn vé, và chỗ "Áp cho nhiều em".
      Hai nút ấy vẫn đi đường cũ (JS chỉ dựng khuôn mới khi `chon.length >= 2`),
      nên đừng nhân tiện gộp hai bộ luật lại.

   ⛔ KHÔNG BÊ MÀU XÁM CỦA TAILWIND VÀO. Mẫu dùng `bg-gray-50`/`bg-gray-200`/
      `border-gray-200`; ở đây thay bằng bộ biến của app (`--nen2` `--the` `--vien`)
      nên nền tối tự đúng theo mà không phải khai lại lần nữa.

   ⛔ BO GÓC 4px (`--r-sm`), KHÔNG PHẢI `rounded-md` CỦA MẪU. App cố ý VUÔNG
      (`--r-lg: 0px`, `css/nen.css`); `--r-sm`/`--r-md` = 4px là nấc dành cho
      "chip · nhãn · nút bé". Nâng lên 6px kiểu Tailwind là lệch khỏi cả app.
   ══════════════════════════════════════════════════════════════════════════════ */

  /* ── KHU TRÊN: các mục ĐÃ CHỌN ───────────────────────────────────────────────
     Cao 48px CỐ ĐỊNH và cuộn ngang, đúng `h-12 overflow-x-scroll` của mẫu.
     ⚠️ Số đã đo 12/09: mục thật của Boss dài 21-33 ký tự, nên ở khổ 390 chỉ vừa
        MỘT thẻ một lần nhìn — tích 2 mục là phải kéo ngang mới thấy hết. Dòng
        "Sẽ ghi: A · B · C" ngay dưới hai khu là thứ chữa được điều đó, ⛔ đừng gỡ.
     `overscroll-behavior-x: contain` để kéo ngang trong khu này không lật sang
     trang trước của trình duyệt trên điện thoại. */
  /* ⭐ BOSS CHOT 13/09/2026 — LAY BAN B: the XUONG DONG, khong cuon ngang.
     Boss bam chon giua hai ban, kem anh o kho 390:
       ban A (cu) — mot dong, cuon ngang: the dau bi cat con MOT chu cai,
                    phai keo ngang moi doc het. Muc that dai 21-33 ky tu nen
                    o kho 390 chi vua DUNG MOT the mot lan nhin.
       ban B (nay) — xuong dong: doc du ca hai the, khong phai keo.
     Doi lai: khu tren cao len khi nhieu the. Do la cai gia Boss da nhin anh
     roi chon, khong phai thu toi tu quyet.

     ⛔ GO TRAN CHIEU CAO THI PHAI KEP LAI. `height: 48px` cu vua la tran vua
        la san. Doi thang sang `height: auto` la khu nay phinh khong gioi han:
        tich 8 muc o kho 390 se day het hop thoai ra ngoai man, va nut Xong
        tut xuong duoi tam nhin — dung benh 'go tran chieu cao phai noi be
        ngang' da tra gia mot lan. Nen: `min-height` giu san 48px (khu rong
        van dung cao nhu cu, khong nhay bo cuc), `max-height` chan o ~3 dong
        the roi moi cho cuon DOC.  [SO NAY SAI, xem dong duoi]
     SO CU GHI SAI, da sua 13/09: toi viet tran '~3 dong the'. Do that: buoc dong 38px
     + dem 8+8 => 3 dong can 122px, nen 112px chi chua 2 dong du + 73% dong 3. Va tu
     13/09 tran khong con la 112px nua — xem chu thich ngay tren `max-height`.
     ⛔ `align-items: center` -> `flex-start`: khi da nhieu dong, canh giua lam
        dong dau bi day xuong, nhin nhu le tren khong deu.
     ⛔ Thanh cuon nay gio la DOC chu khong con NGANG — luat `::-webkit-
        scrollbar { height: 6px }` ngay duoi chi an voi thanh ngang, nen da
        them `width: 6px` cho thanh doc. */
  .ht-tich-tren {
    box-sizing: border-box;
    min-height: 48px;
    /* 13/09/2026 — NOI TRAN SAU KHI NGUOI PHA DO. Truoc la `112px`, toi dat con so
       ay vi SO nut Xong bi day khoi man. Nguoi pha go han tran ra roi do: nut Xong
       VAN LOT o 390x844, 390x640 va ca 320x844 — vi `.ht-nut` da duoc ghim day tu
       truoc (`#htNen > .modal:not(.toan-man)`, dong 1766-1778) va `#htThan` khong he
       cuon o bat cu ca nao. Tuc rui ro toi tu neu KHONG CO THAT, ma cai gia la 112px
       chi chua 2 dong the: tich 8 muc thi 6 the bi che.
       Nay lay tran theo CHIEU CAO MAN (45vh) — 844px cho 380px (du 8 the = 312px),
       640px cho 288px — van con chot chan khi cot co that nhieu muc. */
    max-height: 45vh;
    display: flex;
    align-items: flex-start;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior-x: contain;
    scroll-behavior: auto;
    padding: 8px;
    border: 1px solid var(--vien);
    border-radius: var(--r-sm);
    background: var(--nen2);
  }
  /* Thanh cuộn mảnh — mẫu ẩn hẳn (`no-scrollbar`), nhưng ẩn hẳn thì người dùng
     KHÔNG CÓ DẤU NÀO biết là còn thẻ nằm ngoài tầm nhìn. Giữ mảnh 6px: vẫn thấy
     mà không chiếm chỗ của thẻ. */
  .ht-tich-tren { scrollbar-width: thin; }
  .ht-tich-tren::-webkit-scrollbar { height: 6px; width: 6px; }
  .ht-tich-tren::-webkit-scrollbar-thumb { background: var(--vien-ro); border-radius: 3px; }
  .ht-tich-tren::-webkit-scrollbar-track { background: transparent; }

  /* Hàng thẻ bên trong khu trên — `flex items-center gap-2` của mẫu. */
  /* ⛔ `flex: none` MOT MINH DU LAM `flex-wrap` VO NGHIA — do that, khong doan.
     Hang the la con cua `.ht-tich-tren` (mot flex container). Voi `flex: none`
     no khong bao gio co lai duoi be rong noi dung, nen du co `flex-wrap: wrap`
     thi cung KHONG CO GI de xuong dong: hang cu dai ra mai. Phai cho no co
     duoc (`flex: 1 1 auto`), bo san co nho nhat (`min-width: 0` — mac dinh cua
     flex item la `auto`, tuc khong nho hon noi dung), va chan tran
     (`max-width: 100%`). Thieu MOT trong ba thi ban B khong bao giờ hien ra. */
  .ht-tich-day {
    display: flex; align-items: center; gap: 8px;
    /* 13/09/2026 — SUA LAI CHU THICH VA GO HAI LUAT VO TAC DUNG.
       Toi tung viet o day la 'thieu MOT trong ba thi ban B khong bao gio hien ra'.
       Nguoi pha go tung cai ra do: go `min-width: 0` — khong doi MOT con so nao, ke ca
       o kho 320 noi the (268px) rong hon khung (255px); doi `flex: 1 1 auto` sang
       `flex: none` — cung khong doi gi. Chi khi go `flex-wrap: wrap` moi hong (ve lai
       1 dong, lot 0/8 the). Su that: `flex-wrap` ganh viec, con `max-width: 100%` va
       cap (`flex:1 1 auto` + `min-width:0`) la HAI DUONG DU PHONG CHO NHAU — co mot la
       du. Giu `max-width` vi no don gian hon.
       Va `flex: 1 1 auto` con GAY MOT LOI NHO: luc chua tich muc nao, hang the rong no
       tu 0px ra 50.3px, day cau 'Chua chon muc nao — bam mot the ben duoi' tu sat mep
       TRAI sang sat mep PHAI. Do la thu tro giang nhin thay DAU TIEN moi lan mo o
       trong. Bo di thi cau ay ve dung cho. */
    max-width: 100%;
    flex-wrap: wrap;
  }

  /* Khu trên đang rỗng thì nói một câu, đừng để một hộp xám trống trơn: người
     dùng không đọc được mã, hộp trống với họ nghĩa là "app hỏng". */
  .ht-tich-tren[data-rong="1"]::after {
    content: "Chưa chọn mục nào — bấm một thẻ bên dưới";
    font-size: 12.5px;
    color: var(--mo);
    white-space: nowrap;
  }

  /* ── KHU DƯỚI: các mục CHƯA CHỌN ─────────────────────────────────────────────
     `flex w-full flex-wrap gap-2 rounded-md border p-2` của mẫu. */
  .ht-tich-duoi {
    box-sizing: border-box;
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
    gap: 8px;
    width: 100%;
    margin-top: 8px;
    padding: 8px;
    border: 1px solid var(--vien);
    border-radius: var(--r-sm);
  }
  /* ⛔ PHẢI CÓ DÒNG NÀY. `display:flex` ngay trên ĐÈ được thuộc tính `hidden`, nên
     thiếu nó là "chọn hết thì khu dưới ẩn hẳn" (hành vi ⑤) không bao giờ xảy ra:
     JS đặt `hidden` đúng, mà hộp vẫn hiện ra rỗng. Bẫy kinh điển của [hidden]. */
  .ht-tich-duoi[hidden] { display: none; }

  /* ──── Ô TÌM trong hộp chọn nhiều ────────────────────────────────────────
     Chỉ dựng ra khi danh sách từ 12 mục — xem khối lý do trong `js/tinh-nang.js`.
     Boss 17/09: cột Phụ trách nay chọn nhiều người, mà trung tâm gần trăm tài khoản. */
  .ht-tich-tim {
    box-sizing: border-box;
    width: 100%;
    margin-top: 8px;
    padding: 7px 10px;
    font: inherit;
    color: var(--chu);
    background: var(--nen);
    border: 1px solid var(--vien);
    border-radius: var(--r-sm);
  }
  .ht-tich-tim::placeholder { color: var(--chu-mo); }
  .ht-tich-tim:focus {
    outline: none;
    border-color: var(--xanh);
    box-shadow: 0 0 0 2px rgba(0, 121, 58, .16);
  }
  /* ⛔ PHẢI CÓ DÒNG NÀY, cùng một bẫy với `.ht-tich-duoi[hidden]` ngay trên: thẻ là
     `display:inline-flex` nên nó ĐÈ được thuộc tính `hidden`. Thiếu dòng này thì bộ
     lọc chạy đúng, JS đặt `hidden` đúng, mà mắt vẫn thấy đủ cả danh sách — trông
     hệt như ô tìm bị hỏng. */
  .ht-tich-duoi .ht-tich-the[hidden] { display: none; }

  /* ── THẺ ─────────────────────────────────────────────────────────────────────
     Một `<button>` duy nhất, KHÔNG lồng button trong button (HTML không cho, và
     bàn phím sẽ có hai chặng Tab cho cùng một thẻ). Dấu ✕ là `<span>` bên trong:
     bấm vào đâu trên thẻ đã chọn cũng là bỏ tích — đúng lời app đã hứa sẵn trong
     dòng gợi ý "Bấm lại một mục đang chọn là bỏ tích".

     ⛔ CHỈ `transform` VÀ `opacity` được phép chuyển động. Bảng điểm danh có hàng
        nghìn ô; animate `left/top/width/height` là bắt trình duyệt tính lại cả
        bảng mỗi khung hình.
     ⛔ `transition` PHẢI khai ở đây, trên lớp GỐC, không phải trên lớp dấu
        `.ht-tich-dangbay`. JS đọc `getComputedStyle(the).transitionDuration` để
        biết máy có bật "giảm chuyển động" hay không; khai ở lớp dấu thì lúc JS
        hỏi nó luôn trả "0s" và phép nhận diện ấy mù hoàn toàn. */
  .ht-tich-the {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex: none;
    max-width: 100%;
    min-height: 30px;
    padding: 4px 11px;
    /* ⭐ 18/09/2026 — Boss: *"sửa cái tab lựa chọn ở các ô cho nó có viền có phần
       tròn ra nha"*. Boss chốt: viên thuốc, viền xám rõ hơn hiện nay.
       ⛔ Viền cũ là `transparent` — tức thẻ KHÔNG có đường bao nào, chỉ phân biệt
          bằng nền xám. Đó đúng là thứ Boss thấy thiếu.
       ⛔ Dùng `--vien-ro` chứ đừng `--vien`: thẻ nằm TRÊN nền xám `--nen2`, viền
          nhạt bằng `--vien` đặt lên nền ấy thì gần như tàng hình.
       ⛔ Bo tròn đặt thẳng 999px ở ĐÂY, KHÔNG nâng `--r-lg`/`--r-xl`: hai nấc ấy
          Boss chốt 02/09 phải là 0px cho panel, và lần này Boss chỉ xin tròn cho
          thẻ lựa chọn. Nâng biến chung là làm quá phạm vi.
       Đệm ngang 9 -> 11px: viên thuốc cần thở hai đầu, không thì chữ chạm mép cong. */
    border: 1px solid var(--vien-ro);
    border-radius: 999px;
    background: var(--nen2);
    color: var(--chu);
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.3;
    text-align: left;
    cursor: pointer;
    /* `text-nowrap` của mẫu. Đã đo 12/09 ở khổ 390: mục dài nhất của Boss (33 ký
       tự) vẽ ra ~256px, chỗ trống trong khu dưới ~305px ⇒ vừa. Hai dòng cắt chữ
       dưới đây là VAN AN TOÀN cho mục dài hơn nữa về sau, không phải để dùng hằng
       ngày — mục thật không bao giờ chạm tới. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: transform .26s cubic-bezier(.2, .7, .3, 1);
  }
  .ht-tich-the:hover { border-color: var(--xanh); color: var(--xanh); }
  .ht-tich-the:focus-visible { outline: 2px solid var(--xanh); outline-offset: 2px; }

  /* Thẻ ĐÃ CHỌN: nền trắng + đổ bóng, đúng `bg-white shadow` của mẫu. Viền teal
     và chữ teal là phần của app — ⛔ phân biệt bằng CẢ bóng, viền lẫn màu chữ,
     không chỉ bằng một màu, để người mù màu vẫn đọc ra thẻ nào đang chọn. */
  .ht-tich-the.chon {
    background: var(--the);
    border-color: var(--xanh);
    color: var(--xanh-dam);
    font-weight: 700;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .13);
  }
  .ht-tich-the.chon:hover { background: var(--xanh-nhat); }

  /* Dấu ✕ — `<X size={14} />` của mẫu. */
  .ht-tich-bo {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    font-size: 13px;
    line-height: 1;
    color: var(--mo);
  }
  .ht-tich-the.chon .ht-tich-bo { color: var(--xanh-dam); }

  /* Chữ của thẻ — `<motion.span layout className='text-nowrap'>` của mẫu. */
  .ht-tich-chu { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* Mục ĐỜI CŨ: ô đang giữ một mục mà danh sách cột nay không còn. Hiện ra ở khu
     trên để người ta THẤY mình sắp mất gì, nhưng không bấm được và không vào giá
     trị lưu — cùng nếp với option "(cũ) disabled" của ô chọn. */
  .ht-tich-the.ht-tich-cu {
    background: var(--the);
    border-style: dashed;
    border-color: var(--vien-ro);
    color: var(--mo);
    opacity: .7;
    cursor: not-allowed;
    box-shadow: none;
  }
  .ht-tich-the.ht-tich-cu:hover { border-color: var(--vien-ro); color: var(--mo); }

  /* ⛔ TÔN TRỌNG "GIẢM CHUYỂN ĐỘNG". Thẻ đổi chỗ NGAY, không bay.
     Và đây chính là chỗ app từng có một nút CHẾT VĨNH VIỄN: mã cũ chờ
     `transitionend` để dọn trạng thái, mà `transition:none` thì sự kiện ấy KHÔNG
     BAO GIỜ nổ. Bên JS nay đọc `transitionDuration === "0s"` rồi bỏ hẳn nhịp bay,
     và còn một cái hẹn giờ dự phòng nữa. Đừng gỡ một trong hai. */
  @media (prefers-reduced-motion: reduce) {
    .ht-tich-the { transition: none; }
    .ht-tich-tren { scroll-behavior: auto; }
  }

  /* 🌙 Nền tối: màu đã đi qua biến nên tự đúng, riêng ĐỔ BÓNG đen thì tàng hình
     trên nền tối — đổi sang một vệt sáng mảnh để thẻ đã chọn vẫn nổi lên. */
  body.toi .ht-tich-the.chon {
    box-shadow: 0 1px 3px rgba(0, 0, 0, .5), 0 0 0 1px rgba(255, 255, 255, .06);
  }

/* ══════════════════════════════════════════════════════════════════════════════
   ㊳ Ô CHỌN NHIỀU MỤC CỦA BA MÀN — MỞ RA HỘP THOẠI (Boss chốt 13/09/2026)
   ──────────────────────────────────────────────────────────────────────────────
   Boss bấm chọn hai điều: áp cho cả Dự giờ · Giờ trợ giảng · Follow up HS, và theo
   kiểu MỞ HỘP THOẠI chứ không bày thẻ ngay tại ô trong bảng. Lý do Boss nêu: ô chọn
   ở Dự giờ nằm ngay trong bảng, bày thẻ tại chỗ thì hàng cao lên và một màn thấy
   được ít hàng hơn.

   ⇒ `<details class="dg-chipbox"><summary>` thành `<button class="dg-o-tich">`.

   ⛔⛔ KHỐI NÀY CHỈ LÀM MỘT VIỆC: cho cái nút mới nhìn Y HỆT cái summary cũ.
      Boss KHÔNG xin đổi dáng ô, chỉ xin đổi cách mở. Ô mà nhìn khác đi là tự ý đổi
      thêm một thứ Boss không yêu cầu.
   ⛔ RUỘT Ô KHÔNG ĐỔI MỘT CHỮ: vẫn là `dgChipTom` sinh ra `.dg-tom-tag` ·
      `.dg-tom-trong` · `.dg-tom-mui`. Mọi luật của ba lớp ấy bám `.sheet-moi td`
      chứ không bám `.dg-chipbox`, nên chúng vẫn trúng nguyên vẹn — đã đo bằng
      CSSOM chứ không đọc luật bằng mắt.
   ⛔ ĐỪNG XOÁ CÁC LUẬT `.dg-chipbox` CŨ. Chúng không còn ai dùng trong app, nhưng
      còn nguyên ở đó thì lượt sau muốn quay lại kiểu xổ-tại-chỗ vẫn có sẵn đường về,
      mà xoá thì phải lần lại 36 luật rải khắp file.
   ══════════════════════════════════════════════════════════════════════════════ */
/* ① Gỡ sạch áo mặc định của <button>. Thiếu bước này thì trình duyệt tự cho nó
   phông riêng, chữ căn giữa và nền xám — ô trong bảng lệch hẳn khỏi các ô bên cạnh. */
.dg-o-tich {
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
  /* Dáng hộp — chép đúng `.dg-chipbox > summary` (khối màn Dự giờ, dòng ~4230).
     Đây là dáng dùng ở FORM, nơi cái hộp là đúng. Trong BẢNG thì khối ② gỡ ra. */
  padding: 5px 7px;
  border: 1px solid var(--vien);
  border-radius: var(--r-md);
  background: var(--nen-o);
  min-height: 28px;
}
.dg-o-tich:focus-visible { outline: 2px solid var(--xanh); outline-offset: 1px; }

/* ② TRONG BẢNG thì cởi vỏ hộp — chép đúng `.sheet-moi td .dg-chipbox > summary`
   (khối ⑫, dòng ~12299). Mặc vỏ vào là mỗi ô một khung con nằm trong khung ô, đúng
   thứ Boss chê "không giống Sheets".
   ⛔ Khe ngang PHẢI bằng 0 — xem lý do ở khối ⑫. */
.sheet-moi td .dg-o-tich {
  border: 0;
  border-radius: 0;
  background: transparent;
  padding: 0;
  min-height: 0;
  gap: 0;
}
/* ③ Chiếm trọn ô và căn giữa theo chiều dọc — chép `.sheet-moi tbody td .dg-chipbox`
   (dòng ~13327 và ~14811). Thiếu `min-width:0` thì ô không co được và cột phình ra. */
.sheet-moi tbody td .dg-o-tich {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
}

/* ④ Mũi tên ▾ hiện rõ khi con trỏ vào ô hoặc ô đang được chọn — chép đúng bộ luật
   của summary cũ (dòng ~12398 và ~14646) cho đích danh nút mới. */
.sheet-moi td .dg-o-tich:hover .dg-tom-mui,
.sheet-moi td .dg-o-tich:focus-visible .dg-tom-mui { opacity: 1; }

/* ══════════════════════════════════════════════════════════════════════════════
   ㊴ Ô "＋ TẠO LỰA CHỌN" NẰM NGAY TRONG HỘP THOẠI
   ──────────────────────────────────────────────────────────────────────────────
   ⛔ VÌ SAO KHÔNG MỞ HỘP THỨ HAI: cả app chỉ có MỘT `#htThan` và MỘT tay nghe
      `$("#htOK").onclick`. Mở hộp thoại thứ hai từ trong hộp thứ nhất là ghi đè ruột
      hộp đang mở — người dùng tích xong bảy mục, bấm "Tạo lựa chọn", bảy mục bốc hơi.
   ⛔ Chỉ ô nào nơi gọi khai `themMuc` mới có khối này. Màn Điểm danh không khai, nên
      hộp tích của nó không mọc thêm nút nào — Boss chốt 13/09: *"điểm danh ko được
      thêm bất cứ chức năng nào cả"*.
   ══════════════════════════════════════════════════════════════════════════════ */
.ht-tich-them { margin-top: 8px; }
.ht-tich-them-mo {
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 5px 11px;
  border: 1px dashed var(--vien-ro);
  border-radius: var(--r-lg);
  background: transparent;
  color: var(--chu-mo);
}
.ht-tich-them-mo:hover { border-color: var(--xanh); color: var(--xanh); }
.ht-tich-them-mo:focus-visible { outline: 2px solid var(--xanh); outline-offset: 2px; }
/* ⛔ `[hidden]` phải có luật riêng: `display:flex` ở dòng dưới ĐÈ được `hidden`,
   nên thiếu dòng này thì ô nhập hiện thường trực ngay cả lúc chưa ai bấm mở. */
.ht-tich-them-o[hidden], .ht-tich-them-mo[hidden], .ht-tich-them-loi[hidden] { display: none !important; }
.ht-tich-them-o {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.ht-tich-them-in {
  font: inherit;
  font-size: 13px;
  /* ⛔ `flex: 1 1 160px` + `min-width: 0` — ở khổ 390 ô nhập phải co được, không thì
     hai nút "Thêm"/"Thôi" bị đẩy tràn ra ngoài mép hộp. */
  flex: 1 1 160px;
  min-width: 0;
  padding: 7px 9px;
  border: 1px solid var(--vien);
  border-radius: var(--r-md);
  background: var(--nen-o);
  color: inherit;
}
.ht-tich-them-in:focus { outline: none; border-color: var(--xanh); }
.ht-tich-them-ok, .ht-tich-them-thoi {
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
  flex: none;
  padding: 7px 13px;
  border-radius: var(--r-md);
  border: 1px solid var(--vien);
  background: var(--nen-o);
  color: inherit;
}
.ht-tich-them-ok { background: var(--xanh); border-color: var(--xanh); color: #fff; font-weight: 600; }
.ht-tich-them-ok[disabled] { opacity: .55; cursor: default; }
.ht-tich-them-loi { margin-top: 6px; font-size: 12.5px; color: var(--do); line-height: 1.45; }

/* ============================================================================
   KHUNG XEM DAY DU — phan CSS cua co che o js/tinh-nang.js (sheetMoKhungXem)
   ----------------------------------------------------------------------------
   Boss chot 13/09/2026: bam vao o nhieu chu thi CHI O DO mo ra, duoc tran xuong
   o duoi va sang cot ben phai; het cho duoi thi mo sang phai; khong thua khoang
   trang. Bam mot lan = chi doc, bam dup moi sua.

   ⛔ position: fixed — KHONG phai absolute. Bang nam trong khung cuon rieng
      (.khung-cuon), absolute se bi khung ay cat mat phan tran ra ngoai, dung cai
      Boss doi la "tran xuong o duoi va sang cot ben canh".
   ⛔ z-index phai cao hon o gham (sticky, z-index 2-5) va cao hon thanh cong cu,
      nhung THAP hon hop thoai (.modal-nen dung 12000) — khung nay khong duoc de
      len hop thoai.
   ⛔ NEN DUC hoan toan. Khung trong suot thi chu no chong len chu o duoi, doc
      thanh mot mo — day la ly do khoi 8b cu da ghi va van dung.
   ⛔ pointer-events: none — khung chi de DOC. De no an cu bam thi cu bam thu hai
      cua nguoi dung roi vao khung chu khong roi vao o, va "bam dup de sua" chet.
   ⛔ Dung dat transition/animation: khung mo ra roi dong ngay khi cuon, them nhip
      chuyen la thay chop nhay — dung thu Boss dang che.
   ========================================================================== */
.sheet-khung-xem {
  position: fixed;
  z-index: 60;
  box-sizing: border-box;
  background: var(--the, #fff);
  color: var(--chu, #141F1E);
  border: 2px solid var(--sheet-chon-vien, #00793A);
  border-radius: 4px;
  box-shadow: 0 6px 18px rgba(16, 24, 32, .18);
  white-space: pre-wrap;
  overflow-wrap: break-word;
  word-break: normal;
  text-align: left;
  pointer-events: none;
}

/* O dang duoc xem: giu khung xanh cho biet khung noi kia la cua o nao. */
.sheet-moi tbody td.sheet-o-dang-xem {
  box-shadow: inset 0 0 0 2px var(--sheet-chon-vien, #00793A);
}

/* ⛔⛔ O DANG SUA THI KHONG DUOC KEO CA COT RONG RA — Boss che thang 13/09/2026:
   *"app hien gio dang mo 1 o trong cot do thi toan bo cot tu dong mo ra dieu do
   tao ra hinh toan bo cot mo ra het khung chop nhay 1 luc ngan"*.
   Do that hom ay: bam vao o thi o 260 -> 329px, ca cot va ca bang no theo
   (846 -> 915px). Bay MutationObserver + boc setter style.width cua bang bat duoc
   0 lan, tuc KHONG PHAI JS. Tat tung thuoc tinh cua khoi 8b (position, z-index,
   white-space, text-overflow) cung khong chan duoc.
   THU PHAM la chinh <textarea>: no mang BE RONG NOI TAI theo thuoc tinh cols
   (mac dinh 20 ky tu, khoang 320px o co chu 13px). O rong theo ruot, ruot doi
   theo cols, hai ben keo nhau va trinh duyet go bang kich thuoc noi tai.
   ⇒ Meo chuan: width:1px lam kich thuoc noi tai gan bang 0, roi min-width:100%
     keo lai cho day o. O bam den dau, ruot rong den do — khong nguoc lai.
   ⛔ Ap cho MOI bang sheet chu khong rieng bang nao: do la loi chung. */
.sheet-moi tbody tr.sheet-hang td > textarea,
.sheet-moi tbody tr.sheet-hang td > input[type="text"] {
  width: 1px;
  min-width: 100%;
}

/* ════════════════════════════════════════════════════════════════════════════
   BẢNG XEM ĐẦY ĐỦ MỘT LỰA CHỌN — Boss chốt 17/09/2026 (thay tooltip đen của trình duyệt)
   ────────────────────────────────────────────────────────────────────────────
   Boss: *"nó hiển thị ra 1 block chữ nhật màu đen… tôi muốn bạn sửa nó cho có bo góc
   và màu trắng ở nền chữ đen… kiểu hiệu ứng blur mờ mờ xong nét dần lên hiện hẳn ra
   chứ không phải bụp phát xuất hiện như bây giờ"*.

   ⛔ `position: fixed` và con của `<body>`: `tomXemHien` tính chỗ theo ly màn thật rồi
      chia cho mức phóng. Đặt `absolute` là nó neo vào ô cuộn và trôi mất khi cuộn bảng.
   ⛔ `z-index` PHẢI CAO HƠN hộp thả (100000) trừ một: Boss xin bảng "che các phần đằng
      sau nó đi để nhìn cho rõ", nhưng KHÔNG được che hộp đang chọn — hộp mới là thứ
      người ta đang thao tác.
   ⛔ `pointer-events: none` — ĐỪNG Bỏ. Bảng nằm ngay dưới viên; ăn chuột thì cuộn
      chuột qua nó là `pointerout` bắn ra, bảng tự đóng rồi tự mở lại — nhấp nháy liên tục.
   ⛔ HIỆU ỨNG PHẢI CÓ `filter: blur()` chứ không chỉ `opacity`: Boss tả rõ *"mờ mờ xong
      nét dần"*. Chỉ mờ dần opacity là vẫn "bụp phát", chỉ khác độ đậm.
   ⛔ `prefers-reduced-motion` — giữ đường cho người tắt hiệu ứng trong hệ điều hành.
   ════════════════════════════════════════════════════════════════════════════ */
.tom-xem {
  position: fixed;
  z-index: 99990;
  max-width: 360px;                 /* Boss chốt câu 16 */
  box-sizing: border-box;
  padding: 9px 12px;
  border-radius: 10px;              /* Boss: "cho có bo góc" */
  background: #fff;
  color: #1A1A1A;
  border: 1px solid rgba(0,0,0,.10);
  box-shadow: 0 8px 26px rgba(0,0,0,.16), 0 2px 6px rgba(0,0,0,.08);
  font-size: 13px;
  line-height: 1.5;
  text-align: left;
  white-space: normal;              /* câu dài TỰ XUỐNG DÒNG — Boss câu 12 */
  overflow-wrap: anywhere;
  pointer-events: none;
  opacity: 0;
  filter: blur(6px);
  transform: translateY(-3px);
  transition: opacity .3s ease, filter .3s ease, transform .3s ease;
}
.tom-xem.hien { opacity: 1; filter: blur(0); transform: translateY(0); }
.tom-xem-dong + .tom-xem-dong { margin-top: 5px; }
/* Chế độ tối: nền tối chữ sáng — Boss chốt câu 17. */
body.toi .tom-xem {
  background: #2C3135;
  color: #ECEFF1;
  border-color: rgba(255,255,255,.14);
  box-shadow: 0 8px 26px rgba(0,0,0,.45), 0 2px 6px rgba(0,0,0,.30);
}
@media (prefers-reduced-motion: reduce) {
  .tom-xem { transition: none; filter: none; transform: none; }
}

/* ════════════════════════════════════════════════════════════════════════════
   DỒN CỤM CÔNG CỤ + BẢNG LÊN SÁT THANH TRÊN CÙNG — Boss chốt 17/09/2026 (khuya)
   ────────────────────────────────────────────────────────────────────────────
   Boss: *"tham khảo của google sheet này giữa thanh công cụ và bảng dữ liệu sheet nó
   cách nhau khoảng cách bé tới mức không nhìn thấy được luôn… dồn… lên trên gần cái
   thanh trên cùng màn hình nhất có thể… vì tôi không muốn nó hở ra vùng trắng và để
   diện tích trong các công cụ bị dư thừa"*

   ĐO THẬT trước khi sửa (17/09, Follow up, màn 1600px — từng tầng một):
     `.thanh-tren`      0 → 48
     `.dnc-dai`         48 → 94    (chứa `.sheet-hang-nut` 54 → 87)
     `#noiDung`         94, **padding-top 16px**
     `.dnc-hang-trai`   111 → 151, **margin-bottom 10px**
     hai vỏ CAO 0px    (`.sheet-tcn-vo` + `.sheet-giua-gon`), mỗi cái lề 2px trên dưới
     bảng             161
   ⇒ hở dải xanh → thanh nút = **17px** · hở thanh nút → bảng = **11px**.
   Boss chốt: **4px** và **2px**.

   ⛔⛔ CHỐT LOẠI TRỪAI ĐIỂM DANH bằng ĐÚNG danh sách bảng app đã có (`SHEET_TCN_CHO_PHEP`
      trong js/tinh-nang.js). Lưới Điểm danh là `<table class="luoi">`, KHÔNG mang tên nào
      trong nhóm này — nên nó tự đứng ngoài, không phải thêm cờ hay class mới.
      Đừng đẻ một dấu riêng cho việc này: hai danh sách rồi sẽ lệch nhau, và lệch âm thầm.
   ⛔ KHÔNG DÙNG `!important`: màn nào cần lề riêng sẽ không đè lại được. `#noiDung` +
      `:has()` đã đủ nặng.
   ⛔ KHÔNG BÓP BẰNG `margin` ÂM: bảng sẽ trườn lên đè hàng nút lúc màn hẹp — đã có
      cảnh báo sẵn ở luật `#noiDung > .sheet-hang-nut` bên trên.
   ⛔ HAI VỎ CAO 0px MÀ VẪN ĂN CHỖ: chúng rỗng về chiều cao nhưng lề vẫn cộng dồn.
      Bỏ sót chúng thì bóp hai chỗ kia xong vẫn còn hở 4px không hiểu từ đâu ra.
   ════════════════════════════════════════════════════════════════════════════ */
#noiDung:has(table.dg-bang, table.cts-bang, table.fss-bang, table.lt-bang, table.lt2-bang) {
  padding-top: 4px;                 /* Boss chốt: hở 4px từ thanh trên cùng */
}
/* Thanh nút trắng → bảng: Boss chốt 2px. */
#noiDung:has(table.dg-bang, table.cts-bang, table.fss-bang, table.lt-bang, table.lt2-bang) > .dnc-hang-trai {
  margin-bottom: 2px;
}
/* Hai vỏ cao 0px nằm giữa — không được ăn thêm ly nào. */
#noiDung:has(table.dg-bang, table.cts-bang, table.fss-bang, table.lt-bang, table.lt2-bang) > .sheet-tcn-vo,
#noiDung:has(table.dg-bang, table.cts-bang, table.fss-bang, table.lt-bang, table.lt2-bang) > .sheet-giua-gon {
  margin-top: 0;
  margin-bottom: 0;
}

/* ════════════════════════════════════════════════════════════════════════════
   NÚT ⓘ GOM SỐ LIỆU + BẢNG NỔI — Boss chốt 17/09/2026 (khuya)
   ────────────────────────────────────────────────────────────────────────────
   Boss: *"gom lại 1 nút ấn vào thì nó show số liệu ra và ấn lại để ẩn cái dòng chữ
   thống kê ở các công cụ dạng sheet đi. Làm vậy để gọn hơn được vị trí các công cụ"*

   ⛔⛔ GIẤU `.bl-dem`, KHÔNG GIẤU `.bl-thanh`. Nút "Hiện thêm" nằm trong cùng vỏ ấy —
      giấu cả vỏ là mất luôn đường xem nốt 430 dòng còn lại, mà mất êm ru: không lỗi,
      không bài nào đỏ, chỉ là người dùng không còn bấm được.
   ⛔ GIẤU BẰNG `display:none` CHỨ ĐẮNG `visibility`/`opacity`: `.bl-thanh` là `flex`
      có `gap: 6px`, nên một ô tàng hình vẫn ăn trọn bề ngang của nó cộng thêm một khe.
   ⛔ CHẤM BÁO là `::after` chứ không phải thẻ riêng: khỏi phải dựng/xóa thẻ mỗi lượt vẽ.
      Màu cam (không phải đỏ): đây là lời nhắc *"bảng đang bị cắt bớt"*, không phải lỗi.
   ════════════════════════════════════════════════════════════════════════════ */
.sheet-hang-nut > .sheet-dau-gom.bl-thanh > .bl-dem { display: none; }

.bl-so-nut {
  position: relative;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  margin: 0;
  font-size: 14px;
  line-height: 1;
  color: var(--mo);
  background: transparent;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  transition: background .12s, color .12s;
}
/* ⛔ CỠ CHẮN (16px) chứ đừng 15px của luật chung: `mask-size:contain` chia vùng vẽ theo
   cỡ này, số lẻ là mép vòng tròn rơi vào giữa hai điểm ảnh và bị tán mờ trở lại —
   đúng cái Boss vừa chê. `vertical-align:0` vì nút này là flex canh giữa sẵn rồi. */
.bl-so-nut > i { width: 16px; height: 16px; margin: 0; vertical-align: 0; }
.bl-so-nut:hover { background: rgba(0, 0, 0, .06); color: var(--chu); }
.bl-so-nut[aria-expanded="true"] { background: rgba(0, 121, 58, .12); color: var(--xanh); }
body.toi .bl-so-nut:hover { background: rgba(255, 255, 255, .10); }
/* Chấm báo — chỉ hiện khi bảng đang bị cắt bớt dòng (Boss chốt câu 11). */
/* ⛔ CHẤM PHẢI ĐỨNG Ở MÉP, ĐỪNG ĂN VÀO VÒNG TRÒN — Boss 18/09: *"hơi mờ và nhiễu"*.
   Phần "mờ" là do ký tự phông (đã thay bằng icon vector). Phần "nhiễu" là ở đây:
   chấm đặt `top/right: 1px` nằm ĐÈ LÊN vành vòng tròn, cộng quầng trắng 1.5px nữa là
   cắt hẳn một góc vành — mắt đọc thành "nét đứt, rối". Đẩy ra mép thì vòng tròn liền
   mạch và chấm vẫn thấy rõ.
   Đã ĐO bằng ảnh chụp ở mức phóng 4× — ở 1× không nhìn ra chỗ này. */
.bl-so-nut.co-cham::after {
  content: "";
  position: absolute;
  top: -1px;
  right: -1px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #E08600;
  box-shadow: 0 0 0 1.5px var(--nen, #fff);
}

/* Bảng nổi — đè lên bảng dữ liệu, KHÔNG đẩy gì xuống (Boss chốt câu 10). */
.bl-so-bang {
  position: fixed;
  z-index: 99991;
  max-width: 360px;
  box-sizing: border-box;
  padding: 9px 12px;
  border-radius: 10px;
  background: #fff;
  color: #1A1A1A;
  border: 1px solid rgba(0, 0, 0, .10);
  box-shadow: 0 8px 26px rgba(0, 0, 0, .16), 0 2px 6px rgba(0, 0, 0, .08);
  font-size: 12.5px;
  line-height: 1.5;
  text-align: left;
  white-space: normal;
  overflow-wrap: anywhere;
  opacity: 0;
  transform: translateY(-3px);
  transition: opacity .18s ease, transform .18s ease;
}
.bl-so-bang.hien { opacity: 1; transform: translateY(0); }
.bl-so-dong + .bl-so-dong { margin-top: 5px; color: var(--mo, #666); }
body.toi .bl-so-bang {
  background: #2C3135;
  color: #ECEFF1;
  border-color: rgba(255, 255, 255, .14);
  box-shadow: 0 8px 26px rgba(0, 0, 0, .45), 0 2px 6px rgba(0, 0, 0, .30);
}
@media (prefers-reduced-motion: reduce) {
  .bl-so-bang { transition: none; transform: none; }
}

/* ═══ ⭐ 18/09/2026 — TIÊU ĐỀ CỘT: ĐẬM NHẸ 500 + XUỐNG DÒNG THAY VÌ CẮT CỤT ═══
   Boss: *"Sửa tất cả tiêu đề trong tất cả các cột trong toàn bộ công cụ ko được
   viết tắt nữa sửa lại chữ đầy đủ cho tôi và cho chữ in đậm nhẹ nhàng sẵn cho tôi"*.
   Boss chốt bằng nút bấm: độ đậm **500** · tiêu đề dài **cho xuống hai dòng**.

   ⛔ VIẾT Ở CUỐI FILE, KHÔNG SỬA TẠI CHỖ luật `.bang-keo-cot thead th` (css:4948).
      Luật ấy khai `white-space:nowrap` + ellipsis và ĐÚNG ở thời điểm của nó: 21/08
      Boss chê tiêu đề cụt chỉ còn "ớp" vì <th> căn giữa nên `overflow` cắt cả hai
      đầu. Khối giải thích dài ở trên giữ nguyên làm chứng; luật mới nặng bằng và
      đứng sau nên thắng. Nay Boss đổi ý: thà xuống dòng còn hơn cụt chữ.
   ⛔ GIỮ `overflow:hidden` + `text-overflow:ellipsis` của luật cũ — cột bóp cực hẹp
      thì còn “…”, không để chữ rơi dọc từng ký tự.
   ⛔ `overflow-wrap:break-word` chứ KHÔNG `word-break:break-all`: break-all cắt giữa
      chữ tiếng Việt thành “Số điện tho / ại”.
   ⛔ 700 → 500: `.dg-bang thead th` (css:4201) đang 700. Đừng đi sửa từng bảng một —
      lưới điểm danh và Sổ tuyển sinh còn viết riêng nữa, sót một bảng là lệch hẳn. */
.bang-keo-cot thead th,
.sheet-moi thead th {
  font-weight: 500;
  white-space: normal;
  overflow-wrap: break-word;
  word-break: normal;
  line-height: 1.25;
}

/* ══════════════════════════════════════════════════════════════════════════════
   👥 18/09/2026 — MÀN QUẢN LÝ TÀI KHOẢN DỰNG LẠI (Boss giao, mẫu 21st.dev
   `@arihantcodes/data-table` cho bảng · `@anubra266/invite-team-dialog` cho hộp tạo)
   ──────────────────────────────────────────────────────────────────────────────
   ⛔ VIẾT Ở CUỐI FILE, KHÔNG SỬA TẠI CHỖ các luật `.mtb-*` ở khối 10/09 (css:1959).
      Khối ấy còn dùng nguyên vẹn cho màn "Gán lớp" và cho bảng thành viên ở chỗ
      khác; sửa tại chỗ là đụng luôn những màn không ai nhờ đụng. Luật dưới đây
      nặng bằng hoặc hơn và đứng sau nên thắng ở đúng màn này.
   ⛔ MỌI MÀU ĐỀU PHẢI CÓ BẢN NỀN TỐI. Nền gõ cứng mà chữ để `var(--chu)` thì ở chế
      độ tối chữ hoá sáng và biến mất — đã dính đúng thế ngày 10/09.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ── Dòng đếm đầu màn ─────────────────────────────────────────────────────────
   Boss chốt giữ cả dòng đếm lẫn dòng "Đồng bộ lịch TG gần nhất". Chỉ sắp lại:
   con số tổng đứng đậm trước, sáu chức vụ thành từng ô nhỏ, dòng đồng bộ xuống
   hàng riêng chứ không nối đuôi bằng <br> như cũ. */
.tk-tomtat { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px;
  font-size: 12.5px; color: var(--mo); padding: 2px 0 12px; }
.tk-tt-chinh { font-size: 13.5px; font-weight: 700; color: var(--chu); }
.tk-tt-o { font-variant-numeric: tabular-nums; }
.tk-tt-dongbo { flex: 1 0 100%; font-size: 12px; color: var(--mo); }

/* ── Hàng chip lọc ────────────────────────────────────────────────────────────
   Dáng tab giữ nguyên từ 23/08. Thêm đúng một thứ: chip "Chờ duyệt" có chấm cam
   nhấp nháy nhẹ — việc cần làm ngay thì phải đập vào mắt, mà cả hàng chip đều một
   màu thì nó chìm nghỉm giữa sáu chức vụ. */
.tk-chip.gap { color: var(--cam); }
.tk-chip.gap::before { content: ""; width: 6px; height: 6px; margin-right: 6px;
  border-radius: 999px; background: var(--cam); display: inline-block;
  vertical-align: 1px; animation: tkChamCho 1.9s ease-in-out infinite; }
@keyframes tkChamCho { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) {
  .tk-chip.gap::before { animation: none; }
}

/* ── MỘT BẢNG DUY NHẤT ────────────────────────────────────────────────────────
   ⛔ `overflow:hidden` của `.mtb` phải ĐỔI THÀNH `clip` ở đây: hàng tiêu đề dính
      (`position:sticky`) không dính được bên trong một khối `overflow:hidden` —
      nó cuộn mất cùng nội dung và không ai hiểu vì sao. `clip` cắt góc y hệt mà
      không dựng ra khung cuộn mới. */
.mtb-gom { overflow: clip; }
.mtb-gom .mtb-cuon { overflow-x: auto; overflow-y: visible; }
/* Boss chốt bày hết 79 người, cuộn một mạch — nên hàng tiêu đề phải dính lại trên
   cùng, không thì cuộn tới trợ giảng là quên mất cột nào là cột nào. */
.mtb-gom .mtb-bang thead th { position: sticky; top: 0; z-index: 3;
  background: var(--nen2); }
.mtb-co-tick { min-width: 640px; }
.mtb-gom .mtb-bang tbody tr.dang-chon { background: rgba(20, 160, 160, .10); }
.mtb-gom .mtb-bang tbody tr.dang-chon td:first-child {
  box-shadow: inset 3px 0 0 var(--xanh); }
body.toi .mtb-gom .mtb-bang tbody tr.dang-chon { background: rgba(20, 160, 160, .18); }
/* Hàng vào có nhịp — mẫu 21st.dev Boss gửi có đúng chuyển động này.
   ⛔ CHẶN TRẦN Ở HÀNG THỨ 26 (`--i` đã chặn sẵn bên JS): 79 hàng × 14ms là 1,1 giây
      mới bày xong bảng, người dùng tưởng app treo. */
.mtb-gom .mtb-bang tbody tr { animation: tkHangVao .26s cubic-bezier(.22,.7,.3,1) backwards;
  animation-delay: calc(var(--i, 0) * 14ms); }
@keyframes tkHangVao { from { opacity: 0; transform: translateY(6px); } }
@media (prefers-reduced-motion: reduce) {
  .mtb-gom .mtb-bang tbody tr { animation: none; }
}

/* ── Ô TÍCH ───────────────────────────────────────────────────────────────────
   ⛔ Đích bấm phải là CẢ Ô, không phải mỗi ô vuông 16px: chuẩn tối thiểu 44×44px,
      và trên điện thoại ô vuông 16px là bấm ba lần mới trúng. `<label>` phủ hết ô
      lo việc đó mà không phải viết thêm tay nghe nào. */
.mtb-th-tick, .mtb-td-tick { width: 42px; padding: 0 !important; }
.tk-o-tick-nhan { display: flex; align-items: center; justify-content: center;
  min-height: 44px; padding: 0 12px; cursor: pointer; }
.tk-o-tick-nhan input { width: 16px; height: 16px; margin: 0; cursor: pointer;
  accent-color: var(--xanh); }

/* ── BẤM TÊN CỘT ĐỂ SẮP XẾP ───────────────────────────────────────────────────
   Mũi tên luôn có mặt nhưng mờ, chỉ cột đang sắp mới rõ — ẩn hẳn thì không ai
   đoán được là bấm được, mà hiện rõ cả bốn thì bảng thành cái bàn phím. */
.tk-th-sap { padding: 0 !important; }
.tk-sap { display: flex; align-items: center; gap: 5px; width: 100%;
  padding: 9px 14px; font: inherit; font-size: 12px; font-weight: 600;
  color: var(--chu-mo); background: none; border: 0; cursor: pointer;
  text-align: left; white-space: nowrap; }
.tk-sap:hover { color: var(--chu); background: var(--nen-o); }
.tk-sap:focus-visible { outline: 2px solid var(--xanh); outline-offset: -2px; }
.tk-sap-mui { width: 13px; height: 13px; flex: none; opacity: .3;
  transition: opacity .15s ease, transform .2s ease; }
.tk-th-sap.dang-sap .tk-sap { color: var(--xanh-dam); }
.tk-th-sap.dang-sap .tk-sap-mui { opacity: 1; }
.tk-th-sap.dang-sap.nguoc .tk-sap-mui { transform: rotate(180deg); }

/* ── CỘT LỚP PHỤ TRÁCH: BÀY HẾT ───────────────────────────────────────────────
   Boss 18/09: *"riêng phần lớp phụ trách đó phải có hiển thị ở ngoài đủ nó rất
   quan trọng"*. Mỗi lớp một viên, xuống dòng thoải mái, ô tự cao lên.
   ⛔ ĐỪNG ĐẶT TRẦN CHIỀU CAO rồi cho cuộn trong ô: cuộn trong một ô bảng là thứ
      không ai nghĩ tới mà thử, nên 8 lớp cuối coi như không tồn tại — đúng cái
      Boss vừa bắt sửa.
   ⛔ Cột này phải rộng ra thật: `width:100%` kéo nó ăn hết chỗ thừa, ba cột kia đã
      `white-space:nowrap` nên không bị bóp theo. */
.mtb-gom .mtb-bang td:nth-last-child(2) { width: 100%; min-width: 240px; }
.mtb-gom .mtb-lop { align-items: flex-start; gap: 6px; }
.tk-lop-vien-hang { display: flex; flex-wrap: wrap; gap: 4px; min-width: 0; }
.tk-lop-vien { display: inline-flex; align-items: center; padding: 1px 7px;
  font-size: 11.5px; font-weight: 600; line-height: 1.6; white-space: nowrap;
  color: var(--chu); background: var(--nen2); border: 1px solid var(--vien);
  border-radius: var(--r-md); font-variant-numeric: tabular-nums; }
.mtb-gom .mtb-lop-nut { margin-left: auto; flex: none; }

/* ── THANH NỔI GOM VIỆC ───────────────────────────────────────────────────────
   Boss chốt 18/09: tick vài người thì hiện thanh "Đang chọn N · Đổi chức vụ · Xoá".
   ⛔ `position:fixed` neo vào đáy màn, KHÔNG neo cuối bảng: tick ở hàng thứ 3 rồi
      phải cuộn hết 79 hàng mới tới nút thì thà không có nút.
   ⛔ Chừa chỗ cho vùng an toàn của iPhone (`env(safe-area-inset-bottom)`), không thì
      thanh nằm đúng dưới vạch vuốt và bấm trúng vạch. */
.tk-noi { position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(18px + env(safe-area-inset-bottom, 0px)); z-index: 55;
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  max-width: calc(100vw - 32px);
  padding: 9px 10px 9px 16px; border-radius: 999px;
  background: var(--the); border: 1px solid var(--vien);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .18);
  animation: tkNoiLen .24s cubic-bezier(.22, .7, .3, 1); }
@keyframes tkNoiLen { from { opacity: 0; transform: translate(-50%, 14px); } }
@media (prefers-reduced-motion: reduce) { .tk-noi { animation: none; } }
.tk-noi[hidden] { display: none; }
.tk-noi-dem { font-size: 13px; color: var(--chu); white-space: nowrap; }
.tk-noi-dem b { font-variant-numeric: tabular-nums; }
.tk-noi-nut { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.tk-noi-b { display: inline-flex; align-items: center; gap: 6px; min-height: 36px;
  padding: 0 13px; font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
  color: var(--chu); background: var(--nen2); border: 1px solid var(--vien);
  border-radius: 999px; white-space: nowrap; transition: background .13s, border-color .13s; }
.tk-noi-b:hover { background: var(--nen-o); border-color: var(--xanh); }
.tk-noi-b .ico-nut { width: 14px; height: 14px; flex: none; }
.tk-noi-b.do { color: #C0392B; border-color: #EBC3BD; background: #FDECEA; }
.tk-noi-b.do:hover { background: #F9D9D5; border-color: #C0392B; }
body.toi .tk-noi-b.do { color: #F0A79E; background: rgba(192, 57, 43, .18);
  border-color: rgba(192, 57, 43, .5); }
.tk-noi-thoi { min-height: 36px; padding: 0 10px; font: inherit; font-size: 12.5px;
  color: var(--mo); background: none; border: 0; cursor: pointer; white-space: nowrap; }
.tk-noi-thoi:hover { color: var(--chu); text-decoration: underline; }
/* Thanh nổi che mất mấy hàng cuối bảng — chừa chỗ để hàng cuối vẫn bấm được. */
body.tk-co-thanh-noi #noiDung { padding-bottom: 86px; }

.tk-khong-thay { padding: 26px 16px; text-align: center; font-size: 13px;
  color: var(--mo); }

/* ══ MÀN HẸP: BẢNG HOÁ THẺ XẾP DỌC ═════════════════════════════════════════════
   Boss chốt 18/09. Bảng 5 cột không có cách nào vừa màn 430px; ép cuộn ngang thì
   cột "Lớp phụ trách" — cột Boss vừa bảo là quan trọng nhất — nằm khuất bên phải.
   ⛔ MỘT DOM DUY NHẤT cho cả hai cỡ màn. Vẽ hai bộ HTML là hai chỗ để quên sửa, và
      bài đo sẽ xanh ở bộ này trong khi bộ kia đã hỏng.
   ⛔ `display:block` trên `td` là mất tên cột — nên mỗi ô mang sẵn `data-nhan` và
      hiện nó ra thành nhãn nhỏ. Thiếu bước này thì thẻ chỉ còn một đống chữ.
   ══════════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  .mtb-gom { border: 0; background: none; overflow: visible; }
  .mtb-gom .mtb-cuon { overflow: visible; }
  .mtb-gom .mtb-bang, .mtb-co-tick { min-width: 0; width: 100%; display: block; }
  .mtb-gom .mtb-bang thead { display: none; }
  .mtb-gom .mtb-bang tbody { display: flex; flex-direction: column; gap: 8px; }
  .mtb-gom .mtb-bang tbody tr { display: grid; position: relative;
    grid-template-columns: 42px minmax(0, 1fr) auto;
    align-items: start; gap: 2px 0; padding: 10px 12px 12px;
    background: var(--the); border: 1px solid var(--vien); border-radius: var(--r-md); }
  .mtb-gom .mtb-bang tbody tr:hover { background: var(--the); }
  .mtb-gom .mtb-bang tbody td { display: block; border: 0 !important; padding: 0; }
  .mtb-gom .mtb-bang tbody tr > td:first-child { grid-row: 1; grid-column: 1; }
  .mtb-gom .mtb-bang tbody td[data-nhan="Thành viên"] { grid-row: 1; grid-column: 2; }
  .mtb-gom .mtb-bang tbody td[data-nhan="Chức vụ"] { grid-row: 1; grid-column: 3;
    justify-self: end; padding-right: 34px; }
  /* Nút ⋯ neo vào góc trên phải của thẻ — cùng chỗ trên mọi thẻ thì tay quen ngay. */
  .mtb-gom .mtb-bang tbody td.mtb-td-nut { position: absolute; top: 10px; right: 8px;
    width: auto; grid-row: 1; grid-column: 3; }
  .mtb-gom .mtb-bang tbody td[data-nhan="Lớp phụ trách"] { grid-row: 2;
    grid-column: 2 / -1; margin-top: 9px; padding-top: 9px;
    border-top: 1px solid var(--vien) !important; width: auto; min-width: 0; }
  /* Tên cột hiện lại thành nhãn nhỏ — ô bảng mất `<thead>` thì phải có chữ này. */
  .mtb-gom .mtb-bang tbody td[data-nhan="Lớp phụ trách"]::before {
    content: attr(data-nhan); display: block; margin-bottom: 5px;
    font-size: 10.5px; font-weight: 700; letter-spacing: .05em;
    text-transform: uppercase; color: var(--mo); }
  .mtb-gom .mtb-bang tbody tr.dang-chon td:first-child { box-shadow: none; }
  .mtb-gom .mtb-bang tbody tr.dang-chon { border-color: var(--xanh); }
  /* Ô "Chức vụ" trong thẻ ôm sát chữ, không kéo hết bề ngang như trong bảng. */
  .mtb-gom .mtb-bang .mtb-badge.vt-owner,
  .mtb-gom .mtb-bang .mtb-badge.vt-admin,
  .mtb-gom .mtb-bang .mtb-badge.vt-mem { display: inline-flex; width: auto; }
  .tk-o-tick-nhan { justify-content: flex-start; padding: 0; min-height: 40px; }
  .tk-noi { left: 12px; right: 12px; transform: none; max-width: none;
    justify-content: space-between; }
  @keyframes tkNoiLen { from { opacity: 0; transform: translateY(14px); } }
}

/* ══ HỘP TẠO TÀI KHOẢN — mẫu `@anubra266/invite-team-dialog` ═══════════════════
   Boss 18/09: *"sửa phần tạo tài khoản sao cho giống của 21st dev này bo tròn và
   chức năng có đủ… các mục tạo tài khoản thông tin cần nhập thì để yên như hiện tại"*.
   Nên: ĐỔI DÁNG, KHÔNG ĐỔI Ô. Vẫn đúng ba ô (Boss chốt) — chỉ bo tròn, chia thành
   khối rõ ràng, và hàng mới trượt vào có nhịp.
   ══════════════════════════════════════════════════════════════════════════════ */
.mtv-nhan { font-size: 11px; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--mo); margin: 0 0 8px; }
.mtv-ds { display: flex; flex-direction: column; gap: 8px; }
.mtv-hang { padding: 7px; background: var(--nen2); border: 1px solid var(--vien);
  border-radius: 14px; animation: tkHangVao .22s cubic-bezier(.22,.7,.3,1); }
.mtv-hang input, .mtv-hang select { border-radius: 10px; }
.mtv-hang input:focus, .mtv-hang select:focus {
  box-shadow: 0 0 0 3px rgba(20, 160, 160, .15); }
/* Nút × tròn, chỉ rõ lúc rê vào hàng — bày rõ cả ba cái thì mắt cứ bị kéo về phía
   nút xoá trong khi việc chính là gõ tên. */
.mtv-go { width: 30px; height: 30px; flex: none; border-radius: 999px;
  border: 1px solid transparent; background: none; color: var(--mo);
  font-size: 17px; line-height: 1; cursor: pointer;
  transition: background .13s, color .13s, border-color .13s, opacity .13s; }
.mtv-hang .mtv-go { opacity: .5; }
.mtv-hang:hover .mtv-go, .mtv-hang:focus-within .mtv-go { opacity: 1; }
.mtv-go:hover { background: #FDECEA; color: #C0392B; border-color: #EBC3BD; }
.mtv-go:disabled { opacity: .22; cursor: default; background: none;
  color: var(--mo); border-color: transparent; }
body.toi .mtv-go:hover { background: rgba(192, 57, 43, .2); color: #F0A79E;
  border-color: rgba(192, 57, 43, .45); }
.mtv-them { display: inline-flex; align-items: center; gap: 6px; margin-top: 9px;
  min-height: 38px; padding: 0 14px; font: inherit; font-size: 13px; font-weight: 600;
  color: var(--xanh-dam); background: none; cursor: pointer;
  border: 1px dashed var(--vien); border-radius: 999px;
  transition: background .13s, border-color .13s; }
.mtv-them:hover { background: var(--nen2); border-color: var(--xanh); }
.mtv-mk { margin: 12px 0 0; padding: 11px 13px; font-size: 12.5px; line-height: 1.55;
  color: var(--chu); background: var(--nen2); border: 1px solid var(--vien);
  border-radius: 12px; }
.mtv-vach { margin: 16px 0; border: 0; border-top: 1px solid var(--vien); }
.mtv-link { display: flex; gap: 8px; align-items: center; }
.mtv-link input { flex: 1 1 auto; min-width: 0; height: 40px; padding: 0 13px;
  font-size: 13px; color: var(--chu); background: var(--nen2);
  border: 1px solid var(--vien); border-radius: 10px; }
.mtv-chep { width: 40px; height: 40px; flex: none; display: inline-flex;
  align-items: center; justify-content: center; cursor: pointer;
  color: var(--chu); background: var(--the); border: 1px solid var(--vien);
  border-radius: 10px; transition: border-color .13s, color .13s; }
.mtv-chep:hover { border-color: var(--xanh); color: var(--xanh-dam); }
.mtv-chep svg { width: 16px; height: 16px; }
.mtv-huy { display: flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; margin: 0 0 14px; border-radius: 12px;
  color: var(--xanh-dam); background: var(--nen2); border: 1px solid var(--vien); }
.mtv-huy svg, .mtv-huy i { width: 20px; height: 20px; margin: 0; }
.mtv-xong { padding: 11px 13px; font-size: 13px; line-height: 1.7;
  color: #256B39; background: #E8F5EC; border: 1px solid #B6DDC3; border-radius: 12px; }
body.toi .mtv-xong { color: #A6DCB6; background: rgba(37, 107, 57, .2);
  border-color: rgba(37, 107, 57, .5); }
.mtv-loi { margin-top: 10px; padding: 11px 13px; font-size: 12.5px; line-height: 1.6;
  color: #8E2A20; background: #FDECEA; border: 1px solid #EBC3BD; border-radius: 12px; }
body.toi .mtv-loi { color: #F0A79E; background: rgba(192, 57, 43, .18);
  border-color: rgba(192, 57, 43, .45); }
.mtv-loi[hidden] { display: none; }

/* ══════════════════════════════════════════════════════════════════════════════
   👥 18/09/2026 (LƯỢT 2) — MÀN QUẢN LÝ TÀI KHOẢN: BA KHỐI BO TRÒN TRÊN NỀN XÁM
   ──────────────────────────────────────────────────────────────────────────────
   Boss xem bản lượt 1 rồi chê: *"nhìn ko khác gì như cũ cả cho bé lại đi vừa vin
   và có các block cho đẹp viền tròn và 2 nút tạo tài khoản và đồng bộ vẫn như vậy
   ko đẹp ko thay đổi gì cả"*.

   ⛔ BÀI HỌC GHI LẠI KẺO QUÊN: lượt 1 tôi làm lại đúng cái BẢNG (gom một bảng, tick
      gom, sắp xếp, bày đủ tên lớp) — toàn thứ thật sự cần. Nhưng ba thứ đập vào mắt
      TRƯỚC TIÊN thì không đụng: hai cái nút đầu màn, mảng trắng dàn ngang 1600px, và
      mấy nhãn xám bị kéo dài thành ô nhập liệu. Nên mở ra "y như cũ" là đúng — người
      dùng chấm điểm bằng cái nhìn đầu tiên, không bằng danh sách việc mình đã làm.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ── ① NỀN XÁM + BÓ BỀ NGANG ──────────────────────────────────────────────────
   ⛔ Phải kèm CẢ HAI class trong bộ chọn (`body.man-cong-cu` + `.nd-co-cuon`), y như
      đã làm cho Trang chủ hôm nay: luật `body.man-cong-cu .noi-dung.nd-co-cuon` nặng
      (0,3,0), viết `body:has(...) .noi-dung` (0,2,1) là THUA LẶNG LẼ — trang vẫn hiện
      bình thường, chỉ là nền không đổi, và mình ngồi soi CSS mãi không ra.
   ⛔ Dùng ĐÚNG biến nền của Trang chủ, đừng gõ một mã màu xám khác: hai màn đứng
      cạnh nhau mà lệch tông thì lộ ra ngay là hai người làm. */
body.man-cong-cu:has(.tk-boc) .noi-dung,
body.man-cong-cu:has(.tk-boc) .noi-dung.nd-co-cuon { background: var(--home-nen, #EFEDE8); }
.tk-boc { max-width: 1200px; margin: 0 auto; padding: 4px 0 8px; }
.tk-khoi { background: var(--the); border: 1px solid var(--vien); border-radius: 16px;
  padding: 14px 16px; margin: 0 0 12px; }
.tk-khoi-bang { padding: 0; overflow: clip; }
body.toi .tk-khoi { border-color: var(--vien); }

/* ── ② HAI NÚT ĐẦU MÀN ────────────────────────────────────────────────────────
   Nút chính nền đậm bo tròn hẳn, nút phụ chỉ viền mảnh — bậc việc đọc được ngay,
   không phải hai cái nút giống hệt nhau như trước.
   ⛔ `.nut-them-tk` là tên lớp CÓ SẴN, không đổi: mã và bài kiểm đang bám vào nó. */
.tk-thanh { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin: 0; }
.tk-khoi-thanh .nut-them-tk { display: inline-flex; align-items: center; gap: 7px;
  min-height: 42px; padding: 0 18px; border-radius: 999px;
  font-size: 13.5px; font-weight: 600; cursor: pointer;
  color: #FFFFFF; background: var(--xanh); border: 1px solid var(--xanh);
  box-shadow: 0 1px 2px rgba(0,0,0,.08); transition: background .14s, box-shadow .14s; }
.tk-khoi-thanh .nut-them-tk:hover { background: var(--xanh-dam); border-color: var(--xanh-dam);
  box-shadow: 0 3px 10px rgba(20,160,160,.28); }
.tk-khoi-thanh .nut-them-tk .ico-nut,
.tk-khoi-thanh .nut-them-tk i { width: 15px; height: 15px; margin: 0; }
/* Nút phụ: cùng dáng viên thuốc nhưng chỉ có viền — cùng họ, khác bậc. */
.tk-khoi-thanh .nut-them-tk.phu { color: var(--chu); background: var(--the);
  border-color: var(--vien); box-shadow: none; font-weight: 500; }
.tk-khoi-thanh .nut-them-tk.phu:hover { background: var(--nen2); border-color: var(--xanh);
  color: var(--xanh-dam); box-shadow: none; }
.tk-khoi-thanh .nut-them-tk.phu .ico-nut { color: var(--mo); }

/* Ô tìm: kính lúp nằm TRONG ô, bo tròn cùng họ với hai nút. */
.tk-o-tim { position: relative; display: flex; align-items: center; flex: 1 1 260px;
  min-width: 190px; }
.tk-o-tim svg { position: absolute; left: 14px; width: 16px; height: 16px;
  color: var(--mo); pointer-events: none; }
.tk-thanh .tk-o-tim input, .tk-khoi-thanh #oTimTK {
  width: 100%; min-width: 0; height: 42px; padding: 0 14px 0 38px;
  font-size: 16px;                /* 16px: iPhone khỏi tự phóng to lúc gõ */
  font-family: inherit; color: var(--chu);
  background: var(--nen2); border: 1px solid var(--vien); border-radius: 999px;
  transition: background .14s, border-color .14s, box-shadow .14s; }
.tk-thanh .tk-o-tim input:focus { outline: none; background: var(--the);
  border-color: var(--xanh); box-shadow: 0 0 0 3px rgba(20,160,160,.15); }

/* ── ③ Ô SỐ LIỆU ──────────────────────────────────────────────────────────────
   ⛔ `tabular-nums` là bắt buộc: số không cùng bề rộng thì hàng ô nhảy tới nhảy lui
      mỗi lần đếm lại, trông như trang bị giật. */
.tk-so { display: flex; flex-wrap: wrap; gap: 8px; }
.tk-so-o { display: flex; flex-direction: column; gap: 1px; min-width: 76px;
  padding: 8px 12px; background: var(--nen2); border: 1px solid var(--vien);
  border-radius: 12px; }
.tk-so-o b { font-size: 18px; font-weight: 700; line-height: 1.15; color: var(--chu);
  font-variant-numeric: tabular-nums; }
.tk-so-o span { font-size: 11.5px; color: var(--mo); line-height: 1.3; }
.tk-so-tong { background: var(--xanh); border-color: var(--xanh); }
.tk-so-tong b, .tk-so-tong span { color: #FFFFFF; }
.tk-so-tong span { opacity: .86; }
.tk-so-o.cho { border-color: var(--cam); background: rgba(232,163,61,.12); }
.tk-so-o.cho b { color: var(--cam); }
.tk-tt-dongbo { margin-top: 10px; font-size: 12px; color: var(--mo); }
.tk-tt-dongbo .cho { color: var(--cam); }

/* ── ④ CHIP LỌC KIỂU VIÊN THUỐC ───────────────────────────────────────────────
   ⛔ Đè lên dáng tab gạch chân của 23/08 chứ KHÔNG sửa luật ấy: cùng tên lớp
      `.tk-chip` còn dùng ở màn khác (`.tk-chip-hang` bên Sổ tuyển sinh). */
.tk-khoi-loc .tk-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 12px 0 0;
  padding: 0; border-bottom: 0; overflow: visible; }
.tk-khoi-loc .tk-chip { display: inline-flex; align-items: center; gap: 6px;
  min-height: 34px; padding: 0 13px; margin: 0;
  font-size: 12.5px; font-weight: 500; cursor: pointer; white-space: nowrap;
  color: var(--chu); background: var(--nen2);
  border: 1px solid var(--vien); border-radius: 999px;
  transition: background .13s, border-color .13s, color .13s; }
.tk-khoi-loc .tk-chip:hover { background: var(--nen-o); border-color: var(--xanh); }
.tk-khoi-loc .tk-chip.chon { color: #FFFFFF; font-weight: 600;
  background: var(--xanh-dam); border-color: var(--xanh-dam); }
.tk-khoi-loc .tk-chip .dem-nhom { font-size: 11.5px; font-weight: 600; opacity: .6;
  font-variant-numeric: tabular-nums; }
.tk-khoi-loc .tk-chip.chon .dem-nhom { opacity: .9; }
.tk-khoi-loc .tk-chip.gap { color: var(--cam); border-color: rgba(232,163,61,.55); }
.tk-khoi-loc .tk-chip.gap.chon { color: #FFFFFF; background: var(--cam); border-color: var(--cam); }
.tk-khoi-loc .tk-chip-kholop { border-style: dashed; }

/* ── ⑤ BẢNG: NHẸ ĐI, KHÔNG SỌC SO LE ──────────────────────────────────────────
   Khối bảng đã bo tròn ở ngoài rồi nên khung trong bỏ viền, kẻo hai viền chồng nhau
   thành một đường đôi. */
.tk-khoi-bang .mtb { border: 0; border-radius: 0; background: none; }
.tk-khoi-bang .mtb-bang thead th { background: var(--nen2); font-size: 11.5px;
  letter-spacing: .01em; }
.tk-khoi-bang .mtb-bang tbody td { padding: 9px 14px; }
.tk-khoi-bang .mtb-bang tbody tr:hover { background: var(--nen-o); }
/* ⛔ NHÃN CHỨC VỤ ÔM SÁT CHỮ — đè luật `width:100%` của 10/09 (Boss lúc ấy xin cho
   kín ô; nay 18/09 Boss xem ảnh và đổi ý: kéo dài trông như ô nhập liệu bỏ trống).
   Luật cũ để nguyên vì màn "Gán lớp" còn dùng. */
.tk-khoi-bang .mtb-bang .mtb-badge.vt-owner,
.tk-khoi-bang .mtb-bang .mtb-badge.vt-admin,
.tk-khoi-bang .mtb-bang .mtb-badge.vt-mem {
  display: inline-flex; width: auto; justify-content: flex-start;
  padding: 2px 10px; border-radius: 999px; }
.tk-khoi-bang .mtb-bang td[data-nhan="Chức vụ"] { white-space: nowrap; width: 1%; }
/* "Thấy mọi lớp" / "Chưa có lớp nào": chữ mờ, không khung. */
.tk-moi-lop, .tk-chua-lop { font-size: 12.5px; color: var(--mo); }
.tk-chua-lop { color: #B0645C; }
body.toi .tk-chua-lop { color: #E0958C; }
.tk-dem-lop { border-radius: 999px; padding: 2px 9px; }

/* Ảnh đại diện to hơn một chút, có viền mảnh. */
.tk-khoi-bang .tk-anh { width: 36px; height: 36px; flex: none; border-radius: 999px;
  border: 1px solid var(--vien); overflow: hidden; display: inline-flex;
  align-items: center; justify-content: center; }
.tk-khoi-bang .tk-anh img { width: 100%; height: 100%; object-fit: cover; }

/* Tên + hai chấm cảnh báo trên cùng một hàng. */
.tk-ten-hang { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; }
.tk-cham-nho { display: inline-flex; align-items: center; justify-content: center;
  width: 19px; height: 19px; flex: none; border-radius: 999px; cursor: help;
  color: var(--mo); background: var(--nen2); border: 1px solid var(--vien); }
.tk-cham-nho .ico-the { width: 11px; height: 11px; margin: 0; }
.tk-cham-nho.canh { color: #8A5A00; background: #FFF8E1; border-color: #E8D9A8; }
body.toi .tk-cham-nho.canh { color: #E8C877; background: rgba(138,90,0,.26);
  border-color: rgba(232,217,168,.4); }
.tk-khoi-bang .mtb-the-hang { margin-top: 4px; }

/* Chip lớp + nút "+ Gán lớp" nối đuôi nhau thành một dãy. */
.tk-khoi-bang .mtb-lop { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
.tk-khoi-bang .tk-lop-vien-hang { display: contents; }
.tk-khoi-bang .mtb-lop-nut { margin: 0; flex: none; display: inline-flex;
  align-items: center; min-height: 22px; padding: 1px 9px;
  font-size: 11.5px; font-weight: 600; text-decoration: none; cursor: pointer;
  color: var(--xanh-dam); background: none;
  border: 1px dashed var(--vien); border-radius: var(--r-md);
  transition: background .13s, border-color .13s; }
.tk-khoi-bang .mtb-lop-nut:hover { background: var(--nen2); border-color: var(--xanh);
  color: var(--xanh-dam); text-decoration: none; }

/* ── ⑥ MÀN HẸP ────────────────────────────────────────────────────────────────
   Khối bo tròn giữ nguyên, chỉ thu đệm lại cho khỏi ăn mất bề ngang. */
@media (max-width: 640px) {
  .tk-boc { max-width: none; }
  .tk-khoi { padding: 11px 12px; border-radius: 14px; }
  .tk-khoi-bang { padding: 0; background: none; border: 0; }
  .tk-so-o { min-width: 68px; padding: 7px 10px; }
  .tk-so-o b { font-size: 16px; }
  .tk-khoi-thanh .nut-them-tk { flex: 1 1 auto; justify-content: center; }
  .tk-o-tim { flex: 1 1 100%; }
}

/* ── ⑧ 18/09/2026 (lượt 3) — THANH CÔNG CỤ DÍNH LẠI KHI CUỘN ────────────────────
   Boss: *"lúc kéo xuống thì cái thanh tìm kiếm, tạo tài khoản… phải đi theo"*.
   ⛔ `top` phải trừ chỗ của THANH TRÊN của app (`.thanh-tren` cũng `sticky top:0`,
      cao ~50px, z-index 50). Đặt `top:0` là khối này chui tọt xuống dưới thanh ấy
      và chỉ còn thấy một mảnh.
   ⛔ `z-index` phải THẤP HƠN 50 của thanh trên nhưng CAO HƠN 3 của hàng tiêu đề cột.
   ⛔ Nền phải ĐỤC: khối dính mà nền trong suốt thì chữ của bảng chạy xuyên qua nó. */
.tk-dinh { position: sticky; top: 56px; z-index: 24; }
/* Hàng tiêu đề cột dính NGAY DƯỚI khối thanh — chiều cao thật do JS đo và ghi vào
   `--tk-thanh-cao` ngay sau khi vẽ màn (xem `.tk-khoi-thanh` trong js/tinh-nang.js).
   ⛔⛔ 19/09/2026 — ĐÃ BỎ `+ 12px` Ở ĐÂY. ĐỪNG THÊM LẠI.
      12px ấy vốn là để bù cho `margin: 0 0 12px` của `.tk-khoi`. Nhưng khi CẢ HAI
      cùng dính thì nó không còn là khoảng cách giữa hai khối nữa — nó là một KHE
      TRONG SUỐT nằm chình ình giữa đáy thanh tìm kiếm và đỉnh hàng tiêu đề cột, và
      tên người ở các hàng bên dưới chạy qua đúng khe đó. Boss 19/09: *"lúc kéo xuống
      ko hở ra cái tên và chữ ở đằng sau trông hơi thiếu chuyên nghiệp"*.
      Phần margin vẫn còn nguyên trong dòng chảy — xem `.tk-khoi-thanh` bên dưới. */
.tk-khoi-bang .mtb-bang thead th { top: calc(56px + var(--tk-thanh-cao, 74px)); }
@media (max-width: 640px) {
  /* Màn hẹp: thanh trên mỏng hơn, và khối thanh cao hơn vì xuống hai dòng. */
  .tk-dinh { top: 48px; }
  .tk-khoi-bang .mtb-bang thead th { top: 0; }
}

/* ── ⑨ 19/09/2026 — GHÉP HAI THANH LẠI KHI CUỘN ───────────────────────────────
   Boss chốt bằng nút bấm: **"Bình thường thì rời, cuộn mới dính"** · **"Có — thu
   thấp lại khi cuộn"** · **"Nền ĐẶC hẳn + viền dưới mảnh"**.
   Cờ `body.tk-thanh-dinh` do JS bật/tắt bằng một mốc vô hình cao 1px đặt ngay trên
   khối thanh (xem `tk-moc-dinh` trong js/tinh-nang.js) — không đo lại bố cục mỗi nhịp
   cuộn, nên không có màn nào giật. */
.tk-moc-dinh { height: 1px; margin: 0 0 -1px; pointer-events: none; }

/* ⛔⛔ HAI DÒNG DƯỚI ĐÂY PHẢI ĐI VỚI NHAU, ĐỪNG TÁCH.
   Thanh dính kiểu `sticky` vẫn CHIẾM ĐÚNG CHỖ CŨ trong dòng chảy, nên bớt đệm đi
   12px mà không bù lại là cả cái bảng nhảy lên 12px đúng lúc nó dính — giật một phát
   ngay giữa cú cuộn. Nên đệm bớt bao nhiêu thì `margin-bottom` cộng bù đúng bấy
   nhiêu: chiều cao TRONG DÒNG CHẢY không đổi, chỉ phần VẼ RA mới thấp xuống.
   Sửa `--tk-dem` hay `--tk-dem-dinh` thì phép tính tự theo — đừng gõ số chết. */
.tk-khoi-thanh { --tk-dem: 14px; --tk-dem-dinh: 8px; }
body.tk-thanh-dinh .tk-khoi-thanh {
  padding-top: var(--tk-dem-dinh); padding-bottom: var(--tk-dem-dinh);
  margin-bottom: calc(12px + 2 * (var(--tk-dem) - var(--tk-dem-dinh)));
  /* Nền ĐẶC hẳn: khối dính mà nền trong suốt thì chữ của bảng chạy xuyên qua nó. */
  background: var(--the);
  /* Bo góc dưới về 0 để ghép liền với hàng tiêu đề cột đậu ngay bên dưới; viền dưới
     mảnh là đường phân cách duy nhất giữa hai thanh, không đổ bóng. */
  border-bottom-left-radius: 0; border-bottom-right-radius: 0;
  border-bottom: 1px solid var(--vien); }
@media (max-width: 640px) { .tk-khoi-thanh { --tk-dem: 11px; } }

/* ⛔ CUỘN TỚI MỘT HÀNG THÌ ĐỪNG ĐỂ NÓ CHUI DƯỚI THANH DÍNH — bài đo 18/09 bắt được:
   bấm ô tích của một hàng thì trình duyệt cuộn hàng đó lên đúng vùng bị khối thanh và
   hàng tiêu đề cột đè lên, cú bấm rơi vào thanh chứ không vào ô tích.
   ⛔ ĐÂY KHÔNG CHỈ LÀ CHUYỆN CỦA BÀI ĐO: tính năng "nhảy tới hàng học sinh" (thanh
      tìm tổng thể) cũng dùng `scrollIntoView` — thiếu dòng này thì nó nhảy tới đúng
      một hàng đang bị che. */
.tk-khoi-bang .hang-tk { scroll-margin-top: calc(56px + var(--tk-thanh-cao, 74px) + 62px); }
@media (max-width: 640px) {
  .tk-khoi-bang .hang-tk { scroll-margin-top: calc(48px + var(--tk-thanh-cao, 96px) + 16px); }
}

/* ⛔ HÀNG TIÊU ĐỀ CỘT KHÔNG DÍNH ĐƯỢC — vá 18/09/2026 sau khi ĐO THẬT.
   Đo trên trình duyệt: cuộn 700px thì `thead` có `top = -216px`, tức trôi mất chứ
   không dính. `position:sticky` chỉ dính trong PHẦN TỬ CHA gần nhất có `overflow`
   khác `visible` — ở đây là `.mtb-cuon { overflow-x: auto }`. Khung ấy không cuộn
   theo trục dọc, nên thead "dính" bên trong nó và trôi lên cùng cả khung.
   ⛔ ĐỪNG CHỮA BẰNG `z-index` HAY `top` — hai thứ ấy không dính dáng gì tới đây, và
      sửa chúng thì chỉ tốn buổi mà thead vẫn trôi.
   ⛔ Bỏ khung cuộn ngang ở ĐÚNG MÀN NÀY thôi, không đụng luật `.mtb-cuon` chung:
      bảng đã bó 1200px nên không còn gì để cuộn ngang, còn màn hẹp thì bảng đã hoá
      thẻ xếp dọc. Màn khác vẫn dùng `.mtb-cuon` như cũ. */
.tk-khoi-bang .mtb-cuon { overflow-x: visible; overflow-y: visible; }
.tk-khoi-bang, .tk-khoi-bang .mtb { overflow: visible; }
/* Bảng không còn khung cuộn thì phải tự biết co lại, không được đẩy tràn cả trang. */
.tk-khoi-bang .mtb-co-tick { min-width: 0; }
/* Góc bảng vẫn phải bo theo khối — trước đây `overflow:clip` lo việc cắt góc. */
.tk-khoi-bang .mtb-bang thead th:first-child { border-top-left-radius: 16px; }
.tk-khoi-bang .mtb-bang thead th:last-child { border-top-right-radius: 16px; }
.tk-khoi-bang .mtb-bang tbody tr:last-child td:first-child { border-bottom-left-radius: 16px; }
.tk-khoi-bang .mtb-bang tbody tr:last-child td:last-child { border-bottom-right-radius: 16px; }
@media (max-width: 640px) {
  .tk-khoi-bang .mtb-bang thead th:first-child,
  .tk-khoi-bang .mtb-bang thead th:last-child,
  .tk-khoi-bang .mtb-bang tbody tr:last-child td:first-child,
  .tk-khoi-bang .mtb-bang tbody tr:last-child td:last-child { border-radius: 0; }
}

/* ⛔ HÀNG ĐỈ LÊN HÀNG TIÊU ĐỀ CỘT — Boss chụp ảnh báo 18/09/2026.
   Sau khi cho tiêu đề cột dính được thật, các hàng trôi lên lại VẼ ĐÈ LÊN nó:
   trong bảng, `tbody` vẽ SAU `thead`, nên cùng một mức chồng thì hàng thắng. `z-index:3`
   cũ không đủ vì mỗi hàng còn có `animation` (transform) — đang chạy thì nó tự dựng một
   tầng chồng riêng và trèo lên trên.
   ⛔ NÂNG thật cao (12) chứ đừng nhích lên 4–5: khối thanh dính ở 24, còn menu ⋯ là
      `fixed` ở 60 — còn chỗ trống hẳn giữa hai số ấy.
   ⛔ VÀ PHẢI GHIM NỀN ĐỤC cho `th`: nền trong suốt thì dù nằm trên, chữ của hàng
      bên dưới vẫn hiện xuyên qua và chồng chữ. */
.tk-khoi-bang .mtb-bang thead th { z-index: 12; background: var(--nen2); }
.tk-khoi-bang .mtb-bang tbody tr { position: relative; z-index: 0; }
/* Hàng đang chọn vẫn phải nổi trên hàng thường, nhưng vẫn DƯỚI tiêu đề cột. */
.tk-khoi-bang .mtb-bang tbody tr.dang-chon { z-index: 1; }

/* ⛔ THANH NỔI BỊ THANH CÔNG CỤ ĐÁY CHE TRÊN ĐIỆN THOẠI — bài đo 18/09 bắt được:
   Playwright báo `#thanhDuoi … intercepts pointer events`, tức cú bấm vào nút "Bỏ
   chọn" rơi vào thanh công cụ chứ không vào nút. Người dùng thật cũng vậy.
   ⛔ `bottom` phải tính cả chiều cao thanh đáy (~62px) LẪN vùng an toàn của iPhone.
   ⛔ Chỉ áp ở màn hẹp: màn rộng không có thanh đáy, đẩy lên là thừa một mảng trống. */
@media (max-width: 640px) {
  .tk-noi { bottom: calc(70px + env(safe-area-inset-bottom, 0px)); }
  body.tk-co-thanh-noi #noiDung { padding-bottom: 150px; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   👤 18/09/2026 — MENU AVATAR theo mẫu 21st.dev `@kokonutd/profile-dropdown`
   ──────────────────────────────────────────────────────────────────────────────
   Boss chốt qua nút bấm: giữ ĐÚNG 5 mục đang có, chỉ làm đẹp; đầu menu bày ảnh +
   tên + chức vụ + chấm xanh "đang online" + Gmail đã liên kết.
   ⛔ Viết ở cuối file, không sửa tại chỗ khối `.tk-menu` ở css:607 — khối ấy còn
      giữ mũi tên, hiệu ứng mở và bốn mục ẩn; luật dưới đây nặng bằng và đứng sau.
   ══════════════════════════════════════════════════════════════════════════════ */

/* Hộp rộng hơn một chút để dòng Gmail không phải cắt giữa chừng. */
.tk-menu { min-width: 268px; border-radius: 16px; padding: 7px; }

/* ── Đầu menu ─────────────────────────────────────────────────────────────────
   ⛔ Nền nhạt cho cả khối đầu, không chỉ kẻ một vạch dưới: phần "bạn là ai" tách
      hẳn khỏi phần "bạn làm được gì" thì mắt không phải đọc lại tên mỗi lần liếc. */
.tk-menu .tk-dau { gap: 11px; padding: 11px 12px; margin: -1px -1px 7px;
  background: var(--nen2); border: 0; border-radius: 12px; }
.tk-dau-chu { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.tk-menu .tk-dau b { font-size: 14px; font-weight: 600; line-height: 1.3; }
.tk-menu .tk-dau small { margin: 0; opacity: .7; }
/* Gmail dài hơn bề ngang menu thì cắt bằng "…", đừng để nó đẩy hộp phình ra. */
.tk-dau-mail { overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 190px; opacity: .58 !important; }
.tk-dau-mail[hidden] { display: none; }

/* ── Chấm xanh "đang online" ──────────────────────────────────────────────────
   ⛔ Vẽ bằng `::after` trên chính ảnh, KHÔNG thêm thẻ rời: thẻ rời phải tự tính
      toạ độ theo cỡ ảnh, mà ảnh đổi cỡ theo màn.
   ⛔ Vòng viền cùng màu nền khối đầu (`--nen2`) để chấm tách khỏi ảnh — thiếu vòng
      ấy thì chấm chìm vào ảnh đại diện tối màu. */
.tk-menu .tk-dau .tk-anh { position: relative; flex: none; }
.tk-menu .tk-dau .tk-anh::after {
  content: ""; position: absolute; right: -1px; bottom: -1px;
  width: 11px; height: 11px; border-radius: 999px;
  background: #22A06B; border: 2px solid var(--nen2); }
body.toi .tk-menu .tk-dau .tk-anh::after { background: #3BC98A; }

/* ── Các mục ──────────────────────────────────────────────────────────────────
   Icon đứng thành một cột thẳng nhau; chữ nhích sang cho dễ đọc. */
.tk-menu button { display: flex; align-items: center; gap: 10px;
  min-height: 38px; padding: 0 11px; border-radius: 10px;
  transition: background .12s ease; }
.tk-menu button i[class^="ic-"], .tk-menu button i[class*=" ic-"] {
  width: 16px; height: 16px; flex: none; margin: 0; opacity: .72; }
.tk-menu button:hover { background: var(--nen2); }
.tk-menu button.do { color: #C0392B; }
.tk-menu button.do:hover { background: #FDECEA; }
body.toi .tk-menu button.do:hover { background: rgba(192, 57, 43, .18); }
.tk-menu button[hidden] { display: none; }

/* ── Hai nút Sáng / Tối ───────────────────────────────────────────────────────
   Bo tròn hẳn cho cùng họ với các nút khác trong app sau lượt sửa hôm nay. */
.tk-menu .tk-nhan-nho { padding: 9px 11px 5px; font-size: 10.5px; font-weight: 700;
  letter-spacing: .05em; text-transform: uppercase; opacity: .75; }
.tk-menu .tk-chedo { gap: 6px; padding: 0 7px 5px; }
.tk-menu .tk-chedo button { min-height: 34px; border-radius: 999px; }
.tk-menu .tk-vach { margin: 7px 5px; }

/* ══════════════════════════════════════════════════════════════════════════════
   🔔 18/09/2026 — THANH THÔNG BÁO dựng lại theo mẫu 21st.dev `@uvain/notification-panel`
   ──────────────────────────────────────────────────────────────────────────────
   Boss gửi link và chốt qua nút bấm: gom theo ngày (Hôm nay · Hôm qua · Tuần này ·
   Cũ hơn) · hàng lọc (Tất cả · Chưa đọc · Việc của tôi · Hệ thống) · thêm dấu
   "xong việc" RIÊNG với "đã đọc" · giữ cả ba nút cũ, thu nhỏ và xếp vừa · giữ nết
   trượt ra từ mép phải.

   ⛔ VIẾT Ở CUỐI FILE, KHÔNG SỬA TẠI CHỖ khối `.tb-*` ở css:5060 — khối ấy còn giữ
      phần trượt, nền mờ, và cái chuông có số. Luật dưới đây nặng bằng và đứng sau
      nên thắng ở những chỗ cố ý đè.
   ⛔ HÀNG TIN NAY LÀ HÀNG CÓ VẠCH NGĂN, KHÔNG CÒN LÀ THẺ RỜI CÓ VIỀN. Đây là đổi
      có chủ ý theo đúng mẫu Boss gửi: 40 cái thẻ bo góc xếp dọc thì mỗi dòng tự
      đòi một khoảng hở, đọc lướt thành ra rời rạc. Đừng "sửa lại cho giống cũ".
   ══════════════════════════════════════════════════════════════════════════════ */

.tb-bang { width: min(408px, 100%); }

/* ── Đầu bảng ─────────────────────────────────────────────────────────────── */
.tb-bang .tb-dau { align-items: center; gap: 11px; padding: 13px 14px; }
.tb-dau-ico { flex: none; width: 32px; height: 32px; border-radius: 10px;
  display: grid; place-items: center; background: var(--the); color: var(--muc);
  border: 1px solid var(--vien); }
.tb-dau-ico .ico { width: 17px; height: 17px; margin: 0; }
.tb-dau-chu { display: flex; flex-direction: column; gap: 1px; min-width: 0; }

/* ── Hàng lọc ─────────────────────────────────────────────────────────────────
   ⛔ `overflow-x:auto` + ẩn thanh cuộn: bốn thẻ vừa khít 390px, nhưng màn 320px
      thì không — cho nó trượt ngang còn hơn để chữ bị nén vỡ. */
.tb-tab { flex: none; display: flex; align-items: stretch; gap: 2px;
  padding: 0 8px; background: var(--the); border-bottom: 1px solid var(--vien);
  overflow-x: auto; scrollbar-width: none; }
.tb-tab::-webkit-scrollbar { display: none; }
.tb-tab[hidden] { display: none; }
.tb-tab button { position: relative; flex: none; display: inline-flex; align-items: center;
  gap: 6px; border: 0; background: none; font-family: inherit; font-size: 12.5px;
  font-weight: 600; color: var(--mo); padding: 9px 8px 10px; cursor: pointer;
  white-space: nowrap; }
.tb-tab button:hover { color: var(--chu); }
.tb-tab button.chon { color: var(--chu); }
/* Vạch dưới thẻ đang chọn — đúng nết của mẫu, và rõ hơn kiểu tô nền cả thẻ. */
.tb-tab button.chon::after { content: ""; position: absolute; left: 6px; right: 6px;
  bottom: -1px; height: 3px; border-radius: 999px 999px 0 0; background: var(--muc); }
.tb-tab-so { min-width: 16px; height: 16px; padding: 0 4px; border-radius: 999px;
  background: var(--muc); color: #fff; font-size: 10px; font-weight: 700;
  line-height: 16px; text-align: center; }
.tb-tab-so[hidden] { display: none; }

/* ── Ba nút cũ, thu nhỏ ───────────────────────────────────────────────────────
   Boss 18/09: *"giữ cả ba, thu nhỏ và xếp vừa"* — ảnh Boss chụp cho thấy ba nút có
   viền, `flex:1`, chữ 11,5px đang tràn khỏi mép phải. Nay là nút CHỮ MỜ không viền,
   `flex-wrap` để màn hẹp thì xuống dòng chứ không đẩy nhau ra ngoài. */
.tb-bang .tb-thanh { flex: none; display: flex; flex-wrap: wrap; gap: 4px 6px;
  padding: 8px 10px; }
.tb-bang .tb-thanh button { flex: 0 0 auto; display: inline-flex; align-items: center;
  gap: 5px; border: 0; background: none; color: var(--mo); border-radius: 999px;
  padding: 5px 9px; font-size: 11px; font-weight: 600; white-space: nowrap; }
.tb-bang .tb-thanh button:hover { background: var(--nen2); color: var(--chu);
  border-color: transparent; }
.tb-bang .tb-thanh button i[class^="ic-"] { width: 13px; height: 13px; margin: 0;
  flex: none; opacity: .85; }
.tb-bang .tb-thanh button[hidden] { display: none; }

/* ── Danh sách ────────────────────────────────────────────────────────────── */
.tb-bang .tb-ds { padding: 0 0 14px; }

/* Mốc ngày — dính lại khi cuộn, để lúc nào cũng biết mình đang đọc mốc nào. */
.tb-moc { position: sticky; top: 0; z-index: 2; display: flex; align-items: center;
  gap: 8px; padding: 10px 14px 5px; background: var(--the);
  font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--mo); }
.tb-moc b { padding: 1px 6px; border-radius: 999px; background: var(--nen2);
  font-size: 10px; font-weight: 700; letter-spacing: 0; opacity: .85; }

.tb-bang .tb-1 { margin: 0; padding: 11px 14px; gap: 11px; background: transparent;
  border: 0; border-bottom: 1px solid var(--vien); border-radius: 0; box-shadow: none; }
.tb-bang .tb-1:last-child { border-bottom: 0; }
.tb-bang .tb-1.moi { background: var(--nen2); box-shadow: none; }
.tb-bang .tb-1-ico { width: 32px; height: 32px; border-radius: 10px;
  border: 1px solid var(--vien); }
.tb-bang .tb-1.moi .tb-1-ico { background: var(--the); color: var(--muc);
  border-color: var(--muc); }
.tb-bang .tb-1-than { display: flex; flex-direction: column; gap: 8px; }
.tb-1-tren { display: flex; align-items: flex-start; gap: 8px; }
.tb-1-chinh { flex: 1; min-width: 0; }
.tb-1-chinh.tb-bam { cursor: pointer; }
.tb-1-chinh.tb-bam:hover .tb-1-chu { text-decoration: underline; text-underline-offset: 2px; }
.tb-bang .tb-1-phu { display: flex; flex-wrap: wrap; align-items: center; gap: 3px 7px;
  margin-top: 4px; font-size: 11.5px; }
.tb-lap { padding: 1px 6px; border-radius: 999px; background: var(--nen2);
  font-size: 10.5px; font-weight: 600; }
/* Chấm "chưa đọc" — mẫu để ở mép phải hàng, tách hẳn khỏi mấy nút. */
.tb-cham { flex: none; width: 7px; height: 7px; margin-top: 7px; border-radius: 999px;
  background: var(--muc); }

/* ── Hàng nút trong từng tin ──────────────────────────────────────────────────
   ⛔ BÀY SẴN, KHÔNG GIẤU SAU LƯỢT RÊ CHUỘT (Boss chốt 13/09, nhắc lại 18/09). Nút
      chỉ hiện lúc rê thì trên điện thoại là nút không tồn tại. */
.tb-bang .tb-1-nut { flex: none; flex-direction: row; flex-wrap: wrap; gap: 6px;
  align-items: center; }
.tb-bang .tb-1-nut button { display: inline-flex; align-items: center; gap: 5px;
  border: 1px solid var(--vien); background: var(--the); color: var(--mo);
  border-radius: 999px; padding: 4px 10px; font-size: 11.5px; font-weight: 600;
  white-space: nowrap; }
.tb-bang .tb-1-nut button:hover { background: var(--nen2); color: var(--chu);
  border-color: var(--muc); }
.tb-bang .tb-1-nut button i[class^="ic-"] { width: 13px; height: 13px; margin: 0; flex: none; }

/* ── Dấu "đã xong" — Boss chốt 18/09/2026 ─────────────────────────────────────
   ⛔ MÀU XANH LÁ, KHÔNG DÙNG MÀU THƯƠNG HIỆU. Màu mực của app cũng là xanh; dùng
      lại nó ở đây thì "đã xong" trông y hệt "chưa đọc", mất trắng ý nghĩa của dấu.
   ⛔ Bấm xong RỒI VẪN CÒN CHỖ: nút đổi thành dòng "Đã xong · <giờ>" bấm lại được để
      gỡ. Mẫu 21st.dev gọi nết này là "actions resolve in place" — dòng không biến
      mất, vì biến mất là cách nhanh nhất làm người ta mất dấu việc vừa làm. */
.tb-bang .tb-1-nut button.tb-nut-lam { color: var(--chu); border-color: rgba(34,160,107,.45); }
.tb-bang .tb-1-nut button.tb-nut-lam i[class^="ic-"] { color: #22A06B; }
.tb-bang .tb-1-nut button.tb-nut-lam:hover { background: rgba(34,160,107,.10);
  border-color: #22A06B; color: #1B7A52; }
.tb-bang .tb-1-nut button.tb-nut-xong { border-color: transparent; background: transparent;
  color: #1B7A52; padding-left: 4px; }
.tb-bang .tb-1-nut button.tb-nut-xong i[class^="ic-"] { color: #22A06B; }
.tb-bang .tb-1-nut button.tb-nut-xong:hover { background: var(--nen2);
  border-color: var(--vien); color: #1B7A52; }
.tb-bang .tb-1.tb-xong .tb-1-ico { background: rgba(34,160,107,.12); color: #1B7A52;
  border-color: rgba(34,160,107,.35); }
.tb-bang .tb-1.tb-xong .tb-1-chu { color: var(--mo); }
body.toi .tb-bang .tb-1-nut button.tb-nut-xong,
body.toi .tb-bang .tb-1-nut button.tb-nut-xong:hover,
body.toi .tb-bang .tb-1.tb-xong .tb-1-ico { color: #3BC98A; }
body.toi .tb-bang .tb-1-nut button.tb-nut-lam i[class^="ic-"],
body.toi .tb-bang .tb-1-nut button.tb-nut-xong i[class^="ic-"] { color: #3BC98A; }
body.toi .tb-bang .tb-1-nut button.tb-nut-lam:hover { color: #3BC98A; }

/* ── Hộp rỗng ─────────────────────────────────────────────────────────────────
   ⛔ Bắt bằng `div.tb-trong` chứ đừng `.tb-trong`: màn "kho tin đã ẩn" còn dùng
      `<p class="tb-trong">` có `<br>` bên trong, để nó thành flex là mỗi mẩu chữ
      nhảy thành một dòng riêng. */
div.tb-trong { display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 52px 24px; text-align: center; }
.tb-trong-ico { width: 40px; height: 40px; margin-bottom: 3px; border-radius: 12px;
  display: grid; place-items: center; background: var(--nen2); color: var(--mo); }
.tb-trong-ico .ico { width: 19px; height: 19px; margin: 0; }
div.tb-trong b { font-size: 13px; font-weight: 600; color: var(--chu); }
div.tb-trong span { font-size: 12.5px; color: var(--mo); line-height: 1.55; }
p.tb-trong { padding: 44px 20px; }

/* ── Kho tin đã ẩn ────────────────────────────────────────────────────────────
   Hai thứ này trước nay không có luật riêng nào — trông được là nhờ `.tb-ds` có
   đệm hai bên. Nay `.tb-ds` hết đệm nên phải tự lo, không thì chữ dán vào mép. */
.tb-ghi-an { margin: 0; padding: 11px 14px; font-size: 11.5px; line-height: 1.55;
  color: var(--mo); background: var(--nen2); border-bottom: 1px solid var(--vien); }
.tb-bang .tb-1.tb-daan .tb-1-than { gap: 0; }

/* ⛔ VÙNG CHẠM TRÊN ĐIỆN THOẠI — đo thật 18/09/2026: ba nút ấy cao đúng **25px** ở
   màn 360px. Apple đòi 44pt, Google đòi 48dp; 25px là cỡ bấm trượt.
   Boss dặn "thu nhỏ và xếp vừa" — nên giữ CHỮ nhỏ như cũ, chỉ nới ĐỆM đứng.
   ⛔ CHỈ Ở MÀN HẸP. Màn rộng dùng chuột, nới ra chỉ tốn chiều cao của phần đầu bảng.
   ⛔ `flex-wrap` ở hàng cha lo phần còn lại: nới đệm mà không cho xuống dòng là nút
      tràn mép trở lại — đúng lỗi Boss chụp ảnh hôm nay. */
@media (max-width: 640px) {
  .tb-bang .tb-thanh { gap: 6px; padding: 8px 10px; }
  .tb-bang .tb-thanh button { padding: 10px 12px; }
  .tb-bang .tb-1-nut { gap: 7px; }
  .tb-bang .tb-1-nut button { padding: 9px 12px; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   ⚙ 18/09/2026 — MÀN CÀI ĐẶT: CỘT ACCORDION theo mẫu 21st.dev
   `@cnippet-dev/settings-sidebar-accordion` (Boss gửi link và chốt qua nút bấm)
   ──────────────────────────────────────────────────────────────────────────────
   Boss chốt: cột đứng CẠNH thanh công cụ dọc, nội dung vẫn ở bên phải · một nhóm
   mở tại một thời điểm · giữ nguyên sáu nhóm · có ô tìm ở đầu cột · mở sẵn "Hồ sơ
   của tôi" · chỉ tên + icon · điện thoại thì cột chiếm cả màn, chọn mục mới mở
   nội dung, có nút quay lại · ⛔ BỎ ảnh nền của mẫu (Boss dặn thẳng).

   ⛔ VIẾT Ở CUỐI FILE, KHÔNG SỬA TẠI CHỖ khối `.cd-*` ở css:2210 — khối ấy còn
      dựng từng hàng cài đặt (`.cd-hang`, `.cd-khoi`, icon xám, khuôn điện thoại
      kiểu TikTok đã chốt 10/09). Luật dưới đây chỉ thêm phần KHUNG BAO quanh.
   ⛔ `.cds-than` MANG LUÔN CLASS `cd-boc`, nên nó thừa hưởng `display:flex` +
      `max-width:860px` của khối cũ. Đừng đặt lại `display` cho nó ở màn rộng.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ⛔ 18/09/2026 — BỐ CỤC ĐỔI: CỘT SÁU NHÓM THAY VÀO THANH CÔNG CỤ DỌC.
   Boss chốt: *"bạn thay cái nút setting vào cái thanh công cụ đi"*, rồi chọn bằng
   nút bấm *"Thay vào chính thanh công cụ dọc"* — không dựng cột thứ hai cạnh nó.
   Nên trong `#noiDung` chỉ còn MỘT cột (phần nội dung). Bản `.cds-cot-man` vẫn được
   dựng trong trang nhưng ẨN ỞF ĐÂY, chỉ hiện ở màn hẹp — vì dưới 821px thanh
   công cụ dọc biến thành tấm trượt, mà Boss chốt *"6 nhóm nằm thẳng trong màn,
   không trong tấm trượt"*.
   ⛔ ẨN BẰNG CSS CHỨ ĐỪNG DỌI NODE THEO BỀ NGANG trong JS: dời thì phải tự nghe
      `resize`, nghe sót một lần (xoay máy, kéo cửa sổ) là cột biến mất không dấu vết. */
.cds { display: grid; grid-template-columns: minmax(0, 1fr);
  gap: 0; align-items: start; }
/* ⛔ PHẢI HAI LỚP `.cds .cds-cot-man`, MỘT LỚP LÀ THUA. Bài đo bắt được 18/09:
   `.cds-cot { display:flex }` ở ngay dưới cũng nặng đúng MỘT lớp, mà đứng SAU —
   ngang cơ thì cái sau thắng, nên cột điện thoại vẫn cao 373px ở màn 1400px:
   đúng cái "cột thứ hai" mà Boss bảo đừng dựng. */
.cds .cds-cot-man { display: none; }

/* ── Cột trái ─────────────────────────────────────────────────────────────────
   ⛔ `position:sticky` chỉ dính khi cha gần nhất KHÔNG có `overflow` khác
      `visible`. Vùng cuộn của app là chính cửa sổ (`#noiDung` để `overflow:visible`),
      nên chỗ này dính thật — đã đo. `top` phải bằng chiều cao `.thanh-tren` (48px)
      cộng một khoảng thở, không thì nhãn "CÀI ĐẶT" chui xuống dưới thanh ấy. */
.cds-cot { position: sticky; top: 56px; display: flex; flex-direction: column;
  gap: 9px; min-width: 0; max-height: calc(100vh - 72px); }
.cds-nhan { padding: 2px 8px; font-size: 10.5px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: var(--mo); }

/* Ô tìm — Boss chốt: có ô tìm ở đầu cột. */
.cds-tim { position: relative; display: flex; align-items: center; flex: none; }
.cds-tim i[class^="ic-"] { position: absolute; left: 10px; width: 14px; height: 14px;
  margin: 0; color: var(--mo); pointer-events: none; }
.cds-tim input { width: 100%; height: 36px; padding: 0 10px 0 32px;
  border: 1px solid var(--vien); border-radius: 10px; background: var(--the);
  color: var(--chu); font-family: inherit; font-size: 13px; }
.cds-tim input:focus { outline: none; border-color: var(--muc); }
/* Chrome vẽ sẵn một nút X trong `type=search`; nó lệch tông với cả app. */
.cds-tim input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

.cds-acc { display: flex; flex-direction: column; gap: 2px; min-height: 0;
  overflow-y: auto; }
.cds-khong { margin: 0; padding: 14px 8px; font-size: 12.5px; color: var(--mo);
  line-height: 1.55; }

/* ── Một nhóm ────────────────────────────────────────────────────────────────- */
.cds-dau { display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 38px; padding: 0 9px; border: 0; background: none;
  border-radius: 10px; color: var(--chu); font-family: inherit; font-size: 13.5px;
  font-weight: 600; text-align: left; cursor: pointer;
  transition: background .12s ease; }
.cds-dau:hover { background: var(--nen2); }
.cds-nhom.dang > .cds-dau { background: var(--nen2); }
.cds-dau i.cds-ico { width: 16px; height: 16px; margin: 0; flex: none; color: var(--mo); }
.cds-nhom.dang > .cds-dau i.cds-ico { color: var(--muc); }
.cds-ten { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }
/* Mũi tên quay xuống khi nhóm mở — dấu hiệu duy nhất cho biết bấm vào sẽ bung ra. */
.cds-dau i.cds-mui { width: 14px; height: 14px; margin: 0; flex: none; opacity: .5;
  transition: transform .18s ease; }
.cds-nhom.mo > .cds-dau i.cds-mui { transform: rotate(180deg); }

/* Danh sách mục con — vạch dọc bên trái đúng như mẫu, để mắt biết chúng thuộc
   về cái tên ngay trên chứ không phải một nhóm ngang hàng. */
.cds-con { display: none; flex-direction: column; margin: 2px 0 5px 22px;
  padding-left: 11px; border-left: 1px solid var(--vien); }
.cds-nhom.mo > .cds-con { display: flex; }
.cds-muc { padding: 6px 8px; border: 0; background: none; border-radius: 8px;
  color: var(--mo); font-family: inherit; font-size: 12.5px; font-weight: 500;
  text-align: left; cursor: pointer; transition: background .12s ease, color .12s ease; }
.cds-muc:hover { background: var(--nen2); color: var(--chu); }

/* ── 🚪 Nút Đăng xuất ở ĐÁY CỘT (Boss chốt 20/09/2026) ────────────────────────
   Boss chọn *"Viền đỏ, chữ đỏ"* chứ không phải khối đỏ đặc, và *"đáy cột,
   cách một đường kẻ"*. Cùng lối với `.cd-nut-do` đã có trong bảng Cài đặt —
   app chỉ nên có MỘT cách vẽ việc nguy hiểm, không phải mỗi chỗ một kiểu.
   ⛔ `margin-top: auto` ĐẨY NÚT XUỐNG ĐÁY THẬT, không phải chừa một khoảng cố
      định: `.cds-cot` là `flex-direction: column` và cao tới `100vh - 72px`,
      nên cột ít nhóm thì nút vẫn nằm sát đáy, cột nhiều nhóm thì nó bám ngay
      dưới nhóm cuối. Viết `margin-top: 12px` là màn to có một mảng trống lửng
      lơ bên dưới nút.
   ⛔ ĐƯỜNG KẺ đặt trên `.cds-day` (thẻ bọc), KHÔNG đặt trên chính nút: đặt trên
      nút thì nó nằm sát viền đỏ thành hai nét chồng nhau.
   ⛔ `flex: none` — thiếu nó thì trong cột flex nút bị bóp lại khi danh sách
      nhóm dài ra, chữ "Đăng xuất" cụt còn một dòng mỏng. */
.cds-day { flex: none; margin-top: auto; padding-top: 9px;
  border-top: 1px solid var(--vien); }
/* ⛔ CĂN GIỮA, không căn trái như các nhóm — đã mở Chrome thật nhìn 20/09.
   Căn trái kèm icon thì nút nhìn hệt một mục nữa của danh sách nhóm, mà nó là
   NÚT BẤM làm một việc không quay lại được. Căn giữa tách nút hành động ra khỏi
   mục điều hướng, đúng lối các công cụ cùng loại.
   ⛔ Nút này KHÔNG có icon (xem lý do trong `cdCotHtml`), nên không còn luật
      `.cds-thoat i.cds-ico` nào ở đây nữa — đừng thêm lại icon mà quên luật màu. */
.cds-thoat { display: flex; align-items: center; justify-content: center;
  gap: 8px; width: 100%;
  min-height: 38px; padding: 0 9px; border: 1px solid var(--do);
  background: none; border-radius: 10px; color: var(--do);
  font-family: inherit; font-size: 13.5px; font-weight: 600;
  text-align: center; cursor: pointer; transition: background .12s ease; }
.cds-thoat:hover { background: var(--do-nen); }

/* Nút "← Quay lại" chỉ có nghĩa ở màn hẹp; màn rộng thì hai cột cùng hiện. */
.cds-ve { display: none; }

/* ── Màn hẹp: cột chiếm cả màn, chọn mục mới mở nội dung ──────────────────────
   Mốc 820px trùng mốc mà app đổi màn Cài đặt sang khuôn điện thoại (css:2261) và
   cũng là mốc thanh công cụ dọc thôi đứng cạnh — đặt khác mốc là có một dải bề
   ngang mà cột trái và thanh dọc chen nhau.
   ⛔ `.cds .cds-than` chứ đừng `.cds-than`: thẻ ấy còn mang class `cd-boc` với
      `display:flex`, hai bộ chọn ngang cơ thì cái đứng sau thắng — mà `cd-boc`
      nằm ở css:2210, tức là TRƯỚC khối này. Viết `.cds-than` không thôi vẫn
      thắng, nhưng thắng vì thứ tự file chứ không vì luật — đổi chỗ một khối là
      hỏng. Hai lớp là thắng chắc. */
@media (max-width: 820px) {
  /* Dưới 821px thanh công cụ dọc là TẤM TRƯỢT đang đóng, không dùng làm đường
     đi chính được — nên cột sáu nhóm quay về nằm thẳng trong thân màn. */
  /* ⛔ HAI LỚP `.cds .cds-cot-man` — PHẢI KHỚP ĐỘ NẶNG VỚI LUẬT ẨN Ở TRÊN.
     Luật ẩn là `.cds .cds-cot-man` (hai lớp); viết ở đây một lớp thì dù nằm trong
     `@media` cũng VẪN THUA — `@media` không cộng thêm độ nặng nào cả. Bài đo bắt
     đúng chỗ này: ở 390px cột vẫn `hidden`, màn Cài đặt trống trơn. */
  .cds .cds-cot-man { display: flex; }
  .cds-cot { position: static; max-height: none; gap: 10px; }
  .cds .cds-than { display: none; }
  .cds.cds-dang-xem .cds-cot { display: none; }
  .cds.cds-dang-xem .cds-than { display: flex; }
  /* Vùng chạm: Apple đòi 44pt · Google đòi 48dp. Cột này là đường đi chính của
     cả màn trên điện thoại nên KHÔNG được thu nhỏ như mấy nút phụ. */
  .cds-dau { min-height: 46px; font-size: 14.5px; }
  .cds-muc { min-height: 42px; display: flex; align-items: center; font-size: 13.5px; }
  .cds-tim input { height: 42px; font-size: 14px; }
  .cds-ve { display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
    min-height: 40px; padding: 0 14px 0 11px; margin-bottom: 2px;
    border: 1px solid var(--vien); border-radius: 999px; background: var(--the);
    color: var(--chu); font-family: inherit; font-size: 13px; font-weight: 600;
    cursor: pointer; }
  .cds-ve:hover { background: var(--nen2); }
}

/* ── Bản cột nằm TRONG thanh công cụ dọc (`#ccDS.cc-ds-caidat`) ────────────────
   Thanh này đã có sẵn một lối accordion riêng (`.cc-nhom` · `.cc-nhom-ten` 13,5px/600
   · `.cc-nhom-mui` xoay · `.cc-nhom-muc` thụt 2px). Cột Cài đặt phải MẶC ĐÚNG BỘ ÁO
   ẤY, không thì nó trông như một mảnh dán vào — đúng thứ Boss chê "lộ ra là máy làm".
   ⛔ Nền thanh là XANH SẪM, không phải nền trang. Đừng đặt màu chữ bằng mã cứng —
      lấy qua `var(--chu)` / `var(--mo)` như mọi luật khác trong `#thanhCC`.
   ⛔ Bỏ `overflow-y:auto` của `.cds-acc`: trong thanh, phần cuộn là cả cột công cụ
      (`.cc-panel`). Để hai tầng cuộn lồng nhau thì lăn chuột ở giữa cột là tầng
      trong ăn hết, cột ngoài đứng im — người dùng tưởng thanh bị kẹt. */
/* ⛔ DÒNG MÁCH "Kéo công cụ để đổi vị trí…" PHẢI ẨN KHI THANH BÀY CÀI ĐẶT.
   Hai lý do, cả hai đều thấy bằng mắt khi mở Chrome thật 20/09/2026:
     ① Lúc này thanh không bày công cụ nào cả — câu ấy nói về một việc không còn
        làm được ở đây, đọc vào chỉ thừa.
     ② Nó nằm NGAY DƯỚI nút Đăng xuất, nên nút thôi là thứ dưới cùng — mà Boss
        chốt đúng chữ *"ở dưới cùng"*.
   ⛔ Ẩn bằng CSS ở đây là đúng: thẻ ấy nằm sẵn trong index.html của THANH, không
      phải do cột Cài đặt dựng ra. Gỡ khỏi HTML là màn công cụ thật mất câu mách.
   ⛔ Bộ chọn phải dùng `~` (đứng sau) chứ không phải dấu cách: `.cc-sapco` là ANH
      EM KỀ của `#ccDS`, không phải con của nó. */
#thanhCC #ccDS.cc-ds-caidat ~ .cc-sapco { display: none; }
#thanhCC .cc-ds-caidat .cds-acc { gap: 2px; overflow: visible; max-height: none; }
#thanhCC .cc-ds-caidat .cds-dau { min-height: 32px; padding: 6px 9px;
  border: 1px solid transparent; font-size: 13.5px; font-weight: 600;
  color: var(--chu); }
#thanhCC .cc-ds-caidat .cds-dau:hover { background: var(--nen2); border-color: var(--vien); }
#thanhCC .cc-ds-caidat .cds-nhom.dang > .cds-dau { background: var(--xanh-nhat);
  border-color: var(--xanh); color: var(--muc); }
#thanhCC .cc-ds-caidat .cds-nhom.dang > .cds-dau i.cds-ico,
#thanhCC .cc-ds-caidat .cds-nhom.dang > .cds-dau i.cds-mui { color: var(--muc); }
#thanhCC .cc-ds-caidat .cds-dau i.cds-ico { width: 15px; height: 15px; }
#thanhCC .cc-ds-caidat .cds-dau i.cds-mui { width: 12px; height: 12px; }
#thanhCC .cc-ds-caidat .cds-con { margin: 2px 0 5px 20px; padding-left: 10px; }
#thanhCC .cc-ds-caidat .cds-muc { padding: 5px 8px; font-size: 12.5px; }
#thanhCC .cc-ds-caidat .cds-khong { padding: 10px 9px; font-size: 12px; }

/* ══════════════════════════════════════════════════════════════════════════════
   🌙 21/09/2026 — NỀN TỐI: CHỮ SÁNG, DỄ ĐỌC (lần 4)
   ──────────────────────────────────────────────────────────────────────────────
   Boss: *"sửa lại toàn bộ chữ trong app lúc để nền đen thành sao cho nó đẹp và
   dễ nhìn sáng sủa, ko bị tối nhìn chữ khó"*. Boss chọn bằng nút bấm:
     · chữ sáng hơn + nền dịu hơn (xám than, bỏ gần-đen) · toàn bộ app, kể cả
       Điểm danh (chỉ màu) · chữ chính ≥ 7:1, chữ phụ ≥ 4.5:1
     · SÁU MÀU THƯƠNG HIỆU GIỮ NGUYÊN — chỗ nào chữ trắng trên nút thương hiệu
       khó đọc thì ĐỔI MÀU CHỮ, không đổi màu nút.

   ⛔ LỆNH NÀY NGƯỢC BA LẦN TRƯỚC (06/08 · 06/08 · 13/08 đều HẠ chữ cho "bớt chói").
      Lệnh mới thắng. Giữ lại đúng một thứ của 13/08: SẮC chữ ấm ngả kem — chỉ
      nâng ĐỘ SÁNG (#D2CEC7 → #EDE9E2), không quay về trắng xanh lạnh.

   ĐO TRƯỚC KHI SỬA (Chrome thật, kho mẫu, 24 màn, 1.375 dòng chữ):
     trước: 370 dòng dưới 4.5:1 · thủ phạm lớn nhất chữ phụ #8C8882 (~280 dòng)
   Bộ biến + 71 mã màu gõ cứng trong luật `body.toi` đã nâng cùng một quy tắc
   (nền xám tối +3,5% độ sáng · chữ xám phụ lên ≥68% · màu có sắc KHÔNG đụng).
   Khối dưới đây lo phần còn lại: những chỗ bộ biến không với tới.

   Nguồn đối chiếu: Radix Colors slate-dark (bước 11 chữ phụ, 12 chữ chính),
   GitHub Primer (≥7:1 cho chữ), Material (nền xám đậm thay đen tuyền, bản
   "on-primary" chữ tối trên nút sáng), 21st.dev theme Slate Dark / Darkmatter. */

/* ① Nhãn trạng thái: nền pastel SÁNG nằm giữa màn tối → một mảng loá, chữ lại
      chỉ 2,7–4,4:1. Đổi sang nền pha mờ cùng sắc + chữ sáng cùng sắc (≥6:1). */
body.toi .bc-pt.bc-good, body.toi .tths-tt.ong, body.toi .ql-badge.congkhai,
body.toi .yc-tt.xong              { background:rgba(86,201,138,.16);  color:#7FD6A0; }
body.toi .bc-pt.bc-mid, body.toi .tths-tt.mout, body.toi .ql-badge.mat-tab
                                  { background:rgba(240,160,80,.16);  color:#F2B573; }
body.toi .bc-pt.bc-bad, body.toi .tths-tt.stop
                                  { background:rgba(240,133,124,.16); color:#F29B93; }
body.toi .bc-pt.bc-na, body.toi .tths-tt.baoluu, body.toi .tths-tt.khac
                                  { background:rgba(255,255,255,.08); color:var(--mo); }
body.toi .tths-tt.min, body.toi .ql-badge.sheet
                                  { background:rgba(127,176,238,.16); color:#9CC3F2; }
body.toi .ql-badge.nhap           { background:rgba(242,193,78,.14);  color:#F2C14E; }
body.toi .yc-tt.moi               { background:rgba(245,130,31,.16);  color:#F5A36B; }
body.toi .yc-tt.danglam           { background:rgba(242,193,78,.14);  color:#F2C14E; }

/* ② Nút MÀU THƯƠNG HIỆU: giữ nguyên màu nút, đổi chữ trắng → chữ tối.
      Trắng trên teal #14A0A0 chỉ 3,2:1; trên #4DB6AC 2,4:1; trên cam #D9880B 2,8:1.
      Chữ #0F1A1C: 5,5 · 7,3 · 6,6. Đây là cách Material làm cho nền tối ("on-primary").
   ⛔ Rê chuột: bản sáng tối nút xuống --xanh-dam (#0D8081) — ở đó chữ tối chỉ còn
      ~3:1. Nên nền tối rê chuột SÁNG lên (--xanh-sang, cũng là màu thương hiệu). */
/* Danh sách dưới SINH TỰ ĐỘNG từ chính CSS (mọi luật nền --muc/--xanh/--xanh-sang
   + chữ trắng; chừa .phieu-* vì phiếu in giữ y hệt, và ô xem trước chế độ Tối).
   Quét tay chỉ thấy 7 chỗ đang hiện trên màn — máy quét ra 62. */
/* Chừa ra — nền tối ĐÃ có luật riêng đè mất nền teal, chữ tối sẽ chìm (đo ra 1,37:1):
   .nut-nho.chinh-nho · .chip.chon · .tths-cs-nut.chon · .ht-nut button.chinh · .ht-mota-i.mo */
body.toi .nut-chinh,
body.toi .cts-bung.mo,
body.toi .bd-doi-chon button.chon,
body.toi .lt-tao,
body.toi .lt-mini-luoi button.dangxem,
body.toi .lt-che button.chon,
body.toi .lt-dau-o.dangxem .lt-sn,
body.toi .lt-vach-tha::after,
body.toi .lt-thang .lt-o-ngay.dangxem .lt-sn,
body.toi .lt-tu-dau.dangxem .lt-sn,
body.toi .lgv-mini-luoi button.dangxem,
body.toi .lgv-gat button.chon,
body.toi .lgv-che button.chon,
body.toi .lgv-o-ngay.dangxem .lgv-sn,
body.toi .lgv-dau-o.dangxem .lgv-sn,
body.toi .lgv-gio-nut button.chinh,
body.toi .lgv-cc-nut,
body.toi .lgv-lydo button.chon,
body.toi .lgv-suagv-hang button[data-lgv-luugv],
body.toi .lgv-suagv-hang button[data-lgv-luuthay],
body.toi .lgv-taotk-nut,
body.toi .nn-nut-chinh,
body.toi .nn-dai-o.chon,
body.toi .nn-chang-nut.chon,
body.toi .nn-phan-nut.chon,
body.toi .tks-moc button.chon,
body.toi .hv-xong:hover,
body.toi .home-tb-nut.chon,
body.toi .home-tb-nut.chon:hover,
body.toi .tkm-loc-nut.chon,
body.toi .tkk-nut.chon,
body.toi .nut-caption,
body.toi .ql-tab-nut.chon,
body.toi .nut-themcot:hover,
body.toi .nut-them-tk,
body.toi .mtb-badge.vt-admin,
body.toi .cd-chon button.chon,
body.toi .pq-bang .pq-hoi:hover,
body.toi #thanhCC .cc-toggle,
body.toi .dg-bung.mo,
body.toi .fhs-nhom-so,
body.toi .nv-nhom-so,
body.toi .yc-ngan.chon .yc-ngan-so,
body.toi .oc-tim > .oc-goiy .oc-sang:hover,
body.toi .nv-ct-them:hover,
body.toi .bcn-ver,
body.toi .ht-thu-o.chon,
body.toi .ht-tich-o.chon,
body.toi .ht-nguoi-o.chon,
body.toi .lt-ds-ngay.homnay .lt-ds-dau b,
body.toi .nn-muc-nut.chon .nn-muc-so,
body.toi.dang-trong-lop #ddFab,
body.toi .otp-tiep,
body.toi .lt2-bang td.lt2-c-ct a.lt2-ct-vien:hover,
body.toi .ht-tich-them-ok,
body.toi .tk-khoi-thanh .nut-them-tk,
body.toi .tb-tab-so { color:#0F1A1C; }
body.toi .nut-chinh:hover,
body.toi .lt-tao:hover,
body.toi .lt-mini-luoi button.dangxem:hover,
body.toi .lgv-mini-luoi button.dangxem:hover,
body.toi .nn-nut-chinh:hover,
body.toi .nut-caption:hover,
body.toi .tk-khoi-thanh .nut-them-tk:hover { background:var(--xanh-sang); }
body.toi .yc-act.nhan.dang { color:#0F1A1C; }
body.toi .nut-chinh i, body.toi .nut-chinh svg { color:inherit; }
/* Xanh lá "Hoàn thành" không phải màu thương hiệu → sáng nút lên cho chữ tối đọc được. */
body.toi .yc-act.xong.dang        { background:#56C98A; border-color:#56C98A; color:#0F1A1C; }
/* Nút gọn (`.nv-gon`) in chữ teal thương hiệu trên nền tối: 4,05:1 → chữ teal dịu. */
body.toi .nv-gon button.nut-chinh { color:var(--muc) !important; }

/* ③ Ô đếm số trên nền xám: chữ phụ đứng trên nền xám sáng hơn → dưới 4,5:1. */
body.toi .kl-so, body.toi .ql-tab-so, body.toi .yc-ngan-so { color:var(--chu); }
body.toi .tths-cs-nut.chon .kl-so { color:#fff; }
/* Thanh gọn (.nv-gon) để nút tab trong suốt; ô số nằm trên lớp trắng mờ .28 → chữ trắng 5,3:1. */
body.toi .ql-tab-nut.chon .ql-tab-so { color:#fff; }

/* ④ Nhãn tin trong Tuyển sinh tự khai màu dự phòng #6b7280 (3,6:1). */
body.toi .cts-tin-test            { color:var(--mo); }

/* ⑤ CHỮ teal thương hiệu trên nền tối: --xanh-dam #0D8081 chỉ ~3:1, --xanh #14A0A0 ~4:1.
      Đổi CHỮ sang --muc (#4DB6AC, 6–7:1); nền và nút giữ nguyên màu thương hiệu.
      SINH TỰ ĐỘNG từ CSS: mọi luật chữ --xanh/--xanh-dam chưa có bản nền tối. Chừa: logo,
      phiếu in, luật tự đặt nền trắng/teal (vd nút trắng trên dải đếm ngược #bangDemNguoc). */
body.toi .dn-doi a,
body.toi .pt-them button:hover,
body.toi .cts-tab button.chon,
body.toi .cts-tab button.chon span,
body.toi .nn-thanh button:hover,
body.toi .kq-viet-so,
body.toi .pt-muc,
body.toi .kq-bai-nut.chon b,
body.toi .kq-bai-them:hover,
body.toi .kq-qr-luu:hover,
body.toi .kq-khoi h2,
body.toi .kq-chan .kq-tt,
body.toi .home-khoi-dau .ico,
body.toi .home-khoi-dau i[class^="ic-"],
body.toi .home-gio-1:hover .hv-ico,
body.toi .home-gio-1:hover .home-gio-nhan,
body.toi .home-gio-1.sap:hover .home-gio-nhan,
body.toi .home-viec-them:hover,
body.toi .hv-mo:hover,
body.toi .hv-xong,
body.toi .tk-tieu-de .ico,
body.toi .tkb-them,
body.toi .tim-d.dang .tim-svg,
body.toi .tim-d:hover .tim-svg,
body.toi .kx-lop-ds span.tuan-nay,
body.toi .nhom-coso h2,
body.toi .nut-phieu:hover,
body.toi .dh-day button:hover:not(:disabled),
body.toi .nut-themcot,
body.toi .dai-an-nghi button:hover,
body.toi .ghi-chu-gap > summary:hover,
body.toi .pc-keo:hover,
body.toi .tl-them button:hover,
body.toi .tl-them-nguoi,
body.toi .bcs-hoi:hover,
body.toi .bcs-hoi.mo,
body.toi .gy-them-anh:hover,
body.toi .mtv-chep:hover,
body.toi .tk-chip.chon,
body.toi .fhs-lhcell .fhs-them-lh,
body.toi .tths-khoi-bao,
body.toi #klTom a,
body.toi .htin-o-toi,
body.toi .oc-tim > .oc-goiy .oc-sang,
body.toi .nv-gon button.nut-chinh:hover,
body.toi .nv-gon button.dang-loc,
body.toi .nv-ct-them,
body.toi .nv-ct-luumau:hover,
body.toi .ht-ngay-nut:hover,
body.toi .ht-ds-them,
body.toi .ht-thu-o:hover,
body.toi .ht-tich-o:hover,
body.toi .ht-nguoi-o:hover,
body.toi .ht-gio-nut:hover,
body.toi .ht-gio-nut[aria-expanded="true"],
body.toi .otp-huy,
body.toi .mc-chon-them button,
body.toi .mc-sheet .mc-them-o button,
body.toi .dnc-tha .dnc-tha-muc.chon,
body.toi .lt2-chip,
body.toi .lt2-tt-tren,
body.toi .lt2-tutao:hover,
body.toi .lt2-bang td.lt2-c-ct a,
body.toi .lt2-bang td.lt2-c-ct a.lt2-ct-vien,
body.toi .lt2-ct-them:hover:not(:disabled),
body.toi .lt2-bang .lt2-chip,
body.toi .ht-tich-the:hover,
body.toi .ht-tich-the.chon,
body.toi .ht-tich-the.chon .ht-tich-bo,
body.toi .ht-tich-them-mo:hover,
body.toi .bl-so-nut[aria-expanded="true"],
body.toi .tk-th-sap.dang-sap .tk-sap,
body.toi .mtv-them,
body.toi .mtv-huy,
body.toi .tk-khoi-thanh .nut-them-tk.phu:hover,
body.toi .tk-khoi-bang .mtb-lop-nut,
body.toi .tk-khoi-bang .mtb-lop-nut:hover { color:var(--muc); }
/* Ba luật thanh gọn khai !important → bản nền tối cũng phải !important mới thắng. */
body.toi .nv-gon button.nut-chinh:hover, body.toi .nv-gon button.dang-loc { color:var(--muc) !important; }

/* ⑥ Màn Điểm danh — CHỈ MÀU (luật 20/09: được sửa chữ và icon, cấm sửa cách chạy).
      Nút Xoá buổi / Mở lại và nhãn Xong giữ nền pastel sáng giữa màn tối: 2,3–4:1. */
body.toi .nut-xoacot   { background:rgba(240,133,124,.14); color:#F29B93; }
body.toi .nut-molai    { background:rgba(242,193,78,.12);  color:#F2C14E; }
body.toi .nhan.xong    { background:rgba(86,201,138,.16);  color:#7FD6A0; }

/* ══════════════════════════════════════════════════════════════════════════════
   🌙 21/09/2026 (chiều) — NỀN TỐI LẦN 5: CHỮ DÀY HƠN · Ô TÔ MÀU DỊU XUỐNG
   ──────────────────────────────────────────────────────────────────────────────
   Boss (kèm ảnh Sổ tuyển sinh): *"tôi thấy vẫn khó nhìn để chế độ tối vì chữ nó
   khá mờ bạn dò cả app lại cho tôi và sửa"*.
   ĐO ẢNH BOSS: chữ thân bảng đúng #EDE9E2 trên #24292F = 12:1 — tức là ĐẠT chuẩn
   mà mắt vẫn thấy mờ. Hai thủ phạm con số không bắt được:
     ① Windows vẽ chữ SÁNG trên nền TỐI mảnh hơn hẳn chữ tối trên nền sáng; Boss
        xem ở 80% nên chữ thân bảng chỉ còn ~10px, nét 400 → trông gầy, nhạt.
     ② Ô / hàng tiêu đề người dùng TỰ TÔ MÀU (vàng, trắng, xanh nhạt…) giữ nền
        sáng giữa màn đen → lóa; hàng tiêu đề tô vàng còn lấy chữ xám sáng của nền
        tối → chữ sáng trên nền sáng, đo trong ảnh gần như trùng màu nền.
   Boss chọn (nút bấm): "Đậm hơn + sáng hơn" · "Dịu màu xuống, chữ sáng".

   ⛔ VÌ SAO KHÔNG ĐẶT font-weight:500: Segoe UI trên Windows KHÔNG có nét 500 —
      đo bề rộng chữ trên Chrome thật: 500 ra ĐÚNG BẰNG 600 (Semibold). Đặt 500 là
      cả bảng thành chữ đậm như tiêu đề. Nhìn tận mắt 8 cách (400 · 450 · 500 ·
      Variable Text · viền .25 / .4px): viền chữ .25px dày lên rõ mà chưa thành
      chữ đậm. Chỉ áp cho màn độ phân giải thường — màn nét cao (điện thoại, Mac)
      vẽ chữ sáng đủ dày sẵn, thêm viền là nhòe. */
@media (max-resolution: 1.5dppx) {
  body.toi { -webkit-text-stroke-width: .25px; }
  /* Tờ phiếu buổi (nền trắng, để in / chụp) tự tắt viền chữ — xem luật `body.toi .phieu`
     trong css/nen.css. ⛔ Đừng khai luật `.phieu` thứ hai: thu-phieu-nen-den.js đòi ĐÚNG MỘT. */
}

/* ② Sổ tuyển sinh — 6 màu ô tô sáng. Trước đây CỐ Ý giữ nền sáng + ép chữ đen ở nền
      tối; Boss nay chọn dịu xuống: nền tối cùng sắc, VẠCH mép trái sáng hơn và dày
      hơn một chút để vẫn nhận ra màu đã tô, chữ sáng (10,5–11,7:1).
   ⛔ Phải !important: luật nền sáng khai !important — cùng !important thì luật nặng
      hơn (có body.toi) thắng. */
/* Màu khai MỘT chỗ bằng biến — thu-cts-man-hinh.js không cho luật `.cts-…` gõ cứng mã màu. */
body.toi {
  --ctsm-vang-n:#3D3624;   --ctsm-vang-v:#E8C97A;
  --ctsm-xanhla-n:#25392E; --ctsm-xanhla-v:#7FD6A0;
  --ctsm-xanhbi-n:#243446; --ctsm-xanhbi-v:#7FB0EE;
  --ctsm-hong-n:#432C2C;   --ctsm-hong-v:#F29B93;
  --ctsm-tim-n:#352C45;    --ctsm-tim-v:#C9B2E0;
  --ctsm-xam-n:#33383F;    --ctsm-xam-v:#9AA4B0;
}
body.toi .cts-m-vang   { background:var(--ctsm-vang-n) !important;   box-shadow:inset 3px 0 0 var(--ctsm-vang-v); }
body.toi .cts-m-xanhla { background:var(--ctsm-xanhla-n) !important; box-shadow:inset 3px 0 0 var(--ctsm-xanhla-v); }
body.toi .cts-m-xanhbi { background:var(--ctsm-xanhbi-n) !important; box-shadow:inset 3px 0 0 var(--ctsm-xanhbi-v); }
body.toi .cts-m-hong   { background:var(--ctsm-hong-n) !important;   box-shadow:inset 3px 0 0 var(--ctsm-hong-v); }
body.toi .cts-m-tim    { background:var(--ctsm-tim-n) !important;    box-shadow:inset 3px 0 0 var(--ctsm-tim-v); }
body.toi .cts-m-xam    { background:var(--ctsm-xam-n) !important;    box-shadow:inset 3px 0 0 var(--ctsm-xam-v); }
body.toi [class*="cts-m-"] { color:var(--chu) !important; }

/* ③ Bảng kiểu Sheet — màu người dùng tự tô (ô `.sheet-dd-to`, hàng tiêu đề).
      Người dùng chọn màu cho nền SÁNG; ở nền tối pha 26% màu ấy vào nền bảng →
      còn nhận ra sắc đã chọn mà hết lóa. Chữ trên đó dùng chữ chính (≥ 5:1 kể cả
      màu vàng tươi nhất). Không tô gì thì mọi thứ y như cũ.
   ⛔ Nhận "có tô tiêu đề" bằng thuộc tính style: JS đặt `--sheet-dau-nen` thẳng lên
      thẻ bảng; CSS không hỏi được "biến này có giá trị không", nhưng hỏi được
      "style có chữ ấy không".
   ⛔ `--sheet-nen-th` (màu ô ghăm đầu hàng) cũng do JS viết thẳng lên thẻ bằng màu
      GỐC → phải !important mới thắng, không thì ô đầu hàng vàng tươi lòi ra. */
body.toi .sheet-moi tbody td.sheet-dd-to,
body.toi .sheet-moi[class] tbody tr.sheet-hang td.sheet-dd-to {
  background-color: color-mix(in srgb, var(--sheet-dd-nen, #FFF3C4) 26%, var(--the)); color: var(--chu); }
body.toi .sheet-moi[style*="--sheet-dau-nen"] {
  --dau-bang-nen: color-mix(in srgb, var(--sheet-dau-nen) 26%, #22262B);
  --sheet-nen-th: color-mix(in srgb, var(--sheet-dau-nen) 26%, #22262B) !important;
  --dau-bang-chu: var(--chu);
}

/* ④ Nhãn / ô pastel sáng còn sót ở các màn khác (đo trên bản sao kho thật). */
body.toi .lt2-bang .lt2-nghi               { background:#342F22; }
body.toi .lt2-bang tbody tr.le .lt2-nghi   { background:#383224; }
body.toi .lt2-bang thead th.lt2-nghi,
body.toi .lt2-bang thead th.lt2-nghi .lt2-tuan-ngay { color:#F2C14E; }
body.toi .lt2-bang td.lt2-nghi .lt2-ghi,
body.toi .lt2-bang td.lt2-nghi .lt2-chip   { color:#F2D98A; }
body.toi .the-lop.dang-hoc .nhan-gio       { color:#7FD6A0; background:rgba(86,201,138,.14); }
body.toi .the-lop.sap-hoc  .nhan-gio       { color:#F2C14E; background:rgba(242,193,78,.12); }
body.toi .dg-th.co    { background:rgba(86,201,138,.16);  border-color:#3F7A57; color:#7FD6A0; }
body.toi .dg-th.khong { background:rgba(240,133,124,.14); border-color:#7A4441; color:#F29B93; }
/* Chữ trên nền cam/hổ phách (không phải 6 màu thương hiệu thì làm sáng chữ không
   được — nền quá sáng; đổi chữ sang tối như nút teal). */
/* ⛔ Chỉ nút hổ phách `.cho` — ĐỪNG viết `.lt-o.lt-done`: Chăm sóc cũng dùng `lt-o lt-done`
   cho ô tích nền tối, bắt nhầm là 157 ô thành chữ tối trên nền tối (đo ra 1,32:1). */
body.toi .lt-cg-o.cho, body.toi button.lt-done.cho { color:#1A1206; }
body.toi .nhan-homnay { color:#1A1206; }
/* Tăng/giảm trong Thống kê: đỏ #C0392B / xanh #1E7C45 chỉ 2,7–2,8:1 trên nền tối. */
body.toi .tk-chenh.len    { color:#7FD6A0; }
body.toi .tk-chenh.xuong  { color:#F29B93; }
body.toi .tk-chenh.ngang  { color:#7FB0EE; }
/* Hàng nhóm của Lịch thi: chữ phụ trên nền viền sáng hơn → 3,96:1. */
body.toi .lt-bang thead .lt-nhom { color:var(--chu); }
/* Chỗ CỐ Ý mờ bằng độ trong suốt: giữ ý "mờ đi", nhưng ở nền tối nâng cho đủ đọc. */
body.toi .lgv-o.lgv-nghile        { opacity:.8; }
body.toi .dg-nxtg-dong.trong      { opacity:.85; }

/* ⑤ Màn Điểm danh (chỉ màu) + vài chỗ lẻ đo ra ở lượt cuối. */
body.toi .h-day .nut-done, body.toi .nut-done-lon { color:#1A1206; }   /* chữ trắng trên cam thương hiệu 2,6:1 */
body.toi .h-day.nau .done { color:#FFFFFF; }
body.toi .nhan.mo        { background:rgba(242,193,78,.12); color:#F2C14E; border-color:#7A5F2E; }
body.toi .nhan-nghi-han  { background:#565F68; }                       /* chữ trắng 3,8 → 6,4:1 */
body.toi .nn-dai-o.chon .nn-dai-thu, body.toi .nn-dai-o.chon .nn-dai-ngay,
body.toi .nn-dai-o.chon .nn-dai-so { color:#0F1A1C; }
body.toi .lgv-o .lgv-nghile-nhan { color:var(--chu); }

/* ══════════════════════════════════════════════════════════════════════════════
   ㊲ BỎ DẤU "…" TOÀN APP — Boss 21/09/2026
   ──────────────────────────────────────────────────────────────────────────────
   Boss chốt ba câu (21/09): ô NHIỀU chữ dài quá 4 dòng → cắt gọn ở dòng 4, không
   dấu gì, không mảng trắng · ô MỘT dòng dài hơn cột → cắt gọn ở mép, hàng vẫn phẳng
   như Excel · bấm vào ô vẫn xem đủ chữ. Tối 21/09 bấm nút "Không giữ — bỏ hết":
   mọi chỗ trong app, cả ngoài bảng, cả màn Điểm danh (Boss duyệt riêng cho Điểm danh).
   Luật 11/09 "tối đa 4 dòng rồi dấu ba chấm" nay bỏ phần dấu, GIỮ phần 4 dòng.
   Bảng dò có ảnh: wiki "Bỏ dấu ba chấm 21-09 - bảng cho Boss lọc".

   ① CẮT MỘT DÒNG — 96 luật `text-overflow: ellipsis` rải trong ba file CSS, cộng hai
      chỗ JS tự đặt. Đè MỘT lần bằng `!important` thay vì sửa 96 chỗ: chỗ nào sau
      này lỡ khai `ellipsis` cũng tự về cắt gọn — đúng ý "bỏ hết".
      ⛔ Luật ấy nằm ở CUỐI `css/nen.css`, KHÔNG ở đây. Dời 22/09: luật dấu sao
         áp cả app thì phải ở file nền — bài `thu-css-khong-de-len-nen-chung.js` chặn.
      ⛔ Muốn cắt chữ một dòng thì chỉ cần `overflow: hidden` + `white-space: nowrap`.
   ② KẸP NHIỀU DÒNG — `-webkit-line-clamp` LUÔN tự vẽ "…" ở cuối dòng kẹp, và
      `text-overflow: clip` KHÔNG tắt được (đo Chrome 153, 21/09, có ảnh đối chứng).
      Nên gỡ kẹp, thay bằng TRẦN CHIỀU CAO đúng N dòng: `max-height: Nlh` (`lh` = một
      dòng của chính thẻ ấy) — thẻ cao y như cũ, chỉ mất dấu. Viết lại ĐÚNG bộ chọn gốc
      (cùng độ nặng, cùng điều kiện màn hình) nên thắng nhờ ĐỨNG SAU — ⛔ đừng dời khối
      này lên trên. Gốc: css/man.css `.tk-block-mt` · css/lop.css
      `.cd-hang-chu small` · `#ttSheet .tts-muc-chu b` · `.htin-d-phu` · `.ont-xem` ·
      `.bcs-chu` · `.lt2-lt-chu` · `.dg-ten-xem` · `td.dg-dinh > b`.
      ⛔ Thẻ có ĐỆM 3px (`.ont-xem`, `.dg-ten-xem`): cắt ở mép đệm thì dòng N+1 thò đầu
         vào 3px đệm dưới — dấu thanh tiếng Việt (ể, ỗ, ừ) hiện thành vệt lấm tấm (bản
         kẹp cũ cũng lộ vệt này, đo 21/09). Nên cắt ở MÉP CHỮ: `overflow: clip` +
         `overflow-clip-margin: content-box`. Trần cộng 8px = đệm 3+3 + viền 1+1.
      ⛔ Kẹp mới về sau: làm như dưới, ĐỪNG dùng `-webkit-line-clamp` — bài
         `thu-bo-dau-ba-cham-21-09.js` quét mọi màn và báo đỏ.
   ③ Dấu vẽ riêng ở ô chữ (`.o-cut::after`, ảnh nền `.sheet-o-them`) đã gỡ tại chỗ,
      khối ㊱ và ⑧c phía trên.
   ⛔ GIỮ "…" là LỜI NHẮN, không phải chữ bị cắt: "Tìm công cụ…", "Đang lưu…".
   ══════════════════════════════════════════════════════════════════════════════ */
@media (max-width: 720px) {
  .tk-block-mt { -webkit-line-clamp: none; line-clamp: none; max-height: 2lh; }
}
@media (max-width: 820px) {
  .cd-hang-chu small { -webkit-line-clamp: none; line-clamp: none; max-height: 2lh; }
  .cd-hang:has(.cd-av) .cd-hang-chu small { -webkit-line-clamp: none; line-clamp: none; max-height: 1lh; }
  #ttSheet .tts-muc-chu b { -webkit-line-clamp: none; line-clamp: none; max-height: 2lh; }
}
.htin-d-phu { -webkit-line-clamp: none; line-clamp: none; max-height: 2lh; }
.sheet-moi td .ont > .ont-xem {
  -webkit-line-clamp: none; line-clamp: none; max-height: calc(3lh + 8px);
  overflow: clip; overflow-clip-margin: content-box;
}
.sheet-moi td.dg-tgcell .ont > .ont-xem { -webkit-line-clamp: none; line-clamp: none; max-height: calc(2lh + 8px); }
#bangCoSo:not(.mo) .bcs-chu { -webkit-line-clamp: none; line-clamp: none; max-height: 2lh; }
body.dang-trong-lop #bangCoSo:not(.mo) .bcs-chu { -webkit-line-clamp: none; line-clamp: none; max-height: 1lh; }
.lt2-bang td.lt2-c-lt .lt2-lt-chu,
.sheet-moi tbody tr.sheet-hang td.lt2-c-lt > .lt2-lt-chu {
  -webkit-line-clamp: none; line-clamp: none; max-height: 2lh;
}
.dg-ten-o > .dg-ten-xem {
  -webkit-line-clamp: none; line-clamp: none; max-height: calc(2lh + 8px);
  overflow: clip; overflow-clip-margin: content-box;
}
.sheet-moi tbody td.dg-dinh > b { -webkit-line-clamp: none; line-clamp: none; max-height: 2lh; }

/* ══════════════════════════════════════════════════════════════════════════════
   🕘 LỊCH SỬ THAO TÁC — Coder 22/09/2026 (⚙ Cài đặt → Dữ liệu → "Xem lịch sử")
   ──────────────────────────────────────────────────────────────────────────────
   Khối MỚI của Coder, chỉ dùng tên `lstt-*` (đã grep cả kho: không trùng ai).
   Hàng tab mượn nguyên `.tk-chips` / `.tk-chip` của Quản lý tài khoản, ô tìm mượn
   `.o-tim-dep`, nút "Xem thêm" mượn `.nut-nho` — ở đây KHÔNG đè luật nào của chúng.
   Màu chỉ lấy từ biến có sẵn, nên nền tối tự đổi theo. Designer sửa thoải mái.
   ══════════════════════════════════════════════════════════════════════════════ */
.lstt { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.lstt > .lstt-tab { margin: 0; }
.lstt-ds { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.lstt-dong { display: flex; flex-direction: column; gap: 4px; min-width: 0; padding: 10px 12px;
  border: 1px solid var(--vien); border-radius: var(--r-md); background: var(--the); }
.lstt-dau { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.lstt-loai { flex: none; padding: 1px 8px; border: 1px solid var(--vien); border-radius: var(--r-sm);
  font-size: 11.5px; font-weight: 700; color: var(--mo); }
.lstt-them .lstt-loai { color: var(--xanh-dam); background: var(--xanh-nhat); border-color: transparent; }
.lstt-xoa .lstt-loai { color: var(--do); background: var(--do-nen); border-color: transparent; }
.lstt-sua .lstt-loai { color: var(--cam-dam); }
.lstt-dt { min-width: 0; font-size: 13.5px; color: var(--chu); overflow-wrap: anywhere; }
.lstt-phu { font-size: 12px; color: var(--mo); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.lstt-ct, .lstt-nd ul { display: flex; flex-direction: column; gap: 2px; margin: 2px 0 0; padding: 0;
  list-style: none; font-size: 12.5px; overflow-wrap: anywhere; }
.lstt-tr { color: var(--mo); }
.lstt-tr::after { content: ":"; }
.lstt-cu { color: var(--mo); }
.lstt-moi { color: var(--chu); font-weight: 600; }
.lstt-trong { color: var(--mo); font-style: italic; }
.lstt-nd summary { cursor: pointer; font-size: 12.5px; color: var(--mo); }
.lstt-xem-them { align-self: center; }
/* Nền tối: `--xanh-dam` không đổi theo nền tối (≈2,8:1 trên `--xanh-nhat` tối), cam
   `--cam-dam` ≈4,4:1 trên thẻ tối — đổi sang bản sáng như các nhãn khác của app
   (`.yc-tt.moi`). Bài `thu-nen-toi-chu-sang-21-09.js` ⑥ canh chữ teal. */
body.toi .lstt-them .lstt-loai { color: var(--muc); }
body.toi .lstt-sua .lstt-loai { color: #F5A36B; }

/* ══════════════════════════════════════════════════════════════════════════════
   🖱 CHUỘT NGƯỜI KHÁC — Coder 22/09/2026 (Boss giao 00:39). BÁO DESIGNER.
   ──────────────────────────────────────────────────────────────────────────────
   Mẫu 21st.dev `@preetsuthar17/components/cursor`: mũi tên MousePointer2 ĐẶC màu,
   nhãn tên lệch dưới-phải, cả cụm hiện ra bằng một nhịp phóng 0 → 1. Số của mẫu:
   mũi tên 30px, nhãn 12px chữ trắng, đệm 4×12, nhãn đặt ở (đầu mũi tên + 30, + 30).
   Boss: "chuột bé 1 xíu, tên vừa cỡ chuột" ⇒ mũi tên 22px, nhãn 11px đệm 2×7, đặt ở
   (đầu mũi tên + 22, + 22) — thu đúng tỉ lệ của mẫu.
   ⛔ `--ck-mau` do JS đặt cho TỪNG người (sắc của `mauTheoTen`, đậm lại tới khi chữ
      trắng đạt 4,5:1) — đừng khai màu cố định ở đây, mỗi người một màu là Boss chốt.
   ⛔ `pointer-events: none` ở MỌI tầng là bắt buộc: chuột người khác nằm trên bảng
      mà bắt được cú bấm là bấm trượt ô; và `js/chuot-nguoi-khac.js` soi "ô có bị che
      không" bằng `elementFromPoint` — lớp này bắt chuột thì phép soi hỏng.
   ⛔ z-index 35: TRÊN phần dính của bảng (tiêu đề, cột ghim), DƯỚI thực đơn thả
      xuống (40–66) và hộp thoại (12000) — chuột không được đè lên hộp đang mở.
   ══════════════════════════════════════════════════════════════════════════════ */
#chuotKhac { position: fixed; inset: 0; z-index: 35; pointer-events: none; contain: strict; }
.ck-chuot { position: absolute; left: 0; top: 0; opacity: 0; transition: opacity .15s ease-out;
  will-change: transform; pointer-events: none; }
.ck-chuot.hien { opacity: 1; }
.ck-than { position: relative; width: 22px; height: 22px; transform: scale(0);
  transform-origin: 3.84px 3.84px; transition: transform .22s cubic-bezier(.34, 1.56, .64, 1); }
.ck-chuot.hien .ck-than { transform: scale(1); }
.ck-mui { display: block; width: 22px; height: 22px; overflow: visible; fill: var(--ck-mau);
  stroke: #fff; stroke-width: 1.5; stroke-linejoin: round;
  filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, .28)); }
.ck-ten { position: absolute; left: 26px; top: 26px; padding: 2px 7px; white-space: nowrap;
  font-size: 11px; line-height: 15px; font-weight: 600; color: #fff; background: var(--ck-mau);
  border: 1px solid rgba(255, 255, 255, .12); border-radius: var(--r-sm); box-shadow: var(--bong-2); }
.ck-trai .ck-ten { left: auto; right: 22px; }
.ck-len .ck-ten { top: auto; bottom: 22px; }
body.toi .ck-ten { border-color: rgba(255, 255, 255, .22); }
@media (prefers-reduced-motion: reduce) {
  .ck-chuot, .ck-than { transition: none; }
}
@media print { #chuotKhac { display: none; } }
