/* static/css/design-system.css
   Design System — Quản lý Đường bộ Lào Cai
   Nguồn sự thật duy nhất cho màu sắc, font, spacing.
   Mọi file CSS khác phải import file này, không hardcode giá trị trực tiếp.
*/

:root {
  /* ── Brand Colors ── */
  --color-primary:        #1a3a5c;   /* Navy — màu chủ đạo (sidebar, header) */
  --color-primary-dark:   #122840;   /* Navy đậm hơn — hover sidebar */
  --color-primary-light:  #2a5298;   /* Navy nhạt — accent */
  --color-accent:         #e8a020;   /* Vàng cam — highlight, badge quan trọng */
  --color-accent-light:   #fef3dc;   /* Vàng cam nhạt — background badge */

  /* ── Semantic Colors ──
     🔵 SỬA 19/09 theo PHƯƠNG ÁN A: bốn màu chữ dưới đây đã làm TỐI cho đủ tương phản
        4,5:1 trên nền tương ứng. Sắc màu giữ nguyên, nền không đổi.
        Số đo: docs/kien-truc/TUONG_PHAN_MAU.md */
  --color-success:        #1c7630;
  --color-success-bg:     #d4edda;
  --color-warning:        #8c6a03;
  --color-warning-bg:     #fff3cd;
  --color-danger:         #b82c39;
  --color-danger-bg:      #f8d7da;
  --color-info:           #107180;
  --color-info-bg:        #d1ecf1;

  /* ── Tình trạng mặt đường — nền và chữ của nhãn ──
     🔵 Rút từ giá trị đang ghi cứng trong chính file này (18/09). GIÁ TRỊ KHÔNG ĐỔI.
     Bảy biến `--color-tt-*` cũ đã BỎ: chúng không nơi nào dùng, và giá trị của chúng
     KHÔNG khớp thứ đang hiện trên màn hình — giữ lại chỉ gây hiểu nhầm. */
  --color-tt-tot-bg:      #d4edda;   /* TOT — Tốt */
  --color-tt-tot-fg:      #1c7630;
  --color-tt-tb-bg:       #fff3cd;   /* TB — Trung bình */
  --color-tt-tb-fg:       #856404;
  --color-tt-kem-bg:      #ffe5d0;   /* KEM — Kém */
  --color-tt-kem-fg:      #ac4d1d;
  --color-tt-hh-nang-bg:  #f8d7da;   /* HH_NANG — Hư hỏng nặng */
  --color-tt-hh-nang-fg:  #b82c39;
  --color-tt-thi-cong-bg: #e8d8ff;   /* THI_CONG — Đang thi công */
  --color-tt-thi-cong-fg: #553c9a;
  --color-tt-bao-tri-bg:  #d0fff4;   /* BAO_TRI — Bảo trì */
  --color-tt-bao-tri-fg:  #0d6b54;
  --color-tt-trung-tinh-bg: #f1f3f5; /* CHUA_XD · TAM_DONG · NGUNG — dùng chung */
  --color-tt-trung-tinh-fg: #677078;

  /* ══ CẤP QUẢN LÝ — MỘT CHỖ KHAI, BẢNG VÀ BẢN ĐỒ CÙNG ĐỌC TỪ ĐÂY ══
     🔵 Chốt 19/09/2026 (GĐ 8 đợt ④). Mỗi cấp MỘT MÀU GỐC, hai sắc độ:
        --cap-<MÃ>-net   sắc TƯƠI  → nét đường trên BẢN ĐỒ
        --cap-<MÃ>-chu   sắc ĐẬM   → chữ trong BẢNG (cùng sắc, chỉ tối hơn)
        --cap-<MÃ>-nen   nền nhạt  → nền của nhãn trong bảng
     🔴 TRƯỚC ĐÂY LÀ HAI BỘ RỜI NHAU VÀ LỆCH NHAU: bảng tô Quốc lộ xanh dương
        (#1d4ed8) còn bản đồ tô đỏ (#e74c3c) — cùng một cấp, hai màu.
     🔴 Bản đồ nay ĐỌC THẲNG từ đây bằng getComputedStyle, không còn bảng màu
        riêng trong JavaScript. Đổi ở đây là đổi cả hai nơi, không thể lệch.
     🔴 Mọi cặp `-chu` trên `-nen` đều đã đo, đạt mức AA. Số đo: BO_CHUAN_GIAO_DIEN.md.
     🔴 Đổi một màu thì PHẢI ĐO LẠI cặp ấy. Cổng chuẩn giao diện kiểm tự động. */
  --cap-QL-net:  #e74c3c;   /* Đường quốc lộ — nét bản đồ */
  --cap-QL-nen:  #fbdedb;
  --cap-QL-chu:  #c32818;   /* chữ trong bảng — 4,56:1 trên nền trên */
  --cap-DT-net:  #3498db;   /* Đường tỉnh — nét bản đồ */
  --cap-DT-nen:  #dcedf9;
  --cap-DT-chu:  #1d6ea5;   /* chữ trong bảng — 4,58:1 trên nền trên */
  --cap-DX-net:  #27ae60;   /* Đường xã/Phường — nét bản đồ */
  --cap-DX-nen:  #def8e9;
  --cap-DX-chu:  #1c7d45;   /* chữ trong bảng — 4,60:1 trên nền trên */
  --cap-CT-net:  #8e44ad;   /* Đường cao tốc — nét bản đồ */
  --cap-CT-nen:  #eee2f3;
  --cap-CT-chu:  #8741a5;   /* chữ trong bảng — 5,05:1 trên nền trên */
  --cap-DO-net:  #e49525;   /* Đường đô thị (mã DO; tên token = ma_cap) — nét bản đồ */
  --cap-DO-nen:  #fbeddb;
  --cap-DO-chu:  #965f13;   /* chữ trong bảng — 4,63:1 trên nền trên */
  --cap-TX-net:  #cc3380;   /* Đường thôn, xóm — nét bản đồ */
  --cap-TX-nen:  #f7deeb;
  --cap-TX-chu:  #b82e73;   /* chữ trong bảng — 4,52:1 trên nền trên */
  --cap-CD-net:  #16a296;   /* Đường chuyên dùng — nét bản đồ */
  --cap-CD-nen:  #dbfaf7;
  --cap-CD-chu:  #107970;   /* chữ trong bảng — 4,77:1 trên nền trên */
  --cap-DK-net:  #808a8e;   /* Đường khác — nét bản đồ */
  --cap-DK-nen:  #e9ebec;
  --cap-DK-chu:  #626b6f;   /* chữ trong bảng — 4,56:1 trên nền trên */

  /* ── 6 loại đường CẤP XÃ mới (phiếu 3B, đặc tả 8.9) ──
     🔴 Sắc cách ≥ 25° TRONG NHÓM XÃ (9 loại: DO·CD·TX giữ màu cũ + 6 màu này).
     Mọi cặp `-chu` trên `-nen` đã đo đạt AA (≥4,5:1). Số đo ghi bên phải.
     🔴 Đổi một màu thì PHẢI ĐO LẠI cặp ấy — cổng chuẩn giao diện kiểm tự động. */
  --cap-LT-net:  #acb82e;   /* Đường liên thôn — nét bản đồ (vàng lục) */
  --cap-LT-nen:  #f4f6df;
  --cap-LT-chu:  #68701a;   /* chữ trong bảng — 4,87:1 trên nền trên */
  --cap-LX-net:  #5cb82e;   /* Đường liên xã — nét bản đồ (lục sáng) */
  --cap-LX-nen:  #e7f6df;
  --cap-LX-chu:  #3b781c;   /* chữ trong bảng — 4,79:1 trên nền trên */
  --cap-TT-net:  #2da96b;   /* Đường trục thôn — nét bản đồ (lục-lam, chốt 23/09) */
  --cap-TT-nen:  #dff6eb;
  --cap-TT-chu:  #1c784a;   /* chữ trong bảng — 4,83:1 trên nền trên */
  --cap-NX-net:  #2e73b8;   /* Đường ngõ xóm — nét bản đồ (lam) */
  --cap-NX-nen:  #dfebf6;
  --cap-NX-chu:  #21578c;   /* chữ trong bảng — 6,18:1 trên nền trên */
  --cap-ND-net:  #392eb8;   /* Đường nội đồng — nét bản đồ (chàm) */
  --cap-ND-nen:  #e1dff6;
  --cap-ND-chu:  #2a218c;   /* chữ trong bảng — 9,49:1 trên nền trên */
  --cap-SX-net:  #952eb8;   /* Đường sản xuất — nét bản đồ (tím) */
  --cap-SX-nen:  #f0dff6;
  --cap-SX-chu:  #72218c;   /* chữ trong bảng — 7,18:1 trên nền trên */

  /* Hai màu của bản đồ KHÔNG thuộc cấp nào */
  --cap-geojson:   #f39c12;   /* tuyến nạp từ file GeoJSON — nét đứt cam */

  /* ── Neutral Colors ── */
  --color-bg-page:        #f0f4f8;   /* Nền trang */
  --color-map-nen:        #eaf3ea;   /* Nền giả bản đồ — xem nét cấp trên nền sáng */
  --color-bg-card:        #ffffff;   /* Nền card/bảng */
  /* Chữ và biểu tượng đặt TRÊN nền đậm (nút primary, nút danger, nhãn tô đặc).
     Trước 19/09 mỗi chỗ tự viết `#fff` — 5 chỗ trong riêng khối nút. */
  --color-text-tren-nen-dam: #ffffff;
  /* Màu thương hiệu của Excel — dùng cho biểu tượng xuất dữ liệu.
     🔵 Đây KHÔNG phải màu của dự án; nó là màu của một sản phẩm khác,
     nên không tham gia bảng màu ngữ nghĩa. */
  --color-excel:          #1d6f42;

  /* ── Thang độ mờ TRÊN NỀN NAVY của thanh bên ──
     🔵 Rút từ `static/css/style.css` ngày 19/09 (GĐ 8 đợt ⑤). GIÁ TRỊ KHÔNG ĐỔI.
     Đây không phải màu thương hiệu mà là một thang chữ/nền mờ dần đặt trên nền
     navy — gom lại một chỗ để đổi nền navy thì không phải đi dò từng chỗ. */
  --tren-navy-10:         rgba(255,255,255,.1);   /* nền khi rê chuột lên mục menu */
  --tren-navy-18:         rgba(255,255,255,.18);   /* nền mục menu đang mở */
  --tren-navy-20:         rgba(255,255,255,.2);   /* thanh cuộn, đường kẻ mảnh */
  --tren-navy-25:         rgba(255,255,255,.25);   /* viền ảnh đại diện */
  --tren-navy-30:         rgba(255,255,255,.3);   /* viền ảnh đại diện (bản có ảnh) */
  --tren-navy-35:         rgba(255,255,255,.35);   /* chữ rất mờ — số phiên bản */
  --tren-navy-50:         rgba(255,255,255,.5);   /* chữ mờ — nhãn nhóm, vai trò */
  --tren-navy-60:         rgba(255,255,255,.6);   /* chữ mờ vừa */
  --tren-navy-70:         rgba(255,255,255,.7);   /* chữ gần rõ — mục menu thường */
  --bong-25:              rgba(0,0,0,.25);   /* đổ bóng ảnh đại diện */
  --bong-30:              rgba(0,0,0,.3);   /* đổ bóng đậm */
  --man-che:              rgba(0,0,0,.4);   /* màn che khi mở thanh bên trên điện thoại */
  --gradient-vang-dau:    #f59e0b;   /* đầu dải màu ảnh đại diện */

  /* ── Hiệu ứng đang tải và bản in ── */
  --skeleton-nhat:        #f0f0f0;   /* nền hiệu ứng đang tải */
  --skeleton-dam:         #e0e0e0;   /* vệt sáng chạy qua hiệu ứng đang tải */
  --vien-ban-in:          #ccc;   /* đường kẻ khi in ra giấy */

  /* ── Bốn khối cảnh báo — viền và chữ ──
     🔵 Rút từ thân các luật `.alert-gt-*` ngày 19/09 (GĐ 8 đợt ⑤). GIÁ TRỊ KHÔNG
     ĐỔI. 🔴 Bốn màu chữ này ĐẬM HƠN bộ `--color-danger/success/warning/info`, và
     cố ý như vậy: chúng nằm trên nền nhạt của chính khối cảnh báo, cần đậm hơn
     để đủ tương phản. Đừng gộp vào bộ ngữ nghĩa. */
  --canh-bao-loi-vien:       #f5c6cb;
  --canh-bao-loi-chu:        #721c24;
  --canh-bao-thanh-cong-vien: #c3e6cb;
  --canh-bao-thanh-cong-chu:  #155724;
  --canh-bao-nhac-vien:      #ffeeba;
  --canh-bao-nhac-chu:       #856404;
  --canh-bao-tin-vien:       #bee5eb;
  --canh-bao-tin-chu:        #0c5460;

  /* Đỏ đậm hơn `--color-danger`, dùng khi rê chuột lên nút đỏ. */
  --color-danger-dam:     #b91c1c;
  /* ── LẤY NÉT — MỘT NGUỒN cho MỌI ô nhận nhập liệu (PR E1, 24/09/2026) ──
     🔴 Thay hẳn `--vong-chon` cũ *(0 0 0 3px rgba(42,82,152,.15))*: vòng ấy mờ
        15 % nên chỉ **1,26:1** với nền trắng — mắt thường gần như không thấy,
        và **không đạt WCAG 1.4.11** *(chỉ báo không phải chữ cần ≥ 3:1)*.
     🔴 Vòng lấy nét là **chỉ báo duy nhất** của người dùng bàn phím. Đo thật
        *(số in ở báo cáo PR E1)*: vòng **5,26:1** trên nền thẻ trắng · **4,87:1**
        trên nền trang · viền **11,64:1** · vòng lỗi **4,70:1** / **4,35:1** ·
        vòng trên nền tối **10,12:1**. Tất cả ≥ 3:1.
     🔵 KHÔNG phải màu mới — là độ mờ của `--color-primary-light` đã có, nên
        không phải đo "cách sắc ≥ 25°" như màu phân loại. */
  --focus-ring-width:     3px;
  --focus-ring-color:     rgba(42, 82, 152, .85);
  /* Lỗi THẮNG lấy nét: ô đang báo lỗi thì vòng đổi sang đỏ, viền vẫn đỏ. */
  --focus-ring-color-loi: rgba(184, 44, 57, .85);
  /* Vòng trên NỀN TỐI (thanh bên navy) — vòng navy ở đó là vòng vô hình. */
  --focus-ring-color-toi: rgba(255, 255, 255, .92);
  /* Đổ bóng của cột ghim trong bảng — bóng đổ sang NGANG, không phải xuống. */
  --bong-cot-ghim:        2px 0 4px rgba(0,0,0,.08);
  --bong-cot-ghim-phai:  -2px 0 4px rgba(0,0,0,.08);
  --color-bg-hover:       #f8fafc;   /* Hover row bảng */
  --color-border:         #e2e8f0;   /* Đường kẻ */
  --color-border-strong:  #cbd5e0;
  --color-text-primary:   #0f172a;   /* Chữ chính — đậm hơn */
  --color-text-secondary: #334155;   /* Chữ phụ — tăng tương phản */
  --color-text-muted:     #475569;   /* Chữ mờ — tăng tương phản */
  --color-text-disabled:  #64748b;   /* Disabled — vẫn đọc được */

  /* ── Typography ── */
  /* 🔴 PHÔNG HỆ THỐNG — chốt 18/09/2026, KHÔNG tải phông từ mạng ngoài.
     Lý do đầy đủ: docs/kien-truc/BO_CHUAN_GIAO_DIEN.md mục 2.
     Thứ tự dò: Windows -> macOS/iOS -> Android -> Linux -> dự phòng cuối. */
  --font-family-base:
      'Segoe UI',                    /* Windows 10/11 */
      -apple-system, BlinkMacSystemFont,  /* macOS · iOS */
      'Roboto',                      /* Android */
      'Noto Sans', 'Liberation Sans', 'DejaVu Sans',  /* Linux — đủ dấu tiếng Việt */
      system-ui, sans-serif;
  --font-family-mono:
      'Consolas',                    /* Windows */
      'SF Mono', Menlo,              /* macOS */
      'Roboto Mono',                 /* Android */
      'DejaVu Sans Mono', 'Liberation Mono',  /* Linux */
      ui-monospace, monospace;
  --font-size-xs:         0.75rem;   /* 12px */
  --font-size-sm:         0.8125rem; /* 13px */
  --font-size-base:       0.875rem;  /* 14px — base toàn trang */
  --font-size-md:         0.9375rem; /* 15px */
  --font-size-lg:         1rem;      /* 16px */
  --font-size-xl:         1.125rem;  /* 18px */
  --font-size-2xl:        1.25rem;   /* 20px */
  --font-size-3xl:        1.5rem;   /* 24px */
  --font-size-4xl:        3rem;     /* 48px — biểu tượng trang lỗi */
  --font-size-5xl:        5rem;     /* 80px — mã lỗi 404 / 500 */
  --font-weight-normal:   400;
  --font-weight-medium:   500;
  --font-weight-semibold: 600;
  --font-weight-bold:     700;
  --line-height-tight:    1.3;
  --line-height-base:     1.6;
  --line-height-loose:    1.8;

  /* ── Spacing Scale (bội số 4px) ── */
  --space-1:   0.25rem;   /*  4px */
  --space-2:   0.5rem;    /*  8px */
  --space-3:   0.75rem;   /* 12px */
  --space-4:   1rem;      /* 16px */
  --space-5:   1.25rem;   /* 20px */
  --space-6:   1.5rem;    /* 24px */
  --space-8:   2rem;      /* 32px */
  --space-10:  2.5rem;    /* 40px */
  --space-12:  3rem;      /* 48px */

  /* ── Border Radius ── */
  --radius-sm:  4px;
  --radius-md:  8px;
  --radius-lg:  12px;
  --radius-xl:  16px;
  --radius-full: 9999px;

  /* ── Shadows ── */
  --shadow-xs:  0 1px 2px rgba(0,0,0,.05);
  --shadow-sm:  0 1px 4px rgba(0,0,0,.08);
  --shadow-md:  0 4px 12px rgba(0,0,0,.10);
  --shadow-lg:  0 8px 24px rgba(0,0,0,.12);
  --shadow-xl:  0 16px 48px rgba(0,0,0,.16);

  /* ── Layout ── */
  --sidebar-width:       190px;
  --sidebar-collapsed:    64px;
  --topbar-height:        56px;
  --content-max-width:  1400px;

  /* ── Transitions ── */
  --transition-fast:  150ms ease;
  --transition-base:  250ms ease;
  --transition-slow:  400ms ease;

  /* ── TRANG TỔNG QUAN (PR Tổng quan, DAC_TA_TONG_QUAN.md 1.2 mục 5, 8) ──
     Bộ "Nền tối" (Phụ lục A) - chỉ trang Tổng quan dùng qua `[data-che-do="toi"]` (khối cuối tệp).
     Đo 30/09: chữ #e5e7eb / nền khối #111c33 = 14,1:1 · chữ phụ #94a3b8 / #111c33 = 6,6:1 · trắng / dải #1e293b = 14,6:1. */
  --toi-nen-trang:     #0f172a;
  --toi-nen-khoi:      #111c33;
  --toi-vien:          #22304a;
  --toi-chu:           #e5e7eb;
  --toi-chu-phu:       #94a3b8;
  --toi-ranh:          #1e293b;
  /* "Chưa có thông tin" - xám + hoa văn sọc (đặc tả 5.6). #7c8797: 3,64:1 trên trắng · 4,66:1 trên #111c33 (đồ họa ≥ 3:1).
     Hoa văn là thứ phân biệt với ba tình trạng xám (TAM_DONG · NGUNG · CHUA_XD) và "Chưa vào cấp". */
  --mau-chua-co:       #7c8797;
  --mau-chua-co-soc:   rgba(255,255,255,.55);
  /* Cùng hoa văn, dạng ảnh SVG - dùng khi IN: Chrome bỏ gradient CSS của ô trong chú giải khi in ra PDF */
  --hoa-van-chua-co-in: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='6' height='6'%3E%3Cpath d='M-1.5,1.5 l3,-3 M0,6 l6,-6 M4.5,7.5 l3,-3' stroke='%23fff' stroke-opacity='.6' stroke-width='2'/%3E%3C/svg%3E");
  /* Dải chỉ số - theo tông (đổi ở PR tông màu): nền = màu chủ đạo, dòng phụ = accent-light (10,57:1 trên #1a3a5c) */
  --dai-chi-so-nen:    var(--color-primary);
  --dai-chi-so-phu:    var(--color-accent-light);
  /* Biểu đồ: viền mảnh quanh từng phần (tối trên nền sáng · sáng trên nền tối - cách A của DSC 139) + rãnh thanh */
  --bd-vien:           var(--color-text-secondary);
  --bd-ranh:           var(--color-bg-hover);
  /* Thẻ đang chọn (thanh thẻ) - nền tối đổi sang màu nhấn */
  --tt-chon:           var(--color-primary);
  /* Cỡ số lớn (đặc tả 5.5 - thang không có 44 và 28 px) */
  --font-size-chi-so:  2.75rem;   /* 44px - số lớn dải chỉ số */
  --font-size-so-giua: 1.75rem;   /* 28px - số giữa vòng tròn */

  /* ── Z-index Stack ── */
  --z-sidebar:  100;
  --z-topbar:   200;
  --z-dropdown: 300;
  --z-modal:    400;
  --z-toast:    500;
}

