/* PORT: assets/qlts.css = nguyên văn src/app/globals.css rồi src/app/quan-ly.css của bản Next.js gốc, đúng thứ tự đó (thứ tự quyết định cascade) — chỉ dòng có PORT là khác bản gốc. */
/* M31: giữ nguyên token/cascade; CSS màn riêng nằm ở tệp riêng (vd qlts-thi.css) — không chen rule mới vào đây. */
/* ============================================================
   QLTS — TOKEN & RESET
   ------------------------------------------------------------
   File này CHỈ chứa biến thiết kế và reset. Mọi bố cục, thành phần
   giao diện nằm ở quan-ly.css và được viết theo lối MOBILE FIRST
   (mặc định là điện thoại, mở rộng dần bằng min-width).

   Bảng màu và kiểu chữ giữ nguyên theo nhận diện khách đã duyệt.
   ============================================================ */

:root {
  /* ---- màu thương hiệu ----
     HAI màu nhấn, mỗi màu đúng MỘT việc, không lẫn vào nhau:
       • XANH HIỆU LỆNH — mọi thứ bấm được: nút chính, chip đang chọn, liên kết.
       • VÀNG LOGO — định vị: vạch mục đang mở, viền tiêu điểm bàn phím.
     Chia vai như vậy thì người dùng học một lần: xanh là "bấm được", vàng là
     "bạn đang ở đây". Hai màu cùng nổi trên một trang mà không tranh nhau.

     Xanh lấy theo BIỂN HIỆU LỆNH giao thông (biển tròn nền xanh) — thứ mà học
     viên và giáo viên nhìn hằng ngày, nên nó là màu nghề này tự có, không phải
     màu vay của phần mềm khác. KHÔNG dùng #0078d4 mặc định của Fluent: đo ra
     chỉ 4,53:1 với chữ trắng, vừa sát ngưỡng là hết chỗ lùi khi chữ nhỏ đi.

     Vàng KHÔNG bao giờ làm nền nút, cũng không làm chữ ở mức --vang: #d8a820
     trên nền trắng chỉ 2,20:1. Chữ vàng phải dùng --vang-dam (5,27:1). */
  --primary: #1e3a8a;       /* đặc tả UX — xanh navy quản trị */
  --primary-hover: #1d4ed8; /* hover primary theo đặc tả */
  --primary-light: #eff6ff; /* nền phấn khi trỏ/chọn */

  /* Vàng đo trực tiếp từ file logo: #d8a820 là sắc chiếm nhiều pixel nhất,
     #f0d060 là dải sáng trên nét xe. */
  --vang: #d8a820;
  /* Bản đậm dành riêng cho CHỮ và viền tiêu điểm: #d8a820 trên nền trắng chỉ
     đạt 2.2:1, không đủ đọc. #8a6608 đạt 4.6:1. */
  --vang-dam: #8a6608;
  --vang-nhat: #fdf7e6;

  /* ---- màu theo trạng thái học viên ----
     Ba giá trị mỗi dòng: màu CHỮ, màu NỀN phấn, màu VIỀN của huy hiệu.
     Màu chữ luôn đặt trên nền phấn cùng dòng, nên nó phải đủ đậm so với
     CHÍNH NỀN ĐÓ chứ không phải so với nền trắng. Huy hiệu là chữ 11,5px —
     cỡ thường theo WCAG — nên ngưỡng là 4,5:1. Đo bằng máy trên từng cặp,
     con số ghi ở cuối mỗi dòng. Đừng làm nhạt lại cho "dịu mắt": người dùng
     của phần mềm này đứng ngoài sân tập, nắng chiếu vào màn hình. */
  --c-ksk: #b45309;        --c-ksk-bg: #fffbeb;      --c-ksk-border: #fcd34d;      /* 4,84 */
  --c-ksk-done: #15803d;   --c-ksk-done-bg: #f0fdf4; --c-ksk-done-border: #86efac; /* 4,79 */
  --c-docs: #0369a1;       --c-docs-bg: #f0f9ff;     --c-docs-border: #7dd3fc;     /* 5,57 */
  --c-studying: #065f46;   --c-studying-bg: #d1fae5; --c-studying-border: #6ee7b7; /* đặc tả "Đang học" */
  --c-exam: #7c3aed;       --c-exam-bg: #f5f3ff;     --c-exam-border: #c4b5fd;     /* 5,20 */
  --c-passed: #047857;     --c-passed-bg: #f0fdf4;   --c-passed-border: #6ee7b7;   /* 5,24 */
  --c-failed: #b91c1c;     --c-failed-bg: #fff1f2;   --c-failed-border: #fca5a5;   /* 5,89 */
  --c-dropout: #64748b;    --c-dropout-bg: #f8fafc;  --c-dropout-border: #cbd5e1;  /* 4,55 */

  --success: #10b981;
  --warning: #f59e0b;
  --danger: #ef4444;

  /* ---- màu biểu đồ trang Tổng quan ----
     Bốn màu này đứng cạnh nhau trên cùng một trang nên phải phân biệt được cả
     với mắt mù màu. Đã chạy qua bộ kiểm tra: đủ độ đậm so với nền trắng (>= 3:1),
     đủ khác nhau ở cả ba dạng mù màu. KHÔNG lấy --info (#3b82f6) làm màu cột:
     nó chỉ đạt 2,6:1 với nền trắng, cột nhạt quá đọc không ra chiều cao.
     Màu "đạt"/"không đạt" dùng lại đúng --c-passed/--c-failed của trạng thái
     học viên — cùng một ý nghĩa thì phải cùng một màu. */
  --bd-hv: #b8860b;   /* học viên đăng ký mới */
  --bd-tien: #2563eb; /* học phí đã thu */

  /* ---- nền và chữ ----
     Nền trang ngả xanh nhạt thay cho xám lạnh #f1f5f9: đứng cạnh --surface
     trắng nó tách lớp rõ hơn mà vẫn sáng, và nằm cùng hệ với xanh hiệu lệnh.
     Mọi màu trạng thái phía trên vẫn đủ ngưỡng trên nền này — thấp nhất là
     "bỏ học" 4,43:1, nhưng màu đó chỉ xuất hiện trong huy hiệu, tức là đứng
     trên nền phấn riêng của nó (4,55:1), không bao giờ đứng trực tiếp lên đây. */
  --bg: #f8fafc;
  --surface: #ffffff;
  --acrylic: color-mix(in srgb, #ffffff 72%, transparent);
  --mica: color-mix(in srgb, var(--primary-light) 55%, #ffffff);
  --shadow-1: 0 1px 2px color-mix(in srgb, #0f172a 6%, transparent), 0 0 0 1px color-mix(in srgb, #0f172a 4%, transparent);
  --shadow-2: 0 4px 16px color-mix(in srgb, #0f172a 10%, transparent), 0 0 0 1px color-mix(in srgb, #0f172a 5%, transparent);
  --reveal: color-mix(in srgb, var(--primary) 12%, transparent);
  --tr-fast: 120ms cubic-bezier(0.1, 0.9, 0.2, 1);
  --tr-med: 200ms cubic-bezier(0.1, 0.9, 0.2, 1);
  --border: #cbd5e1;
  --border-light: #e2e8f0;
  --text: #1e293b;
  --text-2: #475569;
  --text-3: #64748b;

  /* ---- kiểu chữ ---- */
  --font: "Be Vietnam Pro", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; /* PORT: var(--font-be-vietnam) do next/font sinh không còn — phông nạp từ Google Fonts trong <head> */
  --font-so: "JetBrains Mono", ui-monospace, Consolas, monospace; /* PORT: var(--font-mono) do next/font sinh không còn — phông nạp từ Google Fonts trong <head> */

  /* Cỡ chữ nền: điện thoại đọc xa hơn nên nhỉnh hơn desktop một bậc. */
  --co-chu: 15px;
  /* Ô nhập LUÔN ≥16px, dưới mức đó iOS tự phóng to trang khi bấm vào. */
  --co-chu-nhap: 16px;

  /* ---- thang khoảng cách (bội số 4 theo đặc tả UX) ---- */
  --k1: 4px;
  --k2: 8px;
  --k3: 12px;
  --k4: 16px;
  --k5: 20px;
  --k6: 24px; /* padding card chuẩn */
  --k7: 32px;
  --gutter: 16px;

  /* ---- kích thước khung ---- */
  --sidebar-w: 260px; /* đặc tả 240–280px */
  --sidebar-thu: 64px;
  --topbar-h: 56px;
  --tabbar-h: 58px;
  /* Vùng chạm tối thiểu cho ngón tay. */
  --cham: 44px;
  --hang-bang: 56px; /* chiều cao hàng bảng 52–60px */

  /* ---- bo góc, đổ bóng ---- */
  --r: 8px; /* ô nhập theo đặc tả */
  --r-lg: 12px;
  --r-xl: 16px;
  --r-full: 9999px;

  /* Đổ bóng theo lối Fluent: mỗi bậc HAI lớp — một lớp mờ sát mép vẽ đường bao
     cho khối, một lớp toả xa tạo độ cao — và ngả navy rgb(11 45 90) chứ không
     đen thuần. Bóng đen trên nền ngả xanh làm đục màu, trông như ảnh bị nhòe. */
  --shadow-sm: 0 1px 2px rgba(11, 45, 90, 0.08), 0 0 1px rgba(11, 45, 90, 0.06);
  --shadow: 0 2px 4px rgba(11, 45, 90, 0.1), 0 0 2px rgba(11, 45, 90, 0.06);
  --shadow-lg: 0 8px 16px rgba(11, 45, 90, 0.12), 0 0 2px rgba(11, 45, 90, 0.06);
  --shadow-xl: 0 16px 32px rgba(11, 45, 90, 0.14), 0 0 2px rgba(11, 45, 90, 0.06);

  --tr: 0.16s ease;
  --ring: 0 0 0 3px color-mix(in srgb, var(--primary) 25%, transparent);

  /* ---- lề an toàn của máy có tai thỏ / thanh gạt ---- */
  --an-toan-duoi: env(safe-area-inset-bottom, 0px);
  --an-toan-tren: env(safe-area-inset-top, 0px);
}

@media (min-width: 1024px) {
  :root {
    --co-chu: 14px;
    --topbar-h: 60px;
  }
}

/* ============================================================ reset */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  /* Chặn iOS tự phóng chữ khi xoay ngang máy. */
  -webkit-text-size-adjust: 100%;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  font-family: var(--font);
  font-size: var(--co-chu);
  line-height: 1.5;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  /* Không cho trang trượt ngang trên điện thoại. */
  overflow-x: hidden;
}

a {
  color: inherit;
  text-decoration: none;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.01em;
}

p {
  margin: 0;
}

button {
  font: inherit;
  color: inherit;
}

input,
select,
textarea {
  font: inherit;
  /* Cỡ chữ ô nhập cố định 16px trên mọi khổ màn hình. */
  font-size: var(--co-chu-nhap);
}

img,
svg {
  max-width: 100%;
  display: block;
}

:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms;
    transition-duration: 0.01ms;
    scroll-behavior: auto;
  }
}
/* PORT: ======== hết globals.css — từ đây là nguyên văn src/app/quan-ly.css ======== */
/* ============================================================
   QLTS — GIAO DIỆN, VIẾT THEO LỐI MOBILE FIRST
   ------------------------------------------------------------
   Mặc định của mọi quy tắc trong file này là MÀN HÌNH ĐIỆN THOẠI.
   Màn lớn hơn chỉ được mở rộng thêm bằng @media (min-width: …).

   Vì sao mobile first có ý nghĩa với phần mềm này: giáo viên đứng
   ngoài sân tập ghi buổi Cabin/DAT bằng điện thoại; nhân viên văn
   phòng tra cứu học viên khi đang nghe điện thoại. Ba việc trên
   điện thoại là TÌM — XEM — GHI. Việc hàng loạt (gán đợt thi, thu
   học phí, xuất báo cáo) mới cần màn rộng.

   Ba quyết định xuyên suốt:
   1. Bảng nhiều cột KHÔNG cuộn ngang trên điện thoại mà đổi thành
      DANH SÁCH THẺ, mỗi thẻ chỉ giữ những gì đủ để nhận ra và quyết
      định. Bảng đầy đủ quay lại từ 768px.
   2. Điều hướng chính nằm ở THANH DƯỚI ĐÁY, trong tầm ngón cái.
      Sidebar chỉ xuất hiện từ 1024px.
   3. Hộp thoại trên điện thoại là TẤM TRƯỢT TỪ ĐÁY, nút chính ghim
      dưới cùng nên không bị bàn phím ảo che.
   ============================================================ */

/* ============================================================
   1. KHUNG ỨNG DỤNG
   ============================================================ */

/*
 * Khung ứng dụng cao ĐÚNG một màn hình và không tự cuộn. Cuộn nằm bên trong
 * vùng nội dung, nên thanh trên cùng, thanh công cụ và thanh phân trang luôn
 * đứng yên — trước đây cả trang trôi lên, danh sách dài là mất luôn chỗ bấm
 * sang trang.
 */
.app {
  height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.main {
  flex: 1;
  min-width: 0;
  /* min-height: 0 là bắt buộc trong flex — thiếu nó thì con không co được
     xuống dưới nội dung, và mọi tính toán chiều cao bên dưới thành vô nghĩa. */
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/*
 * Vùng nội dung: cột dọc, tự cuộn khi cần. Trang có danh sách thì `.khung-ds`
 * bên trong nhận `flex: 1` nên nó kéo dài tới chân trang và tự cuộn phần danh
 * sách — vùng nội dung ngoài đứng yên. Trang không có danh sách (Tổng quan,
 * Cài đặt) thì chính vùng này cuộn. Một quy tắc, hợp cả hai kiểu trang.
 */
/* Lề vùng nội dung 5px — sát mép, nhường gần như toàn bộ bề ngang cho dữ liệu.
   Riêng lề dưới vẫn phải chừa thanh tab và vạch Home của máy, nếu không hàng
   cuối bị che. */
.content {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 5px;
  overflow-y: auto;
  padding-bottom: calc(var(--tabbar-h) + var(--an-toan-duoi) + 5px);
}

/*
 * MỘT bậc lề duy nhất: 5px ở mọi khổ màn.
 *
 * Trước đây chỗ này có BA khối chồng nhau — 5px (từ 1024px), rồi 20px (từ
 * 768px), rồi 24px (từ 1024px). Khối 1024px thứ hai viết sau nên nó thắng, và
 * lề thật trên máy tính là 24px chứ không phải 5px như khối đầu định. Đo tại
 * chỗ ở bề ngang 1280px: padding 24px cả bốn phía. Nghĩa là chủ ý "sát mép,
 * nhường gần như toàn bộ bề ngang cho dữ liệu" ghi ở đầu file này chưa bao giờ
 * có hiệu lực trên máy tính.
 */
@media (min-width: 1024px) {
  .app {
    flex-direction: row;
  }
  /* Từ 1024px thanh tab dưới đáy nhường chỗ cho thanh bên, nên lề dưới không
     phải chừa chỗ cho nó nữa. */
  .content {
    padding: 5px;
    padding-bottom: 5px;
  }
}

/* ============================================================
   2. THANH TRÊN
   ============================================================ */

.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: var(--k2);
  height: calc(var(--topbar-h) + var(--an-toan-tren));
  padding: var(--an-toan-tren) var(--k3) 0;
  background: var(--acrylic);
  backdrop-filter: blur(20px) saturate(1.4);
  -webkit-backdrop-filter: blur(20px) saturate(1.4);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow-1);
}

/* Tiêu đề trang giờ mang cả icon — khối tiêu đề trùng lặp ở thân trang đã bỏ,
   nên đây là chỗ duy nhất nói người dùng đang ở màn hình nào. */
.topbar h1 {
  display: flex;
  align-items: center;
  gap: var(--k2);
  /* KHÔNG dùng flex: 1. Ngay bên cạnh có .topbar-spacer cũng flex: 1, nên hai
     đứa chia đôi chỗ trống — tiêu đề bị xén ("Quản lý thí sin…") trong khi một
     mảng trống y hệt nằm ngay cạnh nó. Tiêu đề lấy đúng bề ngang nó cần, phần
     thừa để spacer nuốt; chỉ khi thật sự không đủ chỗ nó mới co lại. */
  flex: 0 1 auto;
  min-width: 0;
  font-size: 16px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.topbar h1 i {
  flex: 0 0 auto;
  font-size: 15px;
  color: var(--vang-dam);
}

/* Dưới 420px, chuông + ảnh đại diện + nút thoát ăn gần 150px, tiêu đề bị bóp
   thành "Thi tốt ng…". Thu nhỏ chữ và bỏ icon để tên màn hình hiện đủ — biết
   mình đang ở đâu quan trọng hơn một cái biểu tượng trang trí. */
@media (max-width: 419px) {
  .topbar h1 {
    font-size: 15px;
    gap: var(--k1);
  }

  .topbar h1 i {
    display: none;
  }
}

.topbar-spacer {
  flex: 1;
}

@media (min-width: 1024px) {
  .topbar {
    padding-left: var(--k6);
    padding-right: var(--k6);
  }
  .topbar h1 {
    font-size: 17px;
    flex: 0 0 auto;
  }
}

.user-chip {
  display: flex;
  align-items: center;
  gap: var(--k2);
  flex: 0 0 auto;
}

.user-chip .who {
  display: none;
  line-height: 1.15;
}

.user-chip .who b {
  display: block;
  font-size: 13px;
}

.user-chip .who span {
  font-size: 11px;
  color: var(--text-3);
}

@media (min-width: 768px) {
  .user-chip {
    padding: 4px var(--k3) 4px 4px;
    border-radius: var(--r-full);
    background: var(--border-light);
  }
  .user-chip .who {
    display: block;
  }
}

.avatar {
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  border-radius: var(--r-full);
  background: var(--primary);
  color: #fff;
  display: grid;
  place-items: center;
  font-size: 13px;
  font-weight: 700;
}

/* ============================================================
   3. THANH TAB DƯỚI ĐÁY  (điện thoại và máy tính bảng)
   ------------------------------------------------------------
   Ứng dụng có 14 mục. Bốn mục hay dùng nhất theo vai trò đưa xuống
   đáy trong tầm ngón cái; phần còn lại nằm sau nút "Thêm".
   ============================================================ */

.tabbar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  display: flex;
  height: calc(var(--tabbar-h) + var(--an-toan-duoi));
  padding-bottom: var(--an-toan-duoi);
  background: var(--surface);
  border-top: 1px solid var(--border);
}

.tab {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  border: 0;
  background: none;
  color: var(--text-3);
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
  padding: 0 2px;
  position: relative;
}

.tab i {
  font-size: 17px;
}

.tab span {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tab.on {
  color: var(--primary);
}

.tab.on::before {
  content: '';
  position: absolute;
  top: 0;
  left: 22%;
  right: 22%;
  height: 2px;
  border-radius: 0 0 3px 3px;
  background: var(--primary);
}

.tab-dem {
  position: absolute;
  top: 5px;
  left: 50%;
  margin-left: 5px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: var(--r-full);
  background: var(--danger);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

@media (min-width: 1024px) {
  .tabbar {
    display: none;
  }
  /* Thanh tab đã ẩn thì chiều cao của nó phải về 0, nếu không mọi thứ ghim
     đáy (thông báo nổi, thanh nút "Gán") sẽ bị đẩy hẫng lên 58px. */
  :root {
    --tabbar-h: 0px;
  }
}

/* ============================================================
   4. NGĂN KÉO / SIDEBAR
   ============================================================ */

.sidebar {
  position: fixed;
  z-index: 60;
  top: 0;
  bottom: 0;
  left: 0;
  width: min(84vw, 300px);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-right: 1px solid var(--border);
  transform: translateX(-100%);
  transition: transform var(--tr);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-top: var(--an-toan-tren);
  padding-bottom: var(--an-toan-duoi);
}

.sidebar.open {
  transform: none;
  box-shadow: var(--shadow-xl);
}

.sidebar-nen {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: rgba(15, 23, 42, 0.45);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--tr);
}

.sidebar-nen.hien {
  opacity: 1;
  pointer-events: auto;
}

.sidebar-brand {
  display: flex;
  align-items: center;
  gap: var(--k3);
  padding: var(--k4);
  border-bottom: 1px solid var(--border-light);
}

/* Logo rút gọn. Không đặt nền, không bo góc: nét vàng của dáng xe và chữ TP
   đen đứng thẳng trên nền trắng của thanh bên, đúng như bản gốc. */
.brand-mark {
  width: 54px;
  height: auto;
  flex: 0 0 54px;
  object-fit: contain;
}

.brand-text strong {
  display: block;
  font-size: 15px;
  line-height: 1.2;
}

.brand-text span {
  font-size: 11px;
  color: var(--text-3);
}

.sidebar-dong {
  margin-left: auto;
  width: var(--cham);
  height: var(--cham);
  flex: 0 0 var(--cham);
  border: 0;
  border-radius: var(--r);
  background: none;
  color: var(--text-3);
  font-size: 17px;
  cursor: pointer;
}

.sidebar-nav {
  padding: var(--k2) var(--k2) var(--k5);
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.nav-group {
  margin: var(--k4) 0 var(--k1);
  padding: 0 var(--k3);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
}

.nav-item {
  /* Mốc định vị cho .vach-cho — xem mục 41. */
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--k3);
  min-height: var(--cham);
  padding: 0 var(--k3);
  border-radius: var(--r);
  color: var(--text-2);
  font-weight: 500;
  transition: background var(--tr), color var(--tr);
}

.nav-item i {
  width: 20px;
  text-align: center;
  font-size: 14px;
  color: var(--text-3);
  transition: color var(--tr);
}

.nav-item:active {
  background: var(--border-light);
}

/* Mục đang mở: nền vàng nhạt, vạch vàng bên trái, chữ đen than. Vạch bên trái
   làm việc chính — trên nền vàng nhạt thì chữ đen vẫn tương phản 14:1, còn
   người phân biệt màu kém vẫn thấy được nhờ vạch. */
.nav-item.active {
  background: var(--vang-nhat);
  color: var(--primary);
  font-weight: 600;
  box-shadow: inset 3px 0 0 var(--vang);
}

.nav-item.active i {
  color: var(--vang-dam);
}

.nav-count {
  margin-left: auto;
  min-width: 22px;
  padding: 1px 7px;
  border-radius: var(--r-full);
  background: var(--border-light);
  color: var(--text-2);
  font-size: 11px;
  font-weight: 600;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.nav-item.active .nav-count {
  background: var(--primary);
  color: #fff;
}

/* Viền tiêu điểm bàn phím: vàng đậm, đủ tương phản trên cả nền trắng lẫn nền
   xám của trang, và là chỗ thứ hai màu thương hiệu được xuất hiện. */
:where(a, button, input, select, textarea):focus-visible {
  outline: 2px solid var(--vang-dam);
  outline-offset: 2px;
}

@media (min-width: 1024px) {
  .sidebar {
    position: sticky;
    top: 0;
    height: 100dvh;
    width: var(--sidebar-w);
    flex: 0 0 var(--sidebar-w);
    transform: none;
    box-shadow: none;
  }
  .sidebar-nen,
  .sidebar-dong {
    display: none;
  }
  .nav-item {
    min-height: 38px;
  }
  .nav-item:hover {
    background: var(--border-light);
    color: var(--text);
  }
  /* --primary-light và --vang-nhat CÙNG một giá trị #fdf7e6, nên quy tắc này
     trước đây không đổi gì cả: rê chuột lên đúng mục đang mở là không có phản
     hồi nào. Trộn đậm thêm để thấy được. */
  .nav-item.active:hover {
    background: color-mix(in srgb, var(--vang) 20%, var(--surface));
    color: var(--primary);
  }
}

/* ============================================================
   5. ĐẦU TRANG
   ============================================================ */

.page-head {
  margin-bottom: var(--k4);
}

.page-head h2 {
  display: flex;
  align-items: center;
  gap: var(--k2);
  font-size: 18px;
}

.page-head h2 i {
  color: var(--primary);
  font-size: 16px;
}

.page-head p {
  margin-top: var(--k1);
  color: var(--text-3);
  font-size: 12px;
  line-height: 1.45;
}

@media (min-width: 768px) {
  .page-head h2 {
    font-size: 20px;
  }
  .page-head p {
    margin-left: 26px;
  }
}

/* ============================================================
   6. NÚT & CHIP
   ============================================================ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--k2);
  min-height: var(--cham);
  padding: 0 var(--k4);
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--text-2);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--tr), border-color var(--tr), color var(--tr);
}

.btn:active:not(:disabled) {
  background: var(--border-light);
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}

.btn-primary {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}

.btn-primary:active:not(:disabled) {
  background: var(--primary-hover);
  transform: scale(0.98);
}

/* Nền dùng bước ĐẬM: chữ trắng trên --danger (#ef4444) chỉ đạt 3,76:1, mà đây
   là nút xác nhận XÓA — chỗ ít được phép đọc nhầm nhất. Bước này cho 6,47:1. */
.btn-danger {
  background: #ef4444;
  border-color: #ef4444;
  color: #fff;
}

.btn-danger:active:not(:disabled) {
  transform: scale(0.98);
}

.btn-sm {
  min-height: var(--cham);
  padding: 0 var(--k3);
  font-size: 13px;
}

.btn-icon {
  width: var(--cham);
  min-height: var(--cham);
  padding: 0;
  flex: 0 0 var(--cham);
}

.btn-ghost-danger {
  color: var(--text-3);
}

.btn-ghost-danger:active:not(:disabled) {
  color: var(--c-failed);
  border-color: var(--c-failed-border);
  background: var(--c-failed-bg);
}

@media (min-width: 1024px) {
  /* Trên máy tính dùng chuột, nút không cần cao 44px nữa. */
  .btn {
    min-height: 36px;
  }
  .btn-sm {
    min-height: 30px;
    font-size: 12px;
  }
  .btn-icon {
    width: 34px;
    min-height: 34px;
    flex-basis: 34px;
  }
  .btn:hover:not(:disabled) {
    border-color: var(--text-3);
    color: var(--text);
  }
  .btn-primary:hover:not(:disabled) {
    background: var(--primary-hover);
    border-color: var(--primary-hover);
    color: #fff;
  }
  .btn-ghost-danger:hover:not(:disabled) {
    color: var(--c-failed);
    border-color: var(--c-failed-border);
    background: var(--c-failed-bg);
  }
}

/* Hàng ô lọc chỉ hiện từ máy tính bảng. Dưới mức đó, năm ô select xếp dọc đẩy
   dòng dữ liệu đầu tiên xuống dưới 700px — người dùng mở màn hình Học viên ra
   mà không thấy học viên nào. Trên điện thoại chúng nằm trong tấm trượt "Lọc". */
/* Ô lọc KHÔNG bày ra thanh công cụ ở bất kỳ cỡ màn nào — tất cả nằm sau một
   nút "Lọc". Trên màn rộng, năm ô select xếp thành hai hàng cũng ăn mất chừng
   130px chiều cao, mà đó là chiều cao của bốn dòng dữ liệu. Bộ lọc là thứ dùng
   thỉnh thoảng; danh sách là thứ nhìn suốt. */
.loc-hang {
  display: none;
}

/* Số bộ lọc đang bật, gắn trên nút Lọc — không có nó thì người dùng không biết
   danh sách đang bị thu hẹp, tưởng trung tâm mất hồ sơ. */
.loc-dem {
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  margin-left: 2px;
  border-radius: var(--r-full);
  background: var(--vang);
  /* Mực trên nền vàng: lấy token chứ không viết cứng #1b1e24 — mã đó không có
     trong bảng màu nào, chỉ lệch --primary một chút và sẽ trôi mỗi lần ai đó
     chỉnh bảng màu mà quên chỗ này. */
  color: var(--primary);
  font-size: 11px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
}

.btn.btn-loc-on {
  border-color: var(--vang);
  background: var(--vang-nhat);
  color: var(--text);
}

/* Nút Lọc hiện ở mọi cỡ màn (trước chỉ hiện trên điện thoại). */
.btn.nut-loc {
  display: inline-flex;
}

.loc-tam {
  display: grid;
  gap: var(--k4);
}

.chips {
  display: flex;
  gap: var(--k2);
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: 2px;
  margin-bottom: var(--k3);
  scroll-snap-type: x proximity;
}

.chips::-webkit-scrollbar {
  display: none;
}

@media (min-width: 768px) {
  .chips {
    flex-wrap: wrap;
    overflow: visible;
  }
}

.chip {
  flex: 0 0 auto;
  scroll-snap-align: start;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  /* Đủ vùng chạm như mọi thứ bấm được khác. 36px là chuẩn của chuột, không
     phải của ngón tay. */
  min-height: var(--cham);
  padding: 0 var(--k3);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--surface);
  color: var(--text-2);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--tr), border-color var(--tr), color var(--tr);
}

/* Trên điện thoại chỉ giữ chip có số liệu. Dải chip toàn số 0 chạy ngang màn
   hình là thứ chiếm chỗ mà không nói gì — mà đó đúng là chỗ dữ liệu cần nằm.
   Từ 768px trở lên màn hình đủ rộng thì hiện đủ, vì lúc đó "0" cũng là tin:
   người dùng thấy ngay giai đoạn nào đang trống. */
.chip.rong {
  display: none;
}

@media (min-width: 768px) {
  .chip.rong {
    display: inline-flex;
  }
}

.chip b {
  font-weight: 700;
  opacity: 0.7;
  font-variant-numeric: tabular-nums;
}

.chip.on {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}

.chip:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}

