/* =============================================================================
   BỘ CONTROL DÙNG CHUNG — dựng lại từ bản gốc His_Site_TheoVaiTro
   (GD-13, GD-14, GD-15 của docs/quanly/BACKLOG_GIAO_DIEN.md)

   Đây KHÔNG phải bản phỏng theo. Mọi số đo dưới đây chép từ tệp gốc trên MÁY DỰNG
   His_Site nội bộ — địa chỉ máy ghi ở docs/quanly/QUYET_DINH.md, KHÔNG ghi vào tệp này.

   (Vì sao không ghi: tệp CSS được gửi NGUYÊN VĂN tới trình duyệt của mọi người dùng, và tệp này
   nằm trong bố cục chung nên mọi trang đều tải nó. Một dòng chú thích ở đây là một dòng lộ hạ
   tầng nội bộ ra ngoài, tới mọi cơ sở. Tài liệu vận hành được phép nêu địa chỉ; tệp phục vụ ra
   trình duyệt thì không. Test KhongLoDiaChiNoiBoTests giữ luật này.)

   Đường dẫn tương đối trong kho gốc, ghi ngay cạnh từng khối:

     Css/partCss/bootStrapCustom.css   — biến --ex-input-* và .form-control, .btn
     Css/partCss/master.css            — --main-color và .button
     Css/module-shell.css              — control 28px, viền --line, bo 2px
     Css/exComponent/grid-inrow.css    — .dmg-btn (nút trong form chèn dòng)
     Script/Lib/exControl/dropDown/tom-select.bootstrap5.css — mũi tên ô chọn
     Script/Lib/exControl/tabControl/tabulator_bootstrap5.min.css — lưới newGrid
     Views/Home/ControlController.cshtml — catalog 23 control, nhóm Ô nhập /
       Danh sách chọn / Lưới dữ liệu

   VÌ SAO CÓ TỆP RIÊNG. Trước đây quy tắc ô nhập nằm trong site.css và bị bó vào
   bộ chọn `form.mau …`. Mọi ô nhập NGOÀI một thẻ <form class="mau"> — đáng kể
   nhất là ô số phiên và hai ô chọn nằm trong bảng Tài khoản, và ô lọc trên trang
   Gói dữ liệu — rơi về hình thức mặc định của trình duyệt: viền xám mảnh, bo góc
   của hệ điều hành, ô chọn còn nguyên mũi tên của hệ điều hành. Đó đúng là thứ
   người dùng chụp màn hình gửi lại hai lần. Tệp này gắn hình thức vào CHÍNH THẺ
   qua lớp `.o-nhap` / `.o-xo` / `.nut`, không qua tổ tiên, nên không còn chỗ
   nào tuột ra ngoài được nữa. Test KhongConTheNhapTran giữ điều đó.

   BA RÀNG BUỘC KHÔNG ĐƯỢC PHÁ (giống site.css):
   1. style-src 'self', không unsafe-inline → không style nội tuyến, mũi tên ô
      chọn là tệp SVG cùng nguồn chứ không phải data: URI trong thuộc tính style.
   2. Không :has(), không color-mix() — Firefox ESR 102/115 bỏ qua lặng lẽ.
   3. Không tải gì từ Internet.
   ============================================================================= */

/* Bộ biểu tượng nút (data-bt) — một cách viết dùng chung cho mọi nút, luật 20. @import phải đứng trước mọi luật. */
@import url("bieu-tuong.css");


:root {
  /* --- Ô nhập: chép nguyên bốn biến gốc -------------------------------------
     bootStrapCustom.css dòng 9–13:
         --ex-input-radius: 2px;  --ex-input-height: 32px;
         --ex-input-pad-y:  4px;  --ex-input-pad-x:  8px;
     và dòng 462–471: font-size 13px, line-height 18px, background #fff. */
  --o-cao: 32px;
  --o-dem-doc: 4px;
  --o-dem-ngang: 8px;
  --o-bo: 2px;
  --o-chu: 0.8125rem;   /* 13px */

  /* GD-32. Tầng NHÃN của một trường, khai một chỗ duy nhất và dùng lại ở ba nơi: sàn chiều cao
     của .o-nhan, khe dưới nhãn, và phần chừa của cột nút trong hàng (nút không có nhãn nhưng
     phải chừa đúng bấy nhiêu thì đáy nút mới thẳng đáy ô bên cạnh). */
  --o-nhan-cao: 17px;
  --o-nhan-khe: 4px;
  --o-tang-nhan: calc(var(--o-nhan-cao) + var(--o-nhan-khe));
  --o-dong: 18px;

  /* Viền ô nhập. Bản gốc dùng #ced4da (1,49:1 trên nền trắng). Ở đây KHÔNG chép
     được giá trị đó: WCAG 1.4.11 đòi ranh giới thành phần tương tác đạt 3:1, và
     hạ ngưỡng này là hạ tiêu chí nghiệm thu. #8a94a3 đạt 3,07:1 và là màu SÁNG
     NHẤT còn đạt — nhìn cạnh bản gốc gần như không phân biệt được, nhẹ hơn hẳn
     #6b7280 (4,83:1) mà bản trước dùng và bị chê là "viền xám mảnh xấu".
     Đây là khác biệt CÓ CHỦ Ý duy nhất so với bản gốc; ghi ở NGON_NGU_THIET_KE.md. */
  --o-vien: #8a94a3;
  --o-vien-mo: #b9c1cc;       /* ô chỉ đọc, ô bị vô hiệu */
  --o-nen: #ffffff;
  --o-nen-tat: #f1f3f6;
  --o-chu-mau: #1e293b;       /* bootStrapCustom: color #1e293b của .cc-*-in */
  --o-cho: #94a3b8;           /* placeholder */

  /* Tiêu điểm. bootStrapCustom.css dòng 456–460 và 490–493:
         border-color: var(--tranfer-color);            (= #2563eb85)
         box-shadow:   0 0 3px 1px var(--tranfer-color);
     #2563eb85 là #2563eb ở alpha 0x85 = 133/255 = 0,52. */
  --o-vien-tieu-diem: #2563eb;
  --o-quang-tieu-diem: 0 0 3px 1px rgba(37, 99, 235, .52);

  /* --- Nút: master.css .button + bootStrapCustom .btn/.btn-primary
     + grid-inrow.css .dmg-btn (padding 7px 18px, font-weight 600) ----------- */
  --nut-cao: var(--o-cao);
  --nut-cao-nho: 26px;        /* module-shell .ms-home/.ms-help là 28px vuông */
  --nut-dem-ngang: 18px;
  --nut-dem-ngang-nho: 10px;

  /* --- Lưới: tabulator_bootstrap5 + phần ghi đè của bootStrapCustom --------
     .tabulator            border 1px #dee2e6
     .tabulator-header     background #fff, color #555, font-weight 700,
                           border-bottom 1px #dee2e6
     .grid-header-title    height 34px, padding 0 10px, font-weight 600
     .tabulator-cell       padding 4px, border-right 1px #dee2e6
     ô lọc tiêu đề         height 34px, viền trên #e2e8f0 */
  --luoi-vien: #dee2e6;
  --luoi-vien-nhat: #e9edf2;
  /* Tiêu đề lưới của bản gốc là NỀN TRẮNG, chữ #555, đậm 700 — không phải dải xám như bản trước
     ở đây tự đặt. Chép đúng: đây là thứ đập vào mắt đầu tiên khi so hai lưới cạnh nhau. */
  --luoi-dau-nen: #ffffff;
  --luoi-dau-chu: #555555;
  --luoi-cao-dau: 34px;
  --luoi-dem-doc: 6px;
  --luoi-dem-ngang: 10px;
  --luoi-soc: #fafbfd;
  --luoi-di-chuot: #eef4ff;
}