/* ── Base Reset ── */
*, *::before, *::after { box-sizing: border-box; }

html { font-size: 16px; scroll-behavior: smooth; }

/* 🔴 LUẬT CHUNG: ẢNH KHÔNG BAO GIỜ RỘNG QUÁ KHUNG CHỨA NÓ.
   Chốt 20/09/2026, sau khi logo trang đăng nhập chiếm gần hết màn hình điện
   thoại và đẩy biểu mẫu xuống dưới — người dùng phải vuốt mới thấy ô nhập.

   Nguyên nhân lần ấy là bộ nhớ đệm giữ bản CSS cũ chưa có luật `width: 52px`
   của logo, nên ảnh hiện ở kích thước gốc 1024×1024. Việc đánh số phiên bản
   cho tệp tĩnh (`tinh()` trong `api/templates_chung.py`) đã chặn nguyên nhân
   ấy; luật dưới đây là **lưới chung** — kể cả khi một ảnh nào đó quên khai
   kích thước, nó cũng không tràn ra ngoài khung nữa.

   🔵 `height: auto` giữ đúng tỉ lệ khi bề rộng bị co lại.
   🔴 Lớp riêng của từng ảnh vẫn thắng luật này (một lớp mạnh hơn một thẻ),
      nên `.thuong-hieu-xac-thuc-logo { width: 52px }` không bị ảnh hưởng. */
img { max-width: 100%; height: auto; }

/* 🔵 BẢN ĐỒ KHÔNG CẦN NGOẠI LỆ — Leaflet đã tự che, đo lại 20/09/2026.
   `leaflet.min.css` có sẵn luật này, và nó dùng `!important` nên thắng luật
   trên:

     .leaflet-container .leaflet-marker-pane img, .leaflet-container
     .leaflet-shadow-pane img, .leaflet-container .leaflet-tile,
     .leaflet-container .leaflet-tile-pane img, .leaflet-container
     img.leaflet-image-layer
     { max-width: none !important; max-height: none !important; width: auto; padding: 0 }

   🔴 Bản đầu của chỗ này có thêm một dòng trừ `.leaflet-container img` ra,
   kèm lời giải thích *"bỏ ra thì bản đồ trắng trơn"*. **Câu ấy SAI — nó là
   suy đoán chưa kiểm.** Đo bằng cách bỏ hẳn dòng trừ rồi dựng lại trang:
   kết quả **giống hệt** — ô lưới vẫn `max-width: none`, vẫn 256×256, **0 ô
   bị co về 0**, vẫn 6 đường vẽ, ở cả khung 1500 lẫn khung 390. Nên dòng
   trừ ấy **đã gỡ**: nó không làm gì, mà còn cản việc kẹp những ảnh khác
   người dùng có thể đặt trong bản đồ *(ví dụ ảnh trong bong bóng chú thích)*.

   🔴 Bài học: đừng viết lý do vào chú thích khi chưa đo — người sau sẽ tin. */

body {
  font-family: var(--font-family-base);
  font-size: var(--font-size-base);
  color: var(--color-text-primary);
  background: var(--color-bg-page);
  line-height: var(--line-height-base);
  -webkit-font-smoothing: antialiased;
}

/* ── Typography Utilities ── */
.text-xs      { font-size: var(--font-size-xs); }
.text-sm      { font-size: var(--font-size-sm); }
.text-base    { font-size: var(--font-size-base); }
.text-md      { font-size: var(--font-size-md); }
.text-lg      { font-size: var(--font-size-lg); }
.text-xl      { font-size: var(--font-size-xl); }
.text-muted   { color: var(--color-text-muted); }
.text-secondary { color: var(--color-text-secondary); }
.font-mono    { font-family: var(--font-family-mono); }
.font-medium  { font-weight: var(--font-weight-medium); }
.font-semibold { font-weight: var(--font-weight-semibold); }
.font-bold    { font-weight: var(--font-weight-bold); }

/* ── Badge Tình trạng mặt đường ── */
.badge-tt { display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: var(--radius-full);
  font-size: var(--font-size-xs); font-weight: var(--font-weight-semibold); }
.badge-tt-TOT      { background: var(--color-tt-tot-bg);       color: var(--color-tt-tot-fg); }
.badge-tt-TB       { background: var(--color-tt-tb-bg);        color: var(--color-tt-tb-fg); }
.badge-tt-KEM      { background: var(--color-tt-kem-bg);       color: var(--color-tt-kem-fg); }
.badge-tt-HH_NANG  { background: var(--color-tt-hh-nang-bg);   color: var(--color-tt-hh-nang-fg); }
.badge-tt-THI_CONG { background: var(--color-tt-thi-cong-bg);  color: var(--color-tt-thi-cong-fg); }
.badge-tt-BAO_TRI  { background: var(--color-tt-bao-tri-bg);   color: var(--color-tt-bao-tri-fg); }
.badge-tt-CHUA_XD  { background: var(--color-tt-trung-tinh-bg); color: var(--color-tt-trung-tinh-fg); }
.badge-tt-TAM_DONG { background: var(--color-tt-trung-tinh-bg); color: var(--color-tt-trung-tinh-fg); }
.badge-tt-NGUNG    { background: var(--color-tt-trung-tinh-bg); color: var(--color-tt-trung-tinh-fg); }

/* ── Badge Cấp quản lý ── */
.badge-cap-ql { display: inline-block; padding: 2px 8px; border-radius: var(--radius-full);
  font-size: var(--font-size-sm); font-weight: var(--font-weight-bold); letter-spacing: .03em; }
.badge-cap-QL  { background: var(--cap-QL-nen); color: var(--cap-QL-chu); }
.badge-cap-DT  { background: var(--cap-DT-nen); color: var(--cap-DT-chu); }
.badge-cap-DX  { background: var(--cap-DX-nen); color: var(--cap-DX-chu); }
.badge-cap-CT  { background: var(--cap-CT-nen); color: var(--cap-CT-chu); }
.badge-cap-NT  { background: var(--cap-DO-nen); color: var(--cap-DO-chu); }
.badge-cap-TX  { background: var(--cap-TX-nen); color: var(--cap-TX-chu); }
.badge-cap-CD  { background: var(--cap-CD-nen); color: var(--cap-CD-chu); }
.badge-cap-DK  { background: var(--cap-DK-nen); color: var(--cap-DK-chu); }
/* 🔴 `DO` là mã HIỆN NAY của Đường đô thị (bản 005 đổi `NT`→`DO`). Dùng lại
   màu `NT`. Giữ `DD`/`NT` ở trên cho dữ liệu cũ còn gọi. */
.badge-cap-DO  { background: var(--cap-DO-nen); color: var(--cap-DO-chu); }
/* 6 loại đường cấp xã mới — phiếu 3B (8.9) */
.badge-cap-LT  { background: var(--cap-LT-nen); color: var(--cap-LT-chu); }
.badge-cap-LX  { background: var(--cap-LX-nen); color: var(--cap-LX-chu); }
.badge-cap-TT  { background: var(--cap-TT-nen); color: var(--cap-TT-chu); }
.badge-cap-NX  { background: var(--cap-NX-nen); color: var(--cap-NX-chu); }
.badge-cap-ND  { background: var(--cap-ND-nen); color: var(--cap-ND-chu); }
.badge-cap-SX  { background: var(--cap-SX-nen); color: var(--cap-SX-chu); }

/* ── Đường kẻ NÉT bản đồ theo cấp — dùng cho chú giải bản đồ và trang bộ
   chuẩn. Nét mảnh (3px) trên nền sáng, đọc đúng màu `-net` của cấp. ── */
.net-cap { display: inline-block; width: 88px; height: 3px; border-radius: 2px;
  vertical-align: middle; }
.net-cap-DO { background: var(--cap-DO-net); }
.net-cap-CD { background: var(--cap-CD-net); }
.net-cap-TX { background: var(--cap-TX-net); }
.net-cap-LT { background: var(--cap-LT-net); }
.net-cap-LX { background: var(--cap-LX-net); }
.net-cap-TT { background: var(--cap-TT-net); }
.net-cap-NX { background: var(--cap-NX-net); }
.net-cap-ND { background: var(--cap-ND-net); }
.net-cap-SX { background: var(--cap-SX-net); }
/* Nền giả bản đồ để xem nét trên nền sáng như bản đồ thật */
.nen-ban-do { background: var(--color-map-nen); border-radius: var(--radius-sm);
  padding: var(--space-3); }

/* ── DÒNG THỜI GIAN (lịch sử duyệt) — phiếu 3B (8.5) ──
   Mỗi mốc: giờ · ai · việc · ghi chú, xếp dọc, có chấm mốc bên trái. */
.dong-thoi-gian { list-style: none; margin: 0; padding: 0; }
.dtg-moc { position: relative; padding: 0 0 var(--space-3) var(--space-4);
  border-left: 2px solid var(--color-border); }
.dtg-moc:last-child { border-left-color: transparent; padding-bottom: 0; }
.dtg-moc::before { content: ""; position: absolute; left: -5px; top: 4px;
  width: 8px; height: 8px; border-radius: var(--radius-full);
  background: var(--color-primary); }
.dtg-dau { display: flex; flex-wrap: wrap; gap: var(--space-2);
  align-items: baseline; }
.dtg-gio { color: var(--color-text-muted); font-size: var(--font-size-sm); }
.dtg-ai { font-weight: var(--font-weight-bold); }
.dtg-ghi-chu { color: var(--color-text-secondary); font-size: var(--font-size-sm); }

/* ── Ô TÌM CÓ GỢI Ý (tìm tuyến liên xã, gợi ý tên) — phiếu 3B (8.2) ── */
.o-tim-goi-y { position: relative; }
.otg-ket-qua { list-style: none; margin: var(--space-2) 0 0; padding: 0;
  border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  background: var(--color-bg-card); overflow: hidden; }
.otg-muc { display: flex; gap: var(--space-3); align-items: center;
  padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--color-border);
  cursor: pointer; }
.otg-muc:last-child { border-bottom: none; }
.otg-muc:hover { background: var(--color-bg-page); }
/* 🔵 Vòng lấy nét của mục: khối LẤY NÉT DÙNG CHUNG (PR E1). */
.otg-ma { font-weight: var(--font-weight-bold); font-size: var(--font-size-sm);
  color: var(--color-text-secondary); min-width: 108px; }
.otg-ten { flex: 1; color: var(--color-text-primary); }
.otg-trong { padding: var(--space-3); color: var(--color-text-muted);
  font-size: var(--font-size-sm); }
/* ── PR A2 (23/09/2026) — ba lớp do static/js/tim_lien_xa.js dựng ra ──
   · otg-tieu-de : dòng tiêu đề trên danh sách ("Có phải tuyến này không?")
   · otg-loi     : câu báo lỗi khi API trả 403/500 hoặc đứt mạng — KHÔNG được
                   trông giống "không có kết quả" (DUNG1 M3), nên dùng màu nguy
   · otg-muc--doc: mục CHỈ ĐỂ ĐỌC (không dich, không dan-toi) — con trỏ thường */
.otg-tieu-de { padding: var(--space-2) var(--space-3); font-size: var(--font-size-sm);
  font-weight: var(--font-weight-semibold); color: var(--color-text-secondary);
  background: var(--color-bg-page); border-bottom: 1px solid var(--color-border); }
.otg-loi { padding: var(--space-3); color: var(--color-danger);
  font-size: var(--font-size-sm); }
.otg-muc--doc { cursor: default; }
/* ── Biến thể NỔI — dùng bởi o_nhap_co_goi_y (PR A2) ──
   Danh sách gợi ý ĐÈ LÊN nội dung bên dưới thay vì chen vào dòng chảy ⟹ biểu
   mẫu KHÔNG nhảy khi gợi ý hiện/ẩn. Neo vào `.o-tim-goi-y` (đã `position:
   relative`), tầng --z-dropdown (cùng tầng menu thả).
   🔴 Mỗi mục cao ≥ 44px — ngưỡng chạm: ô này người dùng gõ và bấm thật. Ô TÌM
      trong biểu mẫu đoạn (không --noi) giữ cỡ đã duyệt ở 3B, không đụng. */
.o-tim-goi-y--noi .otg-ket-qua { position: absolute; left: 0; right: 0; top: 100%;
  margin-top: var(--space-1); z-index: var(--z-dropdown); box-shadow: var(--shadow-md); }
.o-tim-goi-y--noi .otg-muc { min-height: 44px; }
/* Chú thích dưới ô nhập có gợi ý — cùng cỡ/màu với chú thích của o_chi_xem. */
.ong-ct { margin-top: var(--space-1); font-size: var(--font-size-sm);
  color: var(--color-text-muted); }

/* ── Khối "đã sửa gì" ở màn hình hẹp (< md) — thay bảng 4 cột (phiếu 3B) ── */
.bss-khoi { padding: var(--space-2) var(--space-3); margin-bottom: var(--space-2);
  border: 1px solid var(--color-border); border-radius: var(--radius-sm); }
.bss-dau { font-size: var(--font-size-sm); color: var(--color-text-secondary); }
.bss-odau { font-weight: var(--font-weight-bold); }
.bss-doi { margin-top: 2px; }
/* 🔴 `DD` là mã CŨ của Đường đô thị — cơ sở dữ liệu dùng `NT`. Giữ lại lớp này để
   chỗ nào còn gọi `DD` thì vẫn ra đúng màu, và cho nó CÙNG màu với `NT`. */
.badge-cap-DD  { background: var(--cap-DO-nen); color: var(--cap-DO-chu); }

/* ── Ô chọn hẹp trong biểu mẫu ──
   Thay cho style="width:auto" rời rạc (CLAUDE.md muc 5.8). CUNG mot be rong. */
.o-chon-hep { width: auto; }

/* ── Lý trình ── */
.ly-trinh {
  font-family: var(--font-family-mono);
  font-size: var(--font-size-sm);
  color: var(--color-primary);
  font-weight: var(--font-weight-medium);
  font-variant-numeric: tabular-nums;   /* chữ số rộng bằng nhau -> cột thẳng hàng */
}

/* ── Chữ số đều nhau — mọi ô bảng căn phải đều là cột số ──
   Chốt 18/09: bảng và cột lý trình phải thẳng hàng theo chữ số. */
.table-gt td.text-end,
.table-gt th.text-end,
.font-mono,
.so-lieu { font-variant-numeric: tabular-nums; }