/* ============================================================
   7. THẺ & BẢNG
   ============================================================ */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
}

.card-head {
  display: flex;
  align-items: center;
  gap: var(--k2);
  padding: var(--k6);
  border-bottom: 1px solid var(--border-light);
  font-weight: 600;
  font-size: 14px;
}

.card-head i {
  color: var(--primary);
}

/* Tên trong tiêu đề thẻ có thể rất dài ("Trong đợt · Sát hạch B2 đợt 1/2027").
   .card-head là flex không xuống dòng, nên phải cho phần chữ co lại và cắt
   bớt — thiếu min-width: 0 thì flex item không co dưới nội dung, chữ đẩy
   badge và nút hành động văng khỏi màn hình 375px. */
.card-head .ten-dai {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.card-body {
  padding: var(--k3);
}

.card.dang-tai,
.ds-the.dang-tai {
  opacity: 0.5;
  pointer-events: none;
}

/* ---- danh sách thẻ (điện thoại) ---- */

.ds-the {
  display: flex;
  flex-direction: column;
  gap: var(--k2);
}

.the-dong {
  display: block;
  width: 100%;
  text-align: left;
  padding: var(--k3) var(--k4);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
  color: inherit;
  font: inherit;
}

.the-dong.bam:active {
  background: var(--border-light);
}

/* 0,7 chứ không phải 0,55: ở 0,55 chữ đen trên nền trắng tụt xuống khoảng
   4,0:1 — dưới ngưỡng — mà hàng bị mờ vẫn phải đọc được TÊN và LÝ DO bị chặn,
   đó chính là thông tin người dùng cần ở đó. 0,7 vẫn thấy rõ là "chưa dùng
   được" nhưng chữ còn đọc tốt. */
.the-dong.mo {
  opacity: 0.7;
}

.the-hang1 {
  display: flex;
  align-items: flex-start;
  gap: var(--k2);
}

.the-ten {
  flex: 1;
  min-width: 0;
  font-weight: 700;
  font-size: 15px;
  line-height: 1.3;
}

.the-phu {
  margin-top: 2px;
  color: var(--text-3);
  font-size: 12px;
  font-weight: 400;
}

/* Vùng thông tin: lưới hai cột cố định, nhãn nhỏ nằm trên giá trị.
   Trước đây là flex cuộn dòng nên mỗi thẻ ngắt dòng một kiểu tùy độ dài tên
   khóa — mắt phải dò lại từ đầu ở từng thẻ. Lưới cố định thì "Còn nợ" của mọi
   học viên nằm đúng một chỗ, lướt dọc là so được ngay. */
.the-meta {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* 10px cho hàng, 16px cho cột. Viết một lệnh: trước đây là
     `gap: var(--k3) var(--k4)` rồi `row-gap: 10px` ngay dòng dưới — nửa hàng
     của lệnh trên bị ghi đè, đọc mã ra hai con số khác nhau cho cùng một chỗ. */
  gap: 10px var(--k4);
  margin: var(--k3) 0 0;
  padding-top: var(--k3);
  border-top: 1px solid var(--border-light);
  font-size: 13px;
  color: var(--text-2);
}

.the-meta > div {
  min-width: 0;
}

.the-meta dt {
  color: var(--text-3);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  margin-bottom: 2px;
}

.the-meta dd {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  /* Thông tin quan trọng phải hiện đủ: tên khóa dài thì xuống dòng, không cắt. */
  overflow-wrap: anywhere;
}

/* Ô chiếm cả hàng khi giá trị dài (tên khóa học, địa chỉ). */
.the-meta > div.rong-het {
  grid-column: 1 / -1;
}

.the-nut {
  display: flex;
  gap: var(--k2);
  margin-top: var(--k3);
  padding-top: var(--k3);
  border-top: 1px solid var(--border-light);
}

/* Việc chính chiếm chỗ, nút biểu tượng giữ đúng một vùng chạm. Trước đây cả
   hai cùng flex:1 nên nút Xóa là một ô trống bằng nửa thẻ, chỉ có cái thùng
   rác ở giữa — vừa xấu vừa dễ bấm nhầm. */
.the-nut .btn {
  flex: 1;
}

.the-nut .btn.btn-icon {
  flex: 0 0 var(--cham);
}

/* ---- bảng (từ 768px) ---- */

.ds-bang {
  display: none;
}

@media (min-width: 768px) {
  .ds-the {
    display: none;
  }
  .ds-bang {
    display: block;
  }
}

.table-wrap {
  overflow-x: auto;
  /* Chiều cao do .vung-cuon quyết định (mục 33) — ở đây chỉ lo cuộn NGANG. */
  -webkit-overflow-scrolling: touch;
}

/* `position: sticky` trên <th> chỉ ăn khi khung cuộn có chiều cao thật.
   Không có max-height thì scrollHeight == clientHeight và hàng tiêu đề
   không bao giờ dính — quy tắc sticky bên dưới sẽ thành mã chết. */
/* Chiều cao do .khung-ds > .vung-cuon quyết định (mục 33). Ở đây chỉ bật cuộn
   cả hai chiều để hàng tiêu đề `position: sticky` có khung cuộn thật mà bám. */
@media (min-width: 768px) {
  .table-wrap {
    overflow: auto;
  }
}

table.tbl {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface);
  font-size: 13px;
  /* Chữ số cùng bề ngang trên TOÀN bảng. Bảng dữ liệu nào cũng đầy số — ngày,
     căn cước, điện thoại, tiền — mà chữ số tỉ lệ thì mỗi dòng lệch vài pixel,
     cột số nhìn như răng cưa và không so dọc được. */
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

/*
 * Bề rộng cột ĐỨNG YÊN, không co giãn theo nội dung trang đang xem.
 *
 * Với table-layout mặc định (auto), `width` khai trên cột chỉ là gợi ý: trình
 * duyệt vẫn ép cột theo nội dung, nên trang 1 cột tên rộng 149px mà trang 2 lại
 * 151px — cả bảng dịch sang phải hai pixel, và với tên thật dài ngắn khác nhau
 * thì độ dịch còn lớn hơn nhiều. Mỗi lần sang trang là mắt phải căn lại cột.
 *
 * `width: max-content` để bảng lấy đúng tổng bề rộng đã khai rồi cuộn ngang
 * trong khung, `min-width: 100%` để khi tổng ấy nhỏ hơn khung thì bảng vẫn phủ
 * kín chứ không co về một cục bên trái.
 *
 * CHỈ bật cho bảng đã khai `rong` cho MỌI cột (xem cotCoDinh trong DanhSach).
 */
table.tbl.tbl-co-dinh {
  table-layout: fixed;
  width: max-content;
  min-width: 100%;
}

table.tbl th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--border-light);
  color: var(--text-2);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-align: left;
  padding: 12px var(--k4);
  white-space: nowrap;
  border-bottom: 1px solid var(--border);
}

table.tbl td {
  /* Hàng 52–60px theo đặc tả UX — dễ quét ngang. */
  padding: 14px var(--k4);
  height: var(--hang-bang);
  border-bottom: 1px solid var(--border-light);
  vertical-align: middle;
  background: #ffffff;
  color: var(--text);
  white-space: nowrap;
}

table.tbl td.xuong-dong {
  white-space: normal;
}

/* Số trong bảng dùng CHUNG một kiểu: chữ thân bài, chữ số đều bề ngang.
   Trước đây số điện thoại dùng phông mono còn mọi thứ khác dùng phông thân
   bài, nên trong cùng một hàng có hai kiểu chữ đá nhau. Phông mono giữ lại
   cho Ô NHẬP, nơi người dùng cần phân biệt 0 với O lúc gõ. */
table.tbl .ma,
table.tbl .num,
table.tbl td.num {
  font-family: var(--font);
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  letter-spacing: 0;
}

table.tbl tbody tr:last-child td {
  border-bottom: 0;
}

/*
 * SỌC XEN KẼ — thứ giữ mắt ở lại đúng một dòng.
 *
 * Bảng học viên có mười hai cột, rộng hơn khung nên phải cuộn ngang. Cuộn tới
 * cột "Còn nợ" rồi thì cột tên đã trôi khỏi tầm mắt (dù có ghim), và chỉ cần
 * một dòng kẻ mảnh giữa các hàng thì mắt rất dễ nhảy nhầm sang hàng bên. Nền
 * xen kẽ nhạt biến mỗi hàng thành một dải liền, đi ngang bao xa cũng không lạc.
 *
 * Phải tô lên chính Ô chứ không phải lên HÀNG: ô ghim trái có nền riêng
 * (var(--surface)) để che nội dung trượt qua dưới nó, tô lên hàng thì ô ghim
 * vẫn trắng và sọc bị đứt đúng chỗ quan trọng nhất.
 */
table.tbl tbody tr:nth-child(even) td,
table.tbl tbody tr:nth-child(even) td.ghim {
  background: #ffffff;
}

@media (hover: hover) and (pointer: fine) {
  table.tbl tbody tr:hover td,
  table.tbl tbody tr:hover td.ghim {
    background: #f0fdf4; /* đặc tả hover hàng */
  }
}

table.tbl tr.locked {
  /* Xem chú thích ở .the-dong.mo — cùng một lý do. */
  opacity: 0.7;
}

/* Cột STT luôn đứng trước cột ghim, nên PHẢI ghim theo — bằng không lúc cuộn
   ngang, cột ghim trượt lên đè chồng số thứ tự. Ghim cả hai và đẩy cột ghim
   sang phải đúng bề rộng cột STT (56px, khai ở từng màn). */
table.tbl-ghim th:first-child,
table.tbl-ghim td:first-child {
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--surface);
}

table.tbl-ghim th:first-child {
  z-index: 3;
  background: var(--border-light);
}

table.tbl-ghim th.ghim,
table.tbl-ghim td.ghim {
  position: sticky;
  z-index: 2;
  background: var(--surface);
  box-shadow: 1px 0 0 var(--border);
}