/* =============================================================================
   1. Ô NHẬP — textBoxStyle / numberStyle / dateTimeStyle / textAreaStyle
   Catalog ControlController.cshtml nhóm "Ô nhập", file exComponent/02-inputs.js.
   Ở His_Site các hàm này gắn class .form-control vào thẻ; ở đây máy chủ sinh sẵn
   lớp .o-nhap nên không cần JavaScript mới có hình thức đúng — trang không bật
   JavaScript vẫn thấy ô nhập chuẩn.
   ============================================================================= */
.o-nhap,
.o-xo,
.o-van-ban {
  display: block;
  width: 100%;
  min-height: var(--o-cao);
  height: var(--o-cao);
  padding: var(--o-dem-doc) var(--o-dem-ngang);
  border: 1px solid var(--o-vien);
  border-radius: var(--o-bo);
  background: var(--o-nen);
  color: var(--o-chu-mau);
  font-family: inherit;
  font-size: var(--o-chu);
  line-height: var(--o-dong);
  box-shadow: none;
  transition: border-color 150ms ease, box-shadow 150ms ease;
}

/* Bản gốc có HAI cỡ chữ ô nhập, và đó không phải sơ suất của họ mà là hai quy tắc chồng nhau:
   bootStrapCustom.css dòng 135–141 đặt `input.form-control { font-size: 14px; line-height: 1.2 }`,
   đặc hiệu hơn quy tắc `.form-control { font-size: 13px; line-height: 18px }` ở dòng 462–471.
   Kết quả: Ô VĂN BẢN và Ô SỐ là 14px/1.2, còn Ô CHỌN và TEXTAREA là 13px/18px. Chép đúng cả
   chỗ này để đo cạnh nhau không lệch — mục tiêu của lượt này là giống bản gốc, không phải
   "dọn cho nhất quán theo ý mình". */
input.o-nhap { font-size: 0.875rem; line-height: 1.2; }

/* Ô nhập đứng trong một hàng thao tác (bảng Tài khoản, thanh lọc) phải co theo
   chỗ trống chứ không chiếm cả hàng. */
.o-nhap-hep { width: auto; }
.o-nhap-so { width: 72px; text-align: right; font-variant-numeric: tabular-nums; }

.o-van-ban {
  height: auto;
  min-height: 84px;
  line-height: 1.55;
  padding: var(--o-dem-ngang) var(--o-dem-ngang);
  resize: vertical;
}

/* Ô tệp không có chiều cao cố định được: nút "Chọn tệp" do trình duyệt vẽ bên
   trong. Giữ đúng viền và bo góc, nới đệm để nút bên trong không chạm viền. */
.o-tep {
  display: block;
  width: 100%;
  padding: 5px var(--o-dem-ngang);
  border: 1px solid var(--o-vien);
  border-radius: var(--o-bo);
  background: var(--o-nen);
  color: var(--o-chu-mau);
  font-family: inherit;
  font-size: var(--o-chu);
  line-height: 1.4;
}

.o-nhap:focus,
.o-xo:focus,
.o-van-ban:focus,
.o-tep:focus {
  border-color: var(--o-vien-tieu-diem);
  box-shadow: var(--o-quang-tieu-diem);
  outline: none;
}
/* Bàn phím vẫn phải có vòng tiêu điểm dày của hệ (site.css :focus-visible) —
   quầng xanh của His_Site quá mảnh để làm chỉ báo bàn phím duy nhất. */