/* ── Số liệu km ── */
.chieu-dai {
  font-family: var(--font-family-mono);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-primary);
  font-variant-numeric: tabular-nums;   /* chữ số rộng bằng nhau -> cột thẳng hàng */
}

/* ── Card chuẩn ── */
.card-gt {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.card-gt-header {
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--color-border);
  display: flex; align-items: center; justify-content: space-between;
}
.card-gt-title {
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-primary);
  margin: 0;
}
.card-gt-body { padding: var(--space-6); }

/* ── Stat Card (Dashboard) ── */
.stat-card {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--transition-base), transform var(--transition-base);
}
.stat-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}
.stat-card-icon {
  width: 48px; height: 48px; border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  font-size: 1.4rem; margin-bottom: var(--space-3);
}
.stat-card-value {
  font-size: var(--font-size-3xl);
  font-weight: var(--font-weight-bold);
  color: var(--color-text-primary);
  line-height: 1;
  margin-bottom: var(--space-1);
}
.stat-card-label {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* ── Bảng dữ liệu chuẩn ── */
.table-gt { width: 100%; border-collapse: collapse; }

/* Scroll ngang — cột đầu sticky */
.card-gt-body.p-0 {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.table-gt thead th:first-child,
.table-gt tbody td:first-child {
  position: sticky;
  left: 0;
  z-index: 2;
  background: var(--color-bg-card);
  box-shadow: var(--bong-cot-ghim);
}
.table-gt thead th:first-child {
  background: var(--color-bg-page);
  z-index: 3;
}
.table-gt tbody tr:hover td:first-child {
  background: var(--color-bg-hover);
}

/* Cột ghim MÉP PHẢI — cho cột Hành động.
   🔴 Bài học của `2.2.1`: bảng rộng hơn khung thẻ thì nút ở cột cuối nằm
   ngoài mép, và trên điện thoại coi như KHÔNG CÓ. Ghim lại thì dù bảng
   cuộn ngang bao nhiêu, cột việc vẫn ở đó. */
.table-gt thead th.cot-ghim-phai,
.table-gt tbody td.cot-ghim-phai {
  position: sticky;
  right: 0;
  z-index: 2;
  background: var(--color-bg-card);
  box-shadow: var(--bong-cot-ghim-phai);
}
.table-gt thead th.cot-ghim-phai {
  background: var(--color-bg-page);
  z-index: 3;
}
.table-gt tbody tr:hover td.cot-ghim-phai {
  background: var(--color-bg-hover);
}
/* 🔴 Ô ghim của hàng DƯỚI đè lên menu đang mở của hàng TRÊN.
   Mọi ô ghim cùng `z-index: 2`, nên ô nào đứng sau trong mã thì vẽ đè lên —
   menu Thao tác bị cắt mất chữ ở CẢ hai cỡ màn hình.
   🔵 Ảnh chụp bắt được; đọc số thôi thì không thấy — `getBoundingClientRect()`
   vẫn báo menu nằm gọn trong khung, vì nó *nằm gọn* thật, chỉ bị vẽ đè. */
.table-gt tbody td.cot-ghim-phai:has(.dropdown-menu.show) {
  z-index: 5;
}

/* Một việc trong menu Thao tác — trông như một dòng menu, không như một nút
   rời. Dùng chung với macro `nut()` nên vẫn qua kho mẫu (nguyên tắc 9). */
.muc-thao-tac {
  display: flex;
  align-items: center;
  width: 100%;
  justify-content: flex-start;
  border: 0;
  border-radius: 0;
  background: transparent;
  padding: var(--space-2) var(--space-3);
}
.muc-thao-tac:hover { background: var(--color-bg-hover); }
.dropdown-menu form { margin: 0; }

.table-gt thead th {
  padding: var(--space-3) var(--space-4);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--color-text-muted);
  background: var(--color-bg-page);
  border-bottom: 1px solid var(--color-border-strong);
  white-space: nowrap;
}
.table-gt tbody td {
  padding: var(--space-3) var(--space-4);
  font-size: var(--font-size-md);
  color: var(--color-text-primary);
  border-bottom: 1px solid var(--color-border);
  vertical-align: middle;
}
.table-gt tbody tr { transition: background var(--transition-fast); }
.table-gt tbody tr:hover { background: var(--color-bg-hover); }
.table-gt tbody tr:last-child td { border-bottom: none; }

/* ── Nút bấm chuẩn ── */
.btn-gt {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-md);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  border: 1px solid transparent;
  cursor: pointer; text-decoration: none;
  transition: all var(--transition-fast);
  white-space: nowrap;
}
.btn-gt-primary {
  background: var(--color-primary);
  color: var(--color-text-tren-nen-dam);
  border-color: var(--color-primary);
}
.btn-gt-primary:hover {
  background: var(--color-primary-dark);
  border-color: var(--color-primary-dark);
  color: var(--color-text-tren-nen-dam); text-decoration: none;
}
.btn-gt-outline {
  background: transparent;
  color: var(--color-primary);
  border-color: var(--color-primary);
}
.btn-gt-outline:hover {
  background: var(--color-primary);
  color: var(--color-text-tren-nen-dam); text-decoration: none;
}
.btn-gt-danger { background: var(--color-danger); color: var(--color-text-tren-nen-dam); border-color: var(--color-danger); }
.btn-gt-danger:hover { background: var(--color-danger-dam); border-color: var(--color-danger-dam); color: var(--color-text-tren-nen-dam); }
/* Viền màu — dùng cho NÚT BẬT/TẮT TRẠNG THÁI trong bảng danh mục.
   Đỏ = đang bật, bấm để vô hiệu · Xanh = đang tắt, bấm để khôi phục.
   🔴 GIẢI TRÌNH khác bản đang dùng: 21 chỗ hiện gọi thẳng `btn-outline-danger` và
      `btn-outline-success` của Bootstrap. Hai lớp dưới đây lấy màu từ TOKEN của dự án
      (`--color-danger` #b82c39, `--color-success` #1c7630) thay vì màu Bootstrap, nên
      sắc đỏ và xanh khớp với phần còn lại của hệ thống.
   Tương phản khi di chuột: 4,55 (đỏ) và 4,60 (xanh) — cả hai ĐẠT mức AA. */
.btn-gt-vien-nguy-hiem {
  background: transparent;
  color: var(--color-danger);
  border-color: var(--color-danger);
}
.btn-gt-vien-nguy-hiem:hover {
  background: var(--color-danger-bg);
  color: var(--color-danger); text-decoration: none;
}
.btn-gt-vien-thanh-cong {
  background: transparent;
  color: var(--color-success);
  border-color: var(--color-success);
}
.btn-gt-vien-thanh-cong:hover {
  background: var(--color-success-bg);
  color: var(--color-success); text-decoration: none;
}
.btn-gt-sm { padding: var(--space-1) var(--space-3); font-size: var(--font-size-xs); }
/* Cỡ RẤT NHỎ — nút nằm trong ô bảng, nơi mỗi hàng chỉ cao ~32px.
   🔴 Khác `btn-gt-sm` ĐÚNG MỘT THỨ: đệm mỏng hơn. Cỡ chữ vẫn `--font-size-xs`.
   Giải trình: 21 chỗ đang ghi cứng `font-size:.73rem` (11,7px) kèm `py-0 px-2`.
   Chênh 0,3px với token 12px — mắt không thấy, mà bỏ được một cỡ chữ ghi cứng. */
.btn-gt-xs { padding: 0 var(--space-2); font-size: var(--font-size-xs); }
/* Nút chiếm trọn bề ngang, chữ căn giữa.
   🔴 Vì sao cần lớp riêng: `.btn-gt` là `inline-flex` KHÔNG khai `justify-content`.
   Với nút tự co theo chữ thì không sao — không có chỗ trống để căn. Nhưng khi ép
   `w-100` thì chữ dồn hết sang TRÁI, trông như lỗi. Thấy ở GĐ 8 đợt ①.
   ✅ Hai chỗ còn sót — `doan_di_chung/form.html` và `he_thong/nguoi_dung.html` —
   đã đổi sang lớp này ngày 19/09 ở GĐ 8 đợt ③. DANH SÁCH CHỜ 39 đóng.
   🔴 Nay KHÔNG còn chỗ nào trong templates/ dùng `btn-gt` kèm `w-100`; có phép
   kiểm quét toàn bộ templates/ để giữ điều đó. */
.btn-gt-khoi { width: 100%; justify-content: center; }
.btn-gt-icon { padding: var(--space-2); }

/* Văn bản dài nhập tay, giữ nguyên chỗ người dùng xuống dòng.
   🔴 Thay cho `style="white-space: pre-line; line-height: 1.7"` — 6 chỗ trong
   tuyen_duong/detail.html. Dùng token `--line-height-loose` (1.8) thay cho 1.7
   và 1.75 đang ghi cứng; chênh đúng 0,05–0,1 dòng, mắt không thấy. */
.van-ban-dai { white-space: pre-line; line-height: var(--line-height-loose); }

/* ── Bề rộng cột bảng cố định ──
   🔴 Thay cho `<th style="width:NNpx">` — 20 chỗ trong ba trang danh mục.
   Đặt tên theo VIỆC cột ấy làm, không theo con số, để chỗ khác dùng lại được.
   Giá trị GIỮ NGUYÊN đúng từng điểm ảnh của bản đang chạy. */
.cot-stt        { width:  60px; }  /* số thứ tự */
.cot-so         { width:  80px; }  /* số ngắn — thứ tự sắp xếp, năm */
.cot-trang-thai { width:  90px; }  /* nhãn Hoạt động / Đã tắt */
.cot-thao-tac   { width: 120px; }  /* nút Sửa + nút bật/tắt */

/* Ô chọn màu — ô vuông nhỏ đứng trước ô nhập mã HEX trong cùng một nhóm.
   🔴 Thay cho `style="width:50px"` — 2 chỗ trong danh_muc/ky_thuat.html. */
.o-chon-mau { width: 50px; flex: 0 0 auto; }

/* Ô nhập mã danh mục — gõ chữ thường vẫn hiện chữ hoa.
   🔴 Thay cho `style="text-transform:uppercase"` — 2 chỗ trong danh_muc/ky_thuat.html.
   Chỉ đổi cách HIỆN, không đổi thứ gửi lên máy chủ. */
.chu-hoa { text-transform: uppercase; }

/* ── Thành phần màu — phần KHUNG nằm ở đây, phần MÀU do dữ liệu truyền vào ──
   🔴 Bốn lớp dưới đây cố ý KHÔNG khai `background` hay `color`: màu đến từ cơ
   sở dữ liệu, mỗi bản ghi một màu, người dùng tự đặt. Kho mẫu sinh phần màu
   bằng style động; ở đây chỉ lo hình dạng. */

/* Nhãn bo tròn tô đặc, màu nền do dữ liệu quyết định. */
.nhan-mau {
  display: inline-block;
  padding: 0 var(--space-2);
  border-radius: var(--radius-full);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-medium);
  line-height: 1.7;
  white-space: nowrap;
}

/* Ô vuông nhỏ xem trước một màu. `co` đổi qua biến, mặc định 18px. */
.o-mau {
  display: inline-block;
  width: var(--o-mau-canh, 18px);
  height: var(--o-mau-canh, 18px);
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border);
  vertical-align: middle;
}
.o-mau--tron { border-radius: var(--radius-full); }
.o-mau--nho  { --o-mau-canh: 10px; }

/* Một hàng chú giải: ô màu + chữ, các mục cách nhau đều. */
.chu-giai      { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }
.chu-giai-muc  { display: inline-flex; align-items: center; gap: var(--space-2); }

/* Hàng bảng được tô nhấn — dùng cho đoạn đi chung trong bảng đoạn tuyến.
   🔴 Màu ở đây là màu CỐ ĐỊNH của hệ thống (nền vàng nhạt của cảnh báo), không
   phải màu từ dữ liệu, nên khai thẳng bằng token. */
.hang-nhan-manh          { background: var(--color-warning-bg); }
.hang-nhan-manh td       { color: var(--color-warning); }
.hang-nhan-manh .text-muted { color: var(--color-warning) !important; }

/* Nhãn "mã" trung tính — viền mảnh, nền rất nhạt. Dùng cho mã kết cấu, mã cấp
   trong bảng thống kê. 🔴 Thay cho `badge bg-light text-dark border` và
   `badge bg-info-subtle text-info border` của Bootstrap kèm cỡ chữ ghi cứng. */
.nhan-ma {
  display: inline-block;
  padding: 0 var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg-page);
  color: var(--color-text-secondary);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-medium);
}

/* Nút KHÔNG có khung — chỉ là vùng bấm, hình dạng do lớp khác lo.
   🔴 Vì sao cần: ba nút khung của thanh bên (mở/đóng nhóm menu, ẩn/hiện thanh
   bên) không phải nút thao tác, chúng là BỘ PHẬN CỦA KHUNG TRANG. Chúng tự có
   hình dạng riêng trong style.css. Lớp này nói rõ điều đó, và cho chúng đi qua
   cổng chuẩn giao diện một cách tử tế thay vì được miễn trừ. */
.btn-gt-tran {
  background: none; border: none; padding: 0;
  color: inherit; cursor: pointer;
}

/* Bề rộng cột bảng — bổ sung cho trang nhật ký. Cùng cách đặt tên với
   .cot-stt / .cot-so / .cot-trang-thai / .cot-thao-tac. */
.cot-hep       { width:  40px; }
.cot-thoi-gian { width: 140px; }
.cot-nguoi     { width: 160px; }
.cot-hanh-dong { width: 100px; }
.cot-doi-tuong { width: 130px; }
.cot-ip        { width: 120px; }
.cot-ip-ngan   { width: 110px; }
.cot-ket-qua   { width:  90px; }
.cot-vi-tri    { width: 180px; }