/*
 * Chỉ đẩy sang phải KHI CÓ cột STT đứng trước.
 *
 * Hai bảng Cài đặt → Tài khoản và Cài đặt → Nhật ký ghim ngay cột đầu tiên,
 * không có cột STT nào. Trước đây chúng vẫn nhận left: 56px (quy tắc .ghim
 * cùng độ ưu tiên với quy tắc :first-child nhưng viết sau nên thắng), thành ra
 * lúc cuộn ngang cột ghim nổi lơ lửng cách mép trái 56px và các cột phía sau
 * trượt qua trượt lại trong dải trống đó. Đo tại chỗ: left = 56px trên cả hai.
 */
table.tbl-ghim th.ghim:not(:first-child),
table.tbl-ghim td.ghim:not(:first-child) {
  left: 56px;
}

table.tbl-ghim th.ghim:first-child,
table.tbl-ghim td.ghim:first-child {
  left: 0;
}

table.tbl-ghim th.ghim {
  z-index: 3;
  background: var(--border-light);
}

@media (hover: hover) and (pointer: fine) {
  table.tbl-ghim tbody tr:hover td.ghim {
    background: var(--primary-light);
  }
}

.hang-thao-tac {
  display: flex;
  gap: var(--k1);
}

/* Học viên: cột thao tác đứng đầu — ghim # + STT + Họ tên khi cuộn ngang */
table.tbl-ghim:has(td[data-cot="__thaotac"]:first-child) th:first-child,
table.tbl-ghim:has(td[data-cot="__thaotac"]:first-child) td:first-child {
  position: sticky;
  left: 0;
  z-index: 4;
  background: var(--surface);
  box-shadow: 1px 0 0 var(--border);
}

table.tbl-ghim:has(td[data-cot="__thaotac"]:first-child) th:first-child {
  z-index: 5;
  background: var(--border-light);
}

table.tbl-ghim:has(td[data-cot="__thaotac"]:first-child) th:nth-child(2),
table.tbl-ghim:has(td[data-cot="__thaotac"]:first-child) td:nth-child(2) {
  position: sticky;
  left: 112px;
  z-index: 3;
  background: var(--surface);
}

table.tbl-ghim:has(td[data-cot="__thaotac"]:first-child) th:nth-child(2) {
  z-index: 4;
  background: var(--border-light);
}

table.tbl-ghim:has(td[data-cot="__thaotac"]:first-child) th.ghim:nth-child(3),
table.tbl-ghim:has(td[data-cot="__thaotac"]:first-child) td.ghim:nth-child(3) {
  left: 164px;
}

@media (hover: hover) and (pointer: fine) {
  table.tbl-ghim:has(td[data-cot="__thaotac"]:first-child) tbody tr:hover td:nth-child(1),
  table.tbl-ghim:has(td[data-cot="__thaotac"]:first-child) tbody tr:hover td:nth-child(2),
  table.tbl-ghim:has(td[data-cot="__thaotac"]:first-child) tbody tr:hover td.ghim:nth-child(3) {
    background: var(--primary-light);
  }
}

/* ============================================================
   8. CHỮ SỐ & NHÃN
   ============================================================ */

/* Mã định danh (biển số, CCCD, số GPLX) đặt bằng chữ đều nét — nhân
   viên phải đọc từng chữ số qua điện thoại, cần phân biệt rõ 0/O, 1/l. */
.ma {
  font-family: var(--font-so);
  font-size: 0.92em;
  letter-spacing: -0.01em;
}

/* Nhưng KHÔNG thu nhỏ trên ô nhập: iOS tự phóng to cả trang mỗi khi chạm vào
   ô có cỡ chữ dưới 16px, và trang đã phóng thì không tự thu lại. Ô nhập biển
   số / CCCD vẫn dùng .ma để lấy kiểu chữ đều nét, chỉ giữ nguyên cỡ. */
input.ma,
select.ma,
textarea.ma {
  font-size: var(--co-chu-nhap);
}

.num,
.tien-no,
.tien-du,
.bar-label span,
.pager-info b,
.stat b {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

.num {
  text-align: right;
}

/* Dùng --c-failed (bước dành cho chữ) chứ không phải --danger: --danger
   (#ef4444) là màu để TÔ nút, làm chữ trên nền trắng chỉ đạt 3,76:1. */
.tien-no {
  color: var(--c-failed);
  font-weight: 600;
}

/* Tương tự: --success (#10b981) làm chữ chỉ đạt 2,54:1 — gần như đọc không
   ra. --c-passed đạt 5,48:1. */
.tien-du {
  color: var(--c-passed);
}

.phu {
  color: var(--text-3);
  font-size: 12px;
}

/* Chữ báo lỗi trong dòng — khác .tien-no (tiền) và .expired-date (ngày). */
.chu-loi {
  color: var(--c-failed);
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px var(--k2);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.s-cho_ksk   { color: var(--c-ksk);      background: var(--c-ksk-bg);      border-color: var(--c-ksk-border); }
.s-da_ksk    { color: var(--c-ksk-done); background: var(--c-ksk-done-bg); border-color: var(--c-ksk-done-border); }
.s-nop_ho_so { color: var(--c-docs);     background: var(--c-docs-bg);     border-color: var(--c-docs-border); }
.s-dang_hoc  { color: var(--c-studying); background: var(--c-studying-bg); border-color: var(--c-studying-border); }
.s-dang_thi  { color: var(--c-exam);     background: var(--c-exam-bg);     border-color: var(--c-exam-border); }
.s-da_dau    { color: var(--c-passed);   background: var(--c-passed-bg);   border-color: var(--c-passed-border); }
.s-thi_lai   { color: var(--c-failed);   background: var(--c-failed-bg);   border-color: var(--c-failed-border); }
.s-nghi_hoc  { color: var(--c-dropout);  background: var(--c-dropout-bg);  border-color: var(--c-dropout-border); }
.s-dropout   { color: var(--c-dropout);  background: var(--c-dropout-bg);  border-color: var(--c-dropout-border); }

/*
 * TRẠNG THÁI HỒ SƠ GPLX — bộ màu RIÊNG, không mượn bộ `s-*` ở trên.
 *
 * Hai thang trạng thái này nói về hai thứ khác nhau: `s-*` là đường đi của một
 * HỌC VIÊN (chờ khám → đang học → đã đậu), `hs-*` là đường đi của một TỜ HỒ SƠ
 * (mới nhận → đã nộp → đang xử lý → đã cấp). Dùng chung một màu cho "Đã đậu" và
 * "Đã cấp" là dạy người dùng một liên tưởng sai — họ sẽ đọc màu xanh ở trang
 * GPLX thành "người này đã thi đậu", trong khi phần lớn người ở trang ấy chưa
 * từng học ở trung tâm.
 *
 * Năm bước lấy từ đúng bảng màu đã đo tương phản ở :root (globals.css), mỗi
 * bước một sắc để phân biệt được cả với mắt mù màu; chữ trên huy hiệu luôn là
 * màu chữ đặt trên nền phấn cùng dòng, đạt >= 4,5:1.
 */
.hs-moi        { color: var(--c-ksk);      background: var(--c-ksk-bg);      border-color: var(--c-ksk-border); }
.hs-da_nop     { color: var(--c-docs);     background: var(--c-docs-bg);     border-color: var(--c-docs-border); }
.hs-dang_xu_ly { color: var(--c-exam);     background: var(--c-exam-bg);     border-color: var(--c-exam-border); }
.hs-da_cap     { color: var(--c-passed);   background: var(--c-passed-bg);   border-color: var(--c-passed-border); }
.hs-tu_choi    { color: var(--c-failed);   background: var(--c-failed-bg);   border-color: var(--c-failed-border); }

/*
 * NGUỒN THU — hai cái sổ của màn Tài chính.
 *
 * Xanh dương cho học viên (cùng sắc với "đang học" trong bộ trạng thái học
 * viên), vàng kim thương hiệu cho hồ sơ GPLX. Hai sắc cách xa nhau đủ để phân
 * biệt được cả với mắt mù màu, mà chữ vẫn nằm ngay trong huy hiệu nên không ai
 * phải đọc màu để biết đó là sổ nào.
 *
 * KHÔNG mượn bộ hs-* ở trên: hs-* nói về đường đi của một tờ hồ sơ (mới → đã
 * nộp → đã cấp), còn đây nói về NGUỒN TIỀN. Trùng màu là trùng nghĩa.
 */
.ng-hv   { color: var(--c-studying); background: var(--c-studying-bg); border-color: var(--c-studying-border); }
.ng-gplx { color: var(--vang-dam);   background: var(--vang-nhat);     border-color: var(--vang); }

/*
 * Hạn dùng sắp hết / đã hết là thứ người dùng mở màn hình lên để tìm, nên nó
 * phải ĐỌC ĐƯỢC trước đã. Trước đây tô bằng --warning (#f59e0b) và --danger
 * (#ef4444) — hai bước dành cho MẢNG TÔ, làm chữ trên nền trắng chỉ đạt
 * 2,15:1 và 3,76:1. Nay dùng bước chữ: 4,84:1 và 5,89:1.
 */
.warn-date {
  color: var(--c-ksk);
  font-weight: 600;
}

.expired-date {
  color: var(--c-failed);
  font-weight: 700;
}

/* ============================================================
   9. Ô SỐ LIỆU
   ============================================================ */

/* Mặc định hai cột: các ô đếm ("3 học viên", "0 chờ KSK") ngắn, xếp hai cột
   thì nhìn hết một lượt, xếp một cột thành chín hàng phải cuộn mãi. */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--k2);
  margin-bottom: var(--k4);
}

@media (min-width: 480px) {
  .stat-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* Biến thể cho ô chứa SỐ TIỀN: một cột trên điện thoại. Hai cột thì mỗi ô chỉ
   còn ~100px cho con số, mà "37.200.000 đ" cần ~115px — hoặc bị xén (đọc ra
   sai gấp trăm lần), hoặc bị ngắt thành "37.200.00 / 0 đ" (sai gấp mười).
   Chỉ những khối thật sự có tiền mới trả cái giá chiều cao này. */
.stat-grid.tien {
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 480px) {
  .stat-grid.tien {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 768px) {
  .stat-grid.tien {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 768px) {
  .stat-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--k3);
  }
}

.stat {
  display: flex;
  align-items: center;
  gap: var(--k2);
  padding: var(--k3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  min-width: 0;
}

.stat .ico {
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  border-radius: var(--r);
  display: grid;
  place-items: center;
  font-size: 14px;
}

.stat > span:last-child {
  min-width: 0;
}

.stat b {
  display: block;
  font-size: 20px;
  line-height: 1.15;
  letter-spacing: -0.02em;
}

/* Chỉ NHÃN mới được xén, con số thì không. Trước đây quy tắc này áp cho cả
   span bọc ngoài (chứa <b> số tiền), nên "12.500.000 đ" bị cắt thành
   "12.500…" — đọc ra sai gấp trăm lần mà không có dấu hiệu gì báo là đã cắt. */
/* Con TRỰC TIẾP, không phải hậu duệ: bên trong ô nhãn còn hai bản chữ (gọn /
   đầy đủ) cũng là span, mà quy tắc này vốn chỉ dành cho chính ô nhãn. Viết
   `span span` thì nó đè luôn display của hai bản ấy và cả hai cùng hiện. */
.stat > span > span {
  font-size: 12px;
  color: var(--text-3);
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.stat > span:not(.ico) {
  min-width: 0;
}

.stat b {
  /* KHÔNG ngắt dòng giữa con số và KHÔNG xén: một ô rộng 1fr trên điện thoại
     thì "37.200.000 đ" luôn vừa, nên chỉ cần cấm cả hai kiểu làm hỏng. */
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* ============================================================
   10. TIẾN ĐỘ
   ------------------------------------------------------------
   Hai vạch tách rời (km và giờ) là ngôn ngữ chung cho mọi loại tiến
   độ — gộp một vạch sẽ giấu mất chuyện học viên đủ km nhưng thiếu giờ.
   ============================================================ */

.bar {
  height: 6px;
  border-radius: var(--r-full);
  background: var(--border-light);
  overflow: hidden;
}

.bar > i {
  display: block;
  height: 100%;
  background: var(--primary);
  border-radius: var(--r-full);
  transition: width var(--tr);
}

.bar.done > i {
  background: var(--success);
}

.bar-label {
  display: flex;
  justify-content: space-between;
  gap: var(--k2);
  font-size: 11px;
  color: var(--text-3);
  margin-bottom: 3px;
}

.bar-nhom {
  display: grid;
  gap: var(--k2);
  min-width: 130px;
}

/* ============================================================
   11. THANH LỌC
   ============================================================ */

/* Thanh công cụ: lề dưới mỏng, nó chỉ là hàng điều khiển chứ không phải nội dung. */
.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--k2);
  margin-bottom: var(--k3);
}

.o-tim {
  position: relative;
  display: flex;
  align-items: center;
  flex: 1 1 100%;
  order: -1;
}

.o-tim > i {
  position: absolute;
  left: var(--k3);
  color: var(--text-3);
  font-size: 13px;
  pointer-events: none;
}

.o-tim .input {
  padding-left: 38px;
}

.o-tim kbd {
  display: none;
}

@media (min-width: 768px) {
  .o-tim {
    flex: 0 1 280px;
    order: 0;
  }
  .o-tim kbd {
    display: block;
    position: absolute;
    right: var(--k2);
    padding: 1px 6px;
    border: 1px solid var(--border);
    border-radius: 5px;
    background: var(--border-light);
    color: var(--text-3);
    font-family: var(--font-so);
    font-size: 11px;
    pointer-events: none;
  }
  .o-tim:focus-within kbd {
    opacity: 0;
  }
  .o-tim .input {
    padding-right: 32px;
  }
}

/* Máy hẹp (≤ 414px) cho ô lọc chiếm trọn hàng: nhãn tiếng Việt như
   "Mọi tình trạng phí" hay "Còn nợ học phí" không đủ chỗ trong nửa hàng và
   bị cắt cụt. Từ 415px trở lên mới xếp hai cột. */
.select-loc {
  flex: 1 1 100%;
  min-width: 0;
  text-overflow: ellipsis;
}

@media (min-width: 415px) {
  .select-loc {
    flex: 1 1 calc(50% - var(--k2) / 2);
  }
}

@media (min-width: 768px) {
  .select-loc {
    flex: 0 1 auto;
    min-width: 160px;
    max-width: 230px;
  }
}

.dang-tai-icon {
  align-self: center;
  color: var(--text-3);
}

/* Cụm nút hành động: trên điện thoại xuống hàng riêng, dàn đều. */
.toolbar-nut {
  display: flex;
  gap: var(--k2);
  flex: 1 1 100%;
}

.toolbar-nut .btn {
  flex: 1;
}

@media (min-width: 768px) {
  .toolbar-nut {
    flex: 0 0 auto;
    margin-left: auto;
  }
  .toolbar-nut .btn {
    flex: 0 0 auto;
  }
  /* `margin-left: auto` sinh ra để đẩy cụm nút về cuối THANH CÔNG CỤ. Khi hàng
     nút nằm trong một ô biểu mẫu (màn Thông báo) thì nó lại đẩy hai nút ra sát
     mép phải thẻ, rời khỏi cột nội dung. */
  .field > .toolbar-nut {
    margin-left: 0;
  }
}

/* ============================================================
   12. PHÂN TRANG
   ============================================================ */

/* Phân trang nằm TRÊN danh sách nên lề là ở dưới, không phải ở trên. */
.pager {
  display: flex;
  align-items: center;
  gap: var(--k2);
  flex-wrap: wrap;
  margin: 0 0 var(--k2);
  flex: 0 0 auto;
}

.pager-co {
  display: inline-flex;
  align-items: center;
  gap: var(--k2);
  flex-wrap: wrap;
  margin: 0 0 var(--k2);
  align-self: flex-end;
}
.pager-co-nhan {
  font-size: 12px;
  color: var(--text-2);
}

/* Một trang: chỉ còn dòng đếm, cho nó nằm sát trái như một nhãn phụ. */
.pager.mot-trang .pager-info {
  flex: 1 1 auto;
  order: 0;
  text-align: left;
}

.pager-info {
  color: var(--text-2);
  font-size: 12px;
  flex: 1 1 100%;
  order: 1;
  text-align: center;
}

/* Từ 480px đã đủ chỗ cho dòng đếm và dãy nút nằm chung một hàng. */
@media (min-width: 480px) {
  .pager-info {
    flex: 1 1 auto;
    order: 0;
    text-align: left;
  }

  .pager-nut {
    flex: 0 0 auto;
    margin-left: auto;
  }
}

.pager-nut {
  display: flex;
  /* Lưới an toàn: dù có thêm nút gì thì cũng xuống dòng chứ không tràn ngang. */
  flex-wrap: wrap;
  gap: var(--k1);
  flex: 1 1 100%;
  justify-content: center;
}

/* Dãy số trang: giấu trên điện thoại, chỉ còn ‹ Trang trước — Trang sau ›.
   `display: contents` để các nút số vẫn là con trực tiếp của .pager-nut,
   khỏi tạo thêm một lớp flex lồng nhau. */
.pager-so {
  display: none;
}

@media (min-width: 768px) {
  .pager-so {
    display: contents;
  }
}

/*
 * DÒNG ĐẾM ĐỨNG MỘT MÌNH (CrudTable) KHÔNG ĐƯỢC GIÃN.
 *
 * `.pager-info` vốn sinh ra để nằm trong `.pager` — một hàng flex NGANG, ở đó
 * `flex: 1 1 100%` nghĩa là "chiếm trọn hàng rồi đẩy dãy nút xuống dòng dưới".
 * Nhưng CrudTable dùng lại nó như một dòng chữ đơn độc, con trực tiếp của
 * `.content` — mà `.content` là cột flex DỌC. Ở đó `flex-basis: 100%` biến
 * thành "cao bằng cả khung", nên dòng chữ "14 bản ghi" nuốt hết phần trống và
 * đẩy danh sách co lại đúng chiều cao tối thiểu của nó.
 *
 * Đo thật trên màn 390×844 ở trang Cấp đổi GPLX: dòng đếm cao 146px, danh sách
 * bị ép còn 220px và chỉ hiện được hai thẻ rưỡi. Sáu trang dùng CrudTable đều
 * dính, không riêng trang này.
 */
.content > .pager-info {
  flex: 0 0 auto;
}

.pager-cach {
  align-self: center;
  padding: 0 3px;
  color: var(--text-3);
}

@media (min-width: 768px) {
  .pager-info {
    flex: 0 0 auto;
    order: 0;
    text-align: left;
  }
  .pager-nut {
    flex: 0 0 auto;
    margin-left: auto;
  }
}

/* ============================================================
   13. BIỂU MẪU
   ============================================================ */

.field {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 0;
}

.field label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-2);
}

@media (min-width: 1024px) {
  .field label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
  }
}

.field label .req {
  color: var(--c-failed);
}

.input,
.select,
.textarea {
  width: 100%;
  min-height: var(--cham);
  padding: var(--k2) var(--k3);
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--text);
  transition: border-color var(--tr), box-shadow var(--tr);
}

.textarea {
  min-height: 76px;
  padding: var(--k3);
  line-height: 1.5;
  resize: vertical;
}

.select {
  /* Bỏ giao diện mặc định để mũi tên không lệch giữa iOS và Android. */
  appearance: none;
  /* Màu mũi tên phải viết cứng vì nằm trong data-URI, không nhận var(). Nó
     là bản sao tay của --text-3 — đổi token thì phải đổi cả đây, nếu không
     mũi tên nhạt hơn mọi chữ phụ khác trên cùng màn hình. */
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%235b6b7f' stroke-width='1.6' d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--k3) center;
  background-size: 11px;
  padding-right: var(--k6);
}