.o-nhap:focus-visible,
.o-xo:focus-visible,
.o-van-ban:focus-visible,
.o-tep:focus-visible { outline: 3px solid #ffbf00; outline-offset: 1px; }

.o-nhap::placeholder,
.o-van-ban::placeholder { color: var(--o-cho); opacity: 1; }

.o-nhap[readonly],
.o-van-ban[readonly],
.o-nhap:disabled,
.o-xo:disabled,
.o-van-ban:disabled {
  background: var(--o-nen-tat);
  border-color: var(--o-vien-mo);
  color: var(--chu-mo);
}
.o-nhap:disabled, .o-xo:disabled { cursor: not-allowed; }

/* Ô sai: viền đỏ + quầng đỏ, cùng lối với quầng xanh của tiêu điểm. */
.o-nhap.o-sai, .o-xo.o-sai, .o-van-ban.o-sai {
  border-color: var(--do);
  box-shadow: 0 0 3px 1px rgba(185, 28, 28, .45);
}

/* =============================================================================
   2. Ô CHỌN — newDropDownSingle
   His_Site KHÔNG dùng <select> của trình duyệt: catalog dựng TomSelect, và
   tom-select.bootstrap5.css vẽ mũi tên bằng ảnh nền SVG:
       background-image: svg viewBox="0 0 16 16" path d="m2 5 6 6 6-6"
                         stroke #343a40, stroke-width 2, linecap/linejoin round
       background-position: right .75rem center;   (= right 12px center)
       background-size: 16px 12px;
       --ts-pr-caret: 2.25rem   → chừa 36px bên phải cho mũi tên
   Ta dùng <select> thật (không JavaScript vẫn chạy, đọc được bằng trình đọc màn
   hình) nhưng TẮT HẲN hình thức của hệ điều hành bằng appearance:none rồi vẽ lại
   đúng mũi tên đó. Đây là điểm người dùng chỉ đích danh: "ô chọn còn nguyên mũi
   tên mặc định của hệ điều hành".
   ============================================================================= */
.o-xo {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-image: url("/img/mui-xo.svg");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 16px 12px;
  /* 28px = 12px cách mép phải + 16px bề ngang mũi tên — đúng con số bản gốc tính ra. */
  padding-right: 28px;
  cursor: pointer;
}
/* Firefox ESR vẫn vẽ nền xanh cho option đang chọn khi ô đóng; ép về nền ô. */
.o-xo:-moz-focusring { color: transparent; text-shadow: 0 0 0 var(--o-chu-mau); }
.o-xo::-ms-expand { display: none; }
.o-xo option { color: var(--o-chu-mau); background: var(--o-nen); }
.o-xo-hep { width: auto; min-width: 118px; }
/* Ô chọn NHỎ — đứng cùng hàng với «.nut-nho» (thanh công cụ trang xem bản in, N10): cao đúng bằng
   --nut-cao-nho (26px) thay vì --o-cao (32px) mặc định, để chân ô và chân nút thẳng hàng. Không đổi
   .o-xo-hep mặc định vì nhiều hàng thao tác khác (Tài khoản, bộ lọc) đứng cạnh Ô NHẬP 32px, đổi ở đó
   sẽ lệch chỗ khác — đây là lớp CỘNG THÊM, chỉ ai khai mới cao 26px. */
.o-xo-nho {
  height: var(--nut-cao-nho);
  min-height: var(--nut-cao-nho);
  padding-top: 0;
  padding-bottom: 0;
  font-size: 0.75rem;
  padding-right: 24px;
  background-position: right 8px center;
  background-size: 14px 10px;
}

/* Ô CHỌN CÓ TÌM KIẾM (site.js, hàm dungOXoTim) — select[data-tim="1"]/OXo.TimKiem, 24/09.
   <select> gốc chuyển sang .oxt-select-vh (ẩn kiểu "chỉ ẩn mắt": vẫn nhận Tab và tham gia kiểm hợp lệ,
   không dùng display:none vì trình duyệt LOẠI select display:none khỏi constraint validation).
   .oxt-nut là control NHÌN THẤY — thừa nguyên lớp .o-xo nên hình thức khớp mọi ô chọn khác. */
.oxt { position: relative; }
.oxt-select-vh {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.oxt-nut { display: flex; align-items: center; text-align: left; }
.oxt-nut-chu { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* [hidden] là thuộc tính THẬT (bang.hidden = true/false trong site.js) — NHƯNG khai display ở đây (chọn bộ
   .oxt-bang trần) sẽ THẮNG luật mặc định `[hidden] { display:none }` của trình duyệt (cùng bậc gốc tác giả,
   luật khai SAU thắng — .oxt-bang là gốc TÁC GIẢ còn [hidden] mặc định là gốc TRÌNH DUYỆT nên đáng lẽ tác giả
   thắng LUÔN, nghĩa là hộp lọc HIỆN SẴN dù đang [hidden] — đúng lỗi đo được 24/09: chụp màn hình trang in thấy
   hộp lọc mở sẵn dù chưa bấm). Phải tự chọn bộ `:not([hidden])` để display chỉ có hiệu lực khi KHÔNG ẩn. */
.oxt-bang:not([hidden]) {
  position: absolute;
  z-index: 60;
  top: calc(100% + 4px);
  left: 0;
  min-width: 100%;
  width: max-content;
  max-width: min(420px, 90vw);
  display: flex;
  flex-direction: column;
  background: var(--o-nen);
  border: 1px solid var(--o-vien);
  border-radius: var(--o-bo);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
}
.oxt-tim {
  flex: none;
  border: 0;
  border-bottom: 1px solid var(--o-vien);
  border-radius: var(--o-bo) var(--o-bo) 0 0;
  width: auto;
}
.oxt-tim:focus { box-shadow: none; outline: none; }
.oxt-ds { list-style: none; margin: 0; padding: 4px 0; max-height: 280px; overflow-y: auto; }
.oxt-muc {
  padding: 6px 10px;
  cursor: pointer;
  font-size: var(--o-chu);
  color: var(--o-chu-mau);
  white-space: nowrap;
}
.oxt-muc.oxt-noibat, .oxt-muc:hover { background: var(--xanh-nhat); }
.oxt-muc.oxt-chon { font-weight: 700; }
.oxt-khop { color: var(--xanh-chu); font-weight: 700; }
.oxt-rong { padding: 8px 10px; color: var(--chu-mo); font-size: var(--o-chu); white-space: normal; }

/* =============================================================================
   3. NHÃN VÀ KHỐI TRƯỜNG
   grouppanel.css: --gp-font-nhan 12px, --gp-mau-nhan #334155, --gp-font-o 13px.
   ============================================================================= */
.o-nhan {
  display: block;
  min-height: var(--o-nhan-cao);
  margin: 0 0 var(--o-nhan-khe);
  font-size: 0.75rem;     /* 12px — --gp-font-nhan */
  font-weight: 600;
  color: var(--chu);         /* --gp-mau-nhan */
  line-height: 1.35;
}
.o-nhan-batbuoc::after { content: " *"; color: var(--do); font-weight: 700; }
.o-truong { min-width: 0; }
.o-truong + .o-truong { margin-top: 10px; }
.o-goi-y { display: block; margin-top: 4px; font-size: 0.6875rem; color: var(--chu-mo); line-height: 1.4; }

/* Hàng trường: grouppanel dựng các trường thành lưới ngang, nhãn trên ô.

   Căn theo ĐỈNH chứ không theo đáy. Căn đáy (align-items:flex-end) là cách làm quen tay nhưng
   sai ở đây: trường nào có câu gợi ý bên dưới thì câu đó đẩy cả ô nhập lên, và hàng bốn ô hoá
   ra bốn độ cao khác nhau — thấy rõ ở ảnh trang Tài khoản trước khi sửa. Căn đỉnh cộng nhãn có
   chiều cao sàn thì mọi ô bắt đầu cùng một dòng, gợi ý cứ việc treo bên dưới. Nút trong hàng
   không có nhãn nên phải tự bù đúng chiều cao nhãn (17px) cộng khoảng cách (4px). */
.o-hang { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-start; }
.o-hang > .o-truong { flex: 1 1 200px; }
/* GD-32. Khe xếp CHỒNG (.o-truong + .o-truong { margin-top: 10px }) chỉ dành cho trường xếp dọc.
   MỌI loại hàng trường phải tắt nó, nếu không trường thứ hai trở đi tụt đúng 10px so với trường
   đầu — khe ngang đã do gap lo rồi.

   Liệt kê MỌI loại hàng ở một chỗ duy nhất, có chủ ý: lượt trước chỉ tắt cho .o-hang và quên
   .thanh-loc-hang, nên MỌI THANH LỌC của site (Gói dữ liệu, Hồ sơ, Người bệnh, Nhật ký…) đều lệch
   10px suốt một thời gian dài mà không ai thấy — phép đo LECH_HANG mới bắt được. Thêm một loại
   hàng mới thì thêm vào đúng dòng này, không phải đi tìm khắp tệp. */
.o-hang > .o-truong + .o-truong,
.thanh-loc-hang > .o-truong + .o-truong { margin-top: 0; }
.o-hang > .o-truong.o-truong-hep { flex: 0 0 auto; }
.o-hang > .o-truong.o-truong-rong { flex: 1 1 100%; }
/* GD-30. Sàn chiều cao của nhãn gắn vào CHÍNH lớp .o-nhan (xem mục GD-30 ở site.css), không
   gắn theo .o-hang: nhãn nằm ngoài hàng thì cũng phải cùng chiều cao, nếu không chân ô nhập
   trong hàng và ngoài hàng lệch nhau. */

/* GD-32. Nút trong hàng trường phải ngồi ở ĐÚNG TẦNG của ô nhập.

   Hàng trường có ba tầng: nhãn · ô · gợi ý. Cột NÚT không có nhãn, nên phải tự chừa đúng chiều
   cao tầng nhãn thì đáy nút mới thẳng đáy ô bên cạnh.

   Trước đây con số đó viết thẳng là 21px, tách rời khỏi hai con số sinh ra nó (sàn nhãn 17px và
   khe 4px) — sửa một bên, bên kia lệch, không ai biết. Nay cả ba lấy từ MỘT token duy nhất, nên
   không thể trôi khỏi nhau nữa.

   Điều kiện để luật này đúng: hàng trường căn theo ĐỈNH (align-items: flex-start), để dòng gợi ý
   treo bên dưới mà không kéo ai. Ai đè align-items của .o-hang là hỏng — xem ghi chú ở mục
   .dong-chi-tiet-cot bên dưới, đó đúng là lỗi người dùng khoanh đỏ.

   Phép đo LECH_HANG trong tools/giaodien/kiem-giao-dien.js giữ luật này: đáy hai control cùng một
   dòng trực quan không được lệch quá 2px. */
.o-hang > .hang-nut { margin-top: var(--o-tang-nhan); }
/* Hai hàng trường liền nhau phải có khoảng thở, nếu không nhãn của hàng dưới dính vào ô của
   hàng trên và đọc thành một khối (thấy rõ ở trang Nhận diện hệ thống trước khi sửa). */
.o-hang + .o-hang { margin-top: 12px; }
/* Trường đơn xếp dọc liền với một hàng trường (và ngược lại) cũng cần khoảng thở — thiếu luật này nhãn «Mã cơ sở» dính sát ô «Phạm vi» ở trang Mượn. */
.o-truong + .o-hang, .o-hang + .o-truong { margin-top: 12px; }
.o-hang + .hang-nut { margin-top: 16px; }

/* Ô tick: master.css ép accent-color theo màu phân hệ. */
/* GD-30. Nhãn ô tích: cả cụm là một đích bấm CAO TỐI THIỂU 24px (WCAG 2.5.5 — đích bấm không
   nhỏ hơn 24×24, và đích ở đây là cái nhãn bọc ngoài chứ không phải riêng ô vuông 16px).
   align-items:center đặt tâm ô tích thẳng tâm dòng chữ; trước đây nó vô hiệu vì luật
   `form.mau label { display:block }` của site.css đè mất display:inline-flex. */
.o-tick {
  display: inline-flex;
  align-items: center;
  /* Cao đúng bằng ô nhập (--o-cao): đứng cùng hàng với ô nhập thì chân hai thứ mới thẳng nhau,
     và vẫn thừa ngưỡng 24px của WCAG 2.5.5. Trước đây 24px nên nhãn ô tích hụt 8px so với ô nhập
     bên cạnh ở biểu mẫu Khoá API — phép đo LECH_HANG bắt được. */
  min-height: var(--o-cao);
  gap: 8px;
  font-size: var(--o-chu);
  font-weight: 400;
  cursor: pointer;
  user-select: none;
}
/* Hình thức của chính ô vuông gắn vào lớp của nó, KHÔNG theo tổ tiên .o-tick: ô tích đặt ngoài
   nhãn (trong ô bảng, trong thanh lọc) vẫn phải đúng cỡ và đúng màu. */
.o-tick-hop {
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: var(--xanh);
  flex: none;
  cursor: pointer;
}

/* =============================================================================
   4. NÚT — .button (master.css) · .btn / .btn-primary (bootStrapCustom)
            · .dmg-btn (grid-inrow.css: padding 7px 18px, font-weight 600)
   Chiều cao bằng ĐÚNG chiều cao ô nhập (32px) để chân nút và chân ô thẳng hàng
   khi đứng cạnh nhau trong một hàng thao tác.
   ============================================================================= */
.nut {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  height: var(--nut-cao);
  padding: 0 var(--nut-dem-ngang);
  border: 1px solid var(--xanh);
  border-radius: var(--o-bo);
  background: var(--xanh);
  color: #ffffff;
  font-family: inherit;
  font-size: var(--o-chu);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
}
.nut:hover { background: var(--xanh-dam); border-color: var(--xanh-dam); color: #fff; text-decoration: none; }
.nut:active { background: var(--xanh-rat-dam); border-color: var(--xanh-rat-dam); }
.nut:disabled, .nut[aria-disabled="true"] {
  background: var(--o-mo); border-color: var(--o-mo); color: var(--chu-mo); cursor: not-allowed;
}

/* Nút phụ = .btn của bootStrapCustom: nền trắng, chữ và viền màu phân hệ,
   di chuột thì đảo màu (đúng .button:hover của master.css). */
.nut-phu { background: var(--the-nen); color: var(--xanh-chu); border-color: var(--xanh); }
.nut-phu:hover { background: var(--xanh); color: #ffffff; border-color: var(--xanh); }

/* Nút trung tính: dùng cho thao tác không mang màu nghiệp vụ (Đóng, Huỷ).
   Lấy .dmg-btn — viền #dce3ea, di chuột thì viền và chữ chuyển màu phân hệ. */
.nut-trung { background: var(--the-nen); color: var(--chu); border-color: var(--vien); }
.nut-trung:hover { background: var(--the-nen); color: var(--xanh-chu); border-color: var(--xanh); }

/* Nút nguy hiểm: khoá tài khoản, gỡ logo. Tô đặc chứ không chỉ viền — thao tác
   không lấy lại được thì phải nặng hơn các nút cạnh nó về thị giác. */
.nut-nguy { background: var(--do); color: #ffffff; border-color: var(--do); }
.nut-nguy:hover { background: var(--do-chu); color: #ffffff; border-color: var(--do-chu); }
/* Biến thể viền, dùng khi nút nguy hiểm đứng lẫn trong một hàng nhiều nút nhỏ
   (hàng thao tác của lưới) — tô đặc ở đó thành ra cả hàng đỏ rực. */
.nut-nguy-vien { background: var(--the-nen); color: var(--do); border-color: var(--do); }
.nut-nguy-vien:hover { background: var(--do); color: #ffffff; border-color: var(--do); }

/* Nút trần: chỉ có chữ, dùng trong dòng văn bản và trong ô lưới. */
.nut-tran { background: transparent; border-color: transparent; color: var(--xanh-chu); padding: 0 6px; }
.nut-tran:hover { background: var(--xanh-nhat); border-color: transparent; color: var(--xanh-chu); }

/* Nút nhỏ trong lưới: module-shell .ms-home là 28px vuông; nút có chữ trong ô
   lưới phải thấp hơn ô nhập nếu không hàng lưới dày gấp đôi. */
.nut-nho { height: var(--nut-cao-nho); padding: 0 var(--nut-dem-ngang-nho); font-size: 0.75rem; gap: 5px; }
.nut-bieu-tuong { width: var(--nut-cao-nho); padding: 0; }
.nut-bieu-tuong svg { width: 14px; height: 14px; }

.hang-nut { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.hang-nut-phai { margin-left: auto; }
/* GD-32. Biến thể nút chiếm hết bề ngang, cao hơn một bậc — dùng cho nút chính của thẻ đăng nhập.
   Trước đây việc này do `.the-cong .nut { width:100%; height:38px }` làm, tức khung chứa với tay
   vào đổi kích thước của nút dùng chung. */
.nut-rong { width: 100%; height: 38px; }

/* =============================================================================
   5. LƯỚI DỮ LIỆU — newGrid (exComponent/04-grid.js trên nền Tabulator)
   Số đo lấy của tabulator_bootstrap5.min.css sau khi bootStrapCustom ghi đè:
     khung        border 1px #dee2e6
     tiêu đề      cao 34px, đệm ngang 10px, đậm 700, kẻ dưới 1px #dee2e6, DÍNH
     ô            đệm 4px (ở đây 6px 10px cho dễ đọc), kẻ phải 1px #dee2e6
     chữ          13px
     cột số       căn phải, chữ số đều bề ngang
     di chuột     đổi nền cả hàng
   ============================================================================= */
.luoi-cuon, .cuon { overflow: auto; }

table.luoi, table.bang {
  width: 100%;
  border-collapse: separate;   /* separate để viền dính của <thead> không biến mất khi cuộn */
  border-spacing: 0;
  background: var(--the-nen);
  font-size: var(--o-chu);
  line-height: 1.45;
  color: var(--o-chu-mau);
}

table.luoi > thead > tr > th, table.bang > thead > tr > th {
  position: sticky;
  top: 0;
  z-index: 2;
  height: var(--luoi-cao-dau);
  padding: 0 var(--luoi-dem-ngang);
  background: var(--luoi-dau-nen);
  color: var(--luoi-dau-chu);
  font-weight: 700;
  font-size: var(--o-chu);
  text-align: left;
  white-space: nowrap;
  vertical-align: middle;
  border-bottom: 2px solid var(--luoi-vien);
  border-right: 1px solid var(--luoi-vien-nhat);
}
table.luoi > thead > tr > th:last-child, table.bang > thead > tr > th:last-child { border-right: 0; }

table.luoi > tbody > tr > td, table.bang > tbody > tr > td {
  padding: var(--luoi-dem-doc) var(--luoi-dem-ngang);
  border-bottom: 1px solid var(--luoi-vien-nhat);
  border-right: 1px solid var(--luoi-vien-nhat);
  vertical-align: middle;
  text-align: left;
}
table.luoi > tbody > tr > td:last-child, table.bang > tbody > tr > td:last-child { border-right: 0; }
table.luoi > tbody > tr:last-child > td, table.bang > tbody > tr:last-child > td { border-bottom: 0; }

/* Hàng sọc và hàng di chuột. Bản gốc tắt sọc (bootStrapCustom ghi đè
   .tabulator-row-even về transparent) nhưng bảng ở đây rộng tới 47 cột và cuộn
   ngang, mất sọc là lạc dòng — dùng sọc rất nhạt #fafbfd thay vì #e9ecef của
   Tabulator, đủ dẫn mắt mà không thành vằn. */
table.luoi > tbody > tr:nth-child(even), table.bang > tbody > tr:nth-child(even) { background: var(--luoi-soc); }
table.luoi > tbody > tr:hover, table.bang > tbody > tr:hover { background: var(--luoi-di-chuot); }

/* Cột số: căn phải, chữ số đều bề ngang để hàng đơn vị thẳng cột. */
table.luoi td.so, table.luoi th.so, table.bang td.so, table.bang th.so {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
table.luoi td.ma, table.bang td.ma {
  font-family: ui-monospace, "Cascadia Mono", "Consolas", "Liberation Mono", "DejaVu Sans Mono", monospace;
  font-size: 0.75rem;
  white-space: nowrap;
}
table.luoi td.giua, table.luoi th.giua, table.bang td.giua, table.bang th.giua { text-align: center; }

/* ADR-0109 (GD-15, GD-17): bảng NHIỀU CỘT tự khai lớp bang-tieu-de-xuong-dong — tiêu đề xuống dòng (tối đa ba dòng) thay vì mỗi cột
   rộng bằng cả câu tiêu đề một dòng rồi cả bảng cuộn ngang ở 1440 («Sửa lỗi nh…» bị cắt). Sàn mỗi cột vừa một từ dài. */
table.bang.bang-tieu-de-xuong-dong > thead > tr > th,
table.bang.bang-tieu-de-xuong-dong > thead > tr > th.so {
  white-space: normal;
  height: auto;
  min-width: 3.5rem;
  padding-top: var(--kc-1);
  padding-bottom: var(--kc-1);
  line-height: 1.3;
  vertical-align: bottom;
  overflow-wrap: normal;
}

/* Ô chứa thao tác: nút và ô nhập trong lưới không được làm hàng cao gấp đôi. */
td.o-thao-tac { padding: 4px var(--luoi-dem-ngang); white-space: nowrap; }
/* GD-32. Biến thể GỌN của hàng nút, dùng trong ô thao tác của bảng: không xuống dòng, khe hẹp,
   dồn về phải. Đây là biến thể do CHÍNH thành phần định nghĩa và trang gắn bằng lớp
   `.hang-nut-gon`, chứ không phải ô bảng với tay vào đổi bố cục của hàng nút — cách sau là đúng
   kiểu lỗi làm nút lệch khỏi ô nhập mà bản kiểm không thấy (xem GD-32 ở .o-hang). */
.hang-nut-gon { flex-wrap: nowrap; gap: 6px; justify-content: flex-end; }

/* Khung lưới khi đứng một mình (không nằm trong thẻ). */
.luoi-khung {
  border: 1px solid var(--luoi-vien);
  border-radius: var(--o-bo);
  overflow: hidden;
  background: var(--the-nen);
}

/* =============================================================================
   5b. DÒNG CHI TIẾT TRONG LƯỚI — "form chèn vào dòng" của His_Site
   Nguồn: Css/exComponent/grid-inrow.css
       .dm-rowdetail { border-top-color: var(--xanh); border-bottom-color: var(--xanh);
                       background: var(--the-dinh); }
       .dmg-form .dmg-foot { border-top-color: var(--vien); margin-top: 14px;
                             padding-top: 12px; }
       .dmg-btn { border-radius: 0; border: 1px solid var(--vien); padding: 7px 18px;
                  font-weight: 600; }

   Đây là lối SỬA MỘT DÒNG của His_Site và là cách giải GD-15: thay vì nhồi bảy
   control lên một hàng bảng, hàng chỉ giữ hai thao tác hay dùng, phần còn lại mở
   ra trong dòng chi tiết ngay bên dưới. Khác hộp thoại nổi ở một điểm quan trọng:
   trang KHÔNG có JavaScript thì dòng chi tiết mở sẵn (quy tắc .khong-js dưới đây)
   nên không mất đường vào thao tác nào.
   ============================================================================= */
tr.dong-chi-tiet { display: none; }
tr.dong-chi-tiet.mo { display: table-row; }
/* Không có JavaScript: hiện sẵn mọi dòng chi tiết. site.js gỡ .khong-js ở dòng đầu. */
.khong-js tr.dong-chi-tiet { display: table-row; }

tr.dong-chi-tiet > td {
  padding: 0 !important;
  border-top: 2px solid var(--xanh);
  border-bottom: 2px solid var(--xanh);
  background: var(--the-dinh);
}
.dong-chi-tiet-noi { padding: 14px 16px 16px; }
.dong-chi-tiet-ten {
  margin: 0 0 12px;
  font-size: 0.8125rem;
  color: var(--chu);
  padding-bottom: 8px;
  border-bottom: 1px solid var(--vien);
}
/* Ba cụm thao tác cạnh nhau khi còn chỗ, xếp dọc khi hẹp — mỗi cụm là một <form>
   riêng nên không thể gộp thành một hàng dài như bản trước. */
/* GD-27. Bỏ repeat(auto-fit, minmax(258px, 1fr)): lưới 24 rãnh dùng chung của site.css
   (.luoi-noi-dung) quyết định số cụm một hàng theo bậc bề rộng, nên ở 1920 không còn sinh ra
   bốn năm cột hẹp ngoài ý muốn. Lớp .luoi-noi-dung gắn kèm trong Razor. */
.dong-chi-tiet-cot {
  gap: 16px;
  align-items: start;
}
.dong-chi-tiet-cot:not(.luoi-noi-dung) { display: grid; grid-template-columns: minmax(0, 1fr); }
.dong-chi-tiet-cot > form {
  background: var(--the-nen);
  border: 1px solid var(--vien);
  border-radius: var(--o-bo);
  padding: 11px 13px 13px;
}
/* Tên cụm: lối .oh của .cc-ex-opts trong catalog — 11px, đậm 700, chữ hoa nhỏ. */
.o-nhom-ten {
  display: block;
  margin: 0 0 9px;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--chu-mo);
}
/* GD-32. ĐÃ BỎ: `.dong-chi-tiet-cot .o-hang { align-items: flex-end }`.
   Đây là luật bó tổ tiên đè vào thành phần hàng trường dùng chung, độ đặc hiệu (0,2,0) thắng
   `.o-hang` (0,1,0). Căn ĐÁY làm mọi cột dóng theo đáy cột CAO NHẤT, nên ở cụm "Số phiên đồng
   thời" — nơi ô số có thêm dòng gợi ý — nút "Lưu" bị kéo xuống ngang đáy dòng gợi ý, tức
   19,4px (= 15,4px gợi ý + 4px khe) dưới đáy ô số. Đúng chỗ người dùng khoanh đỏ.
   Hàng trường căn theo ĐỈNH, và luật đó thuộc về chính .o-hang, không ai được đè. */

/* Nút mở dòng chi tiết: đổi chữ theo trạng thái mà không cần JavaScript viết chữ. */
.nut-mo-dong[aria-expanded="true"] { background: var(--xanh); color: #fff; border-color: var(--xanh); }
.cot-thao-tac { width: 1%; }

/* =============================================================================
   6. NHÃN TRẠNG THÁI — badge của catalog (.cc-h .badge2 / .lib):
      font-size 11px, font-weight 700, padding 2px 9px, bo tròn 999px.
   ============================================================================= */
.nhan {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1.5;
  white-space: nowrap;
  background: var(--nen-nhat);
  color: var(--chu);
}
.nhan-xanh { background: var(--xanh-nhat-2); color: var(--xanh-chu); }   /* .badge2 của catalog */
.nhan-luc  { background: var(--luc-nen); color: var(--luc-chu); }   /* .lib của catalog */
.nhan-vang { background: var(--vang-nen); color: var(--vang-chu); }
.nhan-do   { background: var(--do-nen); color: var(--do-chu); }
.nhan-tim  { background: var(--tim-nen); color: var(--tim-chu); }
.nhan-xam  { background: var(--nen); color: var(--chu-mo); }

/* =============================================================================
   7. THANH LỌC — hàng ô nhập + nút đứng ngang, chân thẳng nhau.
   ============================================================================= */
.thanh-loc-hang { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-start; }
.thanh-loc-hang > .o-truong { flex: 0 1 200px; }
/* GD-32. Cùng một token tầng nhãn với .o-hang. */
.thanh-loc-hang > .hang-nut { flex: 0 0 auto; margin-top: var(--o-tang-nhan); }


/* =============================================================================
   8. HỘP THOẠI (GD-17) — .ms-help-ov / .ms-help-box của module-shell.css:
        nền phủ rgba(0,0,0,.42)
        hộp   width min(720px, 92vw), max-height 84vh, cột flex,
              viền 1px --line, bóng 0 10px 40px rgba(0,0,0,.3)
        đầu   đệm 10px 14px, nền màu phân hệ, chữ trắng, kẻ dưới
        thân  đệm 12px 16px, cuộn được
   Dựng bằng <dialog> gốc: Esc và bẫy tiêu điểm là hành vi sẵn có của trình duyệt
   khi mở bằng showModal(), không phải thứ phải tự viết rồi viết sai.
   ============================================================================= */
/* GD-27. Nới từ 1040px lên 1360px: hộp thoại nay chứa KHỐI GOM NHÓM của Bảng 1 (sáu nhóm nghiệp
   vụ, lưới 12 cột) chứ không còn là bảng ba cột thô. Ở 1040px mỗi cột chỉ còn 66px và giá trị
   ngày "20250101" bị bẻ đôi giữa dòng. */
dialog.hop-thoai {
  width: min(1360px, 94vw);
  max-width: 94vw;
  max-height: 86vh;
  padding: 0;
  border: 1px solid var(--vien);
  border-radius: 6px;
  background: var(--the-nen);
  color: var(--o-chu-mau);
  box-shadow: 0 10px 40px rgba(0, 0, 0, .3);
  overflow: hidden;
}
dialog.hop-thoai::backdrop { background: rgba(0, 0, 0, .42); }
/* Firefox ESR 102 chưa có <dialog>; site.js khi đó dựng hộp bằng div mang cùng
   lớp cộng .hop-thoai-the. Hai nhánh dùng chung mọi quy tắc con bên dưới. */
.hop-thoai-the {
  position: fixed;
  z-index: 9999;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(1360px, 94vw);
  max-height: 86vh;
  border: 1px solid var(--vien);
  border-radius: 6px;
  background: var(--the-nen);
  box-shadow: 0 10px 40px rgba(0, 0, 0, .3);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.hop-thoai-phu {
  position: fixed;
  z-index: 9998;
  inset: 0;
  background: rgba(0, 0, 0, .42);
}

dialog.hop-thoai[open] { display: flex; flex-direction: column; }

.hop-thoai-dau {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
  padding: 10px 14px;
  background: var(--xanh);
  color: #ffffff;
  border-bottom: 1px solid var(--xanh-dam);
}
.hop-thoai-ten { font-weight: 700; font-size: 0.9375rem; margin: 0; }
.hop-thoai-phu-de { font-size: 0.75rem; color: var(--xanh-chu-phu); }
.hop-thoai-dong {
  margin-left: auto;
  width: 28px;
  height: 28px;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(255, 255, 255, .45);
  border-radius: var(--o-bo);
  background: transparent;
  color: #ffffff;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}
.hop-thoai-dong:hover { background: rgba(255, 255, 255, .18); border-color: var(--the-nen); }
.hop-thoai-than { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 12px 16px; }
.hop-thoai-than > .luoi-cuon, .cuon { overflow: auto; }
.hop-thoai-chan {
  flex: 0 0 auto;
  display: flex;
  gap: 8px;
  align-items: center;
  padding: 10px 14px;
  border-top: 1px solid var(--vien);
  background: var(--the-dinh);
}

/* Khi hộp thoại mở, trang nền không cuộn theo. */
body.co-hop-thoai { overflow: hidden; }

/* Phần tử được MƯỢN vào hộp thoại (GD-17) là chính khối gấp của bảng, nên nó mang theo tiêu đề
   riêng — trùng với tên đã in trên thanh đầu hộp thoại. Giấu tên trùng và cái mũi nhọn thu/mở,
   giữ lại dải số liệu (số dòng, số tiền, số trường, số trường che) vì đó mới là thứ đáng đọc.
   Và ép thân khối mở sẵn: thu nó lại khi đang ở trong hộp thoại thì hộp rỗng, vô nghĩa. */
.hop-thoai-than > .khoi-gap { border: 0; box-shadow: none; margin: 0; }
.hop-thoai-than > .khoi-gap > .khoi-gap-dau {
  background: transparent;
  border-bottom: 1px solid var(--vien);
  cursor: default;
  padding-left: 0;
  padding-right: 0;
}
.hop-thoai-than > .khoi-gap > .khoi-gap-dau > .khoi-gap-caret,
.hop-thoai-than > .khoi-gap > .khoi-gap-dau > .khoi-gap-ten { display: none; }
.hop-thoai-than > .khoi-gap > .khoi-gap-than { display: block; grid-template-rows: none; }
.hop-thoai-than > .khoi-gap .khoi-gap-cat { overflow: visible; }

/* =============================================================================
   9. BẢN IN
   Hộp thoại KHÔNG ra giấy (nó chỉ là lối xem nhanh), nhưng mọi bảng gốc vẫn ra
   đủ — đó là điều kiện của GD-17 và của test BanIn_BungMoiTabVaMoiKhoiGap.
   ============================================================================= */
@media print {
  dialog.hop-thoai, .hop-thoai-the, .hop-thoai-phu { display: none !important; }
  body.co-hop-thoai { overflow: visible !important; }

  .o-nhap, .o-xo, .o-van-ban, .o-tep {
    border: 1px solid #94a3b8;
    box-shadow: none;
    background: #fff;
  }
  .nut, .hang-nut { display: none !important; }

  table.luoi, table.bang { font-size: 9.5pt; }
  table.luoi > thead > tr > th, table.bang > thead > tr > th {
    position: static;
    background: #f1f3f6 !important;
    color: #000;
    border-bottom: 1px solid #94a3b8;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  table.luoi > tbody > tr:nth-child(even), table.bang > tbody > tr:nth-child(even) { background: transparent; }
  table.luoi > tbody > tr:hover, table.bang > tbody > tr:hover { background: transparent; }
  table.luoi > tbody > tr > td, table.bang > tbody > tr > td { border-bottom: 1px solid #d5dae1; }
  /* Dòng chi tiết chỉ để sửa dữ liệu, không thuộc nội dung bản in. */
  tr.dong-chi-tiet { display: none !important; }
}

@media (prefers-reduced-motion: reduce) {
  .o-nhap, .o-xo, .o-van-ban, .o-tep, .nut { transition: none; }
}

/* R8 (HL-VII.4.1-002): văn bản nhiều dòng do người dùng soạn (mô tả ca giảng dạy) — giữ xuống dòng, không tràn ngang. */
.giu-dong { white-space: pre-line; overflow-wrap: anywhere; }