/* Ô chữ dài trong bảng — cắt bớt và thêm dấu ba chấm thay vì kéo rộng cột. */
.o-cat-bot {
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Nhãn thao tác xuất dữ liệu — mang màu thương hiệu Excel, chữ trắng. */
.nhan-excel {
  background: var(--color-excel);
  color: var(--color-text-tren-nen-dam);
}

/* Bốn màu của ô biểu tượng trong thẻ thống kê đầu trang.
   🔴 Trước đây ghi cứng ngay trong mẫu, và HAI trong bốn cặp KHÔNG khớp bảng màu
   ngữ nghĩa của dự án (`#28a745` thay cho `--color-success`, `#721c24` thay cho
   `--color-danger`). Nay dùng đúng token, nên màu khớp phần còn lại của hệ thống. */
.o-bieu-tuong--xanh-duong { background: var(--cap-DT-nen);       color: var(--cap-DT-chu); }
.o-bieu-tuong--xanh-la    { background: var(--color-success-bg); color: var(--color-success); }
.o-bieu-tuong--vang       { background: var(--color-warning-bg); color: var(--color-warning); }
.o-bieu-tuong--do         { background: var(--color-danger-bg);  color: var(--color-danger); }

/* Biểu tượng Excel — giữ đúng màu thương hiệu của Excel, không phải màu dự án. */
.bieu-tuong-excel { color: var(--color-excel); }

/* ── Trang lỗi 404 / 500 ──
   🔵 Chuyển vào đây 19/09 (GĐ 8 đợt ⑤). Trước đó mỗi trang lỗi mang một thẻ
      `<style>` riêng, với màu ghi cứng và HAI BIẾN CSS KHÔNG TỒN TẠI:
      `--color-bg-secondary` và `--color-primary` viết kèm giá trị dự phòng
      `#1e40af` — khác hẳn màu chủ đạo thật `#1a3a5c`. Nghĩa là mã lỗi trên hai
      trang ấy suốt thời gian qua hiện SAI MÀU so với phần còn lại của hệ thống.
   🔴 Cỡ chữ và khoảng cách giữ NGUYÊN từng giá trị. Chỉ đổ bóng là xấp xỉ:
      `0 4px 24px rgba(0,0,0,.08)` → `--shadow-lg` (`0 8px 24px rgba(0,0,0,.12)`). */
.trang-loi {
  background: var(--color-bg-page);
  display: flex; align-items: center; justify-content: center;
  min-height: 100vh;
}
.the-loi {
  background: var(--color-bg-card);
  border-radius: var(--radius-lg);
  padding: var(--space-12) var(--space-10);
  text-align: center;
  max-width: 480px;
  box-shadow: var(--shadow-lg);
}
.ma-loi {
  font-size: var(--font-size-5xl);
  font-weight: var(--font-weight-bold);
  color: var(--color-primary);
  line-height: 1;
}
.bieu-tuong-loi {
  font-size: var(--font-size-4xl);
  color: var(--color-text-disabled);
  margin-bottom: var(--space-4);
}

/* Khung biểu mẫu một cột — giới hạn bề ngang để dòng chữ không dài quá, khó đọc.
   🔴 Thay cho `style="max-width:700px"` / `760px` — 2 chỗ trong biểu mẫu tuyến
   và đoạn tuyến. Gộp về MỘT bề rộng 760px: chênh 60px, không chỗ nào đang dựa
   vào con số 700 cả. */
.khung-bieu-mau { max-width: 760px; }

/* Ẩn một phần tử — JavaScript bật/tắt bằng `classList`, KHÔNG bằng `style.display`.
   🔴 Thay cho `style="display:none"` — doan_di_chung/form_them.html.

   🔴 VÌ SAO CÓ `!important` (PR E2, 24/09/2026 — lỗi thật trên máy chủ):
      Câu nhắc đổi mật khẩu mang `d-flex` của Bootstrap, mà `.d-flex` khai
      `display: flex !important`. `.an-di` không có `!important` nên **thua**:
      JavaScript gắn lớp xong, `classList.contains('an-di')` trả `true`, mà
      `getComputedStyle().display` vẫn là `flex` và khối **vẫn chiếm 1250×54
      trên màn hình**. Cả ba cách tắt câu nhắc *(nút ×, tự tắt 30 giây, sang
      trang khác)* cùng hỏng vì đúng một lý do này.
   🔵 `!important` ở đây là **cùng nghĩa với `.d-none` của Bootstrap** — một
      lớp tiện ích chỉ làm một việc, và việc ấy phải thắng. Đây là ngoại lệ
      có chủ ý, không phải thói quen: đừng thêm `!important` cho lớp khác.

   🔴 VÀ PHẢI LẶP TÊN LỚP — `!important` MỘT MÌNH KHÔNG ĐỦ. Đo tiếp sau khi
      thêm `!important`: câu nhắc **vẫn `display: flex`, vẫn chiếm 1250×54**.
      Lý do: `.d-flex` của Bootstrap cũng có `!important`, hai bên **cùng độ
      đặc hiệu 0-1-0**, mà `base.html` nạp Bootstrap **SAU** tệp này — hoà thì
      **cái nạp sau thắng**. Lặp tên lớp đẩy lên 0-2-0 nên thắng chắc.
      🔵 Cùng một mẹo với `.form-select.form-select:focus` ở khối LẤY NÉT.
   🔴 Ca gác: `tests/test_an_di_an_that.py` — đo **hiển thị thật**
      *(`display` tính toán và ô có còn chiếm chỗ không)*, KHÔNG đo "có lớp". */
.an-di.an-di { display: none !important; }




/* ── Form controls ── */
.form-gt-label {
  display: block;
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-text-secondary);
  margin-bottom: var(--space-1);
}
.form-gt-input {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  font-size: var(--font-size-base);
  font-family: var(--font-family-base);
  color: var(--color-text-primary);
  background: var(--color-bg-card);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.form-gt-input::placeholder { color: var(--color-text-disabled); }

/* ══════════════════════════════════════════════════════════════════════
   LẤY NÉT — MỘT QUY TẮC CHO MỌI Ô NHẬN NHẬP LIỆU (PR E1, 24/09/2026)
   ══════════════════════════════════════════════════════════════════════
   🔴 NƠI KHAI DUY NHẤT. Trước PR E1 có **năm** chỗ tự khai chỉ báo lấy nét,
      mỗi chỗ một kiểu: `.form-gt-input:focus` · `.nhom-ck-the:has(…)` ·
      `.nhom-ck-nut:focus-visible` *(outline 2px)* · `.the-so-lieu--bam` và
      `.sidebar-user-bam` *(chỉ đổi nền)* · `.otg-muc:focus` *(chỉ đổi nền)*.
      Năm kiểu khác nhau trên cùng một hệ thống đọc ra là cẩu thả, và ba
      trong năm chỗ **không đạt tương phản**.

   🔴 VÌ SAO PHẢI NHÂN ĐÔI TÊN LỚP *(`.form-select.form-select:focus`)*:
      `base.html` nạp Bootstrap **SAU** tệp này, nên `.form-select:focus` của
      Bootstrap *(cùng độ đặc hiệu 0-2-0)* sẽ thắng. Viết lặp tên lớp đẩy độ
      đặc hiệu lên 0-3-0 — **không** dùng `!important`, vì `!important` thì
      trang sau không đè lại được khi có lý do chính đáng.

   🔴 `:focus` chứ không chỉ `:focus-visible` cho Ô NHẬP: bấm chuột vào ô nhập
      rồi gõ là việc bình thường, người dùng cần thấy mình đang ở ô nào. Với
      thứ BẤM ĐƯỢC mà không nhập *(thẻ, mục gợi ý)* thì dùng `:focus-visible`
      — bấm chuột vào đó không cần vòng.

   🔴 CHỌN BẰNG CẢ HAI ĐƯỜNG — đo 24/09/2026 trên **128 ô** nhận nhập liệu
      ngoài kho mẫu *(17 tệp)*: chọn **chỉ bằng lớp** thì với tới 121 ô và
      **hụt 7** — bốn ô `form-check-input` *(hộp kiểm, nút chọn)* và ba
      `<select>` **không mang lớp nào**. Nên danh sách dưới đây có hai nhóm:
      · nhóm theo **LOẠI PHẦN TỬ** — lo mọi ô, kể cả ô không lớp;
      · nhóm theo **LỚP lặp hai lần** — chỉ để **đè Bootstrap**, vì Bootstrap
        nạp sau và `.form-control:focus` của nó thắng `input:focus` của ta
        *(0-2-0 > 0-1-1)*.
      Hai nhóm cùng MỘT khai báo, nên vẫn là **một quy tắc**.                */
input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="image"]):focus,
select:focus,
textarea:focus,
.form-gt-input:focus,
.form-select.form-select:focus,
.form-control.form-control:focus,
.form-check-input.form-check-input:focus,
.ocht-o:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
}

/* LỖI THẮNG LẤY NÉT — ô đang báo lỗi giữ viền đỏ, vòng đổi sang đỏ.
   🔴 Không dùng vòng navy cho ô lỗi: hai tín hiệu ngược nhau trên cùng một ô
      *(viền "sai", vòng "đang ổn")* thì người dùng tin cái nào?             */
.form-gt-input[aria-invalid="true"],
.form-select[aria-invalid="true"],
.form-control[aria-invalid="true"],
.ocht-o[aria-invalid="true"] { border-color: var(--color-danger); }
.form-gt-input[aria-invalid="true"]:focus,
.form-select.form-select[aria-invalid="true"]:focus,
.form-control.form-control[aria-invalid="true"]:focus,
.ocht-o[aria-invalid="true"]:focus {
  border-color: var(--color-danger);
  box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color-loi);
}

/* Thứ BẤM ĐƯỢC mà không nhập — cùng vòng, `:focus-visible`. */
.otg-muc:focus-visible,
.the-so-lieu--bam:focus-visible,
.nhom-ck-the:has(.nhom-ck-nut:focus-visible) {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
}
/* Vòng nằm ở THẺ BỌC, nên nút radio bên trong không vẽ vòng thứ hai. */
.nhom-ck-nut:focus-visible { outline: none; }

/* Trên NỀN TỐI — vòng trắng; giữ nền sáng nhẹ đã có của thanh bên. */
.sidebar-user-bam:focus-visible {
  outline: none;
  box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color-toi);
}

/* Ô nhập nằm trong nhóm có nút kèm bên phải (ví dụ nút hiện/ẩn mật khẩu).
   🔴 Vì sao cần: `.form-gt-input` khai `width: 100%`, nên khi đặt trong
   `.input-group` của Bootstrap nó chiếm trọn hàng và đẩy nút xuống dòng dưới.
   Bootstrap chỉ xử lý sẵn cho `.form-control`, không biết tới lớp của ta.
   Thấy ở GĐ 8 đợt ①, trang đăng ký. */
.input-group > .form-gt-input {
  flex: 1 1 auto;
  width: 1%;
  min-width: 0;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.input-group > .form-gt-input + .btn-gt {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  border-left: 0;
}

/* ── Alert/Flash messages ── */
.alert-gt {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  font-size: var(--font-size-sm);
  border: 1px solid transparent;
  display: flex; align-items: flex-start; gap: var(--space-3);
}
.alert-gt-error   { background: var(--color-danger-bg);  border-color: var(--canh-bao-loi-vien); color: var(--canh-bao-loi-chu); }
.alert-gt-success { background: var(--color-success-bg); border-color: var(--canh-bao-thanh-cong-vien); color: var(--canh-bao-thanh-cong-chu); }
.alert-gt-warning { background: var(--color-warning-bg); border-color: var(--canh-bao-nhac-vien); color: var(--canh-bao-nhac-chu); }
.alert-gt-info    { background: var(--color-info-bg);    border-color: var(--canh-bao-tin-vien); color: var(--canh-bao-tin-chu); }

/* ── Empty state ── */
.empty-state {
  text-align: center;
  padding: var(--space-12) var(--space-8);
  color: var(--color-text-muted);
}
.empty-state-icon { font-size: 3rem; margin-bottom: var(--space-4); opacity: .5; }
.empty-state-text { font-size: var(--font-size-md); margin-bottom: var(--space-2); }
.empty-state-hint { font-size: var(--font-size-sm); }

/* ══════════════════════════════════════════════════════════════════════
   TRANG XÁC THỰC — đăng nhập · đăng ký · đăng ký thành công (GĐ 8 đợt ①)
   🔴 Ba trang này KHÔNG kế thừa base.html, vì base.html có thanh bên và
      khối người dùng đang đăng nhập — không hiện ra được khi chưa ai
      đăng nhập. Nên chúng tự dựng trang, và cần một bộ lớp riêng ở đây
      thay cho khối <style> viết tại chỗ.
   🔴 Mọi giá trị lấy từ token. Không ghi cứng màu, cỡ chữ, phông.
   ══════════════════════════════════════════════════════════════════════ */
.trang-xac-thuc {
  background: var(--color-bg-page);
  font-family: var(--font-family-base);
  font-size: var(--font-size-base);
  color: var(--color-text-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: var(--space-4);
}

.hop-xac-thuc {
  background: var(--color-bg-card);
  border-radius: var(--radius-lg);
  padding: var(--space-8);
  box-shadow: var(--shadow-md);
  width: 100%;
  max-width: 380px;
}
/* Biểu mẫu đăng ký nhiều ô hơn nên rộng hơn */
.hop-xac-thuc--rong { max-width: 440px; }

/* ── Khối thương hiệu — trình bày như thanh bên của base.html,
      nhưng trên nền SÁNG nên chữ dùng màu chữ chính, không dùng trắng ── */
.thuong-hieu-xac-thuc {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  text-align: center;
  padding-bottom: var(--space-4);
  margin-bottom: var(--space-5);
  border-bottom: 1px solid var(--color-border);
}
.thuong-hieu-xac-thuc-logo {
  width: 52px;
  height: 52px;
  flex-shrink: 0;
  border-radius: var(--radius-full);
  object-fit: cover;
  border: 2px solid var(--color-border);
  box-shadow: var(--shadow-sm);
}
.thuong-hieu-xac-thuc-ten {
  color: var(--color-primary);
  font-weight: var(--font-weight-bold);
  font-size: var(--font-size-md);
  line-height: var(--line-height-tight);
}
.thuong-hieu-xac-thuc-phu {
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
}

/* Dòng tiêu đề nhỏ dưới khối thương hiệu */
.tieu-de-xac-thuc {
  text-align: center;
  color: var(--color-text-secondary);
  font-size: var(--font-size-md);
  font-weight: var(--font-weight-semibold);
  margin-bottom: var(--space-4);
}

/* ── Dòng gợi ý dưới ô nhập, dùng ở trang đăng ký ──
   🔴 GIỮ NGUYÊN TÊN `hint-text` và hai lớp màu của Bootstrap đi kèm.
      Phần JS kiểm tra dữ liệu trong `dang_ky.html` gán thẳng chuỗi
      'hint-text text-danger' / 'hint-text text-success' vào `className`.
      Đổi tên lớp ở đây là phải sửa JS — mà phiếu cấm đụng phần kiểm tra
      dữ liệu. Nên chỉ chuyển màu sang token, không đổi tên. */
.hint-text {
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  margin-top: var(--space-1);
}
.hint-text.text-danger  { color: var(--color-danger) !important; }
.hint-text.text-success { color: var(--color-success) !important; }

/* Viền ô nhập khi dữ liệu sai hoặc đúng — phần JS kiểm tra dữ liệu
   gắn/gỡ hai lớp này, giữ nguyên tên để không phải sửa JS. */
.form-gt-input.is-invalid { border-color: var(--color-danger); }
.form-gt-input.is-valid   { border-color: var(--color-success); }

/* ── Dấu tích trang đăng ký thành công ── */
.dau-tich-thanh-cong {
  color: var(--color-success);
  font-size: var(--font-size-3xl);
  line-height: 1;
  margin-bottom: var(--space-3);
}

/* Dòng liên kết phụ cuối trang */
.lien-ket-phu-xac-thuc {
  text-align: center;
  font-size: var(--font-size-sm);
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}

/* ══════════════════════════════════════════════════════════════════════
   TRANG MẪU BỘ CHUẨN — /he-thong/bo-chuan (việc 7.6)
   🔴 Chỉ dùng cho trang mẫu. Mọi giá trị lấy từ token, không ghi cứng.
   ══════════════════════════════════════════════════════════════════════ */
.bc-luoi {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: var(--space-3);
}
.bc-o-mau { display: flex; align-items: center; gap: var(--space-2); }
.bc-mau {
  width: var(--space-8); height: var(--space-8); flex: none;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
}
.bc-ten {
  font-family: var(--font-family-mono);
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
}
.bc-dong-chu {
  display: flex; align-items: baseline; gap: var(--space-3);
  padding: var(--space-1) 0;
  border-bottom: 1px solid var(--color-border);
}
.bc-ma {
  background: var(--color-bg-page);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3);
  font-family: var(--font-family-mono);
  font-size: var(--font-size-xs);
  color: var(--color-text-secondary);
  margin-bottom: var(--space-2);
  white-space: pre-wrap;
}
/* Trang mẫu: chỗ trống dưới ô "đang mở gợi ý" (dựng tĩnh) để danh sách NỔI
   không đè lên đoạn mã bên dưới — chỉ dùng trên /he-thong/bo-chuan. */
.bc-cho-noi { min-height: 200px; }
.bc-khoang { background: var(--color-primary-light); width: var(--space-4); }
.bc-bo, .bc-bong {
  width: var(--space-12); height: var(--space-12);
  background: var(--color-bg-card);
  border: 1px solid var(--color-border-strong);
}
.bc-bong { border: none; margin: var(--space-2); }


/* Ô màu — mỗi token một lớp */
.bc-mau--primary { background: var(--color-primary); }
.bc-mau--primary-dark { background: var(--color-primary-dark); }
.bc-mau--primary-light { background: var(--color-primary-light); }
.bc-mau--accent { background: var(--color-accent); }
.bc-mau--accent-light { background: var(--color-accent-light); }
.bc-mau--success { background: var(--color-success); }
.bc-mau--success-bg { background: var(--color-success-bg); }
.bc-mau--warning { background: var(--color-warning); }
.bc-mau--warning-bg { background: var(--color-warning-bg); }
.bc-mau--danger { background: var(--color-danger); }
.bc-mau--danger-bg { background: var(--color-danger-bg); }
.bc-mau--info { background: var(--color-info); }
.bc-mau--info-bg { background: var(--color-info-bg); }
.bc-mau--bg-page { background: var(--color-bg-page); }
.bc-mau--bg-card { background: var(--color-bg-card); }
.bc-mau--bg-hover { background: var(--color-bg-hover); }
.bc-mau--border { background: var(--color-border); }
.bc-mau--border-strong { background: var(--color-border-strong); }
.bc-mau--text-primary { background: var(--color-text-primary); }
.bc-mau--text-secondary { background: var(--color-text-secondary); }
.bc-mau--text-muted { background: var(--color-text-muted); }
.bc-mau--text-disabled { background: var(--color-text-disabled); }

/* Cỡ chữ */
.bc-co--xs { font-size: var(--font-size-xs); }
.bc-co--sm { font-size: var(--font-size-sm); }
.bc-co--base { font-size: var(--font-size-base); }
.bc-co--md { font-size: var(--font-size-md); }
.bc-co--lg { font-size: var(--font-size-lg); }
.bc-co--xl { font-size: var(--font-size-xl); }
.bc-co--2xl { font-size: var(--font-size-2xl); }
.bc-co--3xl { font-size: var(--font-size-3xl); }

/* Khoảng cách */
.bc-khoang--1 { height: var(--space-1); }
.bc-khoang--2 { height: var(--space-2); }
.bc-khoang--3 { height: var(--space-3); }
.bc-khoang--4 { height: var(--space-4); }
.bc-khoang--5 { height: var(--space-5); }
.bc-khoang--6 { height: var(--space-6); }
.bc-khoang--8 { height: var(--space-8); }
.bc-khoang--10 { height: var(--space-10); }
.bc-khoang--12 { height: var(--space-12); }

/* Bo góc */
.bc-bo--sm { border-radius: var(--radius-sm); }
.bc-bo--md { border-radius: var(--radius-md); }
.bc-bo--lg { border-radius: var(--radius-lg); }
.bc-bo--xl { border-radius: var(--radius-xl); }
.bc-bo--full { border-radius: var(--radius-full); }

/* Đổ bóng */
.bc-bong--xs { box-shadow: var(--shadow-xs); border-radius: var(--radius-md); }
.bc-bong--sm { box-shadow: var(--shadow-sm); border-radius: var(--radius-md); }
.bc-bong--md { box-shadow: var(--shadow-md); border-radius: var(--radius-md); }
.bc-bong--lg { box-shadow: var(--shadow-lg); border-radius: var(--radius-md); }
.bc-bong--xl { box-shadow: var(--shadow-xl); border-radius: var(--radius-md); }

/* ══════════════════════════════════════════════════════════════════════
   THANH TỈ LỆ trong bảng — GĐ 8 đợt ②
   🔴 Thay cho `<div class="progress" style="height:6px; max-width:80px">`
      cộng `<div class="progress-bar" style="width:NN%">`.
      Bề rộng là DỮ LIỆU, nên không thể đưa vào lớp CSS. Dùng thẻ `<progress>`
      của chính HTML: giá trị đi qua thuộc tính `value`, không qua `style`.
      ⟹ hết ba chỗ `style=` rời mà vẫn giữ nguyên diện mạo.
   ══════════════════════════════════════════════════════════════════════ */
.thanh-ti-le {
  appearance: none;
  -webkit-appearance: none;
  width: 80px;
  height: 6px;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--color-border);
  overflow: hidden;
  vertical-align: middle;
}
.thanh-ti-le::-webkit-progress-bar {
  background: var(--color-border);
  border-radius: var(--radius-full);
}
.thanh-ti-le::-webkit-progress-value {
  background: var(--color-primary);
  border-radius: var(--radius-full);
}
.thanh-ti-le::-moz-progress-bar {
  background: var(--color-primary);
  border-radius: var(--radius-full);
}

/* Ô số phần trăm cạnh thanh tỉ lệ — giữ bề ngang cố định để các dòng
   thẳng cột, thay cho `style="min-width:42px"`. */