.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--primary);
  border-width: 2px;
  padding: calc(var(--k2) - 1px) calc(var(--k3) - 1px);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 22%, transparent);
}

.textarea:focus {
  padding: calc(var(--k3) - 1px);
}

.input.is-loi,
.input:user-invalid,
.select.is-loi,
.textarea.is-loi {
  border-color: #ef4444;
  border-width: 2px;
}

.field .loi-o {
  margin: 0;
  font-size: 12.5px;
  color: #ef4444;
  font-weight: 500;
}

.input:disabled,
.select:disabled,
.textarea:disabled {
  background: var(--border-light);
  color: var(--text-3);
  cursor: not-allowed;
}

.grid-2 {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--k3);
}

@media (min-width: 640px) {
  .grid-2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--k4);
  }
}

.rong-het {
  grid-column: 1 / -1;
}

fieldset.nhom {
  border: 0;
  border-top: 1px solid var(--border-light);
  margin: 0 0 var(--k5);
  padding: var(--k4) 0 0;
  min-width: 0;
}

fieldset.nhom:first-of-type {
  border-top: 0;
  padding-top: 0;
}

fieldset.nhom:last-of-type {
  margin-bottom: 0;
}

fieldset.nhom > legend {
  padding: 0 var(--k2) 0 0;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-3);
}

.goi-y {
  color: var(--text-3);
  font-size: 12px;
  line-height: 1.45;
}

.o-chon {
  display: flex;
  align-items: center;
  gap: var(--k2);
  min-height: var(--cham);
  text-transform: none;
  font-size: 14px;
  font-weight: 500;
  color: var(--text);
  cursor: pointer;
}

.o-chon input[type='checkbox'] {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  accent-color: var(--primary);
}

/* Ô chọn trong bảng cần vùng chạm rộng hơn chính nó. */
.o-chon-bang {
  display: grid;
  place-items: center;
  width: var(--cham);
  height: var(--cham);
  margin: calc(var(--k3) * -1) 0;
  cursor: pointer;
}

.o-chon-bang input {
  width: 18px;
  height: 18px;
  accent-color: var(--primary);
}

/* Lựa chọn lớn (loại xe, kênh gửi) — quyết định chính của biểu mẫu. */
.chon-lon {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--k2);
}

.the-chon {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--k2);
  min-height: 56px;
  padding: var(--k3);
  border: 1.5px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--text-2);
  font-weight: 600;
  cursor: pointer;
  transition: border-color var(--tr), background var(--tr), color var(--tr);
}

.the-chon i {
  font-size: 17px;
}

.the-chon.on {
  border-color: var(--primary);
  background: var(--primary-light);
  color: var(--primary);
}

.the-chon:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}

/* Chú thích nhỏ trong thẻ chọn ("Chưa cấu hình"). Xuống dòng riêng dưới tên
   kênh, nên thẻ phải xếp dọc khi có nó — dùng flex-wrap thay vì đổi hẳn
   flex-direction để thẻ KHÔNG có chú thích vẫn nằm ngang như cũ. */
.the-chon {
  flex-wrap: wrap;
}

.the-chon-phu {
  flex: 1 1 100%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  color: var(--c-ksk);
  font-size: 11.5px;
  font-weight: 600;
}

.the-chon-phu i {
  font-size: 11.5px;
}

@media (min-width: 640px) {
  .chon-lon {
    max-width: 400px;
  }
}

/* ------------------------------------------------ xem trước tin nhắn */

/*
 * Bong bóng tin nhắn: cố ý trông giống màn hình điện thoại chứ không giống một
 * ô nhập nữa. Người soạn phải đọc nó bằng con mắt của người NHẬN — mà một khối
 * chữ nằm trong khung xám bo tròn thì tự khắc được đọc như vậy, còn cùng chữ
 * ấy đặt trong ô viền vuông lại được đọc như một trường dữ liệu.
 */
.tin-bong-bong {
  padding: var(--k3);
  border-radius: var(--r-lg);
  border-top-left-radius: var(--k1);
  background: var(--primary-light);
  border: 1px solid var(--vang);
  font-size: 13.5px;
  line-height: 1.55;
}

.tin-bong-bong strong {
  display: block;
  margin-bottom: var(--k1);
  font-size: 13.5px;
}

.tin-bong-bong p {
  margin: 0;
  /* Giữ đúng chỗ xuống dòng người soạn đã gõ — tin nhắn thật cũng xuống y vậy. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.xt-so {
  display: flex;
  flex-wrap: wrap;
  gap: var(--k1) var(--k4);
  margin: var(--k2) 0 0;
  font-size: 12px;
  color: var(--text-3);
}

.xt-so b {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* ============================================================
   14. HỘP THOẠI
   ------------------------------------------------------------
   Điện thoại: tấm trượt từ đáy, cao tối đa 92% màn hình, nút chính
   ghim dưới cùng. Máy tính: hộp giữa màn hình.
   ============================================================ */

.overlay {
  position: fixed;
  inset: 0;
  bottom: var(--neo-ban-phim, 0px);
  z-index: 70;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: color-mix(in srgb, #0f172a 42%, transparent);
}

.tam-truot {
  width: 100%;
  max-height: calc(92dvh - var(--neo-ban-phim, 0px));
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  box-shadow: var(--shadow-2);
  animation: truot-len 0.2s ease-out;
  border: 1px solid var(--border);
  border-bottom: 0;
}

@keyframes truot-len {
  from {
    transform: translateY(16px);
    opacity: 0.5;
  }
}

.tam-tay-cam {
  width: 36px;
  height: 4px;
  margin: 8px auto 0;
  border-radius: var(--r-full);
  background: var(--border);
  flex: 0 0 auto;
}

.tam-dau {
  display: flex;
  align-items: center;
  gap: var(--k2);
  padding: 10px 14px;
  border-bottom: 1px solid var(--border-light);
  flex: 0 0 auto;
}

.tam-dau h2 {
  flex: 1;
  min-width: 0;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.3;
}

.tam-than {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 12px 14px;
  display: grid;
  gap: 10px;
  align-content: start;
}

.tam-chan {
  display: flex;
  gap: 8px;
  padding: 10px 14px;
  padding-bottom: calc(10px + var(--an-toan-duoi));
  border-top: 1px solid var(--border-light);
  background: var(--surface);
  flex: 0 0 auto;
}

.tam-chan .btn {
  flex: 1;
}

.tam-chan .btn-primary {
  flex: 1.6;
}

/* Form trong popup — gọn, một cột thông tin rõ */
.overlay .hop-tom {
  margin: 0;
  font-size: 12.5px;
}

.overlay .hop-alert {
  margin: 0;
}

.overlay .hop-luoi {
  gap: 10px;
}

.overlay .hop-field {
  margin: 0;
}

.overlay .nhan-field {
  display: block;
  margin-bottom: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-2);
}

.chon-nhanh-tien {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.pct-check {
  flex: 1 1 0;
  min-width: 96px;
  position: relative;
  cursor: pointer;
}

.pct-check input {
  position: absolute;
  opacity: 0;
  inset: 0;
  margin: 0;
  cursor: pointer;
}

.pct-check span {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--text-2);
  font-size: 13px;
  font-weight: 650;
  transition: background var(--tr-fast), border-color var(--tr-fast), color var(--tr-fast);
}

.pct-check input:focus-visible + span {
  box-shadow: var(--ring);
}

.pct-check input:checked + span {
  border-color: var(--primary);
  background: var(--primary-light);
  color: var(--primary);
}

.overlay .field > label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-2);
}

.overlay .goi-y {
  font-size: 11.5px;
}

.overlay .o-tien {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  letter-spacing: 0.01em;
}

@media (min-width: 640px) {
  .overlay {
    align-items: center;
    padding: var(--k4);
  }
  .tam-truot {
    max-width: var(--tam-rong, 640px);
    max-height: 88dvh;
    border-radius: var(--r-lg);
    border-bottom: 1px solid var(--border);
    animation: hien-ra 0.16s ease-out;
  }
  @keyframes hien-ra {
    from {
      opacity: 0;
      transform: scale(0.985);
    }
  }
  .tam-tay-cam {
    display: none;
  }
  .tam-dau {
    padding: 12px 16px;
  }
  .tam-chan {
    justify-content: flex-end;
    padding: 10px 16px;
  }
  .tam-chan .btn {
    flex: 0 0 auto;
    min-width: 96px;
  }
  .tam-chan .btn-primary {
    flex: 0 0 auto;
    min-width: 120px;
  }
}

/* ---- hộp xác nhận ---- */

.confirm-box {
  width: 100%;
  max-width: 440px;
  margin: var(--k4);
  padding: var(--k5);
  background: var(--surface);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-xl);
  align-self: center;
}

.confirm-box p {
  margin-bottom: var(--k5);
  line-height: 1.5;
}

.confirm-actions {
  display: flex;
  gap: var(--k2);
}

.confirm-actions .btn {
  flex: 1;
}

@media (min-width: 640px) {
  .confirm-actions {
    justify-content: flex-end;
  }
  .confirm-actions .btn {
    flex: 0 0 auto;
  }
}

/* ============================================================
   15. COMBOBOX
   ============================================================ */

.combo {
  position: relative;
}

.combo-ok {
  position: absolute;
  right: var(--k3);
  top: 50%;
  transform: translateY(-50%);
  color: var(--c-passed);
  font-size: 13px;
  pointer-events: none;
}

/* Danh sách gợi ý render qua portal ra <body> nên không bị vùng cuộn của hộp
   thoại cắt. Trên điện thoại nó là tấm chọn trượt từ đáy — dòng "Thêm …" luôn
   chạm tới được, kể cả khi bàn phím ảo đang bật. */
.combo-list {
  position: fixed;
  z-index: 90;
  left: 0;
  right: 0;
  /* --neo-ban-phim là chiều cao phần màn hình đang bị bàn phím ảo che, đo
     bằng visualViewport trong Combobox.tsx. */
  bottom: var(--neo-ban-phim, 0px);
  max-height: 60dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
  margin: 0;
  padding: var(--k2) var(--k2) calc(var(--k2) + var(--an-toan-duoi));
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  box-shadow: var(--shadow-xl);
  animation: truot-len 0.16s ease-out;
}

@media (min-width: 640px) {
  .combo-list {
    top: var(--neo-top, 0);
    left: var(--neo-left, 0);
    right: auto;
    bottom: auto;
    width: var(--neo-rong, 320px);
    max-height: 44dvh;
    padding: var(--k1);
    border-radius: var(--r);
    box-shadow: var(--shadow-lg);
    animation: none;
  }
}

.combo-list li {
  display: flex;
  align-items: center;
  gap: var(--k2);
  /* Trên điện thoại danh sách này là tấm trượt từ đáy — mỗi dòng là một hàng
     chạm thật, phải đủ 44px như mọi hàng chạm khác. Trước đây khai cứng 42px. */
  min-height: var(--cham);
  padding: var(--k2) var(--k3);
  border-radius: 7px;
  font-size: 14px;
  cursor: pointer;
}

.combo-list li.on {
  background: var(--primary-light);
  color: var(--primary);
}

.combo-list li i {
  font-size: 11px;
  color: var(--text-3);
}

.combo-list li.on i {
  color: var(--primary);
}

.combo-them {
  border-top: 1px solid var(--border-light);
  margin-top: var(--k1);
  font-weight: 600;
  color: var(--primary);
}

.combo-trong {
  color: var(--text-3);
  cursor: default;
}

/* ============================================================
   16. THÔNG BÁO NỔI
   ------------------------------------------------------------
   Trên điện thoại nổi phía TRÊN thanh tab để không che nút.
   ============================================================ */

.toast-stack {
  position: fixed;
  left: auto;
  right: var(--k4);
  top: calc(var(--topbar-h) + var(--an-toan-tren) + var(--k4));
  bottom: auto;
  width: min(360px, calc(100vw - 2 * var(--k4)));
  z-index: 80;
  display: flex;
  flex-direction: column;
  gap: var(--k2);
  pointer-events: none;
}

@media (max-width: 1023px) {
  .toast-stack {
    left: var(--k3);
    right: var(--k3);
    top: auto;
    bottom: calc(var(--tabbar-h) + var(--an-toan-duoi) + var(--k3));
    width: auto;
  }
}

.toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: var(--k2);
  padding: var(--k3);
  border: 1px solid var(--border);
  border-left-width: 3px;
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  font-size: 13px;
  animation: toast-vao 0.16s ease-out;
}

.toast span {
  flex: 1;
}

.toast button {
  position: relative;
  border: 0;
  background: none;
  color: var(--text-3);
  cursor: pointer;
  padding: 0 var(--k1);
  min-width: 28px;
}

/* Nới vùng chạm ra 52×44 mà KHÔNG làm thông báo cao thêm. Dấu × vẽ ra chỉ
   28×20px — bằng nửa ngón tay; phóng to thẳng nút thì cả dải thông báo dày lên
   trong khi nó chỉ nên lướt qua rồi biến mất. */
.toast button::after {
  content: '';
  position: absolute;
  inset: -12px;
}

/* Vạch bên trái là MẢNG TÔ nên giữ bước rực; biểu tượng là hình mang nghĩa nên
   phải đạt 3:1 — --warning chỉ được 2,15:1, --success 2,54:1. */
.toast-ok { border-left-color: var(--success); }
.toast-ok > i { color: var(--c-passed); }
.toast-loi { border-left-color: var(--danger); }
.toast-loi > i { color: var(--c-failed); }
.toast-canh_bao { border-left-color: var(--warning); }
.toast-canh_bao > i { color: var(--c-ksk); }

@keyframes toast-vao {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
}

@media (min-width: 1024px) {
  .toast-stack {
    left: auto;
    right: var(--k5);
    bottom: var(--k5);
    max-width: 400px;
  }
}

/* ============================================================
   17. TRẠNG THÁI RỖNG & CẢNH BÁO
   ============================================================ */

.empty {
  display: grid;
  gap: var(--k4);
  justify-items: center;
  padding: var(--k7) var(--k6);
  text-align: center;
  color: var(--text-3);
}

.empty i {
  font-size: 40px;
  color: var(--border);
  opacity: 0.85;
}

.empty p {
  max-width: 42ch;
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-2);
}

.empty .btn {
  margin-top: var(--k2);
}

.alert {
  display: flex;
  align-items: flex-start;
  gap: var(--k2);
  padding: var(--k3);
  border: 1px solid var(--c-failed-border);
  border-radius: var(--r);
  background: var(--c-failed-bg);
  color: var(--c-failed);
  font-size: 13px;
  line-height: 1.45;
}

.alert.canh-bao {
  border-color: var(--c-ksk-border);
  background: var(--c-ksk-bg);
  color: var(--c-ksk);
}

.alert.ok {
  border-color: var(--c-passed-border);
  background: var(--c-passed-bg);
  color: var(--c-passed);
}

.alert a {
  color: inherit;
  font-weight: 600;
  text-decoration: underline;
}

.tom-tat-nhan {
  display: flex;
  align-items: center;
  gap: var(--k2);
  margin-top: var(--k3);
  padding: var(--k3);
  border: 1px solid var(--c-docs-border);
  border-radius: var(--r);
  background: var(--c-docs-bg);
  color: var(--c-docs);
  font-size: 13px;
}

.tom-tat-nhan b {
  font-variant-numeric: tabular-nums;
}

/* Cột tên hạng bằng: cho xuống dòng, không cắt giữa chừng khi còn chỗ. */
.hang-ten {
  overflow-wrap: anywhere;
  max-width: 28rem;
}

.khoi-lenh {
  margin: 0 0 var(--k3);
  padding: var(--k3);
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--border-light);
  color: var(--text-2);
  font-family: var(--font-so);
  font-size: 12px;
  overflow-x: auto;
}

code {
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--border-light);
  font-family: var(--font-so);
  font-size: 0.9em;
}

/* ============================================================
   18. BỐ CỤC HAI CỘT
   ============================================================ */

.cot-doi {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--k4);
  align-items: start;
}