.o-ti-le {
  min-width: 52px;
  display: inline-block;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* ═══════════════════════════════════════════════════════
   TRANG BẢN ĐỒ
   🔵 Chuyển vào đây 19/09 (GĐ 8 đợt ④). Trước đó nằm trong một thẻ `<style>`
      ngay trong `templates/ban_do.html` — trang cuối cùng của dự án còn dùng
      cách ấy. 🔴 Mọi mã màu đã đổi sang token; hình dạng giữ nguyên.
═══════════════════════════════════════════════════════ */
#map {
  height: calc(100vh - var(--topbar-height) - 5rem);
  width: 100%;
  border-radius: var(--radius-lg);
  /* Tạo stacking context riêng: toàn bộ z-index bên trong Leaflet (controls,
     panes) được gom vào đây, không còn cạnh tranh với thanh bên trái. */
  position: relative;
  z-index: 1;
}
.leaflet-bottom.leaflet-left { bottom: 30px; }
.leaflet-popup-content { font-size: var(--font-size-sm); min-width: 180px; }
.popup-title { font-weight: var(--font-weight-bold); margin-bottom: var(--space-1); }

/* Nút nổi trên bản đồ — nút mở bộ lọc và nút đóng panel.
   🔴 Mang lớp `btn-gt` để đi qua cổng chuẩn giao diện, nhưng ghi đè đệm và cỡ:
   đây là nút chỉ có biểu tượng, nằm đè lên bản đồ, không phải nút trong biểu mẫu. */
.btn-gt-noi {
  width: 30px; height: 30px;
  padding: 0;
  justify-content: center;
  background: var(--color-bg-card);
  color: var(--color-text-secondary);
  border-color: transparent;
  box-shadow: var(--shadow-sm);
  font-size: var(--font-size-sm);
}
.btn-gt-noi:hover { background: var(--color-bg-hover); color: var(--color-text-primary); }
.btn-gt-noi--nho  { width: 22px; height: 22px; box-shadow: none; flex-shrink: 0; }

/* Nút mở bộ lọc — luôn ở góc trên-phải của bản đồ */
#btn-map-filter { position: absolute; top: 10px; right: 10px; z-index: 91; }

/* Panel bộ lọc — trượt vào/ra từ phải */
#sidebar-map {
  position: absolute;
  top: 10px;
  right: 44px;                /* cách nút mở bộ lọc 4px */
  width: 180px;
  z-index: 90;                /* dưới --z-sidebar (100) */
  background: var(--color-bg-card);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  transform: translateX(0);
  opacity: 1;
  transition: transform var(--transition-base), opacity var(--transition-fast);
}
#sidebar-map.collapsed {
  transform: translateX(calc(100% + 54px));   /* trượt hẳn ra ngoài */
  opacity: 0;
  pointer-events: none;
}
.sidebar-map-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--space-2);
  border-bottom: 1px solid var(--color-border);
  border-radius: var(--radius-md) var(--radius-md) 0 0;
}
#sidebar-map-body { padding: var(--space-2); }
.nhan-bo-loc { font-size: var(--font-size-xs); color: var(--color-text-muted); }

/* Vạch màu trong bộ lọc — cùng vai trò với ô màu trong chú giải, nhưng là NÉT
   đường nên dài và mỏng. Màu do dữ liệu truyền vào qua biến. */
.vach-mau {
  display: inline-block;
  width: var(--vach-dai, 16px);
  height: 3px;
  border-radius: 2px;
  vertical-align: middle;
  margin-right: var(--space-1);
  background: var(--vach-mau, currentColor);
}
.vach-mau--ngan { --vach-dai: 14px; height: 2px; }

/* Màu của từng vạch — tám cấp, cộng hai nguồn dữ liệu.
   🔴 Đây là lớp TĨNH chứ không phải style động: màu cấp quản lý là một trong
   tám giá trị biết trước, khai trong `:root`. Chỉ màu do NGƯỜI DÙNG nhập
   (tình trạng mặt đường) mới cần style động. */
.vach-cap-QL { background: var(--cap-QL-net); }
.vach-cap-DT { background: var(--cap-DT-net); }
.vach-cap-DX { background: var(--cap-DX-net); }
.vach-cap-CT { background: var(--cap-CT-net); }
.vach-cap-NT { background: var(--cap-DO-net); }
.vach-cap-TX { background: var(--cap-TX-net); }
.vach-cap-CD { background: var(--cap-CD-net); }
.vach-cap-DK { background: var(--cap-DK-net); }
.vach-cap-DO { background: var(--cap-DO-net); }
.vach-cap-LT { background: var(--cap-LT-net); }
.vach-cap-LX { background: var(--cap-LX-net); }
.vach-cap-TT { background: var(--cap-TT-net); }
.vach-cap-NX { background: var(--cap-NX-net); }
.vach-cap-ND { background: var(--cap-ND-net); }
.vach-cap-SX { background: var(--cap-SX-net); }
.nguon-db      { background: var(--color-text-primary); }
.nguon-geojson { background: var(--cap-geojson); }

@media (max-width: 575px) {
  #sidebar-map { width: min(180px, calc(100vw - 64px)); }
}

/* ══════════════════════════════════════════════════════════════════════
   MA TRẬN QUYỀN — trang /he-thong/phan-quyen (phiếu 2a)

   🔴 Ba màu, ba NGUỒN của một ô tick. Đặc tả 5.3 đòi *"ô nào khác nhóm thì
      tô màu khác, nhìn là biết"* — nên màu ở đây không phải trang trí, nó
      là thứ **mang thông tin**:

        theo nhóm   → màu chữ thường, không nổi bật
        tick riêng  → 🟦 màu thông tin — đây là ô ai đó đã đặt riêng
        ô khóa      → 🟧 màu cảnh báo — chỉ chủ hệ thống mở được

   🔵 Toàn bộ dùng token có sẵn, không ghi cứng một mã màu nào.
   ══════════════════════════════════════════════════════════════════════ */
.nhan-quyen--nhom  { color: var(--color-text-muted); }
.nhan-quyen--rieng { color: var(--color-info); }
.nhan-quyen--khoa  { color: var(--color-warning); }

.chu-giai-quyen .nhan-quyen {
  display: inline-block;
  margin-right: var(--space-3);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-xs);
}
.chu-giai-quyen .nhan-quyen--nhom  { background: var(--color-bg-hover); }
.chu-giai-quyen .nhan-quyen--rieng { background: var(--color-info-bg); }
.chu-giai-quyen .nhan-quyen--khoa  { background: var(--color-warning-bg); }

/* ── Menu tài khoản — phiếu `fix/tu-doi-mat-khau-va-tim-kiem` (Y2) ────────
   Hai chỗ bấm mở CÙNG một menu: khối tên ở góc trái dưới thanh bên, và tên
   ở góc phải trên. Lớp ở đây chỉ làm cho chúng *bấm được*; nội dung menu
   khai một lần trong `templates/base.html`.                              */
.sidebar-user-bam {
  cursor: pointer;
  border-radius: var(--radius-sm);
  padding: var(--space-1) var(--space-2);
  margin: calc(var(--space-1) * -1) calc(var(--space-2) * -1);
  transition: background-color var(--transition-fast);
}
.sidebar-user-bam:hover,
.sidebar-user-bam:focus-visible { background: var(--tren-navy-10); }
/* 🔵 Vòng trắng khi lấy nét: khối LẤY NÉT DÙNG CHUNG (PR E1). */

.topbar-tai-khoan {
  color: var(--color-text-secondary);
  font-size: var(--font-size-sm);
  display: inline-flex;
  align-items: center;
}
.topbar-tai-khoan:hover { color: var(--color-text-primary); }

/* 🔴 Thanh bên có `overflow` riêng, nên menu mở từ khối tên góc trái dưới
   bị CẮT nếu không nâng lên trên. Đây là chỗ đã hỏng thật ở `2.3.0` với ô
   ghim mép phải của bảng — cùng một họ lỗi: thứ nằm gọn trong khung vẫn có
   thể bị khuất.                                                          */
.sidebar-user .dropdown-menu { z-index: var(--z-dropdown); }

/* Ô tìm và bộ lọc trên trang tài khoản — phiếu Y4, tạm thời (xem ghi chú
   trong `templates/he_thong/nguoi_dung.html`).

   🔴 Phải viết KÈM `.card-gt-header` cho đủ độ cụ thể: `base.html` nạp tệp
      này TRƯỚC `bootstrap.min.css`, nên với cùng một mức cụ thể thì luật của
      Bootstrap (`.form-select { width: 100% }`) thắng. Viết một lớp trơn thì
      ba ô giãn hết bề ngang rồi rơi xuống ba dòng — đã thấy tận mắt trên ảnh
      chụp, còn số đo thì vẫn "đúng". */
.card-gt-header .o-tim-tai-khoan { width: 240px; max-width: 100%; }
.card-gt-header .o-loc-tai-khoan { width: auto; min-width: 140px; }

/* ══════════════════════════════════════════════════════════════════════════
   THẺ SỐ LIỆU — đặc tả 8.6, macro `the_so_lieu` trong kho mẫu
   ══════════════════════════════════════════════════════════════════════════
   Hai cỡ: thẻ LỚN cao khoảng gấp đôi thẻ nhỏ, và mang hai con số (số tuyến,
   số km). Thẻ nhỏ mang một con số.

   🔴 KHÔNG có dòng chú thích trong thẻ — đặc tả nói rõ, giải thích bằng
      tooltip. Nên ở đây không có lớp nào cho chú thích.
   🔴 Mọi màu, khoảng cách, bán kính lấy từ token. Không ghi cứng gì.        */
.the-so-lieu {
  /* 🔴 THẺ NHỎ LÀ MỘT HÀNG — tên bên trái, số bên phải, cùng một dòng.
        Chủ dự án chốt 21/09 vòng hai: thẻ phải chiếm ít chiều cao, nhường
        diện tích cho danh sách tuyến đường bên dưới. Hai dòng cho một con
        số là tốn chỗ mà không thêm thông tin gì.                          */
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  text-decoration: none;
  color: inherit;
  transition: box-shadow var(--transition-fast), border-color var(--transition-fast);
}
.the-so-lieu-nhan {
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: .03em;
  /* 🔵 Chiếm hết chỗ còn lại để đẩy con số sang mép phải. Tên dài nhất —
        "Đã trả lại, chờ xã sửa" — vẫn xuống dòng được chứ không bị cắt.  */
  flex: 1 1 auto;
  min-width: 0;
}
.the-so-lieu-so { flex: 0 0 auto; }
.the-so-lieu-so {
  font-size: var(--font-size-xl);
  font-weight: var(--font-weight-bold);
  color: var(--color-text-primary);
  line-height: 1.2;
}
.the-so-lieu-so-2 {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  font-weight: var(--font-weight-medium);
}
.the-so-lieu-don-vi { font-weight: var(--font-weight-normal); }
/* Biểu tượng: thẻ nhỏ để cạnh tên; thẻ lớn vẫn ở góc phải trên. */
.the-so-lieu-bieu-tuong {
  flex: 0 0 auto;
  order: -1;
  font-size: var(--font-size-sm);
  opacity: .55;
}
.the-so-lieu--lon .the-so-lieu-bieu-tuong {
  float: right;
  order: 0;
  font-size: var(--font-size-lg);
}

/* Thẻ LỚN — ba dòng xếp dọc: tên · số tuyến · số km.
   🔴 Đệm CẮT BỚT so với bản đầu (`space-4/space-5` → `space-3`): bản ấy cao
      104px, phần lớn là khoảng trống. Cỡ chữ và cỡ số KHÔNG đổi — thứ bỏ đi
      là chỗ trống, không phải thông tin.                                  */
.the-so-lieu--lon {
  display: block;
  padding: var(--space-3) var(--space-3);
}
.the-so-lieu--lon .the-so-lieu-so { font-size: var(--font-size-3xl); }
.the-so-lieu--lon .the-so-lieu-nhan { flex: none; }

/* Bấm được: đổi con trỏ và nhấc nhẹ khi trỏ vào.
   🔵 Thẻ không bấm được thì KHÔNG có hai thứ ấy — người dùng phải phân biệt
      được thẻ nào bấm được mà không cần thử.                               */
.the-so-lieu--bam { cursor: pointer; }
.the-so-lieu--bam:hover {
  box-shadow: var(--shadow-sm);
  border-color: var(--color-border-strong);
}
/* 🔵 Lấy nét: khối LẤY NÉT DÙNG CHUNG (PR E1) — không khai lại ở đây. */

/* Đang chọn — viền đậm hơn hẳn, không chỉ đậm hơn một chút.
   🔴 Dùng `box-shadow` làm viền thứ hai thay vì tăng `border-width`: tăng bề
      dày viền làm THẺ TO RA và cả hàng thẻ nhảy chỗ khi bấm.               */
.the-so-lieu--chon {
  border-color: var(--color-primary);
  box-shadow: inset 0 0 0 1px var(--color-primary);
}

/* Sáu màu nền nhẹ. Mỗi thẻ một màu — đặc tả 8.6. */
.the-so-lieu--xanh_duong { background: var(--cap-DT-nen); }
.the-so-lieu--vang       { background: var(--color-warning-bg); }
.the-so-lieu--xanh_la    { background: var(--color-success-bg); }
.the-so-lieu--do         { background: var(--color-danger-bg); }
.the-so-lieu--tim        { background: var(--cap-CT-nen); }
/* 🔴 `xam` KHÔNG còn là trắng. Bản đầu dùng `--color-surface` (#ffffff),
      nên hai thẻ "Dự thảo" và "Tuyến chưa có đoạn" trông như không có nền —
      lệch với luật "nền nhẹ, mỗi thẻ một màu" của đặc tả 8.6.            */
.the-so-lieu--xam        { background: var(--color-bg-hover); }

/* ══════════════════════════════════════════════════════════════════════
   HÀNG THẺ THEO CẤP ĐƯỜNG — đặc tả 8.6, ngoại lệ 3 hàng (chốt 22/09)
   ══════════════════════════════════════════════════════════════════════ */
.hang-cap {
  /* 🔴 MỘT DÒNG VUỐT NGANG, không xuống dòng — đặc tả 8.6 nói rõ cho cỡ
        điện thoại. Năm ô xuống thành năm dòng thì hàng 3 cao hơn cả hai
        hàng trên cộng lại, và người dùng phải cuộn mới thấy danh sách.   */
  display: flex;
  gap: var(--space-2);
  overflow-x: auto;
  /* 🔵 Giữ cho ô không bị bóp lại thành cột chữ dựng đứng khi thiếu chỗ. */
  scroll-snap-type: x proximity;
  /* Ẩn thanh cuộn ngang trên máy tính — vuốt/kéo vẫn được.
     🔵 Không dùng `scrollbar-width: none` một mình: Chrome cần cả hai. */
  scrollbar-width: thin;
}
.hang-cap > .the-so-lieu {
  /* 🔴 `flex: 0 0 auto` — KHÔNG cho co lại. Để `1 1 auto` thì ở 390 năm ô
        chia nhau 390px, mỗi ô ~70px, và chữ "Đường xã" xuống thành ba dòng. */
  flex: 0 0 auto;
  min-width: 11rem;
  scroll-snap-align: start;
}
/* 🔵 Dấu gạch chéo giữa số tuyến và số km — sinh bằng CSS, KHÔNG viết vào
      kho mẫu. Đặc tả 8.6 viết dạng `Tổng số  49 / 2.531,67 km`.          */
.hang-cap .the-so-lieu-so-2::before {
  content: "/ ";
  color: var(--color-text-muted);
}
/* Ở màn hình rộng thì năm ô chia đều cho hết bề ngang, không dồn về trái. */
@media (min-width: 768px) {
  .hang-cap > .the-so-lieu { flex: 1 1 0; min-width: 9rem; }
  .hang-cap { overflow-x: visible; }
}


/* ══════════════════════════════════════════════════════════════════════
   Ô CHỈ HIỂN THỊ — macro `o_chi_xem` (PR A)
   ══════════════════════════════════════════════════════════════════════
   Giá trị hệ thống tự gắn / tự cấp: người dùng ĐỌC, không sửa.

   🔴 CHIỀU CAO PHẢI BẰNG `.form-gt-input` — MỘT NGUỒN, KHÔNG GHI CỨNG.
      Chủ dự án chốt 23/09: ô này **không bấm, không sửa, không nằm trong
      vòng Tab**, nên ngưỡng chạm 44px **không áp dụng**; nó phải cao đúng
      bằng ô nhập thường để hai khung **thẳng cả đỉnh lẫn đáy**.
      🔴 Cách giữ một nguồn — đo thật 23/09, hai ô ra **cùng một bộ số**:
          đệm dọc `8px + 8px`  ← cùng `var(--space-2)`
          cỡ chữ  `14px`       ← cùng `var(--font-size-base)`
          viền    `1px + 1px`  ← cùng khai `1px solid`
          dòng    `21px`       ← 🔴 **KHÔNG khai ở cả hai nơi**, cùng THỪA
                                  KẾ từ một chỗ. Tổng: 8+8+21+1+1 = **39px**.
      🔴 **ĐỪNG khai `line-height` ở đây.** Đã thử: đặt
      `var(--line-height-base)` (1,6) cho ra **22,4px**, trong khi ô nhập
      đang thừa kế **21px** — khai thêm là **phá** đúng phép khớp này.
      🔴 **Đừng đặt `height` hay `min-height` bằng số** — cũng cắt sợi dây ấy.
      Ô nhập đổi cỡ *(DANH SÁCH CHỜ 78 — nâng mọi ô nhập lên 44px)* thì ô
      này **tự đổi theo**, không phải sửa hai nơi.

   🔵 Mọi màu lấy từ token có sẵn. Đo tương phản WCAG AA cho **bốn cặp của
      riêng ô này**: 4/4 đạt, thấp nhất **6,86:1** *(biểu tượng khóa trên nền
      xám)*. 🔵 Tính cả `nhom_co_khong` thì **13/13 cặp đạt** và cặp thấp nhất
      là **6,07:1** *(dấu `*` đỏ trên nền trắng)* — đừng chép nhầm 6,86 thành
      "thấp nhất của cả 13".                                              */