@media (min-width: 1024px) {
  .cot-doi {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ============================================================
   19. ĐĂNG NHẬP
   ============================================================ */

.auth-screen {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: var(--k4);
  /* Nền sáng, cùng hệ với xanh hiệu lệnh của --primary, và giữ lại quầng vàng
     hắt từ trên xuống đúng chỗ logo đứng — vàng là màu nét xe trong logo, đây
     là chỗ nó được xuất hiện to nhất trong cả phần mềm.
     Chữ "THUẬN PHÁT" trong logo màu đen nhưng logo đứng trên .auth-card TRẮNG,
     không đứng trên dải nền này, nên nền sáng không làm nó chìm. */
  background:
    radial-gradient(760px 380px at 50% 4%, rgba(216, 168, 32, 0.28) 0%, rgba(216, 168, 32, 0) 62%),
    linear-gradient(168deg, #eaf1fa 0%, #dfe9f6 46%, #ccdcef 100%);
}

.auth-card {
  width: 100%;
  max-width: 400px;
  padding: var(--k5);
  background: var(--surface);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-xl);
}

/* Màn đăng nhập: logo đầy đủ đứng giữa, xếp dọc. Đây là chỗ duy nhất trong
   phần mềm dùng bản đầy đủ — mọi nơi khác dùng bản rút gọn. */
.auth-brand {
  display: grid;
  justify-items: center;
  gap: var(--k3);
  padding-bottom: var(--k4);
  margin-bottom: var(--k5);
  border-bottom: 1px solid var(--border-light);
}

/* Logo đứng trên chính nền thẻ trắng — file PNG nền trong suốt nên không có
   viền hộp nào quanh nó. Bề rộng chốt theo tỉ lệ thật của file (900×449) để
   trình duyệt chừa sẵn chỗ, khỏi giật khung lúc ảnh tải xong. */
.auth-logo {
  width: 100%;
  max-width: 250px;
  height: auto;
  display: block;
}

.auth-tieu-de {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--text-3);
  text-align: center;
}

/* ============================================================
   21. ẨN / HIỆN THEO KHỔ MÀN HÌNH
   ============================================================ */

/* Chỉ hiện từ máy tính bảng trở lên — dùng cho câu giải thích dài,
   cột phụ, nút ít dùng. Trên điện thoại chúng chỉ làm rối. */
.chi-man-lon {
  display: none;
}

@media (min-width: 768px) {
  .chi-man-lon {
    display: block;
  }
}

/* Ngược lại: chỉ hiện trên điện thoại. */
.chi-dien-thoai {
  display: block;
}

@media (min-width: 768px) {
  .chi-dien-thoai {
    display: none;
  }
}

/*
 * Nút mang .chi-dien-thoai phải giữ dạng inline-flex, đối xứng với quy tắc
 * .btn.chi-man-lon ngay dưới.
 *
 * .chi-dien-thoai viết SAU .btn và cùng độ ưu tiên nên `display: block` của nó
 * thắng `inline-flex` của .btn — ô "2 / 7" ở thanh phân trang mất luôn phần
 * căn giữa theo chiều dọc, chữ dính lên mép trên trong khung cao 44px.
 *
 * Phải kèm cả bậc 768px tắt lại: `.btn.chi-dien-thoai` có độ ưu tiên (0,2,0),
 * để trần thì nó thắng luôn `.chi-dien-thoai { display: none }` (0,1,0) trong
 * media query trên, và ô "2 / 7" hiện trở lại trên máy tính cạnh dãy số trang
 * đầy đủ — hỏng nặng hơn thứ đang chữa.
 */
.btn.chi-dien-thoai {
  display: inline-flex;
}

@media (min-width: 768px) {
  .btn.chi-dien-thoai {
    display: none;
  }
}

/* Nút trong toolbar dùng .chi-man-lon phải giữ dạng inline-flex khi hiện. */
@media (min-width: 768px) {
  .btn.chi-man-lon {
    display: inline-flex;
  }
}

/* ============================================================
   22. THANH TAB TRONG TRANG — MÀN HÌNH CÀI ĐẶT
   ------------------------------------------------------------
   Ở mọi màn hình khác, chip bo tròn LUÔN có nghĩa là bộ lọc. Sáu mục
   của trang Cài đặt thì ngược lại: bấm vào là đổi hẳn nội dung đang
   xem chứ không lọc bớt dòng nào. Dùng chung một hình dạng thì người
   dùng bấm xong lại đi tìm nút "bỏ lọc" không thấy. Nên tab gạch chân
   — khác chip về mọi mặt — mà vẫn cuộn ngang được trên điện thoại.
   ============================================================ */

.tab-cai-dat,
.cd-nav {
  display: flex;
  gap: var(--k1);
  overflow-x: auto;
  scrollbar-width: none;
  scroll-snap-type: x proximity;
  margin: 0;
  padding: 0;
  border-bottom: 1px solid var(--border);
  background: transparent;
}

.tab-cai-dat::-webkit-scrollbar,
.cd-nav::-webkit-scrollbar {
  display: none;
}

.tab-cai-dat > a,
.tab-cai-dat > button,
.cd-nav-muc {
  flex: 0 0 auto;
  scroll-snap-align: start;
  display: inline-flex;
  align-items: center;
  gap: var(--k2);
  min-height: var(--cham);
  padding: 0 var(--k3);
  border: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  border-radius: var(--r) var(--r) 0 0;
  background: none;
  color: var(--text-2);
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: color var(--tr), border-color var(--tr), background var(--tr);
}

.tab-cai-dat > a > i,
.tab-cai-dat > button > i,
.cd-nav-muc > i {
  font-size: 13px;
  opacity: 0.7;
}

.tab-cai-dat > a.on,
.tab-cai-dat > button.on,
.cd-nav-muc.on {
  color: var(--primary);
  border-bottom-color: var(--primary);
  background: var(--primary-light);
}

.tab-cai-dat > a.on > i,
.tab-cai-dat > button.on > i,
.cd-nav-muc.on > i {
  opacity: 1;
}

@media (hover: hover) and (pointer: fine) {
  .tab-cai-dat > a:hover:not(.on),
  .tab-cai-dat > button:hover:not(.on),
  .cd-nav-muc:hover:not(.on) {
    color: var(--text);
    background: var(--border-light);
  }
}


/* ============================================================
   30. CHUÔNG CẢNH BÁO
   ============================================================ */

.chuong-hop {
  position: relative;
  flex: 0 0 auto;
}

.chuong-nut {
  position: relative;
}

/* Có cảnh báo nghiêm thì viền vàng — đủ để mắt bắt được mà không nhấp nháy
   gây khó chịu cho người dùng cả ngày. */
.chuong-nut.co-nghiem {
  border-color: var(--vang);
  background: var(--vang-nhat);
}

.chuong-dem {
  position: absolute;
  top: -5px;
  right: -5px;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: var(--r-full);
  /* Chữ trắng trên --danger (#ef4444) chỉ đạt 3,76:1 — dưới ngưỡng. Bước đậm
     hơn cho 6,47:1 mà vẫn đỏ rõ. */
  background: var(--c-failed);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  line-height: 17px;
  text-align: center;
}

/* Điện thoại: bảng cảnh báo phủ gần trọn chiều ngang, neo dưới thanh trên cùng.
   Không dùng dropdown hẹp vì mỗi dòng là một câu dài (tên + số tiền + đợt thi). */
.chuong-bang {
  position: fixed;
  top: calc(var(--topbar-h) + var(--an-toan-tren) + var(--k2));
  right: var(--k3);
  left: var(--k3);
  z-index: 70;
  max-height: min(70dvh, 520px);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: 0 18px 48px rgb(15 23 42 / 0.22);
  overflow: hidden;
}

@media (min-width: 640px) {
  .chuong-bang {
    position: absolute;
    top: calc(100% + var(--k2));
    left: auto;
    right: 0;
    width: 400px;
  }
}

.chuong-dau {
  display: flex;
  align-items: center;
  gap: var(--k2);
  padding: var(--k3) var(--k3) var(--k3) var(--k4);
  border-bottom: 1px solid var(--border-light);
}

.chuong-dau .phu {
  margin-left: auto;
  font-size: 12px;
}

.chuong-than {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.chuong-dong {
  display: flex;
  gap: var(--k3);
  padding: var(--k3) var(--k4);
  border-bottom: 1px solid var(--border-light);
  color: inherit;
  text-decoration: none;
  text-align: left;
}

.chuong-dong:last-child {
  border-bottom: 0;
}

/* Vạch trái phân loại: vàng = phải xử lý, xám = chỉ để biết. Có màu VÀ có
   vị trí, không chỉ dựa vào màu. */
.chuong-dong.nghiem {
  box-shadow: inset 3px 0 0 var(--vang);
  background: var(--vang-nhat);
}

.chuong-dong.nhac {
  box-shadow: inset 3px 0 0 var(--border);
}

.chuong-icon {
  flex: 0 0 18px;
  margin-top: 2px;
  color: var(--text-3);
}

.chuong-dong.nghiem .chuong-icon {
  color: var(--vang-dam);
}

.chuong-chu {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.chuong-chu b {
  font-size: 13px;
  overflow-wrap: anywhere;
}

.chuong-chu > span {
  font-size: 12px;
  color: var(--text-2);
  overflow-wrap: anywhere;
}

.chuong-rong {
  display: flex;
  gap: var(--k2);
  align-items: flex-start;
  margin: 0;
  padding: var(--k5) var(--k4);
  color: var(--text-3);
  font-size: 13px;
}

/* ============================================================
   31. HỘP CHI TIẾT
   ============================================================ */

.ct-badge {
  display: flex;
  flex-wrap: wrap;
  gap: var(--k2);
  margin-bottom: var(--k4);
}

.ct-nhom + .ct-nhom {
  margin-top: var(--k5);
}

.ct-nhom h4 {
  margin: 0 0 var(--k3);
  padding-bottom: var(--k2);
  border-bottom: 1px solid var(--border-light);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* Một cột trên điện thoại, hai cột từ 480px. Giá trị dài (địa chỉ, tên khóa)
   khai `rong-het` để chiếm trọn hàng thay vì bị bóp còn nửa màn. */
.ct-luoi {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--k3) var(--k4);
  margin: 0;
}

@media (min-width: 480px) {
  .ct-luoi {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .ct-dong.rong-het {
    grid-column: 1 / -1;
  }
}

.ct-dong {
  min-width: 0;
}

.ct-dong dt {
  margin-bottom: 2px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text-3);
}

.ct-dong dd {
  margin: 0;
  font-size: 14px;
  font-weight: 500;
  overflow-wrap: anywhere;
}

.ct-ghi-chu {
  margin: 0;
  white-space: pre-wrap;
  font-size: 13px;
  color: var(--text-2);
}

/* Tên trong bảng bấm được để mở chi tiết — trông như chữ thường, không phải nút. */
.o-lien-ket {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: var(--text);
  text-align: left;
  cursor: pointer;
}

.o-lien-ket:hover {
  color: var(--vang-dam);
  text-decoration: underline;
}

/* ============================================================
   32. THANH BÊN THU GỌN
   ============================================================ */

/* Chỉ có nghĩa từ 1024px — dưới đó thanh bên là ngăn kéo trượt, thu gọn một
   ngăn kéo thì chẳng để làm gì. */
.sidebar-thu {
  display: none;
}

@media (min-width: 1024px) {
  .sidebar-thu {
    display: grid;
    place-items: center;
    margin-left: auto;
    width: 30px;
    height: 30px;
    flex: 0 0 30px;
    border: 1px solid var(--border);
    border-radius: var(--r);
    background: var(--surface);
    color: var(--text-3);
    cursor: pointer;
  }

  .sidebar-thu:hover {
    color: var(--text);
    border-color: var(--text-3);
  }

  .sidebar.thu-gon {
    --sidebar-w: 64px;
    width: var(--sidebar-w);
  }

  /* Ẩn phần chữ, giữ icon. Mục menu canh giữa và có `title` nên rê chuột vẫn
     đọc được tên — xem thuộc tính title trong AppChrome. */
  .sidebar.thu-gon .brand-text,
  .sidebar.thu-gon .nav-group,
  .sidebar.thu-gon .nav-item span {
    display: none;
  }

  .sidebar.thu-gon .sidebar-brand {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
  }

  .sidebar.thu-gon .sidebar-thu {
    margin-left: 0;
  }

  .sidebar.thu-gon .brand-mark {
    display: none;
  }

  .sidebar.thu-gon .nav-item {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
  }

  .sidebar.thu-gon .nav-item i {
    font-size: 16px;
  }
}

/* ============================================================
   33. VÙNG BẢNG CAO CỐ ĐỊNH
   ============================================================ */

/*
 * Danh sách nằm trong một khung cao cố định và tự cuộn BÊN TRONG, thay vì kéo
 * dài mãi làm cả trang phải cuộn. Nhờ vậy thanh công cụ, hàng tiêu đề và thanh
 * phân trang luôn nhìn thấy được — 25 hay 5.000 học viên thì màn hình vẫn y
 * như nhau, và người dùng không bị lạc giữa chừng.
 *
 * Dùng dvh chứ không phải vh: trên điện thoại thanh địa chỉ co giãn, vh tính
 * theo lúc thanh địa chỉ đã ẩn nên khung bị hụt mất một đoạn dưới đáy.
 */
/* Thẻ chứa bảng phải giãn theo khung, nếu không nó chỉ cao bằng số dòng đang
   có và để hở một mảng trắng từ đó xuống chân trang. */
@media (min-width: 768px) {
  .khung-ds > .ds-bang {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }
}

/* Khung chiếm trọn phần còn lại của vùng nội dung. Không còn calc() trừ tay
   mấy con số phỏng đoán — chúng sai ngay khi thanh công cụ xuống thêm một
   dòng, mà thanh công cụ xuống dòng là chuyện thường trên màn hẹp. */
.khung-ds {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* Bỏ dấu `>`: ở bảng, .vung-cuon là CHÁU của .khung-ds (qua thẻ .ds-bang), nên
   bộ chọn con trực tiếp không với tới. Hệ quả là khung không giãn và thanh cuộn
   ngang bám ngay dưới dòng cuối cùng thay vì nằm ở chân khung. */
.khung-ds .vung-cuon {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

/* ============================================================
   34. MÀN HÌNH ĐÀO TẠO
   ============================================================ */

.mon-ds {
  display: grid;
  gap: var(--k2);
}

/* Điện thoại: xếp dọc (tên môn / số giờ / ô Đạt). Từ 560px xếp ngang thành
   một hàng — vừa đủ chỗ mà vẫn đọc được cả tên môn dài. */
.mon-dong {
  display: grid;
  gap: var(--k2);
  padding: var(--k3);
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
}

@media (min-width: 560px) {
  .mon-dong {
    grid-template-columns: minmax(0, 1fr) auto auto;
    align-items: center;
    gap: var(--k4);
  }

  .mon-dong[data-loai="tu-dong"] {
    grid-template-columns: minmax(0, 1fr) auto;
  }
}

/* Môn đã đạt: nền vàng nhạt + vạch trái. Có cả màu lẫn vị trí, không chỉ màu. */
.mon-dong.dat {
  background: var(--vang-nhat);
  border-color: var(--vang);
  box-shadow: inset 3px 0 0 var(--vang);
}

.mon-ten {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.mon-ten b {
  font-size: 13px;
  overflow-wrap: anywhere;
}

.mon-ten small {
  font-size: 12px;
}

.mon-gio {
  display: flex;
  align-items: center;
  gap: var(--k2);
  white-space: nowrap;
}

.mon-gio .input {
  width: 74px;
  text-align: right;
}

.mon-dat {
  white-space: nowrap;
}

/* Danh sách buổi cabin / sân tập / DAT trong hộp chi tiết. */
.buoi-ds {
  margin: 0 0 var(--k3);
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--k2);
}

.buoi-ds li {
  padding: var(--k2) var(--k3);
  border: 1px solid var(--border-light);
  border-radius: var(--r);
  font-size: 13px;
  background: var(--surface);
}

.buoi-tong {
  margin: 0 0 var(--k3);
  font-size: 13px;
  color: var(--text-2);
}

.buoi-hang {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--k2) var(--k3);
}

.buoi-hang .input[type="date"],
.buoi-hang .input[type="time"],
.buoi-form .input[type="date"],
.buoi-form .input[type="time"] {
  width: auto;
  min-width: 9.5rem;
}

.buoi-hang .input[type="number"] {
  width: 5.5rem;
}

.buoi-form {
  margin-top: var(--k3);
  padding: var(--k3);
  border: 1px dashed var(--border);
  border-radius: var(--r);
}

.buoi-them .ct-nhom {
  margin-top: var(--k4);
}

/* Vạch tiến độ mảnh, dùng trong ô bảng dưới con số. */
.vach {
  height: 4px;
  margin-top: 3px;
  border-radius: var(--r-full);
  background: var(--border-light);
  overflow: hidden;
}

.vach > span {
  display: block;
  height: 100%;
  background: var(--text-3);
}

.vach > span.du {
  background: var(--success);
}

/* ============================================================
   35. THẺ GỌN (điện thoại)
   ============================================================ */

/*
 * Ba dòng, cao chừng 76px. Cách bố trí này đến từ việc hỏi lại: trên điện
 * thoại, nhân viên cần gì để NHẬN RA đúng học viên rồi mới quyết định mở ra?
 * Tên, hạng, số điện thoại, và tiền còn nợ. Bấy nhiêu thôi. Lưới hai cột kèm
 * nhãn viết hoa của bản trước tốn 200px cho cùng lượng tin ấy — một hồ sơ còn
 * chưa hiện hết màn hình đã phải cuộn.
 */
.ds-the {
  gap: 6px;
}

/* Đệm nằm ở CHÍNH thẻ, không giao cho nút bên trong: `.the-bam` chỉ được dựng
   khi màn hình truyền `onChon`, nên nếu đệm nằm ở đó thì màn nào không truyền
   sẽ có chữ dán sát viền. */
.the-dong.gon {
  padding: var(--k2) var(--k3);
}

.the-dong.gon:has(> .the-bam) {
  padding: 0;
}

.the-bam {
  display: block;
  width: 100%;
  padding: var(--k2) var(--k3);
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.the-dong.gon .the-hang1 {
  align-items: center;
}

.the-dong.gon .the-ten {
  font-size: 15px;
  /* Tên không xuống dòng — "Nguyễn Thị Thanh Hương" gãy làm hai làm thẻ cao
     thêm một dòng mà chẳng rõ hơn. Dài quá thì cắt bằng dấu ba chấm. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Dòng nhận diện: hạng · số điện thoại · ngày. Một dòng, chữ số đều bề ngang
   để cột số dóng thẳng khi lướt dọc. */
.the-dong2 {
  margin-top: 3px;
  font-size: 12px;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Dấu phân cách giữa các mẩu tin. Lớp độc lập để hộp chi tiết và dòng nổi bật
   dùng lại được, không chỉ riêng dòng nhận diện. */
/* Dấu chấm ngăn giữa hai mẩu thông tin. Trước đây tô bằng --border và chỉ đạt
   1,23:1 — nghĩa là gần như vô hình, nên nó không ngăn được gì cả. */
.cach {
  margin: 0 6px;
  color: var(--text-3);
}

/* Con số đáng chú ý nhất — dòng duy nhất được phép to và có màu. */
.the-noi-bat {
  margin-top: 4px;
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Hàng nút trong thẻ gọn: giữ lề trên mỏng hơn thẻ thường vì thẻ đã chật. */
.the-dong.gon .the-nut {
  margin-top: var(--k2);
  padding-top: var(--k2);
}

/* Hàng nút chấm cả loạt trong hộp Đào tạo. */
.mon-cong-cu {
  display: flex;
  flex-wrap: wrap;
  gap: var(--k2);
  margin-bottom: var(--k4);
  padding-bottom: var(--k3);
  border-bottom: 1px solid var(--border-light);
}

/* Ô số kèm đơn vị đứng bên phải. */
.o-co-hau-to {
  display: flex;
  align-items: center;
  gap: var(--k2);
}

.o-co-hau-to .input {
  flex: 1;
  min-width: 0;
}

.o-co-hau-to .hau-to {
  flex: 0 0 auto;
  font-size: 12px;
  color: var(--text-3);
  white-space: nowrap;
}

/* ============================================================
   36. LỚP TIỆN ÍCH — thay cho style nội tuyến lặp ở nhiều màn
   ============================================================ */

/* .card-head vốn nằm trong .card nên tự nó không có lề dưới. Khi nó đứng riêng
   ngay trên một danh sách thì phải chừa khoảng cách. */
.alert.trong-form {
  margin-bottom: var(--k4);
}

/* Khe điều khiển chính của thanh công cụ (ô chọn kỳ thi). */
.toolbar .o-chinh {
  flex: 1 1 280px;
}

/* Thanh nút ghim đáy màn hình — nền đặc để danh sách không cuộn xuyên qua. */
/* Ô chọn/ô nhập đặt trong dòng nổi bật của thẻ: .the-noi-bat in đậm cho con số,
   nhưng ô nhập phải trông giống mọi ô nhập khác. */
.the-noi-bat .select,
.the-noi-bat .input {
  font-weight: 400;
}

/* Ô chọn nằm TRONG bảng: 44px vùng chạm của .select đẩy hàng lên 60px, lệch hẳn
   nhịp hàng của bảng bên cạnh. Trong bảng thì thao tác bằng chuột. */
table.tbl .select {
  min-height: 32px;
  padding-top: 2px;
  padding-bottom: 2px;
  font-size: 12px;
}

/* Nút biểu tượng đứng chung hàng với nút chữ phải CÙNG chiều cao. */
@media (min-width: 1024px) {
  .btn-sm.btn-icon {
    min-height: 30px;
    width: 30px;
    flex-basis: 30px;
  }
}

/* `.toolbar-nut .btn { flex: 1 }` có độ ưu tiên cao hơn `.btn-icon`, nên nút
   biểu tượng đặt trong thanh công cụ bị kéo giãn méo. Nâng độ ưu tiên lên. */
.toolbar-nut .btn.btn-icon {
  flex: 0 0 var(--cham);
}

/* ============================================================
   37. SIẾT KHOẢNG CÁCH
   ============================================================ */

/* Ô nhập phụ nằm ngay dưới một ô tích (ví dụ "Số GPLX" dưới "Đã có GPLX"):
   lề trên mỏng để hai thứ đọc thành một cụm, không phải hai mục rời. */
.field.o-phu {
  margin-top: var(--k2);
}

/* Nhóm trường trong biểu mẫu. Bộ chọn phải là `fieldset.nhom` để thắng quy tắc
   gốc ở mục 15 — `.nhom` trơn có độ ưu tiên thấp hơn nên không ăn.
   Biểu mẫu thêm học viên có năm nhóm; mỗi nhóm dư 8px là màn hình dài thêm
   40px, tức thêm một lần vuốt trên điện thoại. */
fieldset.nhom {
  margin-bottom: var(--k4);
  padding-top: var(--k3);
}

.grid-2 {
  gap: var(--k3);
}

.field {
  gap: 4px;
}

/* Thân tấm trượt / hộp thoại: lề mỏng, nhất là trên điện thoại — đây là nơi
   bàn phím ảo ăn mất nửa màn hình. */
.tam-than {
  padding: var(--k3);
}

/*
 * Từ 640px thì trả lại 20px cho khớp .tam-dau và .tam-chan.
 *
 * Bậc này BẮT BUỘC phải nằm ở đây chứ không phải ở khối @media (min-width:
 * 640px) phía trên: quy tắc siết ngay trên viết sau, cùng độ ưu tiên, nên nó
 * đè khối kia. Hậu quả trước đây: thân hộp thoại thụt 12px trong khi tiêu đề
 * và hàng nút thụt 20px — một bậc gãy 8px chạy dọc mép trái mọi hộp thoại trên
 * máy tính bảng và máy tính.
 */
@media (min-width: 640px) {
  .tam-than {
    padding: 14px 16px;
  }
}

/* Khối tóm tắt / cảnh báo: mỏng lại, chúng là chú thích chứ không phải nội dung. */
.tom-tat-nhan,
.alert {
  padding: var(--k2) var(--k3);
}

/* ============================================================
   38. TRANG CÀI ĐẶT — HỆ THỐNG PANEL
   ------------------------------------------------------------
   Một khung: nav → lead → lưới panel. Không cuộn trong bảng ngắn;
   cuộn trang (.content). Danh mục: lưới 2 cột. Form: cột hẹp.
   ============================================================ */

.cd-trang,
.trang-nhieu-bang {
  display: grid;
  align-content: start;
  gap: var(--k4);
  flex: 0 0 auto;
  min-width: 0;
  max-width: 100%;
}

.trang-nhieu-bang > .khung-thi,
.trang-nhieu-bang > .tab-cai-dat {
  min-width: 0;
  max-width: 100%;
}

.trang-nhieu-bang > .tab-cai-dat,
.cd-trang > .cd-nav {
  min-height: var(--cham);
}

.cd-lead {
  margin: calc(var(--k2) * -1) 0 0;
  color: var(--text-2);
  font-size: 13px;
  line-height: 1.45;
  max-width: 52rem;
}

.cd-noi {
  display: grid;
  gap: var(--k4);
  min-width: 0;
}

.cd-luoi {
  display: grid;
  gap: var(--k4);
  align-items: start;
}

.cd-luoi--dm {
  grid-template-columns: 1fr;
}

@media (min-width: 900px) {
  .cd-luoi--dm {
    grid-template-columns: 1fr 1fr;
  }
  .cd-luoi--dm > .cd-panel:last-child:nth-child(odd) {
    grid-column: 1 / -1;
  }
}

.cd-luoi--form {
  grid-template-columns: 1fr;
  max-width: 720px;
}

@media (min-width: 1100px) {
  .cd-luoi--form {
    max-width: none;
    grid-template-columns: 1fr 1fr;
  }
  .cd-luoi--form > .cd-panel:last-child:nth-child(odd),
  .cd-luoi--form > .cd-canh-bao {
    grid-column: 1 / -1;
  }
}

.cd-canh-bao { margin: 0; }

.cd-panel {
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
  overflow: hidden;
  box-shadow: 0 1px 0 color-mix(in srgb, var(--text) 4%, transparent);
}

.cd-panel-dau {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--k3);
  flex-wrap: wrap;
  padding: 10px var(--k4);
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, var(--border-light) 0%, var(--surface) 100%);
}

.cd-panel-tieu {
  display: inline-flex;
  align-items: center;
  gap: var(--k2);
  min-width: 0;
}

.cd-panel-tieu > i {
  color: var(--primary);
  font-size: 14px;
  opacity: 0.9;
}

.cd-panel-tieu h3 {
  margin: 0;
  font-size: 14px;
  font-weight: 650;
  color: var(--text);
}

.cd-dem {
  display: inline-flex;
  align-items: center;
  padding: 1px 8px;
  border-radius: var(--r-full);
  background: var(--primary-light);
  color: var(--primary);
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.cd-panel-nut {
  display: inline-flex;
  align-items: center;
  gap: var(--k2);
  flex-wrap: wrap;
}

.cd-panel-than { padding: var(--k4); }
.cd-panel-than--bang { padding: 0; }

.cd-trang .khung-ds,
.trang-nhieu-bang .khung-ds {
  flex: 0 0 auto;
  min-height: 0;
  display: block;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  margin: 0;
  background: transparent;
}

.cd-trang .khung-ds .vung-cuon,
.cd-trang .khung-ds .table-wrap,
.trang-nhieu-bang .khung-ds .vung-cuon,
.trang-nhieu-bang .khung-ds .table-wrap {
  flex: none;
  max-height: none;
  overflow: visible;
}

.cd-trang .khung-ds > .ds-bang,
.trang-nhieu-bang .khung-ds > .ds-bang {
  display: block;
  flex: none;
  min-height: 0;
  border: 0;
  box-shadow: none;
  background: transparent;
}

.cd-panel-than .tbl { width: 100%; }
.cd-panel-than .tbl th,
.cd-panel-than .tbl td { vertical-align: middle; }

.cd-form { display: grid; gap: var(--k3); }
.cd-form-chan {
  display: flex;
  gap: var(--k2);
  flex-wrap: wrap;
  padding-top: var(--k1);
}

.cd-pre {
  white-space: pre-wrap;
  margin: 0 0 var(--k3);
  padding: var(--k3);
  background: var(--border-light);
  border-radius: var(--r);
  border: 1px solid var(--border);
  font-size: 12px;
}

.cd-ds { margin: 0; padding: 0; list-style: none; }

.cd-hang {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--k2) var(--k3);
  align-items: center;
  padding: 10px var(--k4);
  border-top: 1px solid var(--border);
}
.cd-hang:first-child { border-top: 0; }
.cd-hang:hover { background: var(--border-light); }

.cd-hang-chinh { display: grid; gap: 2px; min-width: 0; }
.cd-hang-ten { font-weight: 650; font-size: 14px; color: var(--text); }
.cd-hang-phu { font-size: 12px; color: var(--text-2); overflow-wrap: anywhere; }
.cd-hang-phu .ma { font-weight: 600; color: var(--text); }
.cd-hang-meta {
  display: inline-flex;
  align-items: center;
  gap: var(--k2);
  flex-wrap: wrap;
  justify-content: flex-end;
}

.cd-trong {
  padding: var(--k6) var(--k4);
  text-align: center;
  color: var(--text-2);
  font-size: 13px;
  line-height: 1.45;
}
.cd-trong > i {
  display: block;
  margin-bottom: var(--k2);
  font-size: 22px;
  opacity: 0.5;
  color: var(--primary);
}

.cot-khoi { display: grid; gap: var(--k4); }
.cd-khoi {
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
  overflow: hidden;
}
.cd-khoi-dau {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--k3);
  flex-wrap: wrap;
  padding: 10px var(--k4);
  border-bottom: 1px solid var(--border);
  background: var(--border-light);
}
.cd-khoi-dau h3 {
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: var(--k2);
  font-size: 14px;
  font-weight: 650;
}
.cd-khoi-than { padding: var(--k4); }
.cd-khoi-than.cd-khoi-bang { padding: 0; }



/* ============================================================
   FLUENT — QAT / REVEAL / DEPTH / MOTION / PHÂN QUYỀN
   ============================================================ */

.qat {
  display: none;
  align-items: center;
  gap: 2px;
  flex: 0 0 auto;
}

.qat-tach {
  display: none;
  width: 1px;
  height: 22px;
  background: var(--border);
  margin: 0 var(--k1);
  flex: 0 0 auto;
}

@media (min-width: 768px) {
  .qat { display: inline-flex; }
  .qat-tach { display: block; }
}

.qat-nut {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: var(--r);
  background: transparent;
  color: var(--text-2);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--tr-fast), color var(--tr-fast), box-shadow var(--tr-fast);
}

.qat-nut:hover,
.qat-nut:focus-visible {
  background: var(--reveal);
  color: var(--primary);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--primary) 25%, transparent);
  outline: none;
}

/* Reveal highlight trên nút / mục menu */
.btn,
.sidebar-nav a,
.cd-nav-muc,
.cd-hang {
  transition: background var(--tr-fast), box-shadow var(--tr-fast), border-color var(--tr-fast), transform var(--tr-fast);
}

.btn:hover:not(:disabled),
.sidebar-nav a:hover {
  background-image: linear-gradient(var(--reveal), var(--reveal));
}

.btn:active:not(:disabled) {
  transform: scale(0.98);
}

/* Depth — panel / card / khung danh sách */
.cd-panel,
.card,
.khung-ds > .ds-bang.card {
  box-shadow: var(--shadow-1);
}

.overlay .tam-truot {
  box-shadow: var(--shadow-2);
  animation: fluent-pop var(--tr-med) both;
}

@keyframes fluent-pop {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .overlay .tam-truot { animation: none; }
  .btn:active:not(:disabled) { transform: none; }
}

/* Sidebar acrylic (desktop) */
@media (min-width: 1024px) {
  .sidebar {
    background: var(--mica);
    backdrop-filter: blur(24px) saturate(1.35);
    -webkit-backdrop-filter: blur(24px) saturate(1.35);
    box-shadow: var(--shadow-1);
    border-right: 1px solid var(--border);
  }
}

.user-chip {
  max-width: 240px;
}

.user-chip .who span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 160px;
  display: block;
}

/* Ma trận vai trò */
.cd-luoi--tk {
  grid-template-columns: 1fr;
  max-width: none;
}

.cd-matran {
  display: grid;
  gap: var(--k3);
  grid-template-columns: 1fr;
}

@media (min-width: 720px) {
  .cd-matran { grid-template-columns: 1fr 1fr; }
}

@media (min-width: 1100px) {
  .cd-matran { grid-template-columns: repeat(4, 1fr); }
}

.cd-matran-muc {
  display: grid;
  gap: var(--k2);
  padding: var(--k3);
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: linear-gradient(165deg, var(--surface) 60%, var(--primary-light));
  box-shadow: var(--shadow-1);
  min-height: 100%;
  transition: box-shadow var(--tr-med), transform var(--tr-med);
}

.cd-matran-muc:hover {
  box-shadow: var(--shadow-2);
}

.cd-matran-muc header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--k2);
  flex-wrap: wrap;
}