.o-chi-xem {
  /* 🔴 Thẻ là `<output>` (gắn nhãn được, ngoài vòng Tab). Trình duyệt cho
        `<output>` mặc định `display: inline`, nên PHẢI ép về flex ở đây. */
  display: flex;
  align-items: center;
  gap: var(--space-2);
  /* ── Ba thứ dưới đây PHẢI trùng `.form-gt-input` (cùng token) ──
        Thứ tư — chiều cao dòng — CỐ Ý không khai, để cùng thừa kế.     */
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  font-size: var(--font-size-base);
  /* ─────────────────────────────────────────────────────────────── */
  border-radius: var(--radius-md);
  background: var(--color-bg-page);
  color: var(--color-text-primary);
  /* 🔴 Giá trị dài phải XUỐNG DÒNG, không tràn ngang ở 390 (mục 3c). */
  overflow-wrap: anywhere;
}
/* 🔴 KHÔNG có phép lấy nét — ô này ĐỨNG NGOÀI vòng Tab (chốt 23/09).
      Ô không bấm, không sửa; để trong vòng Tab là bắt người dùng bàn phím
      đi qua hai ô "chết" trước khi tới ô nhập đầu tiên. Nhãn vẫn nối với
      giá trị bằng `for` ↔ `id` nên trình đọc màn hình vẫn đọc đủ.
      Ca gác: `tests/test_thanh_phan_bieu_mau.py`.                       */
.o-chi-xem-bt { flex: 0 0 auto; color: var(--color-text-muted); }
.o-chi-xem-gt { flex: 1 1 auto; min-width: 0; }
.o-chi-xem-ct {
  margin-top: var(--space-1);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* ══════════════════════════════════════════════════════════════════════
   NHÓM CHỌN MỘT TRONG HAI — macro `nhom_co_khong` (PR A)
   ══════════════════════════════════════════════════════════════════════
   🔴 Trạng thái chọn hiện BẰNG CSS (`:has(:checked)`), không cần JavaScript.
   🔵 `:has()` chạy trên mọi trình duyệt hiện hành; trình duyệt cũ không hiểu
      thì thẻ vẫn bấm được và nút tròn vẫn hiện đúng — chỉ mất phần tô nền.  */
.nhom-ck { border: 0; padding: 0; margin: 0; min-width: 0; }
.nhom-ck-hoi {
  float: none;                      /* bỏ mặc định của <legend> */
  width: auto;
  padding: 0;
  margin-bottom: var(--space-2);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-text-primary);
}
/* Dấu * bắt buộc — MỘT nguồn cho cả nhóm Có/Không lẫn ô nhập có gợi ý (PR A2). */
.nhom-ck-sao, .dau-bat-buoc { color: var(--color-danger); }

/* 390: xếp dọc — 1440: hai thẻ nằm ngang, chia đều. */
.nhom-ck-the-hang { display: flex; flex-direction: column; gap: var(--space-2); }
@media (min-width: 768px) {
  .nhom-ck-the-hang { flex-direction: row; }
  .nhom-ck-the { flex: 1 1 0; }
}

/* Cả khối bấm được, không riêng chấm tròn. */
.nhom-ck-the {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  min-height: 44px;
  padding: var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-bg-card);
  cursor: pointer;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
.nhom-ck-the:hover { background: var(--color-bg-hover); }
.nhom-ck-nut { flex: 0 0 auto; margin-top: 2px; width: 18px; height: 18px;
  accent-color: var(--color-primary); cursor: pointer; }
.nhom-ck-chu { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.nhom-ck-nhan {
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-primary);
}
.nhom-ck-ct { font-size: var(--font-size-sm); color: var(--color-text-muted); }

/* Đang chọn — viền đậm màu chính, nền nhạt. */
.nhom-ck-the:has(.nhom-ck-nut:checked) {
  border-color: var(--color-primary);
  border-width: 2px;
  /* 🔴 Trừ lại đúng 1px đệm cho phần viền dày thêm, để thẻ KHÔNG nhảy
        kích thước lúc chọn — chỗ này nhìn rất rõ khi hai thẻ nằm cạnh. */
  padding: calc(var(--space-3) - 1px);
  background: var(--color-bg-page);
}
/* 🔵 Lấy nét bàn phím của thẻ Có/Không: khai ở khối LẤY NÉT DÙNG CHUNG
   phía trên (PR E1) — ở đây cố ý KHÔNG khai lại. */

.nhom-ck-loi {
  margin-top: var(--space-2);
  font-size: var(--font-size-sm);
  color: var(--color-danger);
}

/* ══ Ô CHỌN CÓ TÌM (macro `o_chon_co_tim`) — PR E1, 24/09/2026 ══
   Ô chữ + nút × + ô ẩn giữ mã. Dùng lại `.o-tim-goi-y--noi` (danh sách nổi)
   và `.otg-*` đã có — KHÔNG dựng bản thứ hai của danh sách gợi ý. */
.ocht { position: relative; }
/* Chừa chỗ cho nút × nằm đè lên mép phải ô chữ. */
.ocht-o { padding-right: calc(var(--space-3) + 20px); }
.ocht-xoa {
  position: absolute;
  right: var(--space-2);
  top: 50%;
  transform: translateY(-50%);
  border: none;
  background: none;
  padding: var(--space-1);
  line-height: 1;
  color: var(--color-text-muted);
  cursor: pointer;
}
.ocht-xoa:hover { color: var(--color-text-primary); }
/* Dòng phụ dưới tên trong một mục gợi ý ("Của xã · dự thảo"). */
.otg-phu { color: var(--color-text-muted); font-size: var(--font-size-sm); }
/* Mục đang được nhắm bằng phím ↑ ↓ — KHÁC với mục đang rê chuột, và phải
   thấy rõ vì người dùng bàn phím không có con trỏ để nhìn theo. */
.otg-muc--nham { background: var(--color-bg-page); box-shadow: inset 3px 0 0 var(--color-primary); }

/* Câu lỗi dưới một ô chọn (macro `o_chon`, tham số `loi`) — PR E1. */
.oc-loi {
  margin-top: var(--space-1);
  font-size: var(--font-size-sm);
  color: var(--color-danger);
}
.nhom-ck--loi .nhom-ck-the { border-color: var(--color-danger); }
.nhom-ck-chu-thich {
  margin-top: var(--space-2);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* ══════════════════════════════════════════════════════════════════════════
   PHIẾU G (24/09/2026) — BỐ CỤC TRANG BIỂU MẪU · THANH NÚT · CHÚ THÍCH RÊ
   CHUỘT · Ô LÝ TRÌNH · VÁ DANH SÁCH GỢI Ý BỊ CHE
   ══════════════════════════════════════════════════════════════════════════ */

/* ── ① BA MỐC BỀ NGANG — KHAI ĐÚNG MỘT CHỖ ────────────────────────────────
   🔴 Ghi ở đây, không rải trong từng tệp. Đổi ý về mốc thì sửa một dòng.
   🔵 CSS chưa cho dùng biến trong `@media`, nên các `@media` bên dưới vẫn
      phải viết số. Bảng này là NGUỒN để đối chiếu — sửa số thì sửa cả hai,
      và `tests/test_ly_trinh_va_bo_cuc.py` so chúng với nhau.

   | Mốc | Từ | Bố cục |
   |---|---|---|
   | hẹp | < 768px | một cột, tràn hết bề ngang |
   | vừa | 768–1599px | một cột, tối đa 1200px |
   | rộng | ≥ 1600px | có vùng phụ ⟹ hai cột · không có ⟹ một cột tối đa 1400px | */
:root {
  --moc-vua: 768px;
  --moc-rong: 1600px;
  --tbm-rong-vua: 1200px;
  --tbm-rong-rong: 1400px;
  --tbm-vung-phu: 420px;      /* trong khoảng 400–440 chủ dự án duyệt */
  --tbm-o-toi-thieu: 220px;   /* bề ngang nhỏ nhất của một ô trong lưới */
}

/* ── ② TRANG BIỂU MẪU — bố cục dùng chung ────────────────────────────────
   Dùng:
     <div class="trang-bieu-mau">
       <div class="tbm-chinh"> …biểu mẫu… </div>
       <aside class="tbm-phu"> …thông tin phụ (TÙY CHỌN)… </aside>
     </div>
   🔴 LUẬT (phiếu M, 25/09/2026): vùng phụ KHÔNG BAO GIỜ ẩn. Dưới 1600px nó
      XẾP XUỐNG dưới vùng chính; khối mang `.tbm-len-dau` (vd khung Quyết định)
      lên ĐẦU trang. `display: contents` cho khối con của vùng phụ xếp thứ tự
      cùng vùng chính. */
.trang-bieu-mau { width: 100%; display: flex; flex-direction: column; }
.tbm-chinh { min-width: 0; }          /* 0 để ô con co được, không tràn lưới */
.tbm-phu { display: contents; }
.tbm-len-dau { order: -1; }

@media (min-width: 768px) {
  .trang-bieu-mau { max-width: 1200px; }
}

@media (min-width: 1600px) {
  /* 🔴 BỎ TRẦN CHUNG CỦA KHUNG TRANG cho trang biểu mẫu — sửa sau DỪNG ẢNH G1
     (chủ dự án, 24/09/2026). `.page-body` khai `max-width: 1400px` và KHÔNG
     căn giữa, nên ở 1920 khung nội dung dừng ở 1.352px và **dồn hết sang
     trái**, chừa một khoảng trống bên phải. Trang biểu mẫu tự quyết bề ngang
     của mình, nên ở đây trả quyền ấy lại cho nó.
     🔵 Phạm vi hẹp: chỉ những trang CÓ `.trang-bieu-mau`. Trang khác giữ
        nguyên trần 1400px như trước. */
  .page-body:has(.trang-bieu-mau) { max-width: none; }

  /* Không có vùng phụ ⟹ một cột, rộng thêm, **CĂN GIỮA**. `:has()` đã dùng ở
     dự án này (nhóm Có/Không dùng `:has(:checked)`), không phải kỹ thuật mới. */
  .trang-bieu-mau:not(:has(> .tbm-phu)) {
    max-width: var(--tbm-rong-rong);
    margin-inline: auto;
  }

  /* Có vùng phụ ⟹ dùng HẾT bề ngang nội dung (lề của `.page-body` giữ nguyên),
     vùng chính co giãn, vùng phụ đúng 420px. */
  .trang-bieu-mau:has(> .tbm-phu) {
    max-width: none;
    display: grid;
    grid-template-columns: minmax(0, 1fr) var(--tbm-vung-phu);
    gap: var(--space-6);
    align-items: start;
  }
  .tbm-phu {
    display: block;
    position: sticky;                 /* dính khi cuộn */
    top: var(--space-6);
  }
  .tbm-len-dau { order: 0; }

  /* 🔴 TRANG CÓ BẢNG DỮ LIỆU cũng bỏ trần 1400px — phiếu H, luật bảng chuẩn
     Y1e. Cùng lý do với trang biểu mẫu ở trên: `.page-body` dừng ở 1400px
     nên ở 1920 khung bảng chỉ còn **1.350px** trong khi màn hình rộng
     1.920px. Bảng mười ba cột phải chen vào chỗ ấy, mà hai bên màn hình thì
     bỏ trống. Đo trước khi sửa: cột cộng lại 1.546px ⟹ thừa 196px. */
  .page-body:has(.trang-bang) { max-width: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   THANH CÔNG CỤ ĐẦU BẢNG — nút "☰ Cột" (phiếu H, luật bảng chuẩn Y1d)
   ══════════════════════════════════════════════════════════════════════════
   🔵 `bang.js` dựng thanh này cho MỌI bảng, nên không có macro kho mẫu:
      không mẫu nào gõ tay ra nó. Luật ghi ở BO_CHUAN_GIAO_DIEN.md mục bảng.
   ────────────────────────────────────────────────────────────────────────── */
/* 🔴 HÀNG LỌC LÀ HÀNG ĐẦU CỦA KHUNG BẢNG thì phải DÙNG HẾT bề ngang.
   `.card-gt-header` là `display: flex`, nên một `<form>` đặt vào đó **co theo
   nội dung**: đo ở 1920 ra biểu mẫu rộng **1.133px** trong khung **1.680px**,
   và `ms-auto` của nhóm nút vì thế **không có chỗ nào để đẩy** — nhóm Xóa lọc ·
   Lọc · Cột dính ngay sau ô lọc cuối thay vì ra mép phải.
   🔵 Phạm vi hẹp: chỉ khung mang `.trang-bang`. Các `<form>` khác nằm trong
   đầu thẻ — ô tìm tài khoản chẳng hạn — giữ nguyên bề ngang theo nội dung. */
.card-gt.trang-bang > .card-gt-header > form {
  flex: 1 1 auto;
  min-width: 0;
}

/* Hàng nhãn dưới tiêu đề trang · một dòng thông tin — phiếu K, demo ⑦.
   Chữ cỡ thường, các mục cách nhau bằng dấu chấm giữa do CSS sinh. */
.hang-nhan,
.dong-thong-tin {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
}

.hang-nhan > * + *::before,
.dong-thong-tin > * + *::before {
  content: "·";
  color: var(--color-text-muted);
  margin-right: var(--space-3);
}

/* 🔴 Màn hình hẹp: mỗi mục MỘT DÒNG và BỎ dấu chấm. Để nguyên thì dấu "·"
   rơi xuống ĐẦU DÒNG sau khi xuống hàng - trông như một gạch đầu dòng lạc. */
@media (max-width: 575.98px) {
  .hang-nhan,
  .dong-thong-tin { display: block; }
  .hang-nhan > *,
  .dong-thong-tin > * { display: block; }
  .hang-nhan > * + *::before,
  .dong-thong-tin > * + *::before { content: none; }
}

/* Thông tin chung: mỗi mục MỘT DÒNG, tự xếp 3 cột ở màn hình rộng. */
.luoi-thong-tin {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--tbm-o-toi-thieu), 1fr));
  gap: var(--space-2) var(--space-4);
}

.luoi-thong-tin--doc { grid-template-columns: 1fr; }

.tt-nhan { color: var(--color-text-muted); }

/* Trang duyệt đề xuất sửa (phiếu L, demo ⑩): ô đổi nền nhạt, giá trị MỚI đậm,
   dòng nhỏ "trước: …" là giá trị đang dùng. Cùng nền với `.hang-nhan-manh`. */
.o-doi { background: var(--color-warning-bg); border-radius: var(--radius-sm);
         padding: 0 var(--space-1); }
.o-doi-truoc { display: block; font-size: var(--font-size-xs);
               color: var(--color-text-muted); font-weight: var(--font-weight-normal); }
/* Ô đổi TRONG BẢNG (phiếu M): chỉ nền — không padding (Tabulator đo lại ô). */
.tabulator-cell.o-doi-o { background: var(--color-warning-bg); }
/* Khung Quyết định — viền đậm để mắt tìm thấy ngay trong vùng phụ. */
.card-gt.the-quyet-dinh { border: 2px solid var(--color-primary); }
/* Bảng có `bamDong`: cả dòng là một liên kết. */
.bang-bam-dong .tabulator-row { cursor: pointer; }

/* Ô chữ dài xuống dòng (`bang_chuan.LOP_XUONG_DONG`): khoảng lý trình hai dòng, ghi chú. */
.tabulator-row .tabulator-cell.o-xuong-dong { white-space: normal; overflow-wrap: break-word; }
/* Lý do của ô "Kiểm tra" (đoạn dùng chung): máy tính rê chuột đọc `title`; màn hẹp hiện luôn dưới nhãn. */
.o-ly-do { display: none; }
.bang-hep .o-ly-do { display: block; margin-top: var(--space-1); font-size: var(--font-size-sm);
                     color: var(--color-text-muted); white-space: normal; }

/* Bảng chuẩn - CHẾ ĐỘ HẸP (việc chờ 113, `cau_hinh(che_do_hep=True)`, chỉ dưới 768px):
   mỗi dòng một khối - ô chính xuống dòng đủ chữ, cột phụ "Nhãn: giá trị" dưới, nút ≥ 44px. */
.bang-hep .tabulator-header { display: none; }
.bang-hep .tabulator-row .tabulator-cell { white-space: normal; overflow-wrap: anywhere; }
.bang-hep .tabulator-row .btn-gt { min-height: 44px; }
.bang-hep .tabulator-responsive-collapse { padding: 0 var(--space-3) var(--space-2) 44px;
                                           border-top: 0; font-size: var(--font-size-sm);
                                           color: var(--color-text-muted); }
.bang-hep .tabulator-responsive-collapse table { width: 100%; }
.bang-hep .tabulator-responsive-collapse td { white-space: normal; overflow-wrap: anywhere; vertical-align: top; }
.bang-hep .tabulator-responsive-collapse td:first-child { white-space: nowrap; width: 1%; }
.bang-hep .tabulator-responsive-collapse td { padding: 0 var(--space-2) 0 0; }
.bang-hep .tabulator-responsive-collapse td:first-child strong { font-weight: var(--font-weight-normal); }
.bang-hep .tabulator-responsive-collapse td:first-child strong::after { content: ":"; }
/* Ít dòng - vừa một trang: ẩn CẢ thanh phân trang, giữ dòng tổng (mọi bảng chuẩn). */
.bang-it-dong .tabulator-footer .tabulator-footer-contents { display: none; }
.bang-it-dong .tabulator-footer:not(:has(.tabulator-calcs-holder)) { display: none; }

/* Thanh phân trang MÀN HẸP, mọi bảng (A2b, chủ dự án duyệt 27/09): một dòng Trước · Trang x/y · Sau · Số dòng;
   bỏ Đầu, Cuối, số trang, chữ nhãn "Số dòng" (ô chọn giữ aria-label). `body` thắng độ ưu tiên CSS Tabulator. */
@media (max-width: 767.98px) {
  body .tabulator .tabulator-footer .tabulator-footer-contents {
    flex-direction: row; flex-wrap: nowrap; align-items: center; justify-content: flex-start;
    gap: var(--space-2); white-space: nowrap; }
  body .tabulator .tabulator-footer .tabulator-paginator { display: contents; }
  body .tabulator .tabulator-footer .tabulator-pages,
  body .tabulator .tabulator-footer .tabulator-page[data-page="first"],
  body .tabulator .tabulator-footer .tabulator-page[data-page="last"] { display: none; }
  body .tabulator .tabulator-footer .tabulator-page[data-page="prev"] { order: 1; }
  body .tabulator .tabulator-footer .tabulator-page-counter { order: 2; }
  body .tabulator .tabulator-footer .tabulator-page[data-page="next"] { order: 3; }
  body .tabulator .tabulator-footer .tabulator-paginator > label { display: none; }
  body .tabulator .tabulator-footer .tabulator-page-size { order: 5; }
  body .tabulator .tabulator-footer .tabulator-page,
  body .tabulator .tabulator-footer .tabulator-page-size { min-height: 44px; margin: 0; }
}

/* Khối "Tính năng đang xây dựng" - macro `dang_xay_dung` (kho mẫu). */
.khoi-dang-xay-dung { display: flex; align-items: center; gap: var(--space-3);
                      padding: var(--space-4); border: 1px dashed var(--color-border-strong);
                      border-radius: var(--radius-md); background: var(--color-bg-hover);
                      color: var(--color-text-muted); }
.khoi-dang-xay-dung-bieu-tuong { font-size: var(--font-size-base); }
.khoi-dang-xay-dung-tieu-de { font-weight: var(--font-weight-semibold); }
.khoi-dang-xay-dung-mo-ta { font-size: var(--font-size-sm); }

.bang-thanh-cong-cu {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--color-border);
}

/* Danh sách tích chọn — cao quá màn hình thì cuộn trong menu, không đẩy
   trang dài ra. Bảng nhiều cột nhất hiện nay là 13 cột. */
.bang-menu-cot {
  max-height: calc(11 * 36px);
  overflow-y: auto;
}

/* 🔴 Cả dòng là `<label>` nên bấm vào CHỮ cũng tích được, không bắt người
   dùng nhắm đúng ô vuông 16px. */
.bang-muc-cot {
  display: flex;
  align-items: center;
  cursor: pointer;
  margin-bottom: 0;
}

/* Lưới ô bên trong biểu mẫu — TỰ DÃN, không cố định số cột.
   🔴 `auto-fit` + `minmax` chứ không `repeat(2, 1fr)`: màn hình rộng thì tự
      thêm cột, màn hình hẹp tự rút về một cột, không cần thêm `@media`. */
.luoi-o {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--tbm-o-toi-thieu), 1fr));
  gap: var(--space-4);
}
.luoi-o > .o-rong-het { grid-column: 1 / -1; }

/* ── ③ THANH NÚT CUỐI BIỂU MẪU ───────────────────────────────────────────
   Máy tính: căn PHẢI — nút chính ngoài cùng phải, nút phụ bên trái nó, nút
   nguy hiểm tách hẳn về bên trái thanh (`.nut-tach-trai`).
   390px: xếp DỌC, nút chính TRÊN CÙNG, mỗi nút cao ≥ 44px (ngưỡng chạm).
   🔴 Thứ tự trong mã nguồn là [nguy hiểm?] [phụ] [chính] — ở màn hình hẹp
      `column-reverse` lật lại nên nút chính lên trên, không phải viết hai
      lần khối nút. */
.thanh-nut {
  display: flex;
  flex-direction: column-reverse;
  gap: var(--space-2);
  margin-top: var(--space-5);
}
.thanh-nut > * { min-height: 44px; }

@media (min-width: 768px) {
  .thanh-nut {
    flex-direction: row;
    justify-content: flex-end;
    align-items: center;
    gap: var(--space-3);
  }
  .thanh-nut > * { min-height: 0; }
  .thanh-nut .nut-tach-trai { margin-right: auto; }
}

/* ── ④ CHÚ THÍCH RÊ CHUỘT ────────────────────────────────────────────────
   Nút (i) cạnh nhãn; khối chú thích hiện khi RÊ CHUỘT hoặc LẤY NÉT BÀN PHÍM.
   🔴 Hiện bằng `:hover`/`:focus-visible` của CSS **và** bằng lớp `.gyn-mo`
      do JavaScript bật — chạm trên điện thoại không sinh `:hover` bền, nên
      phải có đường thứ hai. Esc đóng: xem `static/js/app.js`.
   🔴 Khối chú thích đặt DƯỚI nút, canh trái, nên KHÔNG che ô nhập nằm dưới
      nhãn. */
.goi-y-nhan { position: relative; display: inline-flex; vertical-align: middle; }
.gyn-nut {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; padding: 0;
  margin-left: var(--space-1);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: var(--color-bg-page);
  color: var(--color-text-secondary);
  font-size: 11px; line-height: 1;
  cursor: help;
}
.gyn-nut:hover { background: var(--color-bg-card); color: var(--color-primary); }
/* 🔴 ĐẶT PHÍA TRÊN NHÃN — sửa sau DỪNG ẢNH G1 (chủ dự án, 24/09/2026).
   Bản đầu thả khối chú thích XUỐNG DƯỚI nút (i). Mà nút (i) nằm trên dòng
   nhãn, nên "dưới nút" chính là **chỗ của ô nhập**: khối chú thích đè lên giá
   trị trong ô và lấn xuống cả khối cảnh báo bên dưới. Đặt lên trên thì không
   có gì để đè — phía trên nhãn là khoảng trống giữa hai hàng.
   🔵 Sát mép trên màn hình thì `static/js/app.js` gắn `.gyn-ben` (hoặc
      `.gyn-ben-trai` nếu bên phải không đủ chỗ) để lật SANG NGANG — vẫn không
      đè lên ô của chính nó. Ca kiểm đo **hai khung không giao nhau**. */
.gyn-chu {
  position: absolute; bottom: calc(100% + var(--space-1)); left: 0;
  z-index: var(--z-dropdown);
  min-width: 220px; max-width: 320px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg-card);
  box-shadow: var(--shadow-md);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-normal);
  color: var(--color-text-secondary);
  white-space: normal;
  display: none;
}
.goi-y-nhan:hover .gyn-chu,
.gyn-nut:focus-visible + .gyn-chu,
.goi-y-nhan.gyn-mo .gyn-chu { display: block; }

/* Hai thế lật sang ngang — JavaScript chọn khi phía trên không đủ chỗ. */
.goi-y-nhan.gyn-ben .gyn-chu {
  bottom: auto; top: -4px; left: calc(100% + var(--space-2)); right: auto;
}
.goi-y-nhan.gyn-ben-trai .gyn-chu {
  bottom: auto; top: -4px; left: auto; right: calc(100% + var(--space-2));
}

/* ── ⑤ Ô LÝ TRÌNH — "Km [số] + [mét]" ────────────────────────────────────
   Hai ô số thật, tên trường `<ten>_km` và `<ten>_m`. 🔴 Không phải một ô chữ
   rồi tự tách: ô số cho bàn phím số trên điện thoại và giữ được phép kiểm
   sẵn có của trình duyệt. */
.o-ly-trinh { display: flex; align-items: center; gap: var(--space-2); }
.olt-nhan { color: var(--color-text-secondary); font-weight: var(--font-weight-semibold); }
.olt-km { width: 6.5rem; }
.olt-m { width: 5.5rem; }
.o-ly-trinh .form-gt-input { text-align: right; }

/* ── ⑥ VÁ DANH SÁCH GỢI Ý BỊ CHE ─────────────────────────────────────────
   🔴 ĐO THẬT trước khi sửa (Chrome, khung nhìn 1440, trang Thêm đoạn):
        danh sách   cao 1.301px, từ y=227 đến y=1528
        tổ tiên cắt div.card-gt (`overflow: hidden`), đáy ở **y = 272**
      ⟹ 1.256px trong số 1.301px bị cắt — người dùng chỉ thấy đúng một mục.
      `elementFromPoint` ở giữa mục cuối trả **null**.

   Hai chuyện khác nhau, sửa cả hai:
   ① CẮT — `.card-gt` có `overflow: hidden` để bo góc. Thẻ nào CHỨA một danh
      sách nổi thì thôi cắt. 🔴 Dùng `:has()` chứ không thêm một lớp phải nhớ
      gắn: lớp phải nhớ gắn thì sẽ có ngày quên, và quên ở đây hỏng IM LẶNG —
      trang vẫn chạy, chỉ là danh sách cụt.
   ② DÀI — 20 mục là 1.301px. Giới hạn ~7 dòng rồi cuộn TRONG danh sách. */
.card-gt:has(.o-tim-goi-y--noi) { overflow: visible; }

/* Khung viền mờ quanh một khối demo trên TRANG MẪU — để thấy rõ bố cục chiếm
   tới đâu. 🔵 Chỉ dùng ở `/he-thong/bo-chuan`, không dùng ở trang thật. */
.bc-khung-demo {
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-sm);
  padding: var(--space-4);
  background: var(--color-bg-page);
}

.o-tim-goi-y--noi .otg-ket-qua {
  /* 7 dòng × 44px (ngưỡng chạm của mỗi mục) + chừa chỗ cho dòng tiêu đề */
  max-height: calc(7 * 44px + 40px);
  overflow-y: auto;
}

/* ══════════════════════════════════════════════════════════════════════════
   PHIẾU G — G2.1: DẢI THÔNG TIN TUYẾN · DANH SÁCH ĐOẠN Ở VÙNG PHỤ ·
   NÚT "NỐI TIẾP ĐOẠN CUỐI"
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Dải thông tin tuyến — một hàng chữ ngay dưới ô Tuyến ────────────────
   🔴 Ba số đều do MỘT hàm tầng dịch vụ tính. Ở đây chỉ là cách bày.
   🔵 `flex-wrap` để màn hình hẹp tự xuống dòng, không cần `@media` riêng. */
.dai-tuyen {
  display: flex; flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  align-items: baseline;
  margin-top: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg-page);
  font-size: var(--font-size-sm);
}
.dt-muc { display: inline-flex; gap: var(--space-2); align-items: baseline; }
.dt-nhan { color: var(--color-text-muted); }
.dt-so { font-weight: var(--font-weight-semibold); color: var(--color-text-primary); }
/* Câu "(n đoạn chưa có số liệu)" — màu nhắc, không phải màu lỗi: đây là
   thông tin về dữ liệu còn thiếu, không phải một việc người dùng làm sai. */
.dt-nhac { color: var(--color-warning); }
.dt-nhac:empty { display: none; }

/* ── Danh sách đoạn ở vùng phụ ──────────────────────────────────────────
   🔴 Giới hạn chiều cao rồi cuộn TRONG danh sách — tuyến có thể có vài chục
      đoạn, để nó dài ra là vùng phụ đẩy trang dài gấp đôi. */
.ds-doan {
  list-style: none; margin: 0; padding: 0;
  max-height: 22rem; overflow-y: auto;
}
.ds-doan-muc {
  display: flex; flex-wrap: wrap;
  gap: var(--space-1) var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
  font-size: var(--font-size-sm);
}
.ds-doan-muc:last-child { border-bottom: none; }
.ds-doan-ma { font-weight: var(--font-weight-semibold); color: var(--color-text-secondary); }
.ds-doan-lt { color: var(--color-text-primary); }
/* Đoạn đang sửa — tô nền nhạt để mắt tìm thấy ngay trong danh sách dài. */
.ds-doan-muc--dang-sua { background: var(--color-accent-light); }
.ds-doan-dau { color: var(--color-primary); font-size: var(--font-size-sm); }
.ds-doan-trong { padding: var(--space-2) 0; color: var(--color-text-muted);
  font-size: var(--font-size-sm); }

/* ── Gợi ý điền nhanh "Nối tiếp đoạn cuối: KmX+YYY" ─────────────────────
   Dùng macro `nut(kieu='tran')` của kho mẫu; lớp này chỉ thêm DÁNG CHỮ.
   🔴 Cổng chuẩn giao diện đã bắt đúng chỗ này một lần: bản đầu tôi viết
      `<button>` tay và cổng báo *"nút tự viết, không qua kho mẫu"*. Đó là
      nguyên tắc 9 làm việc đúng như thiết kế.
   🔵 Vì sao KHÔNG dùng `kieu='chinh'`: đây là **gợi ý điền nhanh nằm trong
      một ô**, không phải hành động của biểu mẫu. Cho nó hình dáng nút chính
      là mời người dùng bấm nhầm khi định Lưu. */
.nut-noi-tiep {
  margin-top: var(--space-1);
  color: var(--color-primary);
  font-size: var(--font-size-sm);
  text-decoration: underline;
}
.nut-noi-tiep:hover { color: var(--color-primary-dark); }

/* ══════════════════════════════════════════════════════════════════════════
   THANH NÚT CỐ ĐỊNH ĐÁY — `thanh_nut_day` (phiếu M, demo ⑫). Chỉ ≤ 768px.
   ══════════════════════════════════════════════════════════════════════════ */
.thanh-nut-day { display: none; }
.thanh-nut-day--trung-bay {
  display: flex; gap: var(--space-2); padding: var(--space-2);
  border: 1px solid var(--color-border); border-radius: var(--radius-sm);
}
.thanh-nut-day .btn-gt { flex: 1 1 0; min-height: 44px; justify-content: center; }
/* pham_vi='moi_co' (phiếu N): mọi cỡ, DÍNH đáy vùng nội dung — không đè thanh bên,
   tự chiếm chỗ nên không che nội dung cuối trang. */
.thanh-nut-day--moi-co {
  display: flex; gap: var(--space-2);
  position: sticky; bottom: 0; z-index: 1020;
  margin-top: var(--space-3); padding: var(--space-2) var(--space-3);
  background: var(--color-bg-card); border-top: 1px solid var(--color-border);
}
@media (min-width: 768px) {
  .thanh-nut-day--moi-co { justify-content: flex-end; }
  .thanh-nut-day--moi-co .btn-gt { flex: 0 0 auto; min-width: 140px; }
}
@media (max-width: 767.98px) {
  .thanh-nut-day:not(.thanh-nut-day--trung-bay):not(.thanh-nut-day--moi-co) {
    display: flex; gap: var(--space-2);
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 1030;
    padding: var(--space-2) var(--space-3);
    background: var(--color-bg-card);
    border-top: 1px solid var(--color-border);
  }
  /* Chừa đệm đáy: thanh không che nội dung cuối trang */
  .page-body:has(.thanh-nut-day:not(.thanh-nut-day--trung-bay):not(.thanh-nut-day--moi-co)) { padding-bottom: 88px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   BẢN ĐỒ TỌA ĐỘ TUYẾN — PR 2 bản đồ (29/09/2026): khung bản đồ · bảng "Hệ thống hiểu là…" · ba con số
   ══════════════════════════════════════════════════════════════════════════ */
:root {
  --ban-do-cao-lon: 560px;
  --ban-do-cao-nho: 280px;
  --ban-do-cao-hep: 360px;     /* dưới 768px - vẫn XEM được, không che hết trang */
}
.khung-ban-do {
  width: 100%;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-map-nen);
}
.khung-ban-do--lon { height: var(--ban-do-cao-lon); }
.khung-ban-do--nho { height: var(--ban-do-cao-nho); }
@media (max-width: 767.98px) {
  .khung-ban-do--lon { height: var(--ban-do-cao-hep); }
}
.so-toa-do { font-family: var(--font-family-mono); white-space: nowrap; }
.bang-hieu-la { overflow-x: auto; }
.bang-hieu-la .bhl-hoi td { background: var(--color-warning-bg); }
.bang-hieu-la .bhl-loi td { background: var(--color-danger-bg); }
.ba-con-so { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-2); }
.bcs-o {
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg-page);
}
.bcs-o--xem-lai { border-color: var(--color-warning); background: var(--color-warning-bg); }
.bcs-nhan { font-size: var(--font-size-xs); color: var(--color-text-muted); }
.bcs-so { font-size: var(--font-size-lg); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); }
.bcs-phu { font-size: var(--font-size-xs); color: var(--color-text-secondary); }
.bcs-ghi-chu { margin-top: var(--space-1); font-size: var(--font-size-xs); color: var(--color-text-secondary); }
@media (max-width: 767.98px) {
  .ba-con-so { grid-template-columns: minmax(0, 1fr); }
}

/* ── Nhóm ô tích (kho mẫu `nhom_o_tich`, PR 3 bản đồ) ── */
.nhom-o-tich { border: 1px solid var(--color-border); border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3); margin: 0; min-width: 0; }
.nhom-o-tich legend { float: none; width: auto; padding: 0 var(--space-1); margin-bottom: 0; }
.nhom-o-tich .form-check { margin-bottom: var(--space-1); }

/* ══ TRANG BẢN ĐỒ CHUNG (kho mẫu PR 3 bản đồ, đặc tả 6.1) ══════════════════
   Bố cục: thanh bên trái thu gọn được + vùng bản đồ; < 768px thanh bên là LỚP PHỦ, mặc định ẩn.
   Ba lớp Leaflet (nền → ranh giới → tuyến) do JS đặt pane; màu nét lấy token `--cap-<MÃ>-net`. */
:root {
  --ban-do-thanh-ben-rong: 300px;
  --ban-do-cao-trang: calc(100vh - 128px);
}
.bd-trang { position: relative; display: flex; height: var(--ban-do-cao-trang); min-height: var(--ban-do-cao-lon);
  border: 1px solid var(--color-border); border-radius: var(--radius-md); overflow: hidden;
  background: var(--color-bg-card); }
.bd-trang:fullscreen, .bd-trang.bd-toan-man { height: 100vh; border-radius: 0; }
.bd-trang.bd-toan-man { position: fixed; inset: 0; z-index: var(--z-modal, 1050); }
.bd-thanh-ben { flex: 0 0 var(--ban-do-thanh-ben-rong); width: var(--ban-do-thanh-ben-rong); overflow-y: auto;
  border-right: 1px solid var(--color-border); background: var(--color-bg-page); }