.cd-matran-muc p {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.35;
}

.cd-matran-muc small {
  color: var(--text-2);
  font-size: 12px;
  line-height: 1.4;
}

.cd-pham-vi {
  display: inline-grid;
  gap: 2px;
}

.cd-pham-vi > .phu {
  font-size: 11px;
}

/* ---- Đồng bộ Fluent: thanh lọc / danh sách / chip vai trò ---- */

.content > .toolbar,
.content > form.toolbar,
.ds-dau > .toolbar,
.ds-dau > form.toolbar {
  margin-bottom: 0;
  padding: 6px var(--k2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  box-shadow: none;
  gap: 6px;
}

.ds-dau {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 5px;
}

/* Thống kê học phí — một hàng gọn thay vì 3 thẻ lớn */
.stat-strip {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 5px;
}

.stat-gon {
  display: flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
  padding: 6px 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
}

.stat-gon > i {
  flex: 0 0 auto;
  font-size: 12px;
  color: var(--text-3);
}

.stat-gon > b {
  font-size: 14px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  letter-spacing: -0.02em;
  color: var(--text);
}

.stat-gon > span {
  font-size: 11px;
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.stat-gon.s-da_dau > b { color: var(--c-passed); }
.stat-gon.s-thi_lai > b { color: var(--c-failed); }

.ds-dau > .chips {
  margin-bottom: 0;
  padding-bottom: 0;
}

.ds-dau > .chips .chip {
  min-height: 30px;
  padding: 0 10px;
  font-size: 12.5px;
}

.ds-dau > .tab-cai-dat {
  margin: 0;
}

.ds-dau > .tab-cai-dat > button {
  min-height: 32px;
  padding: 0 10px;
  font-size: 12.5px;
}

.ds-dau > .pager-info,
.ds-dau > .pager {
  margin: 0;
}

.alert.ds-canh {
  margin: 0;
  padding: 6px 10px;
  font-size: 12.5px;
}

.the-dong {
  transition: border-color var(--tr-fast), box-shadow var(--tr-fast), background var(--tr-fast);
}

.the-dong:hover,
.the-dong.bam:hover {
  border-color: color-mix(in srgb, var(--primary) 28%, var(--border));
  box-shadow: var(--shadow-1);
  background-image: linear-gradient(var(--reveal), var(--reveal));
}

.user-chip .avatar {
  background: var(--primary-light);
  color: var(--primary);
  font-weight: 700;
}

.user-chip.vt-owner .avatar {
  background: color-mix(in srgb, var(--vang) 22%, #fff);
  color: var(--vang-dam);
}

.user-chip.vt-admin .avatar {
  background: var(--primary-light);
  color: var(--primary);
}

.user-chip.vt-vptd .avatar {
  background: #ecfdf5;
  color: #047857;
}

.user-chip.vt-gv .avatar {
  background: #eff6ff;
  color: #1d4ed8;
}

.tabbar .tab {
  transition: background var(--tr-fast), color var(--tr-fast);
}

.tabbar .tab:hover,
.tabbar .tab:focus-visible {
  background: var(--reveal);
  color: var(--primary);
  outline: none;
}

.sidebar-nav a .vach-cho {
  background: var(--vang);
}

.empty {
  border-radius: var(--r-lg);
  border: 1px dashed var(--border);
  background: color-mix(in srgb, var(--surface) 88%, var(--primary-light));
}

.stat,
.stat-card {
  box-shadow: var(--shadow-1);
  transition: box-shadow var(--tr-med), transform var(--tr-med);
}

.stat:hover,
.stat-card:hover {
  box-shadow: var(--shadow-2);
}

/* ============================================================
   39. HAI MÀN THI — TỐT NGHIỆP & SÁT HẠCH
   ------------------------------------------------------------
   Luồng: chọn kỳ (một thanh gọn) → trái = trong kỳ / chấm → phải = chọn xếp.
   Kết quả kỳ nằm trong cùng thanh đầu, không chiếm thêm một tầng.
   ============================================================ */

.khung-thi {
  display: flex;
  flex-direction: column;
  gap: 5px;
  flex: 1;
  min-height: 0;
  min-width: 0;
  max-width: 100%;
  overflow-x: hidden;
}

.khung-thi-dau {
  flex: 0 0 auto;
  display: grid;
  gap: 0;
  min-width: 0;
}

/* Form nhập KQ: ẩn input file gốc, dùng nhãn nút */
.tn-nhap-kq {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  margin-left: 0;
  max-width: 100%;
}

.tn-nhap-kq .tn-chon-tep {
  position: relative;
  cursor: pointer;
  overflow: hidden;
}

.tn-nhap-kq input[type="file"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
  font-size: 0;
}

/* ---------------------------------------------------- thanh kỳ */

.kt-ky {
  display: grid;
  gap: 6px;
  padding: 8px 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
}

.kt-hang1 {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 10px;
  min-width: 0;
}

.kt-chinh {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  min-width: 0;
  flex: 1 1 auto;
}

.kt-chon {
  position: relative;
  display: flex;
  align-items: center;
  min-width: 0;
  flex: 1 1 180px;
  max-width: 100%;
}

/*
 * Ô chọn kỳ đóng vai TIÊU ĐỀ TRANG — gọn hơn bản cũ để nhường chỗ danh sách.
 */
.kt-select {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  max-width: 100%;
  min-height: 34px;
  padding: 2px 30px 2px 8px;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.3;
  text-overflow: ellipsis;
  cursor: pointer;
  transition: border-color var(--tr), background var(--tr);
}

.kt-chon > i {
  position: absolute;
  right: 10px;
  color: var(--text-3);
  font-size: 13px;
  pointer-events: none;
}

.kt-select:focus-visible {
  outline: none;
  border-color: var(--primary);
  box-shadow: var(--ring);
}

@media (hover: hover) and (pointer: fine) {
  .kt-select:hover {
    border-color: var(--vang);
    background: var(--vang-nhat);
  }
}

@media (min-width: 768px) {
  .kt-select {
    font-size: 15px;
    max-width: 420px;
  }
}

@media (pointer: coarse) {
  .kt-select { min-height: var(--cham); }
}

.kt-tt { flex: 0 0 auto; }
.tt-mo            { color: var(--c-docs);     background: var(--c-docs-bg);     border-color: var(--c-docs-border); }
.tt-dang_dien_ra  { color: var(--c-exam);     background: var(--c-exam-bg);     border-color: var(--c-exam-border); }
.tt-hoan_tat      { color: var(--c-passed);   background: var(--c-passed-bg);   border-color: var(--c-passed-border); }
.tt-huy           { color: var(--c-dropout);  background: var(--c-dropout-bg);  border-color: var(--c-dropout-border); }

.kt-meta {
  margin: 0;
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-3);
}

.kt-nut {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  flex: 0 0 auto;
  margin-left: auto;
  align-items: center;
  max-width: 100%;
}

.kt-nut .btn {
  flex: 0 0 auto;
}

.kt-nut form {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  max-width: 100%;
}

/* Dải kết quả nằm trong thanh kỳ */
.kt-kq .dai-kq {
  padding: 0;
  border: 0;
  background: transparent;
  border-radius: 0;
  gap: 6px 12px;
}

.kt-kq .dkq-thanh {
  height: 6px;
  flex: 1 1 120px;
}

.kt-kq .dkq-chu {
  font-size: 12px;
  gap: 4px 12px;
}

@media (min-width: 900px) {
  .kt-ky {
    grid-template-columns: minmax(0, 1fr) minmax(220px, 0.85fr);
    align-items: start;
    column-gap: 14px;
  }
  .kt-hang1 { grid-column: 1; grid-row: 1; }
  .kt-meta  { grid-column: 1; grid-row: 2; }
  .kt-kq    {
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: center;
    min-width: 0;
  }
}

/* ------------------------------------------------- dải kết quả (standalone fallback) */

.dai-kq {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--k2) var(--k4);
  padding: var(--k2) var(--k3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
}

.dkq-thanh {
  flex: 1 1 100%;
  display: flex;
  height: 10px;
  border-radius: var(--r-full);
  overflow: hidden;
  background: var(--border-light);
}

.dkq-doan {
  flex-basis: 0;
  min-width: 4px;
}

.dkq-dat { background: var(--c-passed); }
.dkq-rot { background: var(--c-failed); }
.dkq-cho { background: var(--c-exam); }

.dkq-chu {
  display: flex;
  flex-wrap: wrap;
  gap: var(--k1) var(--k4);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 12.5px;
  color: var(--text-2);
}

.dkq-chu li {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.dkq-chu li.khong { color: var(--text-3); }

.dkq-chu b {
  color: var(--text);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.dkq-cham {
  width: 8px;
  height: 8px;
  border-radius: var(--r-full);
}

@media (min-width: 768px) {
  .dkq-thanh { flex: 1 1 220px; }
}

/* --------------------------------------- thanh chọn khối (< 1024px) */

.thi-tab {
  flex: 0 0 auto;
  display: flex;
  gap: 5px;
}

.thi-tab > button {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--k2);
  min-height: 36px;
  padding: 0 var(--k2);
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--text-2);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--tr), color var(--tr), border-color var(--tr);
}

.thi-tab > button > i { font-size: 12px; }

.thi-tab > button.on {
  border-color: var(--primary);
  background: var(--primary);
  color: #fff;
}

.thi-tab > button.on .badge {
  border-color: transparent;
  background: rgba(255, 255, 255, 0.18);
  color: #fff;
}

/* Tablet trở lên đủ chỗ 2 cột — ẩn tab chuyển khối. */
@media (min-width: 768px) {
  .thi-tab { display: none; }
}

/* ------------------------------------------------------- hai khối */

.khung-thi-cot {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--k2);
  align-items: stretch;
  position: relative;
}

@media (min-width: 768px) {
  .khung-thi-cot {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 28px;
  }

  /* Mũi tên luồng: phải → trái (xếp vào kỳ) — nằm giữa khoảng hở 28px */
  .khung-thi-cot::before {
    content: "";
    position: absolute;
    left: 50%;
    top: 36px;
    width: 24px;
    height: 24px;
    margin-left: -12px;
    border-radius: 50%;
    background-color: var(--surface);
    border: 1px solid var(--border);
    box-shadow: var(--shadow-1);
    z-index: 2;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%230b5fb8' d='M10.5 8L6 4.5v7z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 12px;
    pointer-events: none;
  }
}

.khoi-thi {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  overflow: hidden;
}

.khoi-thi.an { display: none; }

@media (min-width: 768px) {
  .khoi-thi.an { display: flex; }
}

.khoi-thi-dau {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--k2);
  margin: 0;
  padding: 6px 10px;
  border-bottom: 1px solid var(--border-light);
  background: linear-gradient(180deg, var(--primary-light), var(--border-light));
  font-size: 12.5px;
  font-weight: 650;
  min-height: 34px;
}

.khoi-thi-dau > i { color: var(--primary); font-size: 12px; }

.khoi-thi-dau > span:not(.badge) {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.khoi-thi-dau .badge {
  margin-left: auto;
  flex: 0 0 auto;
}

.khoi-nhanh {
  display: flex;
  gap: var(--k1);
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
}

.khoi-nhanh::-webkit-scrollbar { display: none; }

.khoi-nhanh > button {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 26px;
  padding: 0 var(--k2);
  border: 1px solid transparent;
  border-radius: var(--r-full);
  background: none;
  color: var(--text-3);
  font-size: 12.5px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--tr), color var(--tr), border-color var(--tr);
}

.khoi-nhanh > button > b {
  font-variant-numeric: tabular-nums;
}

.khoi-nhanh > button.on {
  border-color: var(--border);
  background: var(--surface);
  color: var(--text);
}

@media (hover: hover) and (pointer: fine) {
  .khoi-nhanh > button:hover:not(.on) { color: var(--text); }
}

@media (pointer: coarse) {
  .khoi-nhanh > button { min-height: var(--cham); padding: 0 var(--k3); }
}

.khoi-thi-loc {
  flex: 0 0 auto;
  display: grid;
  gap: 6px;
  padding: 6px 8px;
  border-bottom: 1px solid var(--border-light);
}

.khoi-thi-than {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* Ô rỗng chiếm trọn phần còn lại và canh giữa dọc — nằm dính mép trên của một
   khối cao 500px thì nhìn như trang chưa tải xong. */
.khoi-thi-than > .empty {
  flex: 1;
  align-content: center;
}

.khoi-thi-chan:empty { display: none; }

.khoi-thi-chan {
  flex: 0 0 auto;
  padding: 5px;
  border-top: 1px solid var(--border-light);
  background: var(--bg);
}

/* Đè lại quy tắc ≥768px của .toolbar-nut (dạt phải, nút co theo chữ): trong
   hàng chân của khối thì hai nút chia đôi bề ngang, tay nào cũng với tới. */
.khoi-thi-chan .toolbar-nut {
  display: flex;
  gap: var(--k2);
  margin: 0;
  flex: 1 1 auto;
}

.khoi-thi-chan .toolbar-nut .btn { flex: 1; }

/* ------------------------------------------------ ô tìm trong khối */

.tim-khoi {
  position: relative;
  display: flex;
  align-items: center;
}

.tim-khoi > i {
  position: absolute;
  left: var(--k3);
  color: var(--text-3);
  font-size: 13px;
  pointer-events: none;
}

.tim-khoi .input {
  padding-left: 36px;
  padding-right: 36px;
  min-width: 0;
}

/* Cao bằng đúng ô nhập chứ không phải một nút vuông 32px lơ lửng giữa ô: vùng
   chạm khi ấy mới đủ cho ngón tay. */
.tim-xoa {
  position: absolute;
  top: 0;
  right: 4px;
  bottom: 0;
  width: 36px;
  display: grid;
  place-items: center;
  border: 0;
  background: none;
  color: var(--text-3);
  font-size: 14px;
  cursor: pointer;
}

@media (pointer: coarse), (max-width: 1023px) {
  .tim-xoa { width: var(--cham); right: 2px; }
}

@media (hover: hover) and (pointer: fine) {
  .tim-xoa:hover { color: var(--text); }
}

/* ---------------------------------------------------- chip lọc nhóm */

/*
 * Trên điện thoại: MỘT hàng cuộn ngang, không xuống dòng.
 *
 * Bốn chip vàng đủ chỗ trên một hàng 390px thì tốt, nhưng "Còn nợ học phí 5"
 * đã dài 118px nên thường là hai hàng — mà hai hàng chip cộng ô tìm ăn mất
 * 160px, tức hơn một phần ba khoảng còn lại của danh sách bên dưới. Cuộn ngang
 * thì bộ lọc luôn cao đúng một hàng; hai chip đầu ("Tất cả", "Đủ điều kiện")
 * là hai chip được bấm nhiều nhất nên chúng đứng sẵn trong tầm mắt.
 *
 * Từ 768px màn đủ rộng, cho xuống dòng để thấy hết một lượt.
 */
.chip-loc {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  overflow-x: visible;
  padding: 2px 0;
}

.chip-loc::-webkit-scrollbar { display: none; }

.chip-loc > button { flex: 0 0 auto; }

.chip-loc > button {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 30px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--surface);
  color: var(--text-2);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--tr), color var(--tr), border-color var(--tr);
}