.bd-trang[data-thu="1"] .bd-thanh-ben { display: none; }
.bd-thanh-ben-dau { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
  padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--color-border); }
.bd-tieu-de { font-size: var(--font-size-md); font-weight: var(--font-weight-bold); margin: 0; }
.bd-thanh-ben-than { padding: var(--space-2) var(--space-3); display: flex; flex-direction: column; gap: var(--space-3); }
.bd-muc-ben > .form-gt-label, .bd-muc-ben > h3 { font-size: var(--font-size-sm); font-weight: var(--font-weight-bold);
  color: var(--color-text-secondary); margin-bottom: var(--space-1); }
.bd-vung-ban-do { position: relative; z-index: 0; flex: 1 1 auto; min-width: 0; }   /* tầng riêng: điều khiển Leaflet (z 1000) không đè lớp phủ */
.bd-ban-do { position: absolute; inset: 0; background: var(--color-bg-page); }
.bd-nut-noi { position: absolute; top: var(--space-2); right: var(--space-2); z-index: 500; display: flex;
  gap: var(--space-1); }
@media (max-width: 767.98px) {
  .bd-thanh-ben { position: absolute; left: 0; top: 0; bottom: 0; z-index: 600; width: min(var(--ban-do-thanh-ben-rong), 85vw);
    box-shadow: var(--shadow-lg); }
  .bd-trang:not([data-mo-phu="1"]) .bd-thanh-ben { display: none; }
  .bd-trang[data-thu="1"][data-mo-phu="1"] .bd-thanh-ben { display: block; }
}
/* Thẻ số liệu bản đồ */
.bd-so-lieu { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2); }
.bd-so-o { border: 1px solid var(--color-border); border-radius: var(--radius-sm); padding: var(--space-1) var(--space-2);
  background: var(--color-bg-card); }
.bd-so { font-size: var(--font-size-lg); font-weight: var(--font-weight-bold); color: var(--color-text-primary);
  font-variant-numeric: tabular-nums; }
.bd-so-nhan { font-size: var(--font-size-xs); color: var(--color-text-muted); }
/* Danh sách tuyến nhóm theo cấp */
.bd-ds-tuyen { display: flex; flex-direction: column; gap: var(--space-1); }
.bd-nhom-dau { display: flex; align-items: center; gap: var(--space-1); font-size: var(--font-size-sm);
  font-weight: var(--font-weight-bold); cursor: pointer; }
.bd-dem { margin-left: auto; font-size: var(--font-size-xs); color: var(--color-text-muted); font-weight: normal; }
.bd-nhom-ds { list-style: none; margin: var(--space-1) 0 0; padding: 0; }
.bd-muc-tuyen { display: flex; width: 100%; gap: var(--space-2); align-items: baseline; text-align: left;
  padding: 2px var(--space-2); border-radius: var(--radius-sm); font-size: var(--font-size-sm); }
.bd-muc-tuyen:hover, .bd-muc-tuyen[aria-pressed="true"] { background: var(--color-bg-hover, var(--color-bg-page)); }
.bd-muc-tuyen[aria-pressed="true"] { box-shadow: inset 3px 0 0 var(--color-primary); }
.bd-ma { font-weight: var(--font-weight-bold); color: var(--color-text-primary); white-space: nowrap; }
.bd-ten { color: var(--color-text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bd-muc-tuyen--chua .bd-ma, .bd-muc-tuyen--chua .bd-ten { color: var(--color-text-muted); }
.bd-ghi { margin-left: auto; font-size: var(--font-size-xs); color: var(--color-text-muted); white-space: nowrap; }
/* Chú giải nét */
.bd-chu-giai { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px;
  font-size: var(--font-size-sm); }
.bd-chu-giai .vach-mau { --vach-dai: 22px; height: 4px; }
/* Khung thông tin trên bản đồ (dựng bằng phần tử, không innerHTML) */
.bd-khung-tt { font-size: var(--font-size-sm); min-width: 180px; }
.bd-khung-tt-dau { font-weight: var(--font-weight-bold); color: var(--color-text-primary); }
.bd-khung-tt dl { display: grid; grid-template-columns: auto 1fr; gap: 0 var(--space-2); margin: var(--space-1) 0; }
.bd-khung-tt dt { color: var(--color-text-muted); font-weight: normal; }
.bd-khung-tt dd { margin: 0; }
.bd-nhan-tuyen { font-size: var(--font-size-xs); font-weight: var(--font-weight-bold); color: var(--color-text-primary);
  background: var(--color-bg-card); border: 1px solid var(--color-border); padding: 0 var(--space-1); }
.bd-nhan-xa { font-size: var(--font-size-xs); color: var(--color-text-secondary); background: transparent;
  border: 0; box-shadow: none; padding: 0; }
.bd-nhan-xa--vua { font-size: var(--font-size-sm); }

/* ═══════════════════════════════════════════════════════════════════════════
   TRANG TỔNG QUAN - 8 MẪU (PR Tổng quan, DAC_TA_TONG_QUAN.md 1.2 mục 5, 7, 8, 12.2)
   dải chỉ số · khối biểu đồ · thanh thẻ · nút chế độ tối · nút trình chiếu · dòng "Đang lọc" ·
   ô màu có hoa văn · chú giải một cột. Mọi màu, cỡ, khoảng cách lấy token.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ① Dải chỉ số - khối nền đậm, 4 ô ngang, chữ trắng; ≤ 767px xếp 2 x 2 */
.dai-chi-so { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1px;
  background: var(--dai-chi-so-nen); border-radius: var(--radius-lg); overflow: hidden; }
.dcs-o { display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-4) var(--space-5);
  background: var(--dai-chi-so-nen); color: var(--color-text-tren-nen-dam); text-decoration: none; min-width: 0; }
.dcs-o--bam { cursor: pointer; transition: background var(--transition-fast); }
.dcs-o--bam:hover, .dcs-o--bam:focus-visible { background: var(--color-primary-dark); color: var(--color-text-tren-nen-dam); }
.dcs-nhan { font-size: var(--font-size-lg); font-weight: var(--font-weight-semibold); }
.dcs-so { font-size: var(--font-size-chi-so); font-weight: var(--font-weight-bold); line-height: var(--line-height-tight);
  font-variant-numeric: tabular-nums; white-space: nowrap; }
.dcs-don-vi { font-size: var(--font-size-xl); font-weight: var(--font-weight-semibold); margin-left: var(--space-1); }
.dcs-phu { font-size: var(--font-size-lg); color: var(--dai-chi-so-phu); font-variant-numeric: tabular-nums; }
@media (max-width: 767.98px) {
  .dai-chi-so { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .dcs-o { padding: var(--space-3); }
  .dcs-so { font-size: var(--font-size-3xl); }
  .dcs-nhan, .dcs-phu { font-size: var(--font-size-sm); }
}

/* ② Khối biểu đồ - khung, tiêu đề (20px), vùng vẽ, chú giải (ngang: vẽ trái - chú giải phải; dọc: chú giải dưới) */
.khoi-bd { display: flex; flex-direction: column; min-width: 0; height: 100%; padding: var(--space-4) var(--space-5);
  background: var(--color-bg-card); border: 1px solid var(--color-border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs); color: var(--color-text-primary); font-size: var(--font-size-lg); }
.khoi-bd-dau { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3);
  margin-bottom: var(--space-3); }
.khoi-bd-td { margin: 0; font-size: var(--font-size-2xl); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); }
.khoi-bd-phu { font-size: var(--font-size-sm); color: var(--color-text-secondary); white-space: nowrap; }
.khoi-bd-than { display: flex; flex-direction: column; gap: var(--space-3); flex: 1 1 auto; min-height: 0; }
.khoi-bd--ngang .khoi-bd-than { flex-direction: row; align-items: center; }
.khoi-bd-ve { width: 100%; min-height: 260px; flex: 1 1 auto; }
.khoi-bd--ngang .khoi-bd-ve { flex: 0 0 176px; width: 176px; min-height: 176px; }
/* Thanh xếp chồng chỉ cao ~40px - vùng vẽ không giữ chỗ 260px */
.khoi-bd-ve[data-bieu-do="xep_chong"] { flex: 0 0 44px; min-height: 44px; }
.khoi-bd-chu-giai { flex: 1 1 auto; min-width: 0; }
/* Dòng "Tổng cộng" cuối khối (biểu đồ cấp quản lý) - kẻ phía trên */
.khoi-bd-tong { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--space-2); margin-top: var(--space-2);
  padding-top: var(--space-2); border-top: 1px solid var(--color-border); font-size: var(--font-size-xl);
  font-weight: var(--font-weight-semibold); font-variant-numeric: tabular-nums; }
@media (max-width: 767.98px) {
  .khoi-bd { padding: var(--space-3); }
  .khoi-bd--ngang .khoi-bd-than { flex-direction: column; }
  .khoi-bd--ngang .khoi-bd-ve { flex-basis: auto; }
  .khoi-bd-tong { font-size: var(--font-size-md); }
}

/* ③ Thanh thẻ - hai (hoặc vài) thẻ đầu trang; ≤ 767px chia đều bề ngang, cao ≥ 44px */
.thanh-the { display: flex; gap: var(--space-1); border-bottom: 1px solid var(--color-border); margin: 0 0 var(--space-4);
  padding: 0; list-style: none; }
.tt-the { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); min-height: 44px;
  padding: var(--space-2) var(--space-4); border: 0; border-bottom: 3px solid transparent; background: transparent;
  color: var(--color-text-secondary); font-size: var(--font-size-md); font-weight: var(--font-weight-semibold);
  text-decoration: none; cursor: pointer; margin-bottom: -1px; }
.tt-the:hover { color: var(--color-text-primary); background: var(--color-bg-hover); }
.tt-the[aria-selected="true"], .tt-the.tt-the--chon { color: var(--tt-chon); border-bottom-color: var(--tt-chon); }
.tt-so { display: inline-block; min-width: 1.5em; padding: 0 var(--space-1); border-radius: var(--radius-full);
  background: var(--color-danger); color: var(--color-text-tren-nen-dam); font-size: var(--font-size-xs); text-align: center; }
.tt-so--khong { background: var(--color-text-disabled); }
@media (max-width: 767.98px) {
  .thanh-the--chia-deu .tt-the-o { flex: 1 1 0; }
  .thanh-the--chia-deu .tt-the { width: 100%; padding: var(--space-2); font-size: var(--font-size-sm); }
}

/* ④ ⑤ Nút chế độ tối · nút trình chiếu · nút "Thoát trình chiếu" (nổi góc màn hình khi đang trình chiếu) */
/* Nằm góc phải đầu trang, cuộn theo trang - nổi cố định thì đè lên số khi cuộn; cuộn xuống vẫn thoát bằng Esc */
.nut-thoat-trinh-chieu { position: absolute; top: var(--space-3); right: var(--space-3); z-index: var(--z-toast); }
.nut-thoat-trinh-chieu[hidden] { display: none; }
/* Trang mẫu: giữ nút nổi trong khung (transform tạo khối chứa cho position: fixed) */
.bc-khung-noi { position: relative; transform: translateZ(0); min-height: 56px; }

/* ⑥ Dòng "Đang lọc" - trên danh sách mở từ Tổng quan */
.dong-dang-loc { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3);
  margin-bottom: var(--space-3); border: 1px solid var(--canh-bao-tin-vien); border-radius: var(--radius-md);
  background: var(--color-info-bg); color: var(--canh-bao-tin-chu); font-size: var(--font-size-sm); }
.dong-dang-loc .ddl-so { font-variant-numeric: tabular-nums; }
.dong-dang-loc .ddl-nut { margin-left: auto; }

/* ⑦ Ô màu có hoa văn - "Chưa có thông tin" (sọc chéo trên nền màu) */
.o-mau--hoa-van { background-image: repeating-linear-gradient(45deg, transparent 0 3px, var(--mau-chua-co-soc) 3px 5px); }

/* ⑧ Chú giải một cột - ô màu · tên (một dòng) · km · tỷ lệ; dòng bấm được mở danh sách lọc */
.chu-giai-cot { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-1); width: 100%; }
.cgc-dong { display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; align-items: center; gap: var(--space-2);
  padding: 2px var(--space-2); border-radius: var(--radius-sm); color: var(--color-text-primary); text-decoration: none; }
a.cgc-dong:hover, a.cgc-dong:focus-visible { background: var(--color-bg-hover); color: var(--color-text-primary); }
.cgc-ten { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cgc-km, .cgc-tl { font-variant-numeric: tabular-nums; white-space: nowrap; text-align: right; }
.cgc-km { color: var(--color-text-primary); }
@media (max-width: 767.98px) {       /* đặt SAU luật gốc của .cgc-* - cùng độ ưu tiên thì luật sau thắng */
  /* 390: giữ chữ 16px (đặc tả 5.5); mỗi dòng hai tầng - tên (một dòng) trên, km · tỷ lệ dưới - không dính nhau */
  .cgc-dong { grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: "o ten ten" ". km tl";
    column-gap: var(--space-3); row-gap: 0; padding: var(--space-1) var(--space-2); }
  .cgc-dong > .o-mau { grid-area: o; }
  .cgc-ten { grid-area: ten; }
  .cgc-km { grid-area: km; }
  .cgc-tl { grid-area: tl; min-width: 3.4em; }
}
/* Ô màu chú giải biểu đồ mang cùng viền mảnh với phần biểu đồ (màu nguồn dưới 3:1 vẫn thấy rõ) */
.chu-giai-cot .o-mau { border-color: var(--bd-vien); }
.cgc-tl { color: var(--color-text-secondary); min-width: 3.4em; }

/* NỀN TỐI - chỉ trong khung mang `data-che-do="toi"` (trang Tổng quan, trang mẫu). Chỉ trỏ token, không mã màu. */
[data-che-do="toi"] {
  --color-bg-page:        var(--toi-nen-trang);
  --color-bg-card:        var(--toi-nen-khoi);
  --color-surface:        var(--toi-nen-khoi);
  --color-bg-hover:       var(--toi-ranh);
  --color-border:         var(--toi-vien);
  --color-border-strong:  var(--toi-vien);
  --color-text-primary:   var(--toi-chu);
  --color-text-secondary: var(--toi-chu-phu);
  --color-text-muted:     var(--toi-chu-phu);
  --dai-chi-so-nen:       var(--toi-ranh);
  --bd-vien:              var(--toi-chu);
  --bd-ranh:              var(--toi-ranh);
  --tt-chon:              var(--color-accent);
  background: var(--color-bg-page);
  color: var(--color-text-primary);
}
/* Nút viền trên nền tối: chữ, viền theo token nền tối (màu chủ đạo navy chìm trên nền tối) */
[data-che-do="toi"] .btn-gt-outline { color: var(--color-text-primary); border-color: var(--color-border-strong); }
[data-che-do="toi"] .btn-gt-outline:hover { background: var(--color-bg-hover); color: var(--color-text-primary); }

/* TRÌNH CHIẾU (đặc tả 8.2) - thuộc tính trên <html>: mọi cỡ chữ là rem nên 20px = ~1,25 lần; ẩn menu, thanh tiêu đề,
   thẻ Công việc, hàng nút; nội dung trải hết bề ngang. Nút "Thoát trình chiếu" góc phải đầu trang (`nut_thoat_trinh_chieu`). */
html[data-trinh-chieu] { font-size: 20px; }
html[data-trinh-chieu] .sidebar, html[data-trinh-chieu] .sidebar-overlay, html[data-trinh-chieu] .topbar { display: none; }
html[data-trinh-chieu] [data-an-khi-trinh-chieu] { display: none !important; }   /* thắng tiện ích d-md-inline-flex */
html[data-trinh-chieu] .main-content { margin-left: 0; }
html[data-trinh-chieu] .page-body { max-width: none; padding-top: var(--space-4); }
/* Trước khi in: dựng theo bề ngang trang A4 ngang để biểu đồ vẽ lại đúng cỡ (tong_quan.js, beforeprint) */
html.dang-in .sidebar { display: none; }
html.dang-in .main-content { margin-left: 0; }
html.dang-in .page-body { max-width: 1040px; }
html.dang-in .cgc-ten { white-space: normal; }       /* bản in không cắt tên chú giải - xuống dòng */
/* Chrome xét @media lúc in theo khổ giấy mặc định (dọc, < 768px) dù trang là A4 ngang - luật hẹp bật nhầm.
   Lúc in giữ bố cục máy tính để khớp biểu đồ đã vẽ ở beforeprint */
html.dang-in #trang-tong-quan .col-lg-6 { flex: 0 0 auto; width: 50%; }
html.dang-in .dai-chi-so { grid-template-columns: repeat(4, minmax(0, 1fr)); }
html.dang-in .dcs-o { padding: var(--space-4) var(--space-5); }
html.dang-in .dcs-so { font-size: var(--font-size-chi-so); }
html.dang-in .dcs-nhan, html.dang-in .dcs-phu { font-size: var(--font-size-lg); }
html.dang-in .khoi-bd { padding: var(--space-4) var(--space-5); height: auto; }   /* hàng bị ngắt trang: 100% đo sai, khung ngắn hơn nội dung */
html.dang-in .khoi-bd--ngang .khoi-bd-than { flex-direction: row; }
/* Vòng tròn nhỏ lại khi in để tên chú giải một dòng (đo: "Chưa có thông tin" cần 299px, còn 282px) */
html.dang-in .khoi-bd--ngang .khoi-bd-ve { flex: 0 0 144px; width: 144px; min-height: 144px; }
html.dang-in .khoi-bd-tong { font-size: var(--font-size-xl); }
html.dang-in .cgc-dong { grid-template-columns: auto minmax(0, 1fr) auto auto; grid-template-areas: none;
  column-gap: var(--space-2); padding: 2px var(--space-2); }
html.dang-in .cgc-dong > * { grid-area: auto; }