.chip-loc > button b {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* Màu theo nhóm: xanh cho "xếp được ngay", đỏ cho "còn việc phải làm", xám cho
   "đã xong". Con số nằm ngay cạnh chữ nên người không phân biệt được màu vẫn
   đọc đủ — màu chỉ để mắt nhắm nhanh vào nhóm mình cần. */
.chip-loc > .nh-du   { color: var(--c-passed);  border-color: var(--c-passed-border); }
.chip-loc > .nh-du b { color: var(--c-passed); }
.chip-loc > .nh-chan   { color: var(--c-failed); border-color: var(--c-failed-border); }
.chip-loc > .nh-chan b { color: var(--c-failed); }

/* Đặt SAU các quy tắc màu nhóm ở trên: cùng độ ưu tiên (0,2,0) nên viết sau
   thì thắng, khỏi phải đôn thêm bộ chọn. */
.chip-loc > button.on {
  border-color: var(--primary);
  background: var(--primary);
  color: #fff;
}

.chip-loc > button.on b { color: #fff; }

/* Ngón tay cần 44px; con chuột thì 30px là đủ và đỡ chiếm chỗ của danh sách. */
@media (pointer: coarse), (max-width: 1023px) {
  .chip-loc > button { min-height: var(--cham); padding: 0 var(--k3); }
}

/*
 * Biến thể dùng ngoài khối thi (trang Cấp đổi GPLX).
 *
 * Trong khối thi, hàng chip nằm gọn giữa tiêu đề và danh sách nên không cần lề.
 * Đứng một mình giữa hai khối khác thì phải có: thiếu lề dưới là hàng chip dính
 * luôn vào thanh công cụ của bảng bên dưới, đọc thành một cụm.
 *
 * Chip trạng thái ở đây mang lớp `hs-*` — cùng bộ màu với huy hiệu trong bảng,
 * nên nhìn màu chip là biết nó lọc ra chồng hồ sơ nào.
 */
.chip-hs {
  /* KHÔNG ĐƯỢC CO. `.content` là cột flex, mà hàng chip lại đặt `overflow-x`
     để cuộn ngang — `overflow` khác `visible` thì `min-height: auto` mất tác
     dụng, nên trên màn hình chật hàng chip bị bóp từ 44px xuống còn 11px và
     mấy cái chip hiện ra như bị cắt ngang. Đo thật trên màn 390×844: 11px. */
  flex: 0 0 auto;
  margin-bottom: var(--k3);
}

.chip-hs > button { border-color: currentColor; }
.chip-hs > button.on { border-color: var(--primary); }

/* -------------------------------------------------- danh sách dòng */

.ds-thi {
  flex: 1;
  min-height: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

/* ---- dòng học viên dự thi ---- */

/* Lề dọc 6px chứ không phải 8: dãy nút chấm điểm đã cao 44px cho vừa ngón tay,
   cộng thêm hai lề rộng nữa là mỗi học viên ngốn hơn 110px — màn 844px chỉ còn
   hiện được ba người, đúng cái cảnh mà bản trước đã phải đi sửa. */
.dong-thi {
  display: grid;
  gap: 10px;
  padding: 10px var(--k3);
  border-bottom: 1px solid var(--border-light);
  min-width: 0;
}

.dong-thi:last-child { border-bottom: 0; }

/* Đang gửi lên máy chủ: làm mờ cả dòng chứ không xoay một cái chong chóng bé
   xíu — mờ thì thấy được từ khoảng cách cầm điện thoại ngoài sân nắng. */
.dong-thi.dang-luu { opacity: 0.55; }

.dt-tren {
  display: flex;
  align-items: center;
  gap: var(--k2);
  min-width: 0;
}

.dt-stt {
  flex: 0 0 auto;
  min-width: 20px;
  text-align: right;
  color: var(--text-3);
  font-size: 12px;
}

.dt-ten {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

/*
 * Giãn dòng khai TẬN NƠI, không mượn của thân trang.
 *
 * Thân trang để 1,55 cho đoạn văn dài; ở đây mỗi dòng chỉ có một cụm ngắn nên
 * cùng con số ấy biến khối tên thành 43px thay vì 34px. Chín pixel một dòng,
 * nhân với ba mươi người của một kỳ là mất hơn một màn hình — mà không đổi lại
 * được chút dễ đọc nào, vì hai dòng này không bao giờ xuống hàng.
 */
.dt-ten strong {
  font-size: 14px;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dt-ten small {
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}

.dt-go {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: 1px solid transparent;
  border-radius: var(--r);
  background: none;
  color: var(--text-3);
  font-size: 14px;
  cursor: pointer;
  transition: color var(--tr), background var(--tr), border-color var(--tr);
}

@media (hover: hover) and (pointer: fine) {
  .dt-go:hover {
    color: var(--c-failed);
    background: var(--c-failed-bg);
    border-color: var(--c-failed-border);
  }
}

/* Vùng chạm 44px NHƯNG không kéo dòng cao thêm: lề âm cho nút nở ra ngoài
   khuôn hàng trên, ngón tay vẫn có đủ 44×44 mà chiều cao hàng vẫn do tên học
   viên quyết định. Không có mẹo này thì mỗi dòng cao thêm 11px — nhân với ba
   mươi người của một kỳ là mất hơn một màn hình. */
@media (pointer: coarse) {
  .dt-go {
    width: var(--cham);
    height: var(--cham);
    margin: -6px 0;
  }
}

.dt-kq {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding-left: 28px;
  min-width: 0;
  max-width: 100%;
}

@media (max-width: 419px) {
  .dt-kq { padding-left: 0; }
}

/*
 * NÚT KẾT QUẢ — cùng min-width để các hàng thẳng cột, không kéo full chiều ngang.
 */
.dt-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  min-width: 5.75rem;
  min-height: 30px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--surface);
  color: var(--text-2);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--tr), color var(--tr), border-color var(--tr);
}

.dt-chip:disabled { cursor: default; }

/*
 * Nền chip đang chọn phải là màu ĐẶC (chữ trắng), không lấy --c-passed/--c-failed:
 * ở dark mode hai biến đó bị đảo thành pastel để làm chữ huy hiệu — dùng làm nền
 * thì nút trông nhạt, chữ trắng không đọc được ngoài sân nắng.
 */
.dt-chip.on.kq-dat { color: #fff; background: #047857; border-color: #047857; }
.dt-chip.on.kq-rot { color: #fff; background: #b91c1c; border-color: #b91c1c; }
.dt-chip.on.kq-cho { color: #fff; background: #7c3aed; border-color: #7c3aed; }

@media (hover: hover) and (pointer: fine) {
  .dt-chip:not(.on):not(:disabled):hover {
    border-color: var(--primary);
    color: var(--text);
  }
}

/* Điện thoại: vùng chạm 44px — dùng cả max-width vì giả lập trình duyệt
   thường không bật pointer:coarse. */
@media (pointer: coarse), (max-width: 1023px) {
  .dt-chip { min-height: var(--cham); padding: 0 var(--k3); }
}

/*
 * Ô TÍCH DẠNG NÚT — "đã trả GPLX".
 *
 * Đứng cùng hàng với dãy nút kết quả nên phải cùng chiều cao, cùng bo góc. Nhưng
 * nó KHÁC LOẠI: dãy kia là chọn một trong nhiều, cái này là bật/tắt. Nên tách ra
 * bằng một lề trái và một màu riêng (vàng thương hiệu, không đụng vào bộ ba
 * xanh–đỏ–tím của kết quả), cộng biểu tượng ô vuông có dấu tích.
 */
.dt-tich {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 30px;
  margin-left: auto;
  padding: 0 var(--k2);
  border: 1px dashed var(--border);
  border-radius: var(--r-full);
  background: var(--surface);
  color: var(--text-3);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--tr), color var(--tr), border-color var(--tr);
}

.dt-tich.on {
  border-style: solid;
  border-color: var(--vang);
  background: var(--vang-nhat);
  color: var(--vang-dam);
}

.dt-tich:disabled { cursor: default; }

/* Bản chỉ đọc: bỏ nét đứt "chỗ này bấm được", giữ nguyên màu để đọc trạng thái. */
.dt-tich.tinh {
  border-style: solid;
  cursor: default;
}

@media (hover: hover) and (pointer: fine) {
  .dt-tich:not(:disabled):hover { border-color: var(--vang); color: var(--vang-dam); }
}

@media (pointer: coarse) {
  .dt-tich { min-height: var(--cham); padding: 0 var(--k3); }
}

/* ---- dòng trong danh sách "đã đạt" ---- */

.dong-dat {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--k2) var(--k3);
  min-height: var(--cham);
  padding: var(--k2) var(--k3);
  border-bottom: 1px solid var(--border-light);
}

.dong-dat:last-child { border-bottom: 0; }

.dong-dat > i {
  flex: 0 0 auto;
  color: var(--c-passed);
  font-size: 15px;
}

.dd-than {
  flex: 1 1 160px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.dd-than strong {
  font-size: 14px;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dd-than small {
  font-size: 12px;
  line-height: 1.3;
  color: var(--text-3);
}

/* Trong hàng này ô tích đã tự dạt phải nhờ .dd-than giãn — bỏ lề trái tự động
   của .dt-tich, bằng không nó cộng thêm một khoảng trống thừa. */
.dong-dat .dt-tich { margin-left: 0; }

/* ---- dòng ứng viên chờ xếp kỳ ---- */

.dong-chon {
  border-bottom: 1px solid var(--border-light);
}

.dong-chon:last-child { border-bottom: 0; }

/* Cả dòng là một `label` nên chạm bất cứ đâu cũng tích được — xem chú thích
   trong DongChon ở KhungThi.tsx. */
.dong-chon > label,
.dong-chon > div {
  display: flex;
  align-items: flex-start;
  gap: var(--k3);
  min-height: var(--cham);
  padding: var(--k2) var(--k3);
}

.dong-chon > label { cursor: pointer; }

.dong-chon.khoa > label { cursor: default; }
.dong-chon.khoa .dc-than { opacity: 0.75; }

/* Đã chọn: nền vàng nhạt CỘNG một vạch đậm ở mép trái. Chỉ đổi nền thôi thì
   trên màn hình ngoài nắng gần như không thấy gì. */
.dong-chon.chon {
  background: var(--vang-nhat);
  box-shadow: inset 3px 0 0 var(--vang);
}

.dong-chon > label > input {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  margin: 3px 0 0;
  accent-color: var(--primary);
}

.dc-than {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.dc-hang1 {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--k2);
  min-width: 0;
}

.dc-hang1 strong {
  min-width: 0;
  font-size: 14px;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dc-hang1 .badge { flex: 0 0 auto; }

.dc-phu {
  font-size: 12px;
  line-height: 1.3;
  color: var(--text-3);
}

/* Câu lý do chặn CÓ THỂ dài hai dòng ("Hạng DE bắt buộc chạy DAT nhưng chưa
   đạt định mức km…") nên nó được giãn rộng hơn hai dòng trên — 1,3 đọc ổn khi
   một dòng, chật khi hai. */
.dc-ket-luan {
  font-size: 12px;
  line-height: 1.4;
}

@media (hover: hover) and (pointer: fine) {
  .dong-chon:not(.khoa) > label:hover { background: var(--primary-light); }
}

/* ============================================================
   40. TRANG TỔNG QUAN: CHỌN KỲ, BIỂU ĐỒ, BẢNG SỐ LIỆU
   ------------------------------------------------------------
   Màu cột đã chạy qua bộ kiểm tra tương phản mù màu (xem chú
   thích ở :root trong globals.css). Nhưng màu KHÔNG phải đường
   đọc duy nhất: mỗi biểu đồ chỉ có một lớp dữ liệu và tiêu đề
   đã gọi tên nó, mỗi cột là một nút mang nhãn đọc được cho
   trình đọc màn hình, và cùng bộ số còn có ở khung "Bảng số
   liệu". Người không phân biệt được màu vẫn đọc đủ.
   ============================================================ */

/* ---- một câu, hai bản: gọn cho điện thoại, đầy đủ cho màn rộng ---- */

/*
 * Vì sao không rút gọn bằng JavaScript: đo bề ngang rồi chọn chữ ở phía trình
 * duyệt nghĩa là lượt vẽ đầu tiên (do máy chủ dựng) luôn sai một trong hai, rồi
 * nhảy sang bản kia sau khi hydrate — chữ giật ngay trước mắt người dùng. Dùng
 * display thì CSS quyết định ngay từ lượt vẽ đầu, và trình đọc màn hình cũng
 * chỉ gặp đúng MỘT bản (display: none không vào cây trợ năng), không đọc trùng.
 */
.chu-dai {
  display: none;
}

.chu-gon {
  display: inline;
}

@media (min-width: 768px) {
  .chu-dai {
    display: inline;
  }
  .chu-gon {
    display: none;
  }
}

/* ---- thanh chọn kỳ ---- */

/*
 * Ghim trên đỉnh vùng nội dung: khi trang phải cuộn (màn thấp, hoặc bảng dài),
 * ba nút Tháng / Năm / Tổng vẫn nằm nguyên chỗ — không phải cuộn ngược lên mới
 * đổi được kỳ. Vùng cuộn là .content nên sticky bám theo nó.
 *
 * Lề âm và lề trong bù nhau để dải nền che kín mép khi nội dung trượt qua dưới:
 * .content có lề 5px, thiếu vế này thì thấy một sọc nội dung lấp ló hai bên.
 */
.thanh-ky {
  position: sticky;
  top: -5px;
  z-index: 12;
  margin: -5px -5px 0;
  padding: 5px;
  background: var(--bg);
}

/*
 * Cụm ba nút dính liền: chúng là ba cách xem CÙNG một dữ liệu, không phải ba
 * hành động khác nhau — dính liền thì đọc ra ngay là chọn một trong ba.
 *
 * Nút đang chọn mang luôn kỳ cụ thể ("Tháng 9/2026"), hai nút kia chỉ một từ.
 * Nhờ vậy bỏ được dòng chú thích riêng vốn nằm tách ở mép phải. Bề rộng nút
 * đang chọn vì thế dài hơn hai nút kia — đó là chủ ý, nó cũng là một tín hiệu
 * nữa cho biết đang ở đâu, ngoài màu nền.
 */
.ky-chon {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  background: var(--border-light);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
}

.ky-chon a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  /* Vùng chạm tính trên CHÍNH liên kết. Lề 2px của khung bọc ngoài không phải
     vùng chạm của nó — bấm trúng lề là bấm hụt. */
  min-height: var(--cham);
  /* Lề ngang 12px thay vì 16px: nút đang chọn nay dài hơn hẳn vì mang cả kỳ,
     giữ nguyên 16px thì cả cụm tràn quá nửa hàng trên điện thoại. */
  padding: 0 var(--k3);
  border-radius: var(--r-full);
  font-size: 13px;
  font-weight: 600;
  color: var(--text-2);
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--tr), color var(--tr);
}

.ky-chon a.on {
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-sm);
}

/* Mờ hai nút không chọn trong lúc chờ máy chủ — xem chú thích trong ChonKy.tsx. */
.ky-chon[aria-busy='true'] a:not(.on) {
  opacity: 0.55;
}

@media (hover: hover) {
  .ky-chon a:hover:not(.on) {
    color: var(--text);
  }
}

/* ---- ô số liệu của trang Tổng quan ---- */

.stat-grid.hai-loai {
  /* Một cột trên điện thoại.
     Bốn ô này đều là số TỔNG, ba trong bốn là số tiền. "531.900.000 đ" cần
     khoảng 115px, mà hai cột trên màn 375px chỉ còn ~107px mỗi ô — xén mất
     chữ số là đọc ra sai gấp trăm lần. Xếp một cột thì mọi ô đều đủ chỗ, và
     hàng đầu không còn cảnh một ô đứng lẻ nửa hàng bên cạnh khoảng trống. */
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 640px) {
  .stat-grid.hai-loai {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Bốn ô một hàng phải đợi tới 1200px chứ không phải 1024px. Từ 1024px thanh
   bên hiện ra và ăn mất 248px, nên ở đúng 1024px mỗi ô chỉ còn 173px — chia
   bốn là số tiền bị xén. Đo thật: 1024px ô rộng 173px (xén), 1280px ô rộng
   237px (vừa). */
@media (min-width: 1200px) {
  .stat-grid.hai-loai {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/*
 * Ô số liệu của trang này mang nhãn dài hơn mọi màn khác — "Còn nợ · 27 học
 * viên", "Đã thu · 42% tổng học phí" — vì con số bên trên không tự nói nó đếm
 * trên bao nhiêu người hay chiếm bao nhiêu phần. Nhãn xuống tối đa hai dòng
 * thay vì bị xén: xén đi thì mất đúng cái vế giải thích.
 *
 * Con TRỰC TIẾP, không phải hậu duệ: bên trong ô nhãn còn hai bản chữ (gọn /
 * đầy đủ) cũng là span, viết `span span` thì quy tắc này đè luôn `display` của
 * hai bản ấy và cả hai cùng hiện.
 */
.stat-grid.nhan-dai .stat > span > span {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  white-space: normal;
  line-height: 1.3;
}

/* ---- khung chung của một biểu đồ ---- */

.bd {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.bd-dau {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--k3);
  padding: var(--k3);
  border-bottom: 1px solid var(--border-light);
}

.bd-ten {
  display: flex;
  align-items: center;
  gap: var(--k2);
  min-width: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-2);
}

.bd-ten i {
  font-size: 12px;
  color: var(--text-3);
}

/* Ô đọc số: chỗ DUY NHẤT hiện con số của cột đang chọn. */
.bd-doc {
  flex: 0 1 auto;
  min-width: 0;
  text-align: right;
}

.bd-doc b {
  display: block;
  font-size: 20px;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.bd-doc b em {
  font-style: normal;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-3);
}

.bd-doc > span {
  display: block;
  font-size: 11px;
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.bd-chu-thich {
  display: flex;
  flex-wrap: wrap;
  gap: var(--k1) var(--k4);
  padding: var(--k2) var(--k3) 0;
  font-size: 12px;
  color: var(--text-2);
}

.bd-chu-thich li {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.bd-chu-thich b {
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.bd-cham {
  flex: 0 0 9px;
  width: 9px;
  height: 9px;
  border-radius: 3px;
}

/* ---- vùng vẽ cột ---- */

.bd-than {
  position: relative;
  padding: var(--k4) var(--k3) 0;
}

/* Nhãn đỉnh trục: một con số là đủ để đọc được chiều cao mọi cột còn lại. */
.bd-dinh {
  position: absolute;
  top: 3px;
  left: var(--k3);
  padding-right: var(--k1);
  background: var(--surface);
  font-size: 11px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.bd-day {
  display: flex;
  align-items: stretch;
  gap: 2px;
  height: 116px;
  /* Vuốt dọc vẫn cuộn trang; chỉ vuốt ngang mới thuộc về biểu đồ. Xem chú
     thích theoNgon trong src/components/BieuDo.tsx. */
  touch-action: pan-y;
  border-bottom: 1px solid var(--border);
  /* Hai vạch mốc: đỉnh trục và nửa trục. Vẽ bằng nền nên không thêm thẻ nào. */
  background-image:
    linear-gradient(var(--border-light), var(--border-light)),
    linear-gradient(var(--border-light), var(--border-light));
  background-size: 100% 1px, 100% 1px;
  background-position: 0 0, 0 50%;
  background-repeat: no-repeat;
}

.bd-cot {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: stretch;
  padding: 0;
  border: 0;
  background: none;
  border-radius: var(--k1) var(--k1) 0 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.bd-cot.chon {
  background: color-mix(in srgb, var(--primary) 7%, transparent);
}

.bd-cot:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}

/* column-reverse: con đầu tiên nằm sát đáy, nên các lớp xếp chồng lên nhau
   đúng thứ tự khai báo và luôn mọc từ đường đáy. */
.bd-xep {
  flex: 1;
  display: flex;
  flex-direction: column-reverse;
  gap: 2px;
}

.bd-thanh {
  min-height: 2px;
}

.bd-xep .bd-thanh:last-child {
  border-radius: var(--k1) var(--k1) 0 0;
}

.bd-khong {
  height: 2px;
  border-radius: 2px;
  background: var(--border);
}

.bd-truc {
  display: flex;
  gap: 2px;
  padding: var(--k1) var(--k3) var(--k3);
  font-size: 11px;
  color: var(--text-3);
}

.bd-truc span {
  flex: 1 1 0;
  min-width: 0;
  text-align: center;
  white-space: nowrap;
}

@media (min-width: 768px) {
  .bd-day {
    height: 150px;
  }
}

.bd-trong {
  padding: var(--k6) var(--k3);
  text-align: center;
  font-size: 12px;
  color: var(--text-3);
}

/* ---- thanh tổng hợp cuối trang ---- */

/*
 * Đóng trang bằng một câu duy nhất về dòng tiền. Bốn ô trên cùng đã có ba con
 * số này, nhưng chúng không thay được VẠCH TỶ LỆ — nhìn vạch là biết ngay đã
 * đòi được non nửa hay gần hết. Xem chú thích chỗ gọi trong DienBien.tsx.
 */
.tong-hop {
  padding: var(--k3);
  background: var(--bg);
}

.tien-do-thu {
  display: grid;
  gap: var(--k2);
}

.tdt-dau {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--k2);
  font-size: 12px;
  color: var(--text-2);
}

.tdt-dau b {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.tdt-pt {
  flex: 0 0 auto;
  font-size: 14px;
  font-weight: 700;
}

.tdt-rai {
  display: block;
  height: 8px;
  border-radius: var(--r-full);
  background: var(--border);
  overflow: hidden;
}

.tdt-day {
  display: block;
  height: 100%;
  min-width: 3px;
  border-radius: var(--r-full);
  background: var(--bd-tien);
}

.tdt-chu {
  font-size: 12px;
  color: var(--text-3);
}

/* Còn nợ thì dòng chữ phải khác màu — đây là việc phải làm, không phải một
   dòng ghi chú. */
.tdt-chu.no {
  color: var(--c-failed);
  font-weight: 600;
}

/* ---- chân thẻ biểu đồ ---- */

.bd-chan {
  padding: var(--k3);
  border-top: 1px solid var(--border-light);
  background: var(--bg);
}

/* ---- bảng số liệu theo mốc ---- */

/*
 * Bảng cao CỐ ĐỊNH, cuộn bên trong.
 *
 * Kỳ Tháng có 28–31 dòng. Để bảng dài ra theo số dòng thì cả trang phải cuộn,
 * hàng tiêu đề trôi mất khỏi tầm mắt và người đọc quên cột nào là cột nào.
 * Chốt chiều cao ở đây thì chiều cao TRANG không đổi dù kỳ nào đang xem —
 * chuyển Ngày / Tháng / Năm không còn làm trang nhảy dài ngắn.
 */
.vung-bang-tk {
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  max-height: min(46dvh, 420px);
}

@media (min-width: 768px) {
  .vung-bang-tk {
    max-height: min(52dvh, 520px);
  }
}

.bang-tk {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

.bang-tk th,
.bang-tk td {
  padding: 7px var(--k2);
  border-bottom: 1px solid var(--border-light);
  white-space: nowrap;
  text-align: right;
}

/* Ghim tiêu đề trên đỉnh vùng cuộn — z-index 3 để nó nằm trên cả cột kỳ ghim
   trái (z-index 1) lẫn dòng tổng (z-index 2). */
.bang-tk thead th {
  position: sticky;
  top: 0;
  z-index: 3;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--text-3);
  background: var(--surface);
}

/* Ô đầu dòng là TÊN MỘT MỐC ("Tháng 3/2026"), không phải tiêu đề cột: viết
   thường, cỡ chữ như mọi ô khác. Dùng thẻ th vì nó đúng là tiêu đề của dòng —
   trình đọc màn hình đọc "Tháng 3/2026, HV mới, 4" thay vì đọc trơ con số. */
.bang-tk tbody th,
.bang-tk tfoot th {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text);
  background: var(--surface);
}

.bang-tk tfoot th {
  font-weight: 700;
}

.bang-tk td {
  font-variant-numeric: tabular-nums;
}

/* Cột kỳ ghim trái: bảng cuộn ngang mà mất cột kỳ thì mọi con số vô nghĩa. */
.bang-tk th:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  text-align: left;
  background: var(--surface);
}

.bang-tk tbody td.mo {
  color: var(--text-3);
}

/* Dòng của mốc ĐANG DIỄN RA — cùng ý với cột gạch chéo bên biểu đồ: số này
   chưa trọn, đừng đem so ngang với các dòng đã xong. */
.bang-tk tbody tr.moc-dang th,
.bang-tk tbody tr.moc-dang td {
  background: var(--border-light);
  font-weight: 600;
}

/* Mốc CHƯA TỚI: làm nhạt cả dòng. Chúng có mặt để người đọc thấy trọn hình
   dạng của kỳ (tháng này có 30 ngày), nhưng không được tranh chỗ với những
   dòng có số thật. */
.bang-tk tbody tr.moc-chua th,
.bang-tk tbody tr.moc-chua td {
  color: var(--text-3);
}

/* Tỷ lệ đạt đi kèm ngay sau "đạt/tổng": nhạt hơn để con số gốc vẫn là thứ đọc
   trước, nhưng có sẵn nên không ai phải bấm máy tính. */
.bang-tk .ty-le {
  font-style: normal;
  font-weight: 500;
  color: var(--text-3);
}

/* Ghim dòng tổng dưới đáy: cuộn tới dòng nào cũng còn thấy con số cả kỳ để
   đối chiếu, khỏi phải cuộn xuống hết rồi cuộn ngược lên. */
.bang-tk tfoot td,
.bang-tk tfoot th,
.bang-tk tfoot th:first-child {
  position: sticky;
  bottom: 0;
  z-index: 2;
  font-weight: 700;
  background: var(--bg);
  border-top: 1px solid var(--border);
  border-bottom: 0;
}

@media (hover: hover) {
  .bang-tk tbody tr:hover td,
  .bang-tk tbody tr:hover th {
    background: var(--border-light);
  }
}

/* ============================================================
   41. TRẠNG THÁI CỦA CẢ MÀN HÌNH: ĐANG MỞ · LỖI · KHÔNG THẤY
   ------------------------------------------------------------
   Ba trạng thái này trước đây không có file nào lo, nên người
   dùng gặp: chạm tab thì màn hình đứng im không dấu hiệu gì,
   trang lỗi tiếng Anh của Next khi CSDL rớt, và trang 404 tiếng
   Anh khi tài khoản không đủ quyền. Xem chú thích trong
   AppChrome.tsx (VachCho), error.tsx và not-found.tsx.
   ============================================================ */

/* ---- vạch báo "đang mở" trên mục vừa bấm ---- */

/*
 * Vạch LUÔN có mặt, chỉ đổi độ mờ — nếu chỉ hiện lúc đang chờ thì nó chen vào
 * và đẩy nhãn nhích một nhịp, đúng lúc ngón tay vừa rời khỏi màn hình.
 */
.vach-cho {
  position: absolute;
  left: 50%;
  bottom: 4px;
  width: 18px;
  height: 2px;
  margin-left: -9px;
  border-radius: 2px;
  background: var(--primary);
  opacity: 0;
  transition: opacity 0.1s ease;
}

.vach-cho.cho {
  opacity: 1;
  animation: vach-cho-nhip 0.9s ease-in-out infinite;
}

@keyframes vach-cho-nhip {
  0%,
  100% {
    transform: scaleX(0.35);
  }
  50% {
    transform: scaleX(1);
  }
}

@media (prefers-reduced-motion: reduce) {
  .vach-cho.cho {
    animation: none;
  }
}

/* Mục thanh bên là hàng ngang nên vạch nằm ở mép phải, không phải dưới đáy. */
.nav-item .vach-cho {
  left: auto;
  right: var(--k3);
  bottom: 50%;
  margin: 0 0 -1px 0;
}

/* ---- màn lỗi ---- */

.man-loi {
  display: grid;
  gap: var(--k3);
  align-content: start;
  max-width: 560px;
}

.man-loi .alert b {
  display: block;
  margin-bottom: var(--k1);
}

.man-loi .alert p {
  margin: 0;
}

.man-loi .ma-loi {
  margin-top: var(--k2);
  font-size: 12px;
  opacity: 0.8;
}

.man-loi .toolbar-nut {
  display: flex;
  gap: var(--k2);
  margin: 0;
}

.man-loi .toolbar-nut .btn {
  flex: 1;
}

@media (min-width: 480px) {
  .man-loi .toolbar-nut .btn {
    flex: 0 0 auto;
  }
}

/* ---- màn không tìm thấy ---- */

.man-khong-thay i {
  font-size: 26px;
  color: var(--text-3);
}

.man-khong-thay h2 {
  font-size: 16px;
}

/* ---- dải chọn kỳ đang chờ ---- */


/* ============================================================
   42. TRANG TỔNG QUAN THEO LỐI BẢNG ĐIỀU KHIỂN
   ------------------------------------------------------------
   Ba thứ tách một trang số liệu khỏi một trang bảng biểu:
   so sánh với kỳ trước, bấm được để đi sâu, và nói rõ mốc
   cuối chưa trọn. Xem chú thích đầu src/app/(app)/page.tsx.
   ============================================================ */

/* ---- dòng so sánh với kỳ trước ---- */

/* Cho xuống dòng theo CỤM chứ không xén.
   Ô này rộng ~150px trên điện thoại, mà "↗ +130% so với kỳ trước" cần hơn thế.
   text-overflow: ellipsis vô dụng ở đây vì hộp là flex — kết quả là chữ "trước"
   rơi xuống một mình. Nay cả cụm "so với kỳ trước" là một khối không tách được,
   nên nó xuống nguyên dòng khi chật, và nằm cùng dòng khi rộng. */
.bien-dong {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 2px 5px;
  margin-top: 2px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--text-2);
}

.bien-dong i {
  font-size: 11px;
}

/* Chiều tốt / xấu do nơi gọi quyết định: học viên tăng là mừng, nợ tăng là lo.
   Luôn đi kèm mũi tên, nên màu chỉ là lớp đọc thứ hai. */
.bien-dong.tot {
  color: var(--c-passed);
}

.bien-dong.xau {
  color: var(--c-failed);
}

.bien-dong.trong {
  font-weight: 500;
  color: var(--text-3);
}

/*
 * Vế "so với kỳ trước" CHỈ hiện khi đủ chỗ.
 *
 * Ô trên điện thoại rộng ~150px, không chứa nổi "↗ +130% so với kỳ trước" —
 * ép vào thì mũi tên rơi xuống một dòng riêng, đọc ra rất tệ. Bảng điều khiển
 * thật cũng không lặp lại vế so sánh ở từng ô: mũi tên kèm phần trăm đã là quy
 * ước quen, và thanh chọn kỳ ngay phía trên đã nói đang xem kỳ nào.
 *
 * Nhưng KHÔNG display:none — làm thế thì trình đọc màn hình cũng mất luôn vế
 * ấy, mà người nghe không có thanh chọn kỳ trước mắt để tự suy. Giấu khỏi mắt,
 * giữ cho tai.
 */
.bien-dong em {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (min-width: 640px) {
  .bien-dong em {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip-path: none;
    font-style: normal;
    font-weight: 500;
    color: var(--text-3);
  }
}

/* ---- ô số liệu bấm được ---- */

.stat.bam-duoc {
  position: relative;
  padding-right: var(--k6);
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: border-color var(--tr), box-shadow var(--tr);
}

.stat-mui-ten {
  position: absolute;
  right: var(--k3);
  top: 50%;
  margin-top: -6px;
  font-size: 12px;
  color: var(--text-3);
}

@media (hover: hover) {
  .stat.bam-duoc:hover {
    border-color: var(--text-3);
    box-shadow: var(--shadow-sm);
  }
}

.stat.bam-duoc:active {
  background: var(--border-light);
}

.stat.bam-duoc:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* ---- mốc cuối: kỳ đang diễn ra ---- */

/*
 * Gạch chéo chứ không phải làm nhạt: nhạt đi thì đọc ra thành "ít hơn", mà cột
 * này không ít hơn — nó chỉ CHƯA XONG. Vân gạch là quy ước quen thuộc cho
 * "số tạm". Lớp gạch phủ được là nhờ cột tô bằng backgroundColor chứ không
 * phải background viết tắt — xem chú thích trong BieuDo.tsx.
 */
/* Dòng nổi bật của thẻ in đậm cho CON SỐ. Khi chỗ đó chứa hàng điều khiển
   (ô chọn kết quả + nút gỡ ở hai màn thi) thì ô chọn phải trông giống mọi ô
   chọn khác, không đậm hơn. Trước đây hai màn tự đặt tay fontWeight nội tuyến. */
.the-noi-bat .hang-thao-tac {
  font-weight: 400;
}

.bd-cot.moc-dang .bd-thanh {
  background-image: repeating-linear-gradient(
    45deg,
    rgba(255, 255, 255, 0.55) 0 3px,
    transparent 3px 7px
  );
}

/* Mốc chưa tới: không có cột nào cả, chỉ để chỗ trống cho đúng nhịp trục. Rê
   vào vẫn đọc được nhãn, nhưng không có gì để nhấn. */
.bd-cot.moc-chua {
  cursor: default;
}

.bd-ghi-chu {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 var(--k3) var(--k3);
  font-size: 11px;
  color: var(--text-3);
}

/* Ô mẫu nhỏ mang đúng vân gạch của cột cuối, để câu chú thích tự chỉ vào thứ
   nó đang nói tới. */
.bd-o-gach {
  flex: 0 0 12px;
  width: 12px;
  height: 12px;
  border-radius: 3px;
  background-color: var(--text-3);
  background-image: repeating-linear-gradient(
    45deg,
    rgba(255, 255, 255, 0.55) 0 3px,
    transparent 3px 7px
  );
}
