/* Bảng màu trung tính ngả xanh (slate) + 1 điểm nhấn hổ phách trầm.
   Nền trang xám nhạt, khối nội dung trắng nổi lên — dịu mắt, phân cấp rõ. */
/* ======================= Phase 30c — CHỮ (self-host, không gọi ra mạng) =======================
   Plus Jakarta Sans cho TIÊU ĐỀ, Be Vietnam Pro cho THÂN. Cả hai OFL 1.1 — bản quyền và toàn văn
   giấy phép để cạnh file font (OFL-*.txt trong chính thư mục này), đúng điều kiện của OFL.

   `unicode-range` CHÉP NGUYÊN từ CSS Google sinh ra, không gõ tay: nhờ nó trình duyệt chỉ tải file
   `vietnamese` khi trang thật sự có ký tự Việt. Bỏ nó đi là mỗi lượt tải thừa ~40KB.

   Chỉ mang hai subset `latin` + `vietnamese`. Ký tự ngoài hai dải đó (Cyrillic, latin mở rộng) rơi
   về font hệ thống — chấp nhận được cho một tool nội bộ tiếng Việt, và ghi ra để không ai tưởng là
   sót. `font-display: swap` để chữ hiện ngay bằng font hệ thống rồi mới đổi, không chớp trắng.

   ⚠️ Plus Jakarta Sans: Google trả về ĐÚNG MỘT file cho cả weight 700 lẫn 800 (nó là font biến
   thiên, có bảng fvar/gvar/STAT). Nên hai @font-face dưới đây CỐ Ý trỏ chung một `src` — đó cũng là
   cách CSS gốc của Google làm. Đừng "dọn cho gọn" thành một khai báo: giữ hai weight rời thì trình
   duyệt chọn đúng nét, và nếu mai này thay bằng font tĩnh thì chỉ cần đổi `src`. */
@font-face {
  font-family: "Plus Jakarta Sans"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("../fonts/plus-jakarta-sans-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Plus Jakarta Sans"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("../fonts/plus-jakarta-sans-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: "Plus Jakarta Sans"; font-style: normal; font-weight: 800; font-display: swap;
  src: url("../fonts/plus-jakarta-sans-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Plus Jakarta Sans"; font-style: normal; font-weight: 800; font-display: swap;
  src: url("../fonts/plus-jakarta-sans-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: "Be Vietnam Pro"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("../fonts/be-vietnam-pro-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Be Vietnam Pro"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("../fonts/be-vietnam-pro-400-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: "Be Vietnam Pro"; font-style: normal; font-weight: 500; font-display: swap;
  src: url("../fonts/be-vietnam-pro-500-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Be Vietnam Pro"; font-style: normal; font-weight: 500; font-display: swap;
  src: url("../fonts/be-vietnam-pro-500-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: "Be Vietnam Pro"; font-style: normal; font-weight: 600; font-display: swap;
  src: url("../fonts/be-vietnam-pro-600-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Be Vietnam Pro"; font-style: normal; font-weight: 600; font-display: swap;
  src: url("../fonts/be-vietnam-pro-600-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: "Be Vietnam Pro"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("../fonts/be-vietnam-pro-700-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Be Vietnam Pro"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("../fonts/be-vietnam-pro-700-vietnamese.woff2") format("woff2");
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}

:root {
  /* ===== BENTO (chế độ SÁNG) — 05/09/2026 =====
     Nền kem ấm + vân chấm, thẻ trắng bo góc. CẤU TRÚC giống hệt bộ tối (cùng khoảng
     cách, cùng bo góc, cùng vị trí) — chỉ khác màu, vân và ánh sáng. Lý do: base.html
     đọc `prefers-color-scheme` MỖI LẦN TẢI TRANG, nên máy để "theo hệ thống" mà tự
     chuyển tối lúc hoàng hôn sẽ đổi chế độ giữa buổi làm. Cùng cấu trúc thì đó là
     bật đèn trong cùng căn phòng; khác cấu trúc thì là dọn sang phòng khác. */
  --bg: #fbf7f1;          /* nền trang — kem ấm */
  --card: #ffffff;        /* khối nội dung */

  /* Phase 30c — THANG BO GÓC. Trước đó 73 chỗ khai tay 15 giá trị khác nhau (4,5,6,7,8,9,10,11,12,
     18px…), tức không có thang nào cả: mỗi lần thêm khối là một lần đoán. Bốn bậc, một hình tròn:
       --r-1 chi tiết nhỏ (chip vuông, mã, chấm màu)   --r-2 ô nhập, tab, thẻ nhỏ
       --r-3 thẻ và khối lớn                            --r-4 khung lớn nhất (hộp đăng nhập)
       --r-tron nút và chip tròn hẳn
     `50%` giữ nguyên ở chỗ cần hình tròn THẬT (nút xoá ảnh, chấm bộ phận) — 999px và 50% khác nhau
     khi phần tử không vuông, nên không gộp. */
  --r-1: 8px;  --r-2: 12px;  --r-3: 16px;  --r-4: 20px;  --r-tron: 999px;
  --chrome: #ffffff;      /* thanh trên + sidebar */
  --card-head: #fdfaf5;   /* nền tiêu đề khối */
  --text: #2b2118;
  /* Ba màu chữ dưới đây KHÔNG lấy từ bản vẽ mà là bản vẽ ĐÃ ĐO RỒI CHỈNH: giá trị vẽ
     tay (#8A7A68 / #9E8D7B / #A2917E) chỉ đạt 3.0–3.9:1, dưới ngưỡng 4.5. Đo ở chỗ
     TỆ NHẤT (tâm chấm vân, không phải nền trơn) rồi làm đậm tới khi đạt. */
  --text-2: #544a3e;      /* 6.63:1 ngay tâm chấm vân — chỗ tệ nhất */
  /* Đậm hơn bản cũ (#78829a). Lý do đo được: chữ mờ trên nền SÁNG chỉ đạt 3.53:1,
     dưới ngưỡng 4.5 — tức đã khó đọc TỪ TRƯỚC khi có vân nền, vân chỉ làm tệ thêm
     (còn 3.17:1). Nay 5.09:1 nền trơn / 4.58:1 ngay tâm chấm vân. Vẫn nhạt hơn hẳn
     --text-2 nên thứ bậc chữ không đổi. Anh Tám nhìn tool 8 tiếng/ngày: dễ đọc thắng đẹp. */
  --muted: #706252;       /* 4.52:1 tâm chấm vân · 5.53:1 nền kem · 5.90:1 thẻ trắng.
                             Bản đầu tôi đo --muted trên THẺ TRẮNG rồi tưởng đạt — sai
                             chuẩn: chữ mờ nằm cả trên nền kem có vân, chỗ đó tệ hơn.
                             Và ba tầng chữ phải CÁCH NHAU ĐỀU về độ sáng (0.017 /
                             0.071 / 0.128) — đạt ngưỡng mà hai tầng sát nhau thì số
                             nói "đúng" còn mắt vẫn không phân biệt được. */
  --border: #ece2d4;
  --border-dam: #d9cbb6;
  /* Nét hình minh hoạ chỗ trống (Phase 19, anh Tám chốt 08/09/2026: "Để mức 2.2"). BIẾN RIÊNG, đừng
     gộp vào --border-dam: biến đó là VIỀN ở 11 chỗ khác (ô nhập, thẻ, đầu bảng, chip, vùng thả ảnh…),
     đậm hình mà đổi nó là đổi diện mạo cả tool mà anh chỉ duyệt cái hình (họ L43). Đo trên nền TỆ NHẤT
     (L39): kem #fbf7f1 → 2.224, thẻ trắng → 2.373 (#bda684 chỉ 2.198 — làm tròn 2 số mới thành "2.20"). Cùng tông
     be ấm của --border-dam, chỉ đậm hơn. Test tính lại từ giá trị này, không gõ tay con số. */
  --minh-hoa-net: #bca583;
  /* ===== Cột FEEDBACK (Phase 24) — xanh lam nhạt, tách hẳn khỏi tông be của cột trái, để liếc một
     cái là biết đang đọc idea gốc hay đọc góp ý. Đo trên nền feedback (chỗ chữ THẬT nằm, không phải
     nền card — L39): --text-2 8.03:1 · --muted 5.48:1 · --fb-chu 7.84:1. Viền 3.01:1 (viền, không
     phải chữ). Nền nhạt hơn card không nhiều nên PHẢI có viền trái đậm mới thấy ranh giới. */
  --fb-nen: #eef4fb;
  --fb-vien: #6f92b6;
  --fb-chu: #1d4e86;

  /* Phase 30b — BA MÀU CỘT của màn Feedback & Duyệt (bản vẽ anh Tám đã duyệt, 10/09/2026).
     Idea gốc hổ phách · Feedback 1 lam · Feedback 2 tím. Ba nút chọn cột mang đúng màu cột nó mở,
     nên người ta nhìn nút là biết sắp mở cái gì. `*-cham` dùng cho chấm tròn trước tiêu đề cột và
     vạch 3px mép trên cột — nó là màu ĐẬM NHẤT nên chỉ được làm hình khối, không được làm chữ.
     KHÁC --fb-*: bộ --fb-* vẫn giữ nguyên cho ô feedback ở TRANG CHI TIẾT (macro o_feedback dùng
     chung — L33). Đổi bộ --fb-* là đổi luôn màu trang chi tiết mà không ai đi nhìn. */
  /* Viền nút chọn cột lúc ĐÓNG. Bản vẽ để --border-dam (#d9cbb6) — đo ra 1.49 với nền trang, dưới
     ngưỡng 3.0 của ranh giới thành phần bấm được; mà nền nút (--card) cũng chỉ hơn nền trang 1.07,
     nên nút đóng gần như tàng hình. #94826a đạt 3.48 với nền trang và 3.71 với nền nút — thấy được
     từ CẢ HAI phía của đường viền, cùng tông kem-nâu nên không phá bảng màu. */
  --fd-nut-vien: #94826a;
  --goc-nen: #fff4e9;  --goc-vien: #bd7c2e;  --goc-chu: #9a4a12;  --goc-cham: #cf6f08;
  --fb1-nen: #e6f4ff;  --fb1-vien: #3d7cb2;  --fb1-chu: #14538d;  --fb1-cham: #2b88cf;
  --fb2-nen: #f0eafe;  --fb2-vien: #7d5bcf;  --fb2-chu: #5b21b6;  --fb2-cham: #9070f0;
  /* Nhãn CẢNH BÁO NHẸ trên một chi tiết (28/09/2026) — nay dùng cho chữ "khung 4:3" ở ô thumbnail.
     Giá trị lấy NGUYÊN từ bản vẽ anh Tám đã duyệt: đo lại tương phản trên bản vẽ là 103 cặp × 2 chế độ,
     0 trượt. Tự bịa màu khác ở đây là làm phép đo ấy không còn nói gì về thứ đang chạy. */
  --ve-nen: #fff8e8;  --ve-vien: #d8a13c;  --ve-chu: #7a5310;
  --primary: #b0561a;         /* hổ phách trầm — nhấn nhưng không chói */
  --primary-dam: #8a4214;
  --primary-nhat: #fdf1e7;    /* nền tab đang chọn */
  --primary-text: #ffffff;
  --danger: #b3261e;
  --danger-nhat: #fdecea;
  --ok: #15803d;
  --input-bg: #ffffff;
  --do-bong: 0 1px 2px rgba(28, 35, 51, 0.06), 0 1px 3px rgba(28, 35, 51, 0.04);

  /* ===== MÀU TRẠNG THÁI IDEA — MỘT NGUỒN DUY NHẤT =====
     Badge và ô số liệu ở Tổng quan cùng ăn bộ này. Trước đây badge tự khai màu
     riêng; tách hai nơi thì ngày đổi màu "đã duyệt" sẽ đổi một chỗ quên chỗ kia,
     badge một màu ô số liệu một màu (đúng bệnh L28).
     GIÁ TRỊ GIỮ Y NGUYÊN màu badge đang chạy — bước này chỉ đổi CÁCH KHAI. */
  --tt-cho-nen: #fdf2dc;  --tt-cho-chu: #9a5b09;  --tt-cho-vien: #f4e0b8;
  --tt-duyet-nen: #e4f4e9; --tt-duyet-chu: #15703c; --tt-duyet-vien: #c8e6d2;
  --tt-loai-nen: #fdecea;  --tt-loai-chu: #b3261e;  --tt-loai-vien: #f6d5d2;
  --tt-tong-nen: #fdf1e7;  --tt-tong-chu: #8a4214;  --tt-tong-vien: #f2ddc9;

  /* ===== MÀU BỘ PHẬN =====
     6 màu đã kiểm tương phản. Bộ phận thứ 7 quay vòng về màu 1 — chấp nhận trùng
     vì TÊN BỘ PHẬN LUÔN HIỆN KÈM, màu không bao giờ là tín hiệu duy nhất. */
  --bp-1: #b0561a;  --bp-2: #2563a8;  --bp-3: #157a5b;
  --bp-4: #8a4fb8;  --bp-5: #b03a5b;  --bp-6: #7a6a1f;

  /* ===== NÚT VẶN — chỉnh mấy số này là đổi cả app, khỏi mở lại 11 tab ===== */
  --van-mau: rgba(139, 106, 58, 0.16); /* vân kem ấm — mọi màu chữ đã đo TẠI TÂM chấm */
  /* Vầng sáng góc trên: CHỈ bộ tối có. Khai ở cả hai bộ để `body` viết một lần —
     token vắng mặt ở một bộ là đúng cái bẫy L38 (im lặng không vẽ, không ai báo). */
  --vang-sang: none;

  /* ===== CHIP VAI TRÒ =====
     Bảng riêng, CỐ Ý không mượn --bp-*: chấm bộ phận và chip vai trò đứng cạnh nhau
     trên cùng một dòng, dùng chung bảng màu là hai thứ khác nghĩa mà cùng màu.
     Chip LUÔN kèm CHỮ vai trò nên màu không bao giờ là tín hiệu duy nhất. */
  --vt-admin-nen: #fdf1e7;  --vt-admin-chu: #8a4214;
  --vt-tp-nen:    #e8f0fb;  --vt-tp-chu:    #1d4e86;
  --vt-tbp-nen:   #e9f2fd;  --vt-tbp-chu:   #1f5a9e;
  --vt-qtv-nen:   #fdf2dc;  --vt-qtv-chu:   #7d4a07;
  --vt-nv-nen:    #f1eee9;  --vt-nv-chu:    #5d5245;
  --vt-kiem-nen:  #e4f4e9;  --vt-kiem-chu:  #15703c;

  /* Nhãn nhóm của khối form — tầng chữ NHẠT NHẤT, lùi về sau. Token MỚI, không sửa
     token nào đang có. Vì sao không dùng --muted: nhãn khối phải nhạt hơn --muted một
     bậc để nó lùi hẳn ra sau nội dung (thang độ sáng bộ sáng: --text .017 → --text-2
     .071 → --muted .128 → nhãn khối .176, cách đều nhau — L39b).
     4.64:1 trên nền thẻ trắng, là nền DUY NHẤT nó nằm lên (nhãn khối luôn ở trong .card). */
  --nhan-khoi: #82725f;
  /* Xanh lá xác nhận, cho dòng "✓ luôn là người đang đăng nhập" (bản mẫu #2e7d5b). */
  --xac-nhan: #2e7d5b;
  --van-thua: 18px;                   /* khoảng cách giữa các chấm */
  --van-cham: 1.4px;                  /* đường kính chấm */
  --minh-hoa-co: 64px;                /* cỡ hình ở các chỗ trống */
  --icon-o-nen: var(--primary-nhat);  /* nền ô bo tròn quanh icon tiêu đề khối */
}
:root[data-theme="dark"] {
  /* ===== STUDIO (chế độ TỐI) — 05/09/2026 =====
     Nền tím than + hai vầng sáng cam–đỏ ở góc trên (xem `body`). Bộ thiết kế RIÊNG,
     không phải bộ sáng bôi đậm.

     THẺ LÀ MÀU ĐẶC, KHÔNG TRONG MỜ — đây là quyết định quan trọng nhất của bộ này.
     Bản vẽ để thẻ `rgba(255,255,255,.045)`; đo ra thì cùng một màu chữ đạt 4.61:1 khi
     thẻ nằm chỗ nền trơn nhưng tụt còn 3.43:1 khi thẻ nằm trên vầng sáng. Tức tương
     phản ĐỔI THEO VỊ TRÍ THẺ TRÊN MÀN HÌNH, và mọi con số đo được chỉ là số trung
     bình — một bảng tương phản trông như bằng chứng mà không đo được thứ thật thì tệ
     hơn không có bảng nào. Thẻ đặc thì số đo là số THẬT. Vầng sáng vẫn thấy ở phần
     nền quanh thẻ, đủ chiều sâu. */
  --bg: #120e1a;
  --card: #1e1a25;        /* ĐẶC — xem chú thích trên */
  --chrome: #171223;
  --card-head: #241f2e;
  --text: #f3edfa;
  --text-2: #c3b8d0;
  --muted: #9c8fa8;       /* 4.82:1 kể cả trên NỀN chỗ vầng sáng mạnh nhất */
  --border: #2e2440;
  --border-dam: #43355c;
  /* Khối tối cũng phải khai (L38: thiếu là tối lặng lẽ mất màu). Nền tệ nhất là THẺ #1e1a25 → ≥2.20,
     nền trang #120e1a → 2.472 (#5a4a78 chỉ 2.184 ở thẻ). Cùng tông tím-xám của --border-dam tối. */
  --minh-hoa-net: #5b4b79;
  /* Cột feedback bản TỐI (L38: khối tối cũng phải khai, thiếu là lặng lẽ mất màu). Đo trên nền
     feedback tối: --text-2 7.55:1 · --muted 4.70:1 · --fb-chu 8.23:1. Xanh lam giữ nguyên vai trò
     "đây là góp ý" ở cả hai chế độ — đổi vai màu giữa hai chế độ là bắt người ta học lại. */
  --fb-nen: #1c2b40;
  --fb-vien: #4d76ad;
  --fb-chu: #9fc7ff;

  /* Ba màu cột bản TỐI (L38: khối tối cũng phải khai đủ, thiếu một biến là lặng lẽ mất màu).
     Giữ nguyên vai trò màu giữa hai chế độ: gốc hổ phách, FB1 lam, FB2 tím — đổi vai giữa sáng và
     tối là bắt người dùng học lại một lần nữa. */
  /* Bản tối: --border-dam (#43355c) đo 1.72 với nền trang. #7a67a3 đạt 3.89 và 3.49. */
  --fd-nut-vien: #7a67a3;
  --goc-nen: #2e2317;  --goc-vien: #b0854a;  --goc-chu: #ffd9ae;  --goc-cham: #f0a955;
  --fb1-nen: #13293d;  --fb1-vien: #3e7fbf;  --fb1-chu: #a7d3ff;  --fb1-cham: #5aa9ec;
  --fb2-nen: #251c3d;  --fb2-vien: #8b6be0;  --fb2-chu: #d3bfff;  --fb2-cham: #a78bfa;
  --ve-nen: #2e2413;  --ve-vien: #8a6a22;  --ve-chu: #f0cf88;   /* cặp tối của nhãn cảnh báo nhẹ — bản vẽ */
  --primary: #ffb084;
  --primary-dam: #ffc9a6;
  --primary-nhat: #2f2036;
  --primary-text: #1a1024;
  --danger: #ff8a7a;
  --danger-nhat: #331a26;
  --ok: #8fe6bc;
  --input-bg: #171223;
  --do-bong: 0 8px 24px rgba(0, 0, 0, 0.45);

  /* Bộ tối THIẾT KẾ RIÊNG, không phải lấy màu sáng bôi đậm: nền tối mà dùng nền
     nhạt của bản sáng thì chữ chìm nghỉm. Giá trị giữ y nguyên badge tối đang chạy. */
  --tt-cho-nen: #3a2a12;   --tt-cho-chu: #f0cd8f;   --tt-cho-vien: #4d3a1c;
  --tt-duyet-nen: #16301f; --tt-duyet-chu: #93d9ac; --tt-duyet-vien: #22462f;
  --tt-loai-nen: #35191a;  --tt-loai-chu: #f0a9a3;  --tt-loai-vien: #4a2523;
  --tt-tong-nen: #2a1f16;  --tt-tong-chu: #f0b384;  --tt-tong-vien: #3d2c1e;

  /* Màu bộ phận bản tối: sáng hơn hẳn để nổi trên nền tối */
  --bp-1: #e8a06a;  --bp-2: #7fb2e8;  --bp-3: #6fcfa1;
  --bp-4: #c6a0e8;  --bp-5: #eb92aa;  --bp-6: #d4c47a;

  --van-mau: rgba(243, 237, 250, 0.05);
  /* Hai vầng sáng cam–đỏ. CỐ Ý chỉ nằm trên NỀN TRANG, không nằm dưới thẻ: thẻ đục
     nên chữ không bao giờ đọc trên gradient. Chỗ sáng nhất của nền = #3a2316, và mọi
     màu chữ có thể rơi lên nền đều đã đo TẠI ĐÓ. */
  --vang-sang:
    radial-gradient(circle at 15% 0%, rgba(217, 119, 6, 0.20), transparent 42%),
    radial-gradient(circle at 85% 8%, rgba(201, 42, 34, 0.16), transparent 40%);

  /* Chip vai trò bản tối — nền lấy từ màu thẻ ĐẶC nên tương phản không đổi theo vị trí */
  --vt-admin-nen: #3a2416;  --vt-admin-chu: #ffb08a;
  --vt-tp-nen:    #1c2b40;  --vt-tp-chu:    #9fc7ff;
  --vt-tbp-nen:   #1c2b40;  --vt-tbp-chu:   #9fc7ff;
  --vt-qtv-nen:   #38290f;  --vt-qtv-chu:   #ffd98a;
  --vt-nv-nen:    #2a2534;  --vt-nv-chu:    #b7aec4;
  --vt-kiem-nen:  #16311f;  --vt-kiem-chu:  #8fe6bc;

  /* Bộ tối: giá trị TRÙNG --muted là đúng, không phải quên đổi — dò theo cùng vai trò
     (giữ sắc tím-xám Studio) thì rơi vào đúng màu đó. 5.62:1 trên thẻ đặc. */
  --nhan-khoi: #9c8fa8;
  --xac-nhan: #8fe6bc;
  --van-thua: 18px;
  --van-cham: 1.4px;
  --minh-hoa-co: 64px;
  --icon-o-nen: var(--primary-nhat);
}

* { box-sizing: border-box; }
body {
  /* Dự phòng đủ dài để trang không đổi hẳn dáng khi font chưa tải xong hoặc tải hỏng. */
  font-family: "Be Vietnam Pro", system-ui, -apple-system, "Segoe UI", sans-serif;
  margin: 0;
  background: var(--bg);
  color: var(--text);
  line-height: 1.5;
}
a { color: var(--primary); }
code { background: var(--card); padding: 0.1em 0.35em; border-radius: var(--r-1); }
small { color: var(--muted); }
h1 small { font-size: 0.55em; font-weight: 400; }

/* ---------- Thanh trên ---------- */
.topbar {
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
  padding: 0.6rem 1.1rem;
  border-bottom: 1px solid var(--border);
  background: var(--chrome);
}
.brand {
  font-weight: 700; color: var(--text); text-decoration: none;
  letter-spacing: -0.01em; font-size: 1.02rem;
}
.nav-user { margin-left: auto; display: flex; align-items: center; gap: 0.5rem; }
.chuong { position: relative; }
.badge-chuong {
  position: absolute; top: -6px; right: -6px; min-width: 1.1rem; padding: 0 0.25rem;
  border-radius: var(--r-tron); background: var(--danger); color: #fff;
  font-size: 0.7rem; line-height: 1.1rem; text-align: center;
}

/* ---------- Sidebar dọc ---------- */
.layout { display: grid; grid-template-columns: 232px 1fr; align-items: start; }
/* Vệt nền cột trái, vẽ SUỐT chiều cao trang.
   Vì sao cần: `.sidebar` là `position: sticky; align-self: start` nên hộp của nó chỉ
   cao đúng một màn hình — trang dài hơn thì nền trắng của nó DỪNG GIỮA CHỪNG, để lộ
   một đường cắt ngang giữa trang. Trên nền xám cũ gần như không thấy; trên nền kem
   Bento thì lộ rõ. Vẽ vệt nền ở tầng `.layout` thì nó cao bằng cả hàng lưới, không
   phụ thuộc hộp sticky. Đường viền phải nằm trong CÙNG một gradient, kẻo viền lại
   dừng ở đúng chỗ cũ. */
.layout:not(.layout--khong-menu) {
  background-image: linear-gradient(
    to right,
    var(--chrome) 0 232px,
    var(--border) 232px 233px,
    transparent 233px
  );
}
/* L20 — chưa đăng nhập thì KHÔNG render <aside class="sidebar">, nên <main> sẽ rơi vào
   đúng cột 232px và teo lại. Đổi hẳn số cột theo trạng thái đăng nhập bằng class do
   base.html đặt qua {% if %} — KHÔNG dùng :has() (hỗ trợ trình duyệt không chắc bằng). */
.layout--khong-menu { grid-template-columns: 1fr; }
.sidebar {
  position: sticky; top: 0; align-self: start;
  background: var(--chrome); border-right: 1px solid var(--border);
  min-height: calc(100vh - 3.3rem); padding: 0.85rem 0.6rem;
}
.sidebar nav { display: flex; flex-direction: column; gap: 0.12rem; }

/* Tab CHÍNH: chữ to hơn, đậm hơn, có icon */
.sidebar-tab {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.52rem 0.7rem; border-radius: var(--r-2);
  text-decoration: none; color: var(--text-2);
  font-size: 0.945rem; font-weight: 500; line-height: 1.3;
}
.sidebar-tab:hover { background: var(--card-head); color: var(--text); }
.sidebar-tab.active {
  background: var(--primary-nhat); color: var(--primary-dam); font-weight: 650;
}
.tab-icon { width: 18px; height: 18px; flex: none; opacity: 0.85; }
.sidebar-tab.active .tab-icon { opacity: 1; }

/* Tab PHỤ: nhỏ hơn, nhạt hơn, thụt vào, có vạch dẫn bên trái */
.sidebar-tab.sub {
  margin-left: 1.45rem; padding: 0.34rem 0.6rem;
  font-size: 0.855rem; font-weight: 450; color: var(--muted);
  border-left: 2px solid var(--border-dam); border-radius: 0 var(--r-1) var(--r-1) 0;
}
.sidebar-tab.sub:hover { background: transparent; color: var(--text-2); }
.sidebar-tab.sub.active {
  background: transparent; color: var(--primary-dam);
  font-weight: 600; border-left-color: var(--primary);
}
.sap-co { color: var(--muted); cursor: default; }

@media (max-width: 900px) {
  .layout { grid-template-columns: 1fr; }
  /* Khổ hẹp không còn cột trái — tắt vệt nền, kẻo nó thành một sọc dọc vô nghĩa. */
  .layout:not(.layout--khong-menu) { background-image: none; }
  .sidebar {
    position: static; min-height: 0; padding: 0.3rem 0.4rem;
    border-right: none; border-bottom: 1px solid var(--border);
  }
  /* min-width: 0 BẮT BUỘC. Ô lưới mặc định là min-width:auto — không co được nhỏ
     hơn nội dung tối thiểu của nó. Thanh menu ngang rộng ~1000px nên ô lưới cũng
     bị đẩy lên 1000px, và overflow-x:auto bên trong KHÔNG BAO GIỜ có tác dụng:
     cả TRANG trượt ngang thay vì chỉ thanh menu trượt. Đo trên máy 390px: trang
     rộng 1014px. Lỗi có sẵn từ trước, phát hiện khi chụp ảnh khổ điện thoại. */
  .sidebar { min-width: 0; }
  /* Bảng nhiều cột rộng hơn màn hẹp thì phải cuộn ngang ĐƯỢC, nhưng KHÔNG được
     đẩy cả trang trượt sang phải.
     Cách đầu tôi thử — `table { display: block }` — chặn được tràn nhưng PHÁ bố cục
     bảng: ô mất chiều rộng tự nhiên, dòng cao vọt lên, giữa các dòng hở khoảng trắng
     lớn. Số đo lúc đó vẫn "sạch" (trang 390px, không tràn) mà ảnh thì hỏng rõ ràng.
     Cách này giữ bảng là BẢNG, chỉ cho vùng nội dung cuộn ngang. */
  main.container { overflow-x: auto; }
  .sidebar nav { flex-direction: row; overflow-x: auto; gap: 0.2rem; min-width: 0; }
  .sidebar-tab { white-space: nowrap; }
  .sidebar-tab.sub { margin-left: 0; border-left: none; border-radius: var(--r-2); }
}
.user-menu { position: relative; }
.user-menu summary { cursor: pointer; list-style: none; }
.user-menu-body {
  position: absolute; right: 0; z-index: 10; min-width: 13rem;
  display: flex; flex-direction: column; gap: 0.5rem;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--r-3);
  padding: 0.75rem; margin-top: 0.4rem; box-shadow: var(--do-bong);
}
.user-menu-body form { margin: 0; }
.menu-sep {
  border-top: 1px solid var(--border); padding-top: 0.4rem; margin-top: 0.15rem;
  color: var(--muted); font-size: 0.78rem;
}
.menu-thay-btn { width: 100%; text-align: left; }

/* ---------- Layout ---------- */
/* <main class="container"> là Ô CỦA LƯỚI .layout. Trong CSS Grid, `margin: auto`
   HUỶ hành vi giãn của ô lưới: phần dư bị margin hấp thụ, ô co lại vừa bằng nội
   dung rồi căn giữa. Hậu quả đo được trên màn 1440px (cột cho phép 1208px):
   Thông báo chỉ dùng 405px, Tổng quan 608px, Thống kê 607px — nội dung chiếm
   một phần ba tới một nửa chiều ngang, phần còn lại là nền trống hai bên.
   Đây chính là thứ anh Tám gọi là "nền trống quá".
   Dùng margin-inline: auto + width: 100% để vừa giãn hết cột vừa giữ trần 1180px
   (trần vẫn cần cho màn hình siêu rộng). */
.container { max-width: 1180px; width: 100%; margin-inline: auto; padding: 1.5rem 1.25rem; min-width: 0; }
/* Phase 31 — màn "Feedback & Duyệt" cần bề ngang: hai cột nội dung cạnh nhau, mỗi cột có ảnh và ô
   gõ. 1180px chia đôi còn ~560px mỗi cột, chật đúng như anh Tám kêu. Nới riêng màn này lên 1600px;
   mọi màn khác vẫn 1180px vì chúng là bảng và form một cột, rộng hơn chỉ làm mắt phải chạy xa. */
body.man-fd-rong .container { max-width: 1600px; }

/* Rộng ra thì BẢNG và LƯỚI được lợi, nhưng ĐOẠN VĂN DÀI lại KHÓ ĐỌC HƠN: mắt đọc
   tốt nhất ở 60–75 ký tự một dòng, kéo ngang 1180px là lạc dòng khi xuống hàng.
   Nên giới hạn riêng bề rộng đọc cho khối văn bản dài — nới đúng chỗ được lợi. */
.be-rong-doc { max-width: 70ch; }
.footer { text-align: center; color: var(--muted); padding: 1.5rem 0 2rem; font-size: 0.85rem; }
/* Phase 30c — KHOẢNG THỞ. Thẻ nới từ 1.05/1.3rem lên 1.35/1.5rem và cách nhau 1.25rem thay vì 1rem.
   Ở khổ hẹp thì KHÔNG nới: 390px chỉ có 375px dùng được, thêm mỗi bên 3px là mất 6px chiều ngang của
   nội dung — chỗ đó đang là thứ hiếm nhất. Xem media query cuối file. */
.card {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r-3); padding: 1.35rem 1.5rem; margin-bottom: 1.25rem;
  box-shadow: var(--do-bong);
}
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
/* Nhóm nút bên phải .card-head: gom nhiều nút thành MỘT con, kẻo `space-between` dàn chúng
   ra khắp chiều ngang. `flex-wrap` để khổ hẹp xuống dòng thay vì tràn. */
.card-head-nut { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  justify-content: flex-end; }   /* khổ hẹp: nút xuống dòng thì vẫn thẳng mép phải */

/* Phân cấp chữ: tiêu đề trang > tiêu đề khối > tiêu đề phụ.
   Tiêu đề dùng Plus Jakarta Sans (chỉ có 700/800 nên KHÔNG đặt font-weight nhỏ hơn ở đây — đặt 400
   thì trình duyệt phải tự làm mảnh chữ ra, nét sẽ méo). */
h1, h2, h3 { font-family: "Plus Jakarta Sans", "Be Vietnam Pro", system-ui, sans-serif; }
h1 { font-size: 1.5rem; letter-spacing: -0.015em; margin: 0 0 0.2rem; }
h2 { font-size: 1.08rem; letter-spacing: -0.01em; margin: 0 0 0.6rem; }
h3.tieu-de-phu {
  font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--muted); font-weight: 650; margin: 1rem 0 0.4rem;
}
.page-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem;
}
.page-sub { color: var(--muted); margin: 0; font-size: 0.9rem; }
.ghi-chu { color: var(--muted); font-size: 0.86rem; margin: 0.5rem 0 0; }
.trong { color: var(--muted); }
.auth-card { max-width: 460px; margin: 2rem auto; background: var(--card);
  border: 1px solid var(--border); border-radius: var(--r-3); padding: 1.5rem; }
.pre { white-space: pre-wrap; }
.mt { margin-top: 1rem; }
.an { display: none !important; } /* utility ẩn — phải thắng cả .btn khai báo sau */
.sua-actions { display: flex; gap: 0.5rem; margin: 0 0 1rem; }

/* ---------- Form ---------- */
label { display: block; margin: 0.6rem 0; }
input[type="text"], input[type="password"], input[type="email"], input[type="url"],
input[type="search"], input[type="date"], input[type="number"], select, textarea {
  width: 100%; padding: 0.45rem 0.65rem; margin-top: 0.2rem;
  border: 1px solid var(--border-dam); border-radius: var(--r-2);
  background: var(--input-bg); color: var(--text); font: inherit;
}
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--primary); outline-offset: 1px; border-color: var(--primary);
}
label.checkbox { display: flex; align-items: center; gap: 0.5rem; }
label.checkbox input { width: auto; }
.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0 1rem; }
.inline-form { display: inline-flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; margin: 0.15rem 0; }
.inline-form input, .inline-form select { width: auto; margin-top: 0; }
.filter-form { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 1rem; }
.filter-form input[type="search"] { flex: 1 1 220px; }
.filter-form select { width: auto; }

/* ---------- Nút ---------- */
.btn {
  display: inline-block; padding: 0.42rem 0.85rem; border-radius: var(--r-tron);
  border: 1px solid var(--border-dam); background: var(--card); color: var(--text);
  font: inherit; font-weight: 500; cursor: pointer; text-decoration: none;
}
.btn:hover { border-color: var(--primary); color: var(--primary-dam); }
/* Nút bị vô hiệu phải NHÌN RA là vô hiệu. Phase 18b thêm hai nút `disabled` (lấy tên kênh
   khi chưa có ID, thêm keyword khi chưa có dòng) và ảnh chụp cho thấy chúng y hệt nút
   thường — trạng thái có trong DOM mà mắt không thấy, đúng họ L38. */
.btn:disabled, .btn[disabled] { opacity: .45; cursor: not-allowed; }

.btn-primary {
  background: var(--primary); color: var(--primary-text); border-color: var(--primary);
}
.btn-primary:hover { background: var(--primary-dam); border-color: var(--primary-dam); color: var(--primary-text); }
.btn-danger { background: transparent; color: var(--danger); border-color: var(--danger); }
.btn-danger:hover { background: var(--danger-nhat); color: var(--danger); border-color: var(--danger); }
.btn-sm { padding: 0.2rem 0.6rem; font-size: 0.85rem; }

/* Chip lọc — hàng lựa chọn nhanh (bộ phận, nguồn dữ liệu…) */
.chip-row { display: flex; gap: 0.4rem; flex-wrap: wrap; align-items: center; margin-bottom: 0.9rem; }
.chip-nhan {
  font-size: 0.76rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--muted); font-weight: 650; margin-right: 0.15rem;
}
.chip {
  padding: 0.28rem 0.75rem; border-radius: var(--r-tron); text-decoration: none;
  border: 1px solid var(--border-dam); background: var(--card);
  color: var(--text-2); font-size: 0.875rem; font-weight: 500;
}
.chip:hover { border-color: var(--primary); color: var(--primary-dam); }
.chip-chon {
  background: var(--primary); border-color: var(--primary);
  color: var(--primary-text); font-weight: 600;
}
.chip-chon:hover { color: var(--primary-text); }
/* 18/09/2026 — hàng Dòng SP của Xu hướng là Ô XỔ (bản vẽ anh Tám duyệt). Đặt NGAY SAU .chip-*: .xo-dong-goi-y cùng độ đặc
   hiệu với .ghi-chu (khai phía trên) nên phải đứng sau mới thắng margin (L15). Chữ ô xổ GIỮ 16px (dưới 16px Safari iPhone
   phóng to trang khi chạm). flex-basis 8rem: khổ 320px nhãn + ô + nút Xem vẫn một hàng; ≥328px bề ngang ô không đổi (ô là
   con duy nhất giãn). Mũi tên là của hệ thống (appearance auto) — padding-right giữ như bản vẽ. */
.xo-dong .chip-nhan { margin: 0 .15rem 0 0; }
.xo-dong select.o-dong { flex: 1 1 8rem; min-width: 0; max-width: min(24rem, 100%); margin: 0; height: 2.1rem;
  padding: .2rem 2rem .2rem .7rem; border-radius: var(--r-tron); border: 1px solid var(--primary);
  background-color: var(--card); color: var(--text); font-weight: 600; font-size: 1rem; }
.xo-dong .btn { flex: none; }
.xo-dong-goi-y { flex-basis: 100%; font-size: .8rem; margin: .1rem 0 0; }
/* Hàng nút của thẻ "dòng chưa có chủ đề" (mục 5); chữ .ghi-chu trong hàng bỏ margin-top để không lệch tâm so với nút */
.the-dong-trong-nut { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.the-dong-trong-nut .ghi-chu { margin: 0; }

/* ---------- Banner đăng nhập thay ---------- */
.impersonate-banner {
  display: flex; align-items: center; justify-content: center; gap: 0.6rem; flex-wrap: wrap;
  padding: 0.45rem 1rem;
  background: #fef3c7; color: #92400e; border-bottom: 1px solid #f59e0b;
}
:root[data-theme="dark"] .impersonate-banner { background: #78350f; color: #fde68a; border-color: #b45309; }

/* ---------- Flash ---------- */
.flash {
  padding: 0.65rem 1rem; border-radius: var(--r-2); margin-bottom: 0.75rem;
  border: 1px solid; border-left-width: 3px; font-size: 0.92rem;
}
.flash-success { border-color: var(--ok); background: #e9f5ed; color: #14663a; }
.flash-error { border-color: var(--danger); background: var(--danger-nhat); color: var(--danger); }
/* Cảnh báo (không phải lỗi, không phải thành công): kênh chọi keyword ở form idea (18c). */
.flash-warning { background: var(--primary-nhat); color: var(--text); border-left: 4px solid var(--primary); }
.flash-info, .flash-message { border-color: var(--primary); background: var(--primary-nhat); color: var(--primary-dam); }
:root[data-theme="dark"] .flash-success { background: #16301f; color: #93d9ac; }

/* ---------- Bảng ---------- */
.table-scroll { overflow-x: auto; }

/* ── ĐỢT I1: trang Theo dõi kênh ───────────────────────────────────────────────────────────────
   ⚠️ Mọi class template gắn PHẢI có luật ở đây. Gắn class mà CSS không có luật nào ăn nó thì cái
   móc ấy **chưa từng làm gì** — và grep ra hai kết quả, nhìn qua tưởng khớp (L43 vế bổ sung). */
.td-them { margin-top: .6rem; }
.td-hang { display: flex; gap: .4rem; flex-wrap: wrap; align-items: center; margin-top: .25rem; }
/* `flex: 1 1 14rem` chứ không `width:100%`: ở khổ hẹp ô tự xuống dòng riêng, ở khổ rộng nó nằm cùng
   hàng với nút — khỏi phải viết media query cho một thứ flex tự làm được. */
.td-hang .td-o { flex: 1 1 14rem; min-width: 0; }
.td-chon { flex: 0 1 12rem; min-width: 0; }
.td-do-form { margin-top: .6rem; }
.td-tinh-trang { margin: 0 0 .3rem; }
.td-phong { white-space: nowrap; }
.td-lech { color: var(--danger); }
.td-bang { font-size: .82rem; }
.td-bang th { white-space: nowrap; }
.td-bang th, .td-bang td { padding: .35rem .5rem; border-bottom: 1px solid var(--border);
  text-align: left; vertical-align: top; }
/* Ô tiêu đề video: một dòng, cắt bằng ba chấm, chữ đủ nằm ở `title`. Không cắt thì một tiêu đề dài
   kéo hàng cao lên trong khi phần người ta THẤY chỉ có mấy chục pixel chữ — đã vấp đúng thế ở H1. */
.td-bang td.td-nd { max-width: 14rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 🔴 MỌI Ô MỘT DÒNG, và bảng thì cuộn ngang — ĐO RỒI MỚI SỬA, không đoán:
   ở 390px cột "Tốc độ" bị ép còn **72px** trong khi nó chứa cả câu *"42 view/giờ — tính trên 5 giờ
   20 phút gần nhất"* ⇒ chữ xuống ~10 dòng ⇒ **hàng cao 170px với ~120px trống**, mà phần trống ấy
   nằm NGOÀI khung nhìn nên mắt chỉ thấy một cái lỗ. Mọi số đo tràn báo sạch (chữ nằm TRONG vùng
   cuộn) — đúng lỗi vừa vấp ở đợt H1, lần này nặng hơn.
   ⛔ KHÔNG chữa bằng cách rút gọn câu: *"tính trên 5 giờ 20 phút gần nhất"* là **vế bắt buộc**, bỏ
   nó đi là biến một con số đã-bị-làm-phẳng thành một con số trông như sự thật.
   ⛔ Cũng KHÔNG nhét lý do vào `title`: §5.3 đòi lý do **đọc được**, mà tooltip thì trên điện thoại
   không có. ⇒ Cho chữ đủ chỗ, để bảng rộng ra, và `.table-scroll` làm đúng việc nó sinh ra để làm. */
.td-bang td { white-space: nowrap; }
/* Bảng "Chờ duyệt mới nhất" (Tổng quan). Bọc .table-scroll xong thì hết tràn, NHƯNG ảnh chụp cho
   thấy bảng bị bóp vừa khung: ô mô tả co còn ~70px, một tên bánh gãy làm bốn dòng. Số đo sạch mà
   ảnh xấu — đúng nửa sau của L30. Cho các ô ngắn nowrap và ô mô tả một bề rộng tối thiểu: bảng giữ
   bề rộng tự nhiên rồi CUỘN, thay vì co lại rồi bẻ chữ. Cùng cách đã dùng cho cột QTV ở màn Kênh. */
.bang-cho-duyet td:nth-child(1),
.bang-cho-duyet td:nth-child(4),
.bang-cho-duyet td:nth-child(5) { white-space: nowrap; }
.bang-cho-duyet td:nth-child(2) { min-width: 15rem; }
/* Bảng Phân quyền: cùng chuyện, cột "Mục" bị bóp đến mức "Xem tab Thống kê" vỡ ba dòng, mỗi dòng
   một chữ. Cho cột đầu bề rộng tối thiểu và nhãn chức danh không bẻ: bảng nở ra rồi CUỘN. */
.bang-phan-quyen td:first-child, .bang-phan-quyen th:first-child { min-width: 11rem; }
.bang-phan-quyen th, .bang-phan-quyen .checkbox { white-space: nowrap; }
table { border-collapse: collapse; width: 100%; }
th, td { text-align: left; padding: 0.55rem 0.7rem; border-bottom: 1px solid var(--border); vertical-align: top; }
th {
  color: var(--muted); font-weight: 650; white-space: nowrap;
  font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em;
  background: var(--card-head); border-bottom-color: var(--border-dam);
}
tbody tr:hover { background: var(--card-head); }
tbody tr:last-child td { border-bottom: none; }

/* ---------- Badge trạng thái ---------- */
.badge {
  display: inline-block; padding: 0.1rem 0.6rem; border-radius: var(--r-tron);
  font-size: 0.78rem; font-weight: 600; white-space: nowrap; border: 1px solid transparent;
}
/* Ăn token --tt-* để badge và ô số liệu Tổng quan không bao giờ lệch màu nhau.
   Bản tối tự đúng vì token đã đổi theo data-theme — không cần khai lại. */
.badge-cho_duyet { background: var(--tt-cho-nen);   color: var(--tt-cho-chu);   border-color: var(--tt-cho-vien); }
.badge-da_duyet  { background: var(--tt-duyet-nen); color: var(--tt-duyet-chu); border-color: var(--tt-duyet-vien); }
.badge-loai      { background: var(--tt-loai-nen);  color: var(--tt-loai-chu);  border-color: var(--tt-loai-vien); }
.badge-link, .badge-role {
  background: var(--card-head); color: var(--muted);
  border-color: var(--border); font-weight: 500;
}

/* ---------- Chi tiết idea ---------- */
.meta-grid { display: grid; grid-template-columns: max-content 1fr; gap: 0.3rem 1.1rem; margin: 0.6rem 0; }
.meta-grid dt { color: var(--muted); font-size: 0.86rem; }
.meta-grid dd { margin: 0; }
.transitions { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 1rem;
  padding-top: 0.75rem; border-top: 1px dashed var(--border); }
.link-list { list-style: none; padding: 0; }
.link-list li { margin: 0.25rem 0; overflow-wrap: anywhere; }
.image-grid { display: flex; gap: 0.75rem; flex-wrap: wrap; margin: 0.5rem 0; }
.image-grid figure { margin: 0; max-width: 220px; position: relative; }   /* relative: neo cho .anh-so */
.image-grid img { max-width: 100%; border-radius: var(--r-2); border: 1px solid var(--border); }
.comment-list { list-style: none; padding: 0; }
.comment-list li { border-bottom: 1px dashed var(--border); padding: 0.5rem 0; }
.comment-list p { margin: 0.25rem 0 0; }
.backup-codes { columns: 2; list-style: none; padding: 0; }
.backup-codes li { margin: 0.3rem 0; }
.qr-box svg { max-width: 220px; height: auto; background: #fff; padding: 8px; border-radius: var(--r-2); }

/* ---------- Đính ảnh (chọn file / kéo-thả / paste) ---------- */
.anh-form { margin-top: 0.5rem; }
.drop-zone {
  position: relative;               /* mốc cho chỉ báo Ctrl+V đặt tuyệt đối */
  border: 2px dashed var(--border); border-radius: var(--r-2);
  padding: 1rem; text-align: center; color: var(--muted);
}
.drop-zone.keo-vao { border-color: var(--primary); color: var(--primary); }
.drop-zone .btn { margin-left: 0.3rem; }
.anh-preview { display: flex; gap: 0.5rem; flex-wrap: wrap; margin: 0.5rem 0; }
.anh-preview figure { position: relative; margin: 0; }
.anh-preview img {
  width: 90px; height: 90px; object-fit: cover;
  border-radius: var(--r-1); border: 1px solid var(--border);
}
/* Phase 22 — số thứ tự ảnh (anh Tám: "ảnh thêm vào được đánh số theo thứ tự"). Góc trên-TRÁI, nút ✕ ở
   góc phải nên không đè nhau. Dùng ở CẢ BA vùng: .image-grid (trang xem) · .anh-preview (khung xem trước) ·
   .anh-san-o-anh (ảnh điền sẵn) — L43: thêm vùng mới thì rà lại. Nền đặc trên mọi nền ảnh. */
.anh-so {
  position: absolute; top: 4px; left: 4px; min-width: 20px; height: 20px; padding: 0 6px;
  border-radius: var(--r-tron); background: var(--card); color: var(--text); border: 1px solid var(--border-dam);
  font-size: .72rem; font-weight: 700; line-height: 18px; text-align: center; pointer-events: none;
}
.anh-preview-xoa {
  position: absolute; top: -6px; right: -6px; width: 22px; height: 22px;
  border-radius: 50%; border: 1px solid var(--border);
  background: var(--card); color: var(--danger); cursor: pointer; line-height: 1;
}

/* ---------- Ảnh ĐIỀN SẴN từ trang Nghiên cứu (Phase 17) ----------
   Cố ý KHÁC .anh-preview (ảnh người dùng vừa chọn): ảnh này người dùng không chọn, máy
   tự bỏ vào, nên phải nhìn ra ngay là "máy đề nghị" và phải thấy đường bỏ đi. Rộng hơn
   ảnh preview để soi được BỐ CỤC thumbnail — đó là công dụng của nó.
   Tỉ lệ 16:9 ghim bằng aspect-ratio: bản medium và bản maxres khác kích thước, không
   ghim thì lúc JS nâng ảnh cả khối nhảy một cái. */
.anh-san { margin: .5rem 0 0; }
.anh-san-o-anh {
  position: relative; margin: 0; width: 160px; max-width: 100%;
}
.anh-san-o-anh img {
  display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: cover;
  border-radius: var(--r-1); border: 1px solid var(--border);
}
.anh-san-bo {
  position: absolute; top: -6px; right: -6px; width: 22px; height: 22px;
  border-radius: 50%; border: 1px solid var(--border);
  background: var(--card); color: var(--danger); cursor: pointer; line-height: 1;
}
.anh-san-nhan { font-size: .65rem; color: var(--muted); margin: .25rem 0 0; max-width: 160px; }

/* ---------- Lightbox xem ảnh ---------- */
/* Con trỏ "bấm để xem to" — bám theo VÙNG mà gan() đã thật sự gắn lightbox.
   Luật cũ là `.image-grid img.xem-duoc`, mà class `xem-duoc` chỉ được idea.js gắn cho
   ảnh trong `.anh-preview`. Hai vế **chưa từng gặp nhau**: luật này chưa bao giờ khớp
   một phần tử nào, nên con trỏ zoom chưa từng chạy ở đâu cả — kể cả trang chi tiết.
   Đúng họ L38: thêm một thứ vào mà nó lặng lẽ không có tác dụng, nhìn ảnh không thấy
   thiếu. Nay đổi mốc sang class do chính gan() đặt ⇒ gợi ý con trỏ không nói dối được. */
.co-lightbox figure > img { cursor: zoom-in; }
.lightbox {
  position: fixed; inset: 0; z-index: 100;
  display: none; align-items: center; justify-content: center; gap: 0.25rem;
  background: rgba(0, 0, 0, 0.88);
}
.lightbox.mo { display: flex; }
.lightbox figure { margin: 0; max-width: 90vw; text-align: center; }
.lightbox img { max-width: 90vw; max-height: 84vh; border-radius: var(--r-2); }
.lightbox figcaption { color: #d1d5db; margin-top: 0.5rem; font-size: 0.9rem; }
.lightbox button {
  background: none; border: none; color: #fff; cursor: pointer;
  font-size: 2.4rem; line-height: 1; padding: 0.5rem 0.75rem;
}
.lightbox-dong { position: absolute; top: 0.75rem; right: 1rem; }

/* ---------- Thống kê ---------- */
/* 4 ô trạng thái nên nằm TRÊN MỘT HÀNG: auto-fit theo bề rộng làm ô thứ 4 rơi
   xuống dòng riêng khi cột nội dung hẹp, để lại một khoảng trống nhìn như lỗi. */
.status-cards { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.75rem; }
@media (max-width: 700px) { .status-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.status-card { background: var(--card-head); border: 1px solid var(--border); border-radius: var(--r-3);
  padding: 0.6rem 0.8rem; display: flex; flex-direction: column; gap: 0.3rem; }
.status-card strong { font-size: 1.55rem; font-weight: 700; letter-spacing: -0.02em; }
.bar { background: var(--border); border-radius: var(--r-tron); height: 8px; overflow: hidden; min-width: 80px; }
.bar-fill { background: var(--primary); height: 100%; }
.status-cards { margin-bottom: 1rem; }

/* ---------- Bộ lọc thời gian (kiểu YouTube Studio) ---------- */
.bo-loc-thoi-gian { display: inline-flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; }
.bo-loc-thoi-gian select, .bo-loc-thoi-gian input { width: auto; margin-top: 0; }
.bo-loc-thoi-gian [hidden] { display: none; }
.cum-thang, .cum-tuy-chinh { display: inline-flex; gap: 0.4rem; align-items: center; }

/* ---------- Hai cột (Tổng quan) ---------- */
.two-col { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 0 1rem; }

/* ---------- Thông báo ---------- */
.tb-list { list-style: none; padding: 0; }
.tb-list li { border-bottom: 1px solid var(--border); }
.tb-list form { margin: 0; }
.tb-dong {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: transparent; border: 0; color: var(--text); font: inherit;
  padding: 0.6rem 0.4rem;
}
.tb-dong:hover { background: var(--card); }
/* Tin không có đích cho người xem (chuyển bộ phận → TP/TBP): không trông như bấm được. Khai NGAY SAU .tb-dong —
   cùng độ đặc hiệu, cái sau thắng (L15 vế bổ sung). */
.tb-dong--yen { cursor: default; }
.tb-dong--yen:hover { background: transparent; }
.tb-list li.chua-doc { background: var(--card); }
.tb-list li.chua-doc .tb-noi-dung { font-weight: 600; }
.tb-noi-dung { display: block; }
.goi-y-tag { display: flex; gap: 0.3rem; flex-wrap: wrap; margin-top: 0.3rem; }

/* Nút Loại nhanh ở hàng chờ duyệt: details/summary thuần HTML, không JS */
.inline-loai { display: inline-block; }
.inline-loai summary { list-style: none; display: inline-block; }
.inline-loai summary::-webkit-details-marker { display: none; }

/* ---------- Phân trang ---------- */
.pagination { display: flex; gap: 0.75rem; align-items: center; justify-content: center; margin: 1rem 0; }

/* ---------- Nghiên cứu định hướng ---------- */
.khoi-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; margin-bottom: 0.85rem;
  padding-bottom: 0.7rem; border-bottom: 1px solid var(--border);
}
.khoi-head h2 { margin: 0; }
/* 17/09/2026 — cụm phải của .khoi-head (số video · giờ · nút Làm mới khối) bọc MỘT thẻ con: .khoi-head giữ đúng 2 con
   (L50). margin-left:auto: khi gãy dòng cụm đứng một mình vẫn bám mép PHẢI (space-between với một phần tử = dính trái). */
.khoi-phai { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; justify-content: flex-end; margin-left: auto; }
/* Câu "bản lưu cũ" ~90 ký tự: chiếm trọn một dòng trong cụm phải (không đẩy cả cụm xuống dưới tiêu đề ở 1440), canh phải */
.khoi-ban-cu { flex-basis: 100%; text-align: right; font-size: .8rem; }
.khoi-sub { margin: 0.35rem 0 0; display: flex; gap: 0.35rem; flex-wrap: wrap; }
.the-tieu-chi {
  padding: 0.1rem 0.5rem; border-radius: var(--r-tron);
  background: var(--card-head); border: 1px solid var(--border);
  color: var(--text-2); font-size: 0.78rem;
}

.video-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(255px, 1fr)); gap: 1rem; }
.video-card {
  margin: 0; background: var(--card); border: 1px solid var(--border);
  border-radius: var(--r-3); overflow: hidden; display: flex; flex-direction: column;
}
.video-card:hover { border-color: var(--border-dam); box-shadow: var(--do-bong); }
.video-thumb { position: relative; display: block; }
.video-thumb img { width: 100%; display: block; aspect-ratio: 16 / 9; object-fit: cover; }
.video-time {
  position: absolute; right: 6px; bottom: 6px;
  background: rgba(15, 19, 25, 0.82); color: #fff;
  padding: 0.05rem 0.35rem; border-radius: var(--r-1); font-size: 0.75rem; font-weight: 600;
}
.video-card figcaption { padding: 0.6rem 0.7rem 0.7rem; display: flex; flex-direction: column; gap: 0.45rem; }
.video-title {
  font-weight: 600; font-size: 0.93rem; line-height: 1.35;
  color: var(--text); text-decoration: none;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.video-title:hover { color: var(--primary-dam); }
.video-meta {
  margin: 0; display: flex; gap: 0.4rem; flex-wrap: wrap; align-items: center;
  font-size: 0.8rem; color: var(--muted);
}
.video-meta strong { color: var(--text-2); font-size: 0.83rem; }
/* 17/09/2026: thích · bình luận (cùng hàng meta) và dòng "Đăng hôm qua · lúc 14:05 12/09/2026" riêng */
.video-so { white-space: nowrap; }
/* Điểm giống của Nexlev trên thẻ video — chỉ trang "Video tương tự" truyền `diem` nên chỉ ở đó mới hiện.
   Khai NGAY SAU .video-so (cùng hàng meta) để thứ tự luật không lệch với thứ tự đọc (L15 vế bổ sung). */
/* Trang "Video tương tự" (23/09/2026) — thẻ gốc to hơn một nhịp, hàng video thiếu thì nhạt và có viền
   đứt để nhìn là biết ngay nó khác các thẻ khác (KHÔNG ẩn đi: vứt hàng là đầu trang ghi 10 mà đếm ra 8). */
.the-goc .video-card { max-width: 34rem; }
.video-thieu { border: 1px dashed var(--border); border-radius: var(--r-2); padding: .7rem; opacity: .85; }
.video-thieu .video-meta { margin: .3rem 0; }
.tag-lap-hang { display: flex; flex-wrap: wrap; gap: .35rem; }

/* ===== Ô "SỨC BẬT" trên thẻ video (24/09/2026) =====
   lượt xem ÷ người đăng ký. Nền cam nhạt theo bản vẽ đã duyệt. `--trong` = không có số (dấu gạch):
   nhạt hẳn đi để mắt không đọc nó như một con số thấp — một ô trông-như-số mà là gạch thì tệ hơn
   một ô rõ ràng là trống. */
.the-suc-bat {
  display: inline-flex; align-items: baseline; gap: .3rem; align-self: flex-start;
  padding: .1rem .45rem; border-radius: var(--r-1);
  background: var(--primary-nhat); border: 1px solid var(--primary);
}
.the-suc-bat b { font-size: 0.95rem; font-weight: 800; color: var(--primary-dam); line-height: 1.1; }
/* 28/09/2026: `.the-suc-bat small` ĐÃ XOÁ cùng lúc bỏ chữ "sức bật" khỏi ô (anh Tám). Xoá chứ không để
   lại: một luật CSS không còn khớp phần tử nào là đúng thứ L43 vế bổ sung đã dọn hai lần trong tuần —
   người sau grep ra nó, tưởng có hiệu lực, rồi sửa nó và không hiểu vì sao không đổi gì.
   Nghĩa của ô nay do MỘT DÒNG CHÚ GIẢI ở tầng trang nói (`.chu-giai-o`, xem dưới). */
/* `--trong` mang HAI nghĩa, cố ý, và phân biệt được bằng CHỮ trong ô — ghi ra kẻo người sau tưởng
   nó chỉ có một nghĩa rồi dùng sai:
     nhạt + "—"   = không có dữ liệu (năm lý do)   ·   nhạt + "1x"  = có dữ liệu nhưng ≤ 1 (kẹp sàn)
     đậm + "1x"   = xấp xỉ bằng 1                  ·   đậm + "3,7x" = số thật
   Ca kẹp sàn phải nhạt vì `1x` của nó là con số KHÔNG ĐÚNG, mà sự thật chỉ nằm trong `title` —
   và điện thoại không có rê chuột. */
.the-suc-bat--trong { background: var(--card-head); border-color: var(--border-dam); }

/* Nhãn "vẫn dùng — chưa kiểm được" của khoá dịch vụ (25/09/2026). KHÔNG dùng màu lỗi: 'chua_kiem'
   nghĩa là CHƯA BIẾT, và khoá vẫn đang được gọi — tô đỏ nó là nói sai bằng màu sắc. */
.kdv-the-cho { background: var(--card-head); border: 1px solid var(--border-dam); color: var(--text-2); }
.the-suc-bat--trong b { color: var(--muted); }

/* ===== DÒNG CHÚ GIẢI Ô SỨC BẬT — tầng TRANG, đúng MỘT lần (28/09/2026) =====
   Sinh ra cùng lúc bỏ chữ "sức bật" khỏi ô: bỏ chữ mà không có dòng này thì trên ĐIỆN THOẠI còn lại một
   con số trơ, vì lời giải nghĩa duy nhất nằm trong `title` — tooltip của con trỏ, điện thoại không có.
   Đặt ở `.page-head` của hai trang, KHÔNG đặt trong `_video_luoi.html` (file đó include cho TỪNG Ô ⇒ hiện
   hàng chục lần) và cũng không đặt trong vùng `.o-muc` (Xu hướng thay cả vùng đó bằng `outerHTML` ⇒ dòng
   chú giải biến mất đúng lúc có nhiều thẻ nhất, mà trang vẫn trông bình thường). Có bài kiểm đếm == 1. */
.chu-giai-o { margin: .35rem 0 0; font-size: 0.82rem; color: var(--muted); }
.chu-giai-o b { color: var(--text-2); font-weight: 700; }

/* ===== KHỐI LẤY THUMBNAIL trên thẻ video (28/09/2026) =====
   Anh Tám: "cho anh thêm 1 nút lấy thumbnails video này". Cấu trúc + màu lấy theo bản vẽ đã duyệt
   (`ban-ve-the-video-3-viec.html`, bản 3) — đừng đổi sang bộ màu khác, phép đo tương phản của phiên
   nghiệm thu chạy trên chính bản vẽ đó.
   `.thumb-bang` do JS dựng ra, KHÔNG có trong HTML máy chủ (bấm mới lấy). */
/* Nút mở bảng — anh Tám 28/09: "cho nút bấm lấy Thumbnails nhỏ lại". Nút đang ở `.btn-sm`, tức BẬC NHỎ
   NHẤT repo có, nên phải viết luật riêng ở đây.
   ⚠️ CỐ Ý KHÔNG đẻ một bậc `.btn-xs` toàn cục: một cỡ mới ở tầng dùng chung là thứ người sau lấy dùng
   bừa, mà đợt này không ai xin nó. Nhỏ mà vẫn phải BẤM TRÚNG ở 390px ⇒ giữ vùng chạm ≥ 2rem chiều cao. */
/* ⚠️ KHÔNG đặt `min-height` ở đây. Bản đầu tôi viết `min-height: 2rem` để "bảo đảm vùng chạm" — ĐO ra
   thì bản CÓ và bản KHÔNG đều cho **42px** như nhau, tức luật ấy CHƯA BAO GIỜ ràng buộc gì: chiều cao
   tự nhiên (emoji nong hộp dòng) đã vượt nó. Một luật không bao giờ ăn là một lớp trông như đang gác mà
   không gác — người sau đọc sẽ tin là có sàn (L42 vế 3).
   SỐ ĐO THẬT ở 390px: 49px (bản `.btn-sm` cũ) → **42px** (bản này) ⇒ đã nhỏ lại, và vẫn ≥ 40px.
   ⚠️ Biên chỉ còn 2px: ai đổi chữ hoặc hạ cỡ chữ nữa thì PHẢI ĐO LẠI, đừng suy. */
.thumb-nut { align-self: flex-start; padding: .12rem .45rem; font-size: 0.76rem; }
.thumb-bang { border: 1px solid var(--border); border-radius: var(--r-2); padding: .7rem; margin-top: .5rem; }

/* HÀNG NÚT CỠ (28/09) — thay cho lưới bày cả bốn ảnh. Bọc dòng được vì bốn nút kèm nhãn là hàng dài
   nhất thẻ này từng có, mà thẻ lại nằm trong lưới hẹp ở Xu hướng (L33). */
.thumb-hang { display: flex; flex-wrap: wrap; gap: .3rem; }
/* Cỡ nút CĂN THEO NÚT APP ĐANG CHẠY, không tự đặt một cỡ mới. Đo ở 390px: nút mức thời lượng và
   "+ Tạo idea" — thứ người dùng bấm hằng ngày trên điện thoại — đều **29px**. Bản đầu tôi để 24px, tức
   NHỎ HƠN chuẩn của chính app, mà đây lại là nút bấm chính của khối. Căn về 29px là ĐỐI CHIẾU với thứ
   đang chạy, không phải phát minh một con số (L53: số mong đợi đến từ một phép đo khác, đừng gõ tay). */
.thumb-co-nut { padding: .25rem .45rem; font-size: 0.74rem; font-variant-numeric: tabular-nums; }
/* Dòng "đã lùi cỡ" — CHỈ hiện khi thật sự lùi, nên nó phải ẩn được chắc chắn (xem luật [hidden] dưới). */
.thumb-lui { margin: .4rem 0 0; font-size: 0.74rem; color: var(--text-2); }
.thumb-xem { margin-top: .5rem; display: flex; flex-direction: column; align-items: flex-start; gap: .3rem; }
.thumb-lai { margin-top: .5rem; }
/* ⚠️ KHÔNG ép `aspect-ratio: 16/9` + `object-fit: cover` ở đây, dù bản vẽ vẽ ô xem trước là 16:9 — bản
   vẽ dùng một khối màu giả nên không lộ ra chuyện này. Ép 16:9 thì hai cỡ 4:3 (640×480 · 480×360) bị
   CẮT, và người dùng thấy một tấm sạch rồi tải về một tấm kẹp hai vệt đen: ô xem trước nói ngược với
   nhãn "viền đen" ngay dưới nó. Để ảnh giữ tỉ lệ THẬT thì thứ nhìn thấy đúng bằng thứ tải về.
   Mắt bắt được chuyện này, số đo thì không — ảnh chụp 390px mới lộ (L30). */
.thumb-xem img { display: block; width: 100%; height: auto; border-radius: var(--r-1); }
/* ⚠️ LUẬT ẨN DUY NHẤT CỦA KHỐI NÀY — đừng dọn "cho gọn". `hidden` chỉ là luật UA `display:none`, nó THUA
   `display:block`/`display:flex` khai ngay trên (L15/L45, dự án đã cắn ba lần). Bốn ảnh đều nằm sẵn
   trong DOM và chỉ ảnh ĐANG CHỌN bỏ `hidden` — mất luật này là cả bốn hiện cùng lúc.
   Và phép đo trạng thái phải hỏi `checkVisibility()`, đừng hỏi thuộc tính `hidden` (L45). */
/* ⚠️ `.thumb-nut[hidden]` và `.thumb-bang[hidden]` PHẢI có mặt ở đây — đo được, không phải phòng xa:
   `.btn` khai `display: inline-block` (app.css:499), mà `hidden` chỉ là luật UA `display:none` nên nó
   THUA. Thiếu dòng này thì bấm "✕ Ẩn" xong bảng vẫn hiện và nút mở bảng hiện luôn — hai cái cùng lúc,
   y hệt ca avatar đã cắn dự án ở L45. Và phép đo trạng thái phải hỏi `checkVisibility()`, đừng hỏi
   thuộc tính `hidden` (cũng L45). */
.thumb-xem img[hidden], .thumb-lui[hidden], .thumb-tin[hidden], .thumb-lai[hidden],
.thumb-tai[hidden], .thumb-nut[hidden], .thumb-bang[hidden] { display: none !important; }
/* Nút "✕ Ẩn" đặt ở góc phải trên của bảng — nó là thao tác lên TOÀN khối, không thuộc về cỡ nào. */
.thumb-an { float: right; margin: -.2rem -.2rem .2rem .4rem; padding: .12rem .4rem; font-size: 0.72rem; }
/* Nhãn "khung 4:3" cho hai cỡ 4:3 (sd 640×480 · hq 480×360).
   ⚠️ Nhãn nói HÌNH DẠNG KHUNG — thứ tool biết chắc — chứ KHÔNG nói ảnh có viền đen hay không: cái đó còn
   tuỳ video gốc quay ngang hay vuông, và tool không biết. Bản đầu 28/09 ghi "viền đen" và nó sai NGƯỢC ở
   video gốc 4:3 (ô có nhãn thì lấp đầy khung, ô không nhãn lại có vệt đen hai bên — đo trên jNQXAC9IVRw).
   Hệ quả "thường bị kẹp viền đen" để trong CÂU GIẢI THÍCH dưới bảng, do `thumb.js` dựng. */
.thumb-ve { font-style: normal; font-size: 0.66rem; font-weight: 700; color: var(--ve-chu);
  background: var(--ve-nen); border: 1px solid var(--ve-vien); border-radius: var(--r-1);
  padding: 0 .25rem; margin-left: .2rem; }
/* "Tải về" là HÀNH ĐỘNG CHÍNH của khối, nhưng bản C1 để nó là một chữ gạch chân — đo ở 390px ra
   **14 × 34 px**, thứ nhỏ nhất trên cả thẻ và nhỏ hơn hẳn chuẩn 29px của app. Trên điện thoại đó là
   một mục tiêu khó bấm trúng. Nay cho nó viền và đệm như mọi nút khác. Đây là chỗ tôi LỆCH bản vẽ
   (bản vẽ vẽ nó là link) — khai ra để phiên nghiệm thu chấm. */
.thumb-tai { font-size: 0.74rem; font-weight: 700; color: var(--primary-dam); background: none;
  border: 1px solid var(--border-dam); border-radius: var(--r-1); padding: .25rem .5rem; cursor: pointer; }
.thumb-tai:hover { border-color: var(--primary); }
/* 28/09 chiều: `.thumb-o--thieu` và `.thumb-duoi` ĐÃ XOÁ cùng lúc bỏ lưới-bày-bốn-ảnh. Xoá chứ không để
   lại: chúng thành luật không còn khớp phần tử nào, đúng thứ L43 vế bổ sung đã dọn ba lần trong tuần —
   người sau grep ra, tưởng có hiệu lực, sửa nó rồi không hiểu vì sao không đổi gì.
   Cỡ KHÔNG TỒN TẠI nay nói bằng NÚT MỜ (`.btn:disabled`) + `title`, chứ không bằng một ô xám: bày ảnh
   giữ chỗ 120×90 kéo giãn thì nó trông y hệt thumbnail thật và nút Tải về đưa người ta một tấm xám. */
.thumb-tin { margin: .4rem 0 0; font-size: 0.76rem; color: var(--muted); }

/* ===== VÒNG CHỜ khi đang lấy "Video tương tự" (23/09/2026) =====
   Anh Tám: "mở trang video tương tự ra nếu chưa có ngay thì em cho 1 biểu tượng chạy chạy… kiểu như
   loading". Anh chốt cách A của bản vẽ: vòng xoay + SỐ GIÂY đang chạy + thanh chạy ngang mảnh.
   Khối này máy chủ render kèm `hidden`; CHỈ đoạn script đang đi lấy dữ liệu mới bỏ `hidden` ra.
   Vòng quay là một LỜI HỨA ("có người đang làm việc cho bạn") — JS tắt mà vòng vẫn quay thì nó hứa
   một việc không ai đang làm, và người dùng ngồi đợi mãi. Có bài kiểm chốt HTML máy chủ không chứa
   một vòng đang quay. */
.vc-khoi { display: flex; align-items: flex-start; gap: .75rem; }
/* ⚠️ ĐÂY LÀ CƠ CHẾ ẨN **DUY NHẤT** CỦA VÒNG CHỜ — đừng dọn "cho gọn".
   `hidden` chỉ là luật UA `display:none`, thua `display:flex` khai ngay trên (L15/L45, đã cắn hai lần
   trong dự án). Và `finally` của script ẩn vòng bằng cách ĐẶT `hidden`, không bằng gì khác.
   ⇒ Gỡ dòng này thì vòng **quay mãi ở MỌI ca**, không riêng ca JS tắt — phiên nghiệm thu đo 23/09:
   `vongHien:true` khi JS tắt VÀ `vongConHien:true` sau khi lời gọi đã xong.
   ⇒ Và **28 bài test vẫn XANH** khi gỡ nó (họ đo luôn cả điều này). Bản trước của chú thích này ghi
   nhẹ hơn sự thật — "thiếu dòng này là vòng không ẩn được" — người đọc dễ tưởng chỉ hỏng ca JS tắt. */
.vc-khoi[hidden] { display: none !important; }
.vc-vong {
  flex: none; width: 22px; height: 22px; margin-top: 1px; border-radius: 50%;
  border: 2.5px solid var(--border-dam); border-top-color: var(--primary);
  animation: vc-quay .8s linear infinite;
}
.vc-than { flex: 1; min-width: 0; }
.vc-chu { margin: 0; font-size: 0.85rem; color: var(--text-2); }
.vc-chu b { color: var(--text); }
/* `tabular-nums`: số giây đổi mỗi giây, chữ số không đều bề ngang thì cả dòng giật sang trái phải */
.vc-giay { font-variant-numeric: tabular-nums; color: var(--primary-dam); font-weight: 700; }
.vc-phu { margin: .3rem 0 0; font-size: 0.78rem; color: var(--muted); }
.vc-thanh { height: 3px; background: var(--border); border-radius: var(--r-tron); overflow: hidden; margin-top: .7rem; }
.vc-thanh i { display: block; height: 100%; width: 34%; border-radius: var(--r-tron);
  background: var(--primary); animation: vc-truot 1.6s ease-in-out infinite; }
@keyframes vc-quay { to { transform: rotate(360deg); } }
@keyframes vc-truot { 0% { margin-left: -34%; } 100% { margin-left: 100%; } }

/* ⚠️ KHỐI DÙNG CHUNG CHO MỌI CHUYỂN ĐỘNG VỀ SAU — thêm chuyển động mới thì khai TẮT nó ở ĐÂY,
   đừng mở một khối `prefers-reduced-motion` thứ hai ở chỗ khác. Hai khối rời nhau thì một ngày
   ai đó thêm hiệu ứng mà chỉ sửa một khối, và phần thiếu im lặng không ai thấy.
   Trước 23/09/2026 dự án KHÔNG có chuyển động nào (rà 2078 dòng CSS + toàn bộ JS/template bằng mẫu
   rộng: 0 @keyframes · 0 animation · 0 transition · 0 @media prefers-*) — nên đây là TIỀN LỆ, không
   phải theo mẫu có sẵn.
   TẮT CHUYỂN ĐỘNG, KHÔNG TẮT THÔNG TIN: chữ và số giây vẫn chạy. Người nhạy cảm với chuyển động vẫn
   cần biết tool đang làm việc; tắt hết rồi để màn hình đứng im là lấy mất thông tin của đúng nhóm
   người cần nó nhất. */
@media (prefers-reduced-motion: reduce) {
  .vc-vong, .vc-thanh i { animation: none; }
  /* hết quay thì một cung sáng lệch sang bên chỉ trông như lỗi vẽ — trả về vành đều */
  .vc-vong { border-top-color: var(--border-dam); }
}
.the-diem { white-space: nowrap; padding: 0.05rem 0.4rem; border-radius: var(--r-tron);
  background: var(--card-head); border: 1px solid var(--primary); color: var(--primary); font-size: 0.78rem; }
.video-dang { margin: -0.2rem 0 0; font-size: 0.78rem; color: var(--muted); }
.the-chan-vn {
  background: var(--danger-nhat); color: var(--danger);
  padding: 0.02rem 0.4rem; border-radius: var(--r-1); font-size: 0.72rem; font-weight: 600;
}

/* Tag của video — hiện rõ để nghiên cứu từ khoá, không giấu trong ô gập */
.video-tags { display: flex; gap: 0.25rem; flex-wrap: wrap; align-items: center; }
.tag-nhan {
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--muted); font-weight: 650; margin-right: 0.1rem;
}
.tag {
  display: inline-block; padding: 0.08rem 0.42rem; border-radius: var(--r-1);
  background: var(--card-head); border: 1px solid var(--border);
  color: var(--text-2); font-size: 0.755rem;
}
.tag-them { width: 100%; }
.tag-them summary { cursor: pointer; color: var(--muted); font-size: 0.76rem; }
.tag-them > div { display: flex; gap: 0.25rem; flex-wrap: wrap; margin-top: 0.3rem; }
.tag-trong { color: var(--muted); font-size: 0.78rem; font-style: italic; }

/* 17/09/2026 — từ khoá lặp. Chip "Lặp nhiều" cố ý KHÁC .tag (nền màu chính nhạt, chữ đậm màu chính) để
   không lẫn với tag do chủ kênh đặt; bảng cả khối gập trong <details>, mặc định đóng ở mọi khổ. */
.video-lap { display: flex; gap: 0.25rem; flex-wrap: wrap; align-items: center; }
.chip-lap {
  display: inline-block; padding: 0.08rem 0.42rem; border-radius: var(--r-tron);
  background: var(--primary-nhat); border: 1px solid var(--primary);
  color: var(--primary-dam); font-size: 0.755rem; font-weight: 600;
}
.tk-lap { margin: -0.3rem 0 0.9rem; font-size: 0.88rem; }
.tk-lap summary { cursor: pointer; color: var(--text-2); }
.tk-lap-mo { color: var(--muted); font-size: 0.8rem; white-space: nowrap; }
.tk-lap[open] .tk-lap-mo { display: none; }
.tk-bang { margin-top: 0.5rem; border-collapse: collapse; min-width: 16rem; }   /* 16rem = vừa cột 291px ở khổ 390, không phải cuộn */
.tk-bang th, .tk-bang td { text-align: left; padding: 0.25rem 0.8rem 0.25rem 0; border-bottom: 1px dashed var(--border); }
.tk-bang th { font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); font-weight: 650; }
.tk-bang td:not(:first-child) { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* 17/09/2026 — trang gộp: mỗi bộ phận một nhóm (tiêu đề + Làm mới/Cài đặt của riêng nhóm), lấy từ bản vẽ .nhom-bp */
.nhom-bp { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin: 1.1rem 0 .5rem; padding-top: .6rem; border-top: 1px solid var(--border); }
.nhom-bp:first-of-type { border-top: 0; padding-top: 0; margin-top: .3rem; }
.nhom-bp-ten { margin: 0; font-size: 1.05rem; }
.nhom-bp-ten small { font-weight: 500; color: var(--muted); font-size: .82rem; margin-left: .4rem; }
.nhom-bp .inline-form { margin-left: auto; display: flex; gap: .4rem; }

/* Cài đặt chủ đề */
/* Ô xổ Dòng SP (vá 22/09/2026 — lỗi CÓ SẴN, đo được từ 18/09 và treo chờ anh Tám quyết; anh: "Vá đi").
   Gốc lỗi: `.inline-form select { width: auto }` + `min-width: auto` mặc định của flex item ⇒ ô KHÔNG
   co được và nong theo option dài nhất, mà option là TÊN DÒNG SẢN PHẨM người dùng tự đặt.
   Đo 22/09 trên tên 43 ký tự: tràn 66px ở 390, 81px ở 375. (Số 18/09 là 40/55 — khác vì độ dài tên
   khác; con số này tỉ lệ với tên dài nhất trong DB, nên đừng chốt nó thành hằng.)
   LUẬT HẸP, cố ý: viết cho `.inline-form select` sẽ trúng MỌI ô xổ inline của cả app (L33/L15) mà
   phần lớn chúng không có vấn đề gì. Vá đúng ô nong được.
   `min-width: 0` là vế bắt buộc — thiếu nó thì `max-width` cũng không cứu, vì flex item mặc định
   không co nhỏ hơn nội dung. Và phải là max-width chứ không phải ẩn bớt option: option ẩn VẪN nong
   select (L45a). */
/* `form-co-duoc`: form inline mà nội dung nong theo DỮ LIỆU NGƯỜI DÙNG hoặc theo `size=` — ba form của
   trang này: thêm chủ đề · sửa chủ đề · thêm kênh. Hai nửa PHẢI đi cùng nhau:
     · form: `.inline-form` là inline-flex nên chính nó cũng nong theo con. Chặn ô mà bỏ form thì đo ra
       ô co lại (397→352) mà trang VẪN tràn — đúng cái bẫy "vá một nửa" đo được 22/09 lúc 15:05 (L43).
     · ô bên trong: `min-width: 0` là vế bắt buộc, vì flex item mặc định KHÔNG co nhỏ hơn nội dung —
       thiếu nó thì `max-width` cũng không cứu.
   Ô xổ Dòng SP thêm trần 22rem: nó nong theo TÊN DÒNG do người dùng đặt, dài bao nhiêu cũng được. Và
   phải là max-width chứ không phải ẩn bớt option — option ẩn VẪN nong select (L45a). */
.inline-form.form-co-duoc { max-width: 100%; }
.inline-form.form-co-duoc input[type="text"],
.inline-form.form-co-duoc select { min-width: 0; max-width: 100%; }
.inline-form.form-co-duoc select.o-dong-sp { max-width: min(22rem, 100%); }
.chu-de { border-left: 3px solid var(--primary); }
.danh-sach-kenh { list-style: none; padding: 0; margin: 0 0 0.6rem; }
.danh-sach-kenh li {
  display: flex; align-items: center; justify-content: space-between; gap: 0.6rem;
  padding: 0.35rem 0; border-bottom: 1px dashed var(--border);
}
.thanh-quota {
  height: 8px; border-radius: var(--r-tron); background: var(--border); overflow: hidden; margin: 0.3rem 0;
}
.thanh-quota-fill { height: 100%; background: var(--ok); }
/* 17/09/2026 — khoá YouTube riêng: thanh số THẬT (đếm dòng luot_goi_yt) tách khỏi thanh ước tính; class riêng để test
   cũ canh thanh ước tính không bị ảnh hưởng. */
.thanh-quota-that { margin-bottom: .2rem; }
.thanh-quota-that-fill { height: 100%; background: var(--primary); }
.so-that { margin-bottom: .8rem; }
/* Ô dán khoá: che chữ bằng CSS (Chrome/Safari/Firefox ≥114) thay vì type=password để iOS Keychain không gợi ý mật khẩu
   của tool. Chữ vẫn chọn-copy được → máy chủ luôn trả value="" (không bao giờ đổ khoá lại form). */
.o-khoa { -webkit-text-security: disc; }
.khoa-form { display: flex; flex-wrap: wrap; gap: .6rem 1rem; align-items: flex-end; margin: .5rem 0 0; }
.khoa-form label { display: flex; flex-direction: column; gap: .25rem; font-size: .85rem; color: var(--muted); flex: 1 1 16rem; }
.khoa-form label input { margin-top: 0; }
.khoa-form .ghi-chu { flex-basis: 100%; }
.khoa-form-gap summary { display: inline-block; list-style: none; cursor: pointer; }
.khoa-form-gap summary::-webkit-details-marker { display: none; }
.khoa-form-gap { margin: .6rem 0 0; }
.khoa-dong { margin: .2rem 0 .3rem; }
.hd-khoa { margin-top: .9rem; font-size: .9rem; }
.hd-khoa summary { cursor: pointer; color: var(--primary-dam); font-weight: 600; }
/* Hướng dẫn rút gọn 18/09/2026: dòng đầu chữ phụ · 7 bước CÓ SỐ (số màu nhấn — Safari có thể chỉ nhận color cho ::marker)
   · lưu ý chữ nhỏ, dòng "khong" đỏ đậm. */
.hd-khoa-dau { margin: .4rem 0 0; color: var(--muted); font-size: .85rem; }
.hd-khoa-buoc { margin: .5rem 0 0; padding-left: 1.4rem; }
.hd-khoa-buoc li { margin: .3rem 0; padding-left: .15rem; }
.hd-khoa-buoc li::marker { color: var(--primary-dam); font-weight: 700; }
.hd-khoa-luu-y { margin: .6rem 0 0; padding-left: 1.1rem; font-size: .85rem; color: var(--text-2); }
.hd-khoa-luu-y li { margin: .2rem 0; }
.hd-khoa-luu-y li.hd-khong { color: var(--danger); font-weight: 600; }
#khoi-khoa-yt td:nth-child(2) { white-space: nowrap; }
.badge-link + .badge-link { margin-left: .2rem; }
.thanh-quota-fill.qua-nguong { background: var(--danger); }
.canh-bao-quota { color: var(--danger); }

/* ════════════════════════════════════════════════════════════════════════════════════════════
   ĐỢT J4 — DẢI BĂNG QUOTA YouTube trên màn Nghiên cứu.
   ⚠️ Thêm một TRẠNG THÁI mới mà CSS không có luật cho nó thì nó VÔ HÌNH, và ⛔ không gì báo lỗi
      (L45 vế b: nút `disabled` trông y hệt nút thường suốt một đợt). Nên ba mức dưới đây phải
      KHÁC NHAU NHÌN THẤY ĐƯỢC, và phải đo bằng `getComputedStyle`, ⛔ đừng đo sự có mặt của class.
   ⚠️ Ba class bổ nghĩa khai NGAY SAU class gốc (L15 vế bổ sung): cùng độ đặc hiệu thì cái khai SAU
      thắng, nên khai trước `.qt-bang` là chúng không ăn gì mà tên vẫn đúng chính tả.
   ⛔ KHÔNG có thanh tiến trình ở đây — một thanh tiến trình tự nó hứa rằng con số đã ĐẦY ĐỦ, mà
      con số này chỉ là MỨC TỐI THIỂU. Hình vẽ nói dối thì không chú thích nào gỡ lại được. */
.qt-bang {
  margin: 0 0 0.9rem; padding: 0.6rem 0.8rem;
  background: var(--card); border: 1px solid var(--border);
  border-left: 3px solid var(--border-dam); border-radius: var(--r-1);
}
.qt-bang.qt-nhac { border-left-color: var(--vang-sang); }
.qt-bang.qt-canh_bao { border-left-color: var(--danger); background: var(--danger-nhat); }
.qt-do { margin: 0; font-size: 0.86rem; color: var(--text-2); }
.qt-canh-bao { margin: 0.35rem 0 0; font-size: 0.86rem; color: var(--danger); font-weight: 600; }
.qt-ghi-chu { margin: 0.3rem 0 0; font-size: 0.78rem; color: var(--muted); }
@media (max-width: 760px) {
  /* Khổ điện thoại là nơi anh Tám xem. Luật dành riêng cho khổ này PHẢI nằm TRONG media query của
     nó (L55): `@media` KHÔNG cộng thêm độ đặc hiệu, nên một luật viết ngoài vẫn thắng ở mọi khổ. */
  .qt-bang { padding: 0.5rem 0.6rem; }
  .qt-do, .qt-canh-bao { font-size: 0.82rem; }
}

/* ==================== Trang đăng nhập "YU Ideas" ====================
   Bảng màu riêng của trang này, KHÔNG đụng token chung của app.
   Sáng/tối bám theo cơ chế sẵn có: script đầu <head> đặt data-theme trên <html>. */
.dn-khung {
  --dn-do: #D83024; --dn-do-dam: #B62419; --dn-vien-chu: #8A2410;
  --dn-cam: #FF9F2E; --dn-cam-sang: #FFC44F; --dn-cam-dam: #E8791A;
  --dn-kem: #FFF6E9;
  --dn-nen: #FFFBF5; --dn-vien: #E7DAC7; --dn-vien-dam: #D2BEA4;
  --dn-chu: #2B2118; --dn-chu-2: #7B6B5C; --dn-o-nen: #FFFFFF;

  display: grid; grid-template-columns: 1fr 1fr;
  max-width: 940px; margin: 0 auto; width: 100%; border-radius: var(--r-4);
  overflow: hidden; border: 1px solid var(--dn-vien);
  box-shadow: 0 1px 2px rgba(43,33,24,.05), 0 12px 34px rgba(43,33,24,.10);
}
:root[data-theme="dark"] .dn-khung {
  --dn-cam: #C4691A; --dn-cam-sang: #E29A2C; --dn-cam-dam: #8C440C;
  --dn-vien-chu: #5E1607;
  --dn-nen: #191410; --dn-vien: #3A2F25; --dn-vien-dam: #4E4033;
  --dn-chu: #F7EFE5; --dn-chu-2: #B7A695; --dn-o-nen: #191410;
  box-shadow: 0 1px 2px rgba(0,0,0,.4), 0 12px 34px rgba(0,0,0,.38);
}

/* Căn giữa theo chiều dọc. `align-content: safe center` chứ không phải `center` trơn:
   màn hình thấp hơn khung thì `safe` tự lùi về `start`, khung cuộn được và KHÔNG bị
   cắt mất đầu — lỗi kinh điển của căn giữa bằng flex/grid.
   Trừ ~6rem là chiều cao thanh trên + padding của .container. */
.dn-trang {
  min-height: calc(100vh - 6rem);
  min-height: calc(100dvh - 6rem);   /* dvh: trên điện thoại trừ luôn thanh địa chỉ */
  display: grid; justify-items: center; align-content: safe center;
  padding: .5rem 0;
}

/* ---- Nửa trái: chữ hiệu ---- */
.dn-hieu {
  position: relative; overflow: hidden;
  background: linear-gradient(150deg, var(--dn-cam-sang) 0%, var(--dn-cam) 52%, var(--dn-cam-dam) 100%);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1.3rem; padding: 2.6rem 1.4rem;
}
.dn-hieu::before {
  content: ""; position: absolute; width: 340px; height: 340px; border-radius: 50%;
  background: radial-gradient(circle, rgba(255,246,233,.32) 0%, rgba(255,246,233,0) 68%);
  top: -70px; left: -80px; pointer-events: none;
}
.dn-sao { position: absolute; inset: 0; width: 100%; height: 100%; opacity: .5; pointer-events: none; }
.dn-logo { width: 96px; height: 96px; position: relative; z-index: 1;
  filter: drop-shadow(0 5px 12px rgba(120,50,0,.28)); }

/* CHỮ HIỆU 3 LỚP — z-index ghim cho TỪNG lớp (L21).
   Lớp .dn-chu-ngoai mang transform ⇒ tự sinh stacking context; thiếu z-index là nó
   được vẽ sau cùng, phủ kín 2 lớp kia và chữ thành một cục mực.
   Nét viền giữ dưới ~10% cỡ chữ + nới letter-spacing để không bịt lỗ chữ "e"/"a". */
.dn-chu { position: relative; z-index: 1; display: grid; justify-items: center; }
.dn-chu > span {
  grid-area: 1/1; position: relative;
  font-family: "Bagel Fat One", "Baloo 2", system-ui, sans-serif; font-weight: 400;
  font-size: 3.5rem; line-height: 1.24; letter-spacing: .075em; white-space: nowrap;
}
/* L21 nói giữ nét viền dưới ~10% cỡ chữ vì text-stroke nở về CẢ HAI phía, ăn vào
   trong và bịt lỗ chữ. Ở đây cỡ chữ 3.5rem = 56px:
   - Lớp KEM (z2) là lớp quyết định lỗ chữ nhìn thấy: 4.4px = 7.9% — DƯỚI trần 10%.
   - Lớp SẪM (z1) 9.5px = 17% nhưng nằm DƯỚI lớp kem nên không chạm vào lỗ chữ;
     nó chỉ tạo độ dày sticker mà bản vẽ anh Tám đã duyệt.
   Đã phóng to ảnh chụp x4 kiểm tận mắt: lỗ chữ "d"/"e"/"a" còn thấy rõ, không bịt kín. */
.dn-chu-ngoai { z-index: 1; color: var(--dn-vien-chu);
  -webkit-text-stroke: 9.5px var(--dn-vien-chu); transform: translateY(4px); }
.dn-chu-vien  { z-index: 2; color: var(--dn-kem); -webkit-text-stroke: 4.4px var(--dn-kem); }
.dn-chu-ruot  { z-index: 3; color: var(--dn-do); }

.dn-khau-hieu {
  position: relative; z-index: 1; margin: -.4rem 0 0;
  font-family: "Baloo 2", system-ui, sans-serif; font-weight: 600;
  color: #FFF9F0; font-size: 1.08rem; text-align: center;
  text-shadow: 0 2px 0 rgba(122,45,5,.42);
}

/* ---- Nửa phải: khu đăng nhập ---- */
.dn-form {
  background: var(--dn-nen); color: var(--dn-chu);
  display: flex; flex-direction: column; justify-content: center;
  padding: 2.4rem 2.4rem; gap: .95rem;
}
.dn-nhac {
  display: flex; align-items: flex-start; gap: .6rem;
  background: color-mix(in srgb, var(--dn-cam-sang) 22%, var(--dn-nen));
  border: 1px solid color-mix(in srgb, var(--dn-cam) 45%, transparent);
  border-radius: var(--r-3); padding: .6rem .8rem; font-size: .85rem; color: var(--dn-chu);
}
.dn-nhac svg { flex: none; width: 17px; height: 17px; margin-top: .05rem; color: var(--dn-cam-dam); }
.dn-bao { margin: 0; }   /* flash thay chỗ viên nhắc — cùng vị trí, không nhảy bố cục */

.dn-chao {
  font-family: "Baloo 2", system-ui, sans-serif; font-weight: 700;
  font-size: 1.6rem; line-height: 1.3; color: var(--dn-chu); margin: 0;
  /* Chia dòng cân hai bên cho đẹp. Đây CHỈ là gợi ý cho trình duyệt, không phải
     luật — chống chữ mồ côi thì đã buộc 2 chữ cuối bằng &nbsp; ngay trong template,
     cách đó trình duyệt nào cũng phải theo. */
  text-wrap: balance;
}
.dn-phu { font-size: .88rem; color: var(--dn-chu-2); margin: -.5rem 0 0; text-wrap: pretty; }

.dn-luoi { display: flex; flex-direction: column; gap: .85rem; }
.dn-nhan {
  display: block; font-size: .84rem; font-weight: 600; color: var(--dn-chu);
}
.dn-o {
  display: block; width: 100%; margin-top: .34rem; height: 44px;
  border: 1.5px solid var(--dn-vien-dam); border-radius: var(--r-3);
  background: var(--dn-o-nen); color: var(--dn-chu);
  padding: 0 .85rem; font-size: .95rem; font-family: inherit;
}
.dn-o:focus {
  outline: none; border-color: var(--dn-cam-dam);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--dn-cam) 26%, transparent);
}
.dn-tick {
  display: flex; align-items: center; gap: .5rem;
  font-size: .87rem; color: var(--dn-chu-2);
}
.dn-tick input { width: 16px; height: 16px; accent-color: var(--dn-cam-dam); }
.dn-nut {
  height: 46px; border: 0; border-radius: var(--r-tron); margin-top: .15rem; width: 100%;
  background: linear-gradient(180deg, var(--dn-do) 0%, var(--dn-do-dam) 100%);
  color: #FFF6EC; font-family: "Baloo 2", system-ui, sans-serif;
  font-weight: 700; font-size: 1.06rem; cursor: pointer;
  box-shadow: 0 3px 0 rgba(120,25,15,.42), 0 8px 18px rgba(190,45,30,.24);
}
.dn-nut:hover { filter: brightness(1.05); }
.dn-nut:active { transform: translateY(2px); box-shadow: 0 1px 0 rgba(120,25,15,.42); }
.dn-ky { font-size: .76rem; color: var(--dn-chu-2); text-align: center; margin: .4rem 0 0; }

/* Hàng "Ghi nhớ 30 ngày" + "Quên mật khẩu?" — Phase 03 mới có vế phải nên giờ
   mới cân được hai đầu; Phase 02 để tick đứng một mình bên trái. */
.dn-hang { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.dn-lien-ket { color: var(--dn-do); font-weight: 600; text-decoration: none; font-size: .87rem; }
.dn-lien-ket:hover { text-decoration: underline; }
.dn-dang-ky { font-size: .87rem; color: var(--dn-chu-2); text-align: center; margin: .5rem 0 0; }
.dn-lien-ket-duoi { text-align: center; font-size: .85rem; margin: .6rem 0 0; }
.dn-lien-ket-duoi a { color: var(--dn-do); font-weight: 600; text-decoration: none; }
.dn-lien-ket-duoi a:hover { text-decoration: underline; }
.dn-loi-ds { margin: 0; padding-left: 1.1rem; }
.dn-loi-ds li + li { margin-top: .2rem; }
/* Ô nhập mã 6 số: giãn chữ cho dễ đối chiếu với mã trong email */
.dn-o-ma { letter-spacing: .4em; font-size: 1.15rem; text-align: center; }
/* Phase 21: Họ + Tên hai ô một hàng; chú thích nhóm 4-5-6; select dùng chung dáng .dn-o */
.dn-hai-o { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; }
.dn-phu--muc { margin: .4rem 0 -.3rem; }
select.dn-o { appearance: auto; }

/* ---- Khổ điện thoại: xếp dọc, panel hiệu lên trên ---- */
@media (max-width: 760px) {
  /* Phase 30c: khoảng thở mới CHỈ áp ở khổ rộng. Ở 390px chỉ có ~375px dùng được, nới padding là
     lấy mất chiều ngang của chính nội dung — thứ đang hiếm nhất ở đó. Giữ ĐÚNG giá trị trước 30c,
     không nới mà cũng không bóp: bóp cho bảng đỡ tràn là chữa triệu chứng ở sai chỗ, và là đổi một
     thứ đang không ai kêu. */
  .card { padding: 1.05rem 1.3rem; margin-bottom: 1rem; }
  .container { padding: 1.25rem; }
  .dn-trang { min-height: 0; padding: .25rem 0 1rem; }
  .dn-khung { grid-template-columns: 1fr; max-width: 460px; }
  .dn-hieu { padding: 1.9rem 1.2rem; gap: 1rem; }
  .dn-logo { width: 72px; height: 72px; }
  .dn-chu > span { font-size: 2.4rem; }
  .dn-chu-ngoai { -webkit-text-stroke-width: 6.5px; transform: translateY(3px); }
  .dn-chu-vien  { -webkit-text-stroke-width: 3px; }
  .dn-khau-hieu { font-size: .96rem; }
  .dn-form { padding: 1.6rem 1.3rem; }
  .dn-chao { font-size: 1.35rem; }
  /* Khổ hẹp: cho liên kết xuống dòng riêng thay vì để chữ trong liên kết bị cắt
     ngang giữa chừng — chữ của một liên kết nằm vắt hai dòng nhìn như lỗi. */
  .dn-dang-ky a { display: block; margin-top: .15rem; }
}

/* Thanh trên lúc CHƯA đăng nhập: bỏ nền và viền, chỉ còn nút đổi sáng/tối nổi ở góc phải.
   Không dùng position:absolute để nút không đè lên khung bên dưới ở bất kỳ khổ nào. */
.topbar--tran { background: transparent; border-bottom: 0; padding-bottom: 0; }

/* Cảnh báo dung lượng trong khung đính ảnh — hiện tại chỗ, không phải alert() */
.anh-canh-bao {
  margin: .5rem 0 0; padding: .5rem .7rem; border-radius: var(--r-2);
  background: var(--danger-nhat); color: var(--danger);
  border: 1px solid var(--danger); font-size: .85rem;
}
.khung-anh-moi { border: 1px solid var(--border); border-radius: var(--r-3); padding: .9rem 1rem; margin: 1rem 0; }
.khung-anh-moi legend { padding: 0 .4rem; font-weight: 650; font-size: .9rem; color: var(--text-2); }

/* ---- Nhiều khung đính ảnh trên một trang (trang tạo idea có 2) ---- */
.cum-anh { display: block; }
.cum-anh.o-ca-hang { grid-column: 1 / -1; }   /* nằm trong .form-grid thì chiếm cả hàng */
.khung-anh { margin: .5rem 0 1rem; }
.anh-nhan { font-size: .85rem; font-weight: 650; color: var(--text-2); margin: 0 0 .35rem; }
/* Khung đang được chọn: Ctrl+V sẽ dán vào đây. Chỉ bật khi trang có >1 khung —
   1 khung thì không cần chỉ vì không có gì để nhầm. */
.khung-anh.dang-chon .drop-zone { border-color: var(--primary); background: var(--primary-nhat); }
/* Chỉ báo "Ctrl+V rơi vào khung này" — ĐẶT TUYỆT ĐỐI, không chiếm chỗ trong dòng chảy.
   Trước đây nó là inline-block nằm trong .drop-zone nên khung idea (có chỉ báo) CAO HƠN
   khung thumb (không có) — đúng chỗ anh Tám kêu.
   KHÔNG xoá nó đi cho hai khung bằng nhau: nó là chỉ báo CHỨC NĂNG, cho biết Ctrl+V sẽ
   rơi vào khung nào. Nền + viền của .khung-anh.dang-chon đã là một lớp chỉ báo; chữ này
   là lớp thứ hai cho ai không phân biệt được màu. Bỏ nó là bỏ chức năng để lấy cái đẹp. */
.anh-nhan-dan {
  position: absolute; top: .3rem; right: .55rem;
  font-size: .7rem; font-weight: 700; letter-spacing: .02em;
  color: var(--primary);
  pointer-events: none;   /* không chắn cú bấm vào vùng thả */
}
.anh-nhom { font-size: .9rem; color: var(--text-2); margin: .9rem 0 .35rem; }

/* ==================== Phase 06 — màu sắc & icon ====================
   Tinh thần Kiểu 2 anh Tám chốt: MÀU LÀM VIỆC chứ không chỉ để đẹp. Chất sáng tạo
   đặt ở icon, ở màu bộ phận, ở các chỗ trống — KHÔNG đổ màu vào nền. Nền để yên
   tĩnh cho nội dung nổi lên.
   Muốn chỉnh đậm/nhạt thì xoay mấy token "NÚT VẶN" ở đầu file, đừng sửa rải rác. */

/* ---- Vân nền: rất nhạt, phải chìm xuống dưới nội dung ----
   Dùng cho TOÀN APP. Trang đăng nhập là ngoại lệ DUY NHẤT (class .khong-van),
   vì nó có bản thiết kế riêng đã duyệt. Thêm trang mới thì mặc định là CÓ vân. */
body {
  /* Vân chấm ĐẶT TRÊN, vầng sáng nằm dưới — thứ tự này quyết định: đảo lại thì vầng
     sáng phủ lên vân và vân biến mất ở đúng góc có vầng sáng. */
  background-image:
    radial-gradient(var(--van-mau) var(--van-cham), transparent var(--van-cham)),
    var(--vang-sang);
  background-size: var(--van-thua) var(--van-thua), cover, cover;
  background-repeat: repeat, no-repeat, no-repeat;
  background-attachment: fixed;
}
body.khong-van { background-image: none; }

/* ---- Icon trong ô bo tròn, dùng ở tiêu đề khối ---- */
.icon-o {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: var(--r-2); flex: none;
  background: var(--icon-o-nen); color: var(--primary-dam);
}
.icon-o .tab-icon { width: 17px; height: 17px; }
.icon-o--cho   { background: var(--tt-cho-nen);   color: var(--tt-cho-chu); }
.icon-o--duyet { background: var(--tt-duyet-nen); color: var(--tt-duyet-chu); }
.icon-o--loai  { background: var(--tt-loai-nen);  color: var(--tt-loai-chu); }
.icon-o--tong  { background: var(--tt-tong-nen);  color: var(--tt-tong-chu); }

/* Tiêu đề khối có icon: đứng cùng hàng, không đội chữ lên */
.tieu-de-icon { display: flex; align-items: center; gap: .55rem; }
h2.tieu-de-icon, h3.tieu-de-icon { margin-top: 0; }

/* ---- Ô số liệu theo trạng thái ----
   Nền nhạt + viền cùng tông đậm hơn + số đậm cùng tông. Mỗi ô còn có CHỮ và ICON
   riêng nên bỏ hết màu đi vẫn phân biệt được — màu không phải tín hiệu duy nhất. */
.status-card { border-width: 1px; border-style: solid; }
.status-card--tong  { background: var(--tt-tong-nen);  border-color: var(--tt-tong-vien); }
.status-card--cho_duyet { background: var(--tt-cho-nen);   border-color: var(--tt-cho-vien); }
.status-card--da_duyet  { background: var(--tt-duyet-nen); border-color: var(--tt-duyet-vien); }
.status-card--loai      { background: var(--tt-loai-nen);  border-color: var(--tt-loai-vien); }
.status-card--tong .status-num  { color: var(--tt-tong-chu); }
.status-card--cho_duyet .status-num { color: var(--tt-cho-chu); }
.status-card--da_duyet .status-num  { color: var(--tt-duyet-chu); }
.status-card--loai .status-num      { color: var(--tt-loai-chu); }
.status-card .badge { display: inline-flex; align-items: center; gap: .3rem; }
.status-card .badge .tab-icon { width: 14px; height: 14px; }

/* ---- Màu bộ phận: chấm tròn + chữ, luôn kèm TÊN nên màu không đơn độc ---- */
.cham-bp {
  display: inline-block; width: .62em; height: .62em; border-radius: 50%;
  margin-right: .4em; vertical-align: baseline; flex: none;
}
.bp-1 { background: var(--bp-1); } .bp-2 { background: var(--bp-2); }
.bp-3 { background: var(--bp-3); } .bp-4 { background: var(--bp-4); }
.bp-5 { background: var(--bp-5); } .bp-6 { background: var(--bp-6); }
.bar-fill.bp-1 { background: var(--bp-1); } .bar-fill.bp-2 { background: var(--bp-2); }
.bar-fill.bp-3 { background: var(--bp-3); } .bar-fill.bp-4 { background: var(--bp-4); }
.bar-fill.bp-5 { background: var(--bp-5); } .bar-fill.bp-6 { background: var(--bp-6); }

/* ---- Chỗ trống: minh hoạ + câu chỉ VIỆC TIẾP THEO, không chỉ báo là trống ---- */
.trong-khung {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: .5rem; padding: 1.6rem 1rem; color: var(--muted);
}
.trong-khung svg {
  width: var(--minh-hoa-co); height: var(--minh-hoa-co);
  color: var(--minh-hoa-net); flex: none;   /* KHÔNG phải --border-dam — xem chú thích ở khai báo biến */
}
.trong-khung .trong-chinh { font-weight: 600; color: var(--text-2); margin: 0; }
.trong-khung .trong-phu { margin: 0; font-size: .87rem; max-width: 34ch; text-wrap: pretty; }
.trong-khung .btn { margin-top: .3rem; }

/* Dòng thông báo: icon loại bên trái, nội dung ở giữa — liếc là biết chuyện gì,
   không phải đọc hết câu. Dùng lưới để icon không kéo giãn theo chiều cao dòng. */
.tb-dong { display: grid; grid-template-columns: auto 1fr; gap: .1rem .7rem; align-items: center; }
.tb-dong .icon-o { grid-row: 1 / 3; }
.tb-dong .tb-noi-dung { grid-column: 2; }
.tb-dong small { grid-column: 2; }

/* Thanh tiến độ trong ô số liệu: cùng tông với ô, ăn chung token --tt-* */
.bar-fill.thanh-cho_duyet { background: var(--tt-cho-chu); }
.bar-fill.thanh-da_duyet  { background: var(--tt-duyet-chu); }
.bar-fill.thanh-loai      { background: var(--tt-loai-chu); }
/* Rãnh thanh trong ô màu: nền ô đã có màu nên rãnh phải đậm hơn --border mới thấy */
.status-card .bar { background: color-mix(in srgb, currentColor 16%, transparent); }

/* Nhãn chức danh trong ô tick của bảng phân quyền — ẩn trên màn rộng (đã có tiêu đề
   cột), hiện lại trên màn hẹp khi bảng cuộn ngang và tiêu đề trôi khỏi tầm nhìn. */
.an-nho { display: none; }
@media (max-width: 700px) { .an-nho { display: inline; font-size: .8rem; } }

/* Hàng gán kênh phụ trách trong màn Người dùng */
.kenh-phu-trach { flex-wrap: wrap; gap: .4rem .7rem; margin-top: .4rem; }
.kenh-phu-trach .nhan-nho { font-size: .8rem; color: var(--muted); }

/* Lệnh giao đã huỷ: mờ đi nhưng vẫn đọc được — giữ dấu vết, không xoá khỏi lịch sử */
.lenh-da-huy { opacity: .55; }
.lenh-da-huy td { text-decoration: line-through solid var(--border-dam) 1px; }
.lenh-da-huy td:last-child { text-decoration: none; }

/* Dòng ghi chú của lệnh giao việc: nối liền dòng trên (bỏ viền trên) để đọc ra là
   chú thích của dòng đó, không phải một mục riêng. Không nowrap — ghi chú dài 255
   ký tự phải xuống dòng chứ không được đẩy bảng tràn ngang (L: vá tràn ngang). */
.dong-ghi-chu > td {
  border-top: 0;
  padding-top: 0;
  white-space: normal;
}

/* Khối "Việc được giao" trên Tổng quan: đây là trang AI CŨNG MỞ, kể cả nhân viên
   trên điện thoại. Bảng 5 cột nowrap đẩy main rộng 642px trên màn 375px — trước khi
   thêm khối này trang không hề tràn, nên đây là hồi quy phải vá tại chỗ, không đổ
   cho cơ chế cuộn chung của main. Dưới 700px: mỗi lệnh xếp thành một thẻ dọc. */
@media (max-width: 700px) {
  .bang-viec-giao,
  .bang-viec-giao tbody,
  .bang-viec-giao tr,
  .bang-viec-giao td { display: block; width: auto; }
  .bang-viec-giao tr {
    padding: .6rem 0;
    border-top: 1px solid var(--border);
  }
  .bang-viec-giao tr:first-child { border-top: 0; }
  .bang-viec-giao td {
    border: 0;
    padding: .1rem 0;
    white-space: normal !important;   /* nowrap đặt inline nên phải thắng chắc (L15) */
  }
  .bang-viec-giao tr.dong-ghi-chu { border-top: 0; padding-top: 0; }
}

/* Câu báo thiếu ô ở form idea. Dùng token trạng thái "loại" sẵn có, không đẻ màu mới. */
.bao-thieu {
  margin: .6rem 0;
  padding: .55rem .8rem;
  border-radius: var(--r-2);
  border: 1px solid var(--tt-loai-vien);
  background: var(--tt-loai-nen);
  color: var(--tt-loai-chu);
  font-weight: 600;
}

/* Khối 4 ô bị lệnh giao chốt trên form thêm idea. Không phải ô nhập nên không dùng
   dáng input — dùng dáng "đọc thôi" để mắt phân biệt được ngay cái nào gõ được. */
.khoi-lenh-giao { border-left: 3px solid var(--tt-cho-vien); }
.o-da-khoa {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: .5rem .9rem;
  margin: 0;
}
.o-da-khoa dt { font-size: .78rem; color: var(--muted); text-transform: uppercase; letter-spacing: .03em; }
.o-da-khoa dd { margin: .1rem 0 0; font-weight: 600; }

/* ---- Dòng người dùng ở "Chuyển tài khoản" (trang riêng + lớp phủ dùng chung) ---- */
.dong-tk {
  display: flex; align-items: center; gap: .7rem;
  padding: .55rem .2rem;
  border-top: 1px solid var(--border);
}
.dong-tk:first-child { border-top: 0; }
.dong-tk-chu { flex: 1 1 auto; min-width: 0; }   /* min-width:0 để tên dài co lại được */
.dong-tk-chu b { display: block; }
.dong-tk-chu small { display: block; }
.avatar-tron {
  flex: 0 0 auto;
  width: 34px; height: 34px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: .9rem; color: #fff;
}
/* Cùng bảng màu với chấm bộ phận — không đẻ bảng màu thứ hai. */
.avatar-tron.bp-1 { background: var(--bp-1); } .avatar-tron.bp-2 { background: var(--bp-2); }
.avatar-tron.bp-3 { background: var(--bp-3); } .avatar-tron.bp-4 { background: var(--bp-4); }
.avatar-tron.bp-5 { background: var(--bp-5); } .avatar-tron.bp-6 { background: var(--bp-6); }

/* ---- Lớp phủ "Chuyển tài khoản" ---- */
.lop-phu {
  position: fixed; inset: 0; z-index: 100;
  display: flex; align-items: center; justify-content: center;
  padding: 1rem;
  background: rgba(0, 0, 0, .45);
}
.lop-phu-hop {
  width: 100%; max-width: 520px;
  max-height: 85vh;                      /* cao quá thì hộp cuộn, không đẩy trang */
  display: flex; flex-direction: column; gap: .7rem;
  padding: 1rem 1.1rem;
  border: 1px solid var(--border);
  border-radius: var(--r-3);
  background: var(--card);
  box-shadow: 0 18px 50px rgba(0, 0, 0, .3);
}
.lop-phu-dau { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.lop-phu-dau h2 { margin: 0; font-size: 1.15rem; }
/* Danh sách dài thì CUỘN TRONG hộp, không kéo dài lớp phủ ra ngoài màn hình. */
.lop-phu-ds { flex: 1 1 auto; overflow-y: auto; min-height: 0; }

/* ================= Danh sách người dùng — MỘT NGƯỜI MỘT DÒNG =================
   Cấu trúc này GIỐNG HỆT nhau ở cả hai chế độ; chỉ token màu đổi. Chuyển sáng/tối
   là bật đèn trong cùng căn phòng, không phải dọn sang phòng khác. */
.ds-nguoi { margin-top: 1rem; }
.ds-dau, .ds-hang {
  display: grid;
  grid-template-columns: minmax(0, 2.2fr) minmax(0, 1.3fr) minmax(0, 1.2fr) minmax(0, 1.1fr) 2.5rem;
  gap: .75rem;
  align-items: center;
}
.ds-dau {
  padding: 0 .9rem .5rem;
  font-size: .74rem; letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1px solid var(--border);
}
.ds-nguoi-mot {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-3);
  margin-top: .5rem;
  box-shadow: var(--do-bong);
}
.ds-hang {
  padding: .6rem .9rem;
  cursor: pointer;
  list-style: none;                 /* bỏ mũi tên mặc định của <summary> */
  border-radius: var(--r-3);
}
.ds-hang::-webkit-details-marker { display: none; }
.ds-hang:hover { background: var(--card-head); }
.ds-nguoi-mot[open] > .ds-hang { border-bottom: 1px solid var(--border); border-radius: var(--r-3) var(--r-3) 0 0; }
.ds-o { min-width: 0; }             /* min-width:0 để tên dài co lại thay vì đẩy tràn */
.ds-ai { display: flex; align-items: center; gap: .6rem; }
.ds-ten { min-width: 0; }
.ds-ten b, .ds-ten small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-mo { text-align: right; color: var(--muted); font-weight: 700; letter-spacing: .1em; }
.ds-nguoi-mot[open] .ds-mo { color: var(--primary); }

.ds-bung { padding: .85rem .9rem 1rem; display: flex; flex-direction: column; gap: .7rem; }
.ds-thao-tac { display: flex; flex-wrap: wrap; gap: .4rem; padding-top: .6rem; border-top: 1px dashed var(--border); }

/* Chip vai trò — LUÔN kèm chữ, màu không bao giờ là tín hiệu duy nhất. */
.chip-vt {
  display: inline-block;
  padding: .12rem .5rem;
  border-radius: var(--r-tron);
  font-size: .76rem; font-weight: 600;
  white-space: nowrap;
}
.vt-admin        { background: var(--vt-admin-nen); color: var(--vt-admin-chu); }
.vt-truong_phong { background: var(--vt-tp-nen);    color: var(--vt-tp-chu); }
.vt-truong_bo_phan { background: var(--vt-tbp-nen); color: var(--vt-tbp-chu); }
.vt-qtv          { background: var(--vt-qtv-nen);   color: var(--vt-qtv-chu); }
.vt-nhan_vien, .vt-nv { background: var(--vt-nv-nen); color: var(--vt-nv-chu); }
.vt-kiem         { background: var(--vt-kiem-nen);  color: var(--vt-kiem-chu); }

/* Khổ hẹp: xếp dọc, bỏ hàng tiêu đề (nhãn cột không còn thẳng với gì). */
@media (max-width: 760px) {
  .ds-dau { display: none; }
  .ds-hang { grid-template-columns: 1fr auto; gap: .35rem .6rem; }
  .ds-hang > .ds-ai { grid-column: 1; grid-row: 1 / span 3; align-self: start; }
  .ds-mo { grid-column: 2; grid-row: 1; }
}

/* ---- Menu profile: BỐN MỤC CÙNG MỘT HÌNH DẠNG ----
   Anh Tám kêu "cái thì được đóng khung cái thì không" — vì trước đây 2 mục là <a>
   trần còn 2 mục là .btn. Nay mọi mục cùng một khuôn; Đăng xuất chỉ khác MÀU. */
.menu-muc {
  display: block; width: 100%;
  padding: .42rem .6rem;
  border: 0; border-radius: var(--r-2);
  background: none;
  font: inherit; font-size: .92rem;
  color: var(--text); text-align: left; text-decoration: none;
  cursor: pointer;
}
.menu-muc:hover { background: var(--card-head); }
.menu-muc--thoat { color: var(--danger); }
.user-menu-body form { margin: 0; }

/* ============ Form Thêm idea: 5 khối có đánh số (bản mẫu anh Tám duyệt 05/09) ============
   Cấu trúc GIỐNG NHAU ở cả hai chế độ sáng/tối — chỉ token màu đổi (ràng buộc Phase 13). */
.khoi-form { padding: 1rem 1.15rem 1.15rem; }
/* Nhãn NHÓM, không phải tiêu đề: nhỏ, CHỮ HOA, giãn chữ, nhạt, LÙI VỀ SAU nội dung.
   Bản dựng đầu làm nó thành tiêu đề đen đậm nổi hơn cả nội dung — đúng chỗ anh Tám
   kêu "màu sắc chữ cũng phải giống mẫu". Số đo lấy từ CSS của chính bản mẫu. */
.khoi-tt {
  display: flex; align-items: center; gap: .4rem;
  margin: 0 0 .6rem;
  font-size: .65rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--nhan-khoi);
}
.khoi-so {
  flex: 0 0 auto;
  width: 17px; height: 17px; border-radius: var(--r-1);   /* ô VUÔNG bo nhẹ, không phải tròn */
  display: grid; place-items: center;
  background: var(--primary-nhat); color: var(--primary);
  font-size: .62rem; font-weight: 800;
}

/* Hàng hai cột cân nhau. min-width:0 BẮT BUỘC — ô lưới mặc định min-width:auto, không
   co được nhỏ hơn nội dung nên textarea dài sẽ đẩy tràn ngang. */
.hang-doi { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.hang-doi > * { min-width: 0; }
/* Mẫu KHÔNG có 'mo_ta_thumb' → một cột chiếm TRỌN bề ngang. Ô "Mô tả sản phẩm" là ô
   gõ nhiều chữ nhất form, rộng ra là có lợi; để nửa trang trắng thì người dùng tưởng
   thiếu mất cái gì. */
.hang-doi--mot { grid-template-columns: 1fr; }

/* Khối 4 TỰ DÀN: trường mẫu là động, admin thêm/bớt được. Xếp cứng 3 cột thì hôm nào
   thêm ô thứ tư nó rơi ra ngoài bố cục. */
.luoi-tu-dan {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: .85rem 1rem;
}
.luoi-tu-dan > * { min-width: 0; }

/* Ô khoá hiển thị dạng chữ, KHÔNG phải input — để không ai tưởng sửa được rồi gõ vào. */
.o-khoa-doc {
  margin-top: .2rem; padding: 0.45rem 0.65rem;
  border: 1px dashed var(--border-dam); border-radius: var(--r-2);
  background: var(--card-head); color: var(--muted);
  font-weight: 600;
}
/* Khối 5 theo mẫu: MỘT CỘT DỌC — link rộng hết khối, người phụ trách hẹp lại ở dưới. */
.o-nguoi-lam { margin-top: .6rem; max-width: 330px; }
.tu-dien { font-size: .65rem; color: var(--xac-nhan); margin: .25rem 0 0; font-weight: 600; }

/* Danh sách link bấm được, dưới ô nhập link */
/* Ô Link tham khảo TỰ CAO theo số dòng (JS `tuCao()` trong idea.js) — nhưng phải có
   TRẦN, kẻo dán 50 link là ô dài hết trang và nút "Tạo idea" trôi khỏi tầm mắt.
   12rem ≈ 7 dòng: đủ cho gần như mọi lần dùng thật, quá thì cuộn TRONG ô — đó mới là
   hành vi đúng, không phải kéo dài trang.
   `resize: vertical` (không phải `both`): ô tự cao rồi nên kéo tay gần như không cần,
   nhưng chặn kéo NGANG vì kéo ngang làm vỡ bố cục khối 5. */
#o-link { max-height: 12rem; overflow-y: auto; resize: vertical; }
.ds-link { display: flex; flex-direction: column; gap: .25rem; margin-top: .5rem; }
.ds-link a { font-size: .9rem; word-break: break-all; }
.ds-link .ds-link-bo { color: var(--muted); font-size: .86rem; }

@media (max-width: 760px) {
  .hang-doi { grid-template-columns: 1fr; }
}


/* ============ Phase 15 — dựng cho khớp bản mẫu anh Tám duyệt ============ */

/* --- Khối 2: HAI KHUNG ẢNH BẰNG NHAU ---
   Cho mỗi khung là một cột lưới cao bằng nhau, và vùng thả giãn ra chiếm hết phần
   còn lại. Không đặt chiều cao cứng: nhãn dài ngắn khác nhau thì cứng lại lệch. */
.hang-doi > .khung-anh { display: flex; flex-direction: column; margin: 0; }
.hang-doi > .khung-anh .drop-zone { flex: 1 1 auto; display: grid; place-content: center; }

/* --- Khối 3: HAI Ô MÔ TẢ CAO BẰNG NHAU ---
   Anh Tám chốt lấy theo ô idea đang có. Đặt bằng CSS chứ không bằng `rows`: `rows` chỉ
   là gợi ý ban đầu, ô nào có sẵn nội dung dài vẫn nở ra khác nhau. */
.hang-doi textarea { min-height: 9.5rem; resize: vertical; }

/* --- Khối 4: TỰ DÀN, ô textarea rộng gấp đôi, mọi ô cao bằng nhau ---
   Lưới 3 cột cố định (không auto-fit) để "1 cột / 2 cột" có nghĩa. Ô thứ ba admin thêm
   sau tự rơi xuống hàng mới, không phải sửa code. */
.luoi-tu-dan { grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: stretch; }
.o-dan { min-width: 0; }
.o-dan--rong { grid-column: span 2; }
.o-dan label { display: block; }
/* Mọi ô trong khối 4 CAO BẰNG NHAU — anh Tám: "2 ô = nhau về chiều cao".
   textarea vẫn kéo giãn được nếu người dùng cần viết dài. */
/* `display:block` BẮT BUỘC, không chỉ đặt height: textarea/input mặc định là
   inline-block nên ngồi trên đường chữ và cõng thêm ~6px khoảng thừa phía dưới —
   đo ra 86px vs 92px dù height đặt bằng nhau. Đây đúng loại lệch mà nhìn mắt không
   thấy, chỉ getBoundingClientRect() mới chỉ ra. */
/* TRỪ checkbox ra. Luật này viết cho ô nhập chữ; ném nguyên si vào hộp tick thì
   `display:block` đẩy nhãn xuống dòng dưới và `height:2.5rem` kéo hộp thành 13×40px
   (đo được, không phải phỏng đoán). Đúng họ L35: một selector viết cho vài `type`
   rồi trúng luôn cái `type` không định nhắm. Hôm nay chưa ai khai ô Có/Không nên
   không ai thấy — nhưng cả khối 4 sinh ra để admin thêm ô lúc nào cũng được, mà
   Có/Không là 1 trong 6 kiểu KIEU_TRUONG cho phép chọn. */
.o-dan input:not([type="checkbox"]), .o-dan select, .o-dan textarea {
  display: block; width: 100%;
  height: 2.5rem; min-height: 2.5rem;
}
.o-dan textarea { resize: vertical; }
/* Ô Có/Không: hộp tick giữ cỡ thật của trình duyệt, nhãn nằm CÙNG DÒNG bên phải.
   `.o-dan label.checkbox` (0,2,1) thắng `.o-dan label` (0,1,1) nên không cần !important. */
.o-dan label.checkbox {
  display: flex; align-items: center; gap: .45rem;
  height: 100%; min-height: 2.5rem; margin: 0;
}
.o-dan label.checkbox input[type="checkbox"] {
  width: auto; height: auto; min-height: 0; flex: none; margin: 0;
}

@media (max-width: 760px) {
  /* Khổ hẹp: một cột, "rộng gấp đôi" hết nghĩa nên bỏ span. */
  .luoi-tu-dan { grid-template-columns: 1fr; }
  .o-dan--rong { grid-column: auto; }
  .o-nguoi-lam { max-width: none; }
}

/* --- Nhãn ô trong form idea: theo bản mẫu (.lb) ---
   Mẫu để nhãn NHỎ và trầm (.7rem · 600 · --text-2) để nội dung nổi lên trên nhãn.
   Bản dựng đầu dùng cỡ nhãn mặc định của app — to và đậm hơn hẳn mẫu, đúng chỗ anh
   Tám kêu "màu sắc chữ cũng phải giống mẫu".
   PHẠM VI HẸP trong .khoi-form: nhãn ở các trang khác giữ nguyên, phase này không
   đụng form nào ngoài form Thêm idea. */
.khoi-form label {
  font-size: .7rem; font-weight: 600; color: var(--text-2);
}
/* Ô nhập bên trong thì trả về cỡ chữ bình thường — nhãn nhỏ chứ nội dung không nhỏ. */
.khoi-form label input,
.khoi-form label select,
.khoi-form label textarea,
.khoi-form .o-khoa-doc { font-size: .875rem; font-weight: 400; }
.khoi-form .o-khoa-doc { font-weight: 600; }

/* Viền khung thả theo mẫu: 1.5px, màu --border-dam (mẫu dùng #d9cbb6) — mảnh hơn
   nhưng RÕ hơn màu viền nhạt nhất đang dùng. Phạm vi HẸP trong khối 2 của form idea;
   khung ảnh ở trang chi tiết giữ nguyên, phase này không đụng trang đó. */
.hang-doi > .khung-anh .drop-zone { border-width: 1.5px; border-color: var(--border-dam); }

/* ---------- Trang Cài đặt: lưu tại chỗ (07/09/2026) — từ 17/09 dùng chung cho Xu hướng, 18/09 cho Cài đặt chủ đề ----------
   Cài đặt chủ đề (.trang-nc-cai-dat, 18/09/2026 — anh Tám: "ấn lưu lại nhảy lên đầu trang, anh muốn nó ở tại chỗ
   vừa thao tác"): 13 nhánh redirect của trang đó nay kèm #them-chu-de / #chu-de-<id> / #kenh-chua-gan, nên cùng
   bài toán flash rơi ra ngoài màn — nối selector vào 5 luật dưới, không sao chép, không đổi giá trị. Dòng cảnh báo
   "Chưa cấu hình YOUTUBE_API_KEY" của trang đó nằm NGOÀI #khu-flash nên không nổi: cố ý, nó là cảnh báo thường trú.
   Xu hướng: nút "Làm mới" theo khối redirect kèm #khoi-… kéo khối lên mép trên → #khu-flash đầu <main> rơi ra ngoài
   viewport ở mọi khổ; nối selector .trang-xu-huong vào đúng 4 luật dưới (không sao chép, không đổi giá trị). Mọi .flash
   nằm TRONG block content của Xu hướng (#ghi-chu-luat, #ghi-chu-dong, canh_bao, co_du_lieu_cu, .nhom-ghi-chu) KHÔNG
   nổi — luật scoped #khu-flash, cố ý. Xu hướng không có JS đóng flash: flash sống tới lượt GET kế (mọi chip là GET mới).
   Anh Tám nhập hàng chục dòng liên tiếp; mỗi lần Lưu mà nhảy về đầu trang là mất chỗ (L18).
   Flash nằm đầu <main>; giữ nguyên vị trí cuộn thì flash ra ngoài màn hình → trên trang có
   body.trang-cai-dat cho #khu-flash NỔI ở đáy màn hình. Trang khác giữ nguyên. Không tự ẩn:
   mật khẩu tạm hiện trong flash, phải đọc/copy được; lần lưu sau thay bằng flash mới.
   `position: fixed` bám viewport vì không tổ tiên nào có transform/filter (L21 — đã đo). */
.trang-cai-dat #khu-flash, .trang-xu-huong #khu-flash, .trang-nc-cai-dat #khu-flash {
  position: fixed; left: 50%; bottom: 1rem; transform: translateX(-50%); z-index: 90;
  width: min(100vw - 2rem, 720px); display: flex; flex-direction: column; gap: .5rem;
}
.trang-cai-dat #khu-flash:empty, .trang-xu-huong #khu-flash:empty, .trang-nc-cai-dat #khu-flash:empty { display: none; }
.trang-cai-dat #khu-flash .flash, .trang-xu-huong #khu-flash .flash, .trang-nc-cai-dat #khu-flash .flash { margin: 0; box-shadow: 0 10px 28px rgba(0, 0, 0, .22); }
/* Chừa chỗ ở đáy để flash nổi không đè lên nút cuối trang */
.trang-cai-dat main.container, .trang-xu-huong main.container, .trang-nc-cai-dat main.container { padding-bottom: 7rem; }
/* Xu hướng: neo #khoi-… nằm trên chính section.card (không có #noi-dung) — không nối luật :1505 của Cài đặt */
.trang-xu-huong section.card[id], .trang-nc-cai-dat section.card[id] { scroll-margin-top: 1rem; }
/* Đường không-JS: redirect kèm #neo → cuộn tới đúng khối/dòng, cách mép trên một chút cho dễ nhìn */
.trang-cai-dat #noi-dung [id] { scroll-margin-top: 1rem; }

/* ---------- Khối người dùng: MỘT form, ba mục (07/09/2026) ----------
   Anh Tám: "bố cục lộn xộn như này sao mà chịu được". Trước: ba form rời, ba nút Lưu, sáu ô
   một hàng, ID kênh phơi cạnh tên. Nay: mục có nhãn nhóm (.khoi-tt của form idea), nhãn TRÊN
   ô, ô tích dạng chip, một nút Lưu ở chân. Chỉ dùng token sẵn có. */
.nd-form { display: flex; flex-direction: column; gap: .9rem; }
/* `hidden` phải thắng mọi display của lớp: .nd-nhom là display:contents, .nd-muc/.nd-o là block. */
.nd-form [hidden] { display: none !important; }
.nd-muc + .nd-muc { border-top: 1px dashed var(--border); padding-top: .8rem; }
.nd-muc .khoi-tt { margin-bottom: .45rem; }
.nd-phu-de { margin: -.15rem 0 .55rem; font-size: .84rem; color: var(--muted); }
.nd-luoi { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: .6rem .8rem; align-items: end; }
.nd-luoi > * { min-width: 0; }
.nd-nhom { display: contents; }          /* nhóm ô để ẩn/hiện cùng nhau mà vẫn là ô của lưới */
.nd-o { display: block; margin: 0; }
.nd-nhan { display: block; font-size: .76rem; font-weight: 600; color: var(--text-2); margin: 0 0 .25rem; }
.nd-o input:not([type="checkbox"]), .nd-o select { display: block; width: 100%; margin-top: 0; height: 2.4rem; }
.nd-tick { display: flex; flex-wrap: wrap; gap: .4rem; }
label.chip-tick {
  display: inline-flex; align-items: center; gap: .4rem; margin: 0;
  padding: .32rem .7rem; border: 1px solid var(--border-dam); border-radius: var(--r-tron);
  background: var(--card-head); font-size: .9rem; line-height: 1.2; cursor: pointer; user-select: none;
}
label.chip-tick input[type="checkbox"] { width: auto; height: auto; margin: 0; accent-color: var(--primary); }
label.chip-tick:has(input:checked) { border-color: var(--primary); background: var(--primary-nhat); color: var(--primary-dam); }
.nd-kiem { height: 2.4rem; }              /* ô "kiêm QTV" đứng ngang hàng với các select */
.nd-admin { margin: 0; font-weight: 500; }
.nd-chan {
  display: flex; justify-content: space-between; align-items: center; gap: .6rem; flex-wrap: wrap;
  padding-top: .8rem; border-top: 1px dashed var(--border);
}
.nd-hanh-dong { display: flex; flex-wrap: wrap; gap: .4rem; }
.nd-hanh-dong form { margin: 0; }
/* Form TẠO có 6 ô: 4 cột ở khổ rộng để Phòng + Bộ phận đứng cùng hàng hai (auto-fit xếp 5+1,
   "Bộ phận" rơi xuống một mình). Khổ hẹp trả về auto-fit như các lưới khác. */
@media (min-width: 761px) {
  #form-tao-nguoi .nd-luoi { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
/* Nhóm "Thấy thêm từ cấp dưới" của TP/TBP: chip CHỈ ĐỌC — viền đứt, không con trỏ, để không ai
   tưởng bấm được rồi bấm. Anh em với .o-khoa-doc (ô khoá hiển thị dạng chữ). */
.chip-doc {
  display: inline-flex; align-items: center; padding: .32rem .7rem;
  border: 1px dashed var(--border-dam); border-radius: var(--r-tron);
  background: var(--card-head); color: var(--text-2); font-size: .9rem; line-height: 1.2;
}
.nd-nhan--cach { margin-top: .55rem; }
.nd-luu-y { margin: .4rem 0 0; font-size: .8rem; color: var(--muted); }
/* Ô tóm tắt trong danh sách người dùng: nhãn : số, mỗi thứ một dòng (07/09/2026 chiều — anh Tám:
   "làm cho gọn và đẹp hơn"). Nhãn mờ, số đậm thẳng cột (tabular-nums). Hàng cao hơn trước
   (3–4 dòng) — anh chấp nhận đổi lấy dễ đọc. */
.ds-tom-tat { display: flex; flex-direction: column; gap: .1rem; font-size: .9rem; line-height: 1.3; }
.ds-tom-tat .tt-dong { display: block; }
.ds-tom-tat .tt-nhan { color: var(--muted); }
.ds-tom-tat .tt-so { font-weight: 600; font-variant-numeric: tabular-nums; }

/* Màn Kênh (non-admin): cột "Idea cá nhân / bộ phận" — số thẳng cột, không ngắt dòng. */
.tt-so-kenh { font-variant-numeric: tabular-nums; white-space: nowrap; }
/* ---- Phase 29 (anh Tám 09/09): bốn chỉnh sửa bảng Idea chờ duyệt ---- */
/* 1. Cột Thao tác: MỖI NÚT MỘT DÒNG, căn lề trái. */
.cot-thao-tac { white-space: normal; }
.cot-thao-tac > * { display: block; margin: 0 0 .3rem; }
.cot-thao-tac > .btn, .cot-thao-tac .inline-loai > summary { width: fit-content; }
/* Chữ trong nút KHÔNG được vắt hai dòng: "Feedback &" / "Duyệt" vừa xấu vừa đội cao cả hàng. Số đo
   không thấy chuyện này (nút vẫn thẳng lề, vẫn mỗi cái một dòng) — ảnh chụp mới lộ (L30). */
.cot-thao-tac .btn { white-space: nowrap; }
.cot-thao-tac .tt-ghi { margin: .1rem 0 0; }        /* dòng "còn N vòng" nằm dưới cùng, không đẩy nút */
.cot-thao-tac .inline-form { margin-top: .3rem; }
/* 2. Cột Tuần: nội dung ngắn ("Tuần 37" / "Không") nên cột tự hẹp. */
.cot-tuan { white-space: nowrap; }
/* 3. Cột Người tạo: tên trên MỘT dòng; tên dài thì nhỏ chữ dần. CSS không co cỡ chữ theo ĐỘ DÀI
   nội dung được, nên cỡ chọn ở máy chủ theo số ký tự (xem template). Ngưỡng 16/24 ký tự đo bằng
   CDP với tên thật. SÀN 11px — nhỏ hơn nữa thì thà để nó rộng ra còn hơn không đọc nổi. */
.cot-nguoi { white-space: nowrap; }
.cot-nguoi.ten-dai { font-size: .82rem; }
.cot-nguoi.ten-rat-dai { font-size: max(11px, .72rem); }
/* 4. Cột Phản hồi: căn giữa, số thẳng cột. */
.cot-giua { text-align: center; font-variant-numeric: tabular-nums; }

/* Chữ "i" ở góc trên phải mỗi đoạn feedback (Phase 28, anh Tám 09/09) — bấm mới hiện ai viết. */
.fb-ds > li { position: relative; }
.fb-ai-i > summary { list-style: none; position: absolute; top: .25rem; right: 0;
  /* Vùng chạm ≥ 24×24 và trông NHƯ BẤM ĐƯỢC — L45(b): trạng thái/nút mới mà không có luật CSS thì
     nó vô hình, người ta không biết là bấm được. */
  width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;
  cursor: pointer; border: 1px solid var(--fb-vien); border-radius: 50%;
  font-size: .78rem; font-weight: 700; font-style: italic; color: var(--fb-chu);
  background: var(--card); line-height: 1; }
.fb-ai-i > summary::-webkit-details-marker { display: none; }
.fb-ai-i > summary:hover { background: var(--fb-nen); }
/* Chừa chỗ cho chữ "i" để nó không ĐÈ lên nội dung ở ô hẹp */
.fb-ds > li > .pre, .fb-ds > li > .link-list, .fb-ds > li > .image-grid { padding-right: 1.9rem; }
.fb-ai-i .fb-ai { margin: .1rem 0 .3rem; padding-right: 1.9rem; }

/* ---- Phase 27: trang Feedback & Duyệt (3 cột) ---- */
.fd-dau { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.fd-buoc { display: flex; gap: .5rem; list-style: none; padding: 0; margin: .3rem 0 1rem; flex-wrap: wrap; }
.fd-buoc li { font-size: .84rem; font-weight: 600; border-radius: var(--r-tron); padding: .2rem .7rem;
  border: 1px solid var(--border-dam); color: var(--muted); background: var(--card); }
.fd-buoc li.dang { border-color: var(--primary); color: var(--primary-dam); background: var(--primary-nhat); }
.fd-buoc li.xong { border-color: var(--tt-duyet-chu); color: var(--tt-duyet-chu); background: var(--tt-duyet-nen); }
.fd-luoi { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: .8rem; align-items: start; }
.fd-cot { background: var(--card); border: 1px solid var(--border); border-radius: var(--r-3);
  padding: .85rem; min-width: 0; }
.fd-cot-ten { font-size: .78rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--muted); margin: 0 0 .5rem; }
.fd-v1, .fd-v2 { background: var(--fb-nen); border-color: var(--fb-vien); }
.fd-v1 .fd-cot-ten, .fd-v2 .fd-cot-ten { color: var(--fb-chu); }
/* "Chỉ sáng lên khi đã ấn hoàn thành fb1" — cột chưa mở phải NHÌN RA LÀ CHƯA MỞ, không chỉ khác ở
   chỗ thiếu ô nhập (L45b: trạng thái mới mà không có luật CSS thì nó vô hình). */
.fd-chua-mo { background: var(--card-head); border-style: dashed; border-color: var(--border-dam);
  opacity: .62; }
.fd-chua-mo .fd-cot-ten { color: var(--muted); }
.fd-chua { color: var(--muted); font-size: .9rem; margin: .4rem 0 0; }
/* Vòng đã chốt: KHÔNG RENDER ô gõ nữa (tham số `cho_go` của macro o_feedback, 12/09/2026). Chỗ này
   từng là `.fd-khoa .fb-nhap, .fd-khoa .fb-file { display: none }` — che mắt mà VẪN GỬI (L45): trình
   duyệt gửi hai giá trị cùng tên, máy chủ lấy cái ĐẦU (ô rỗng của vòng cũ) ⇒ không ai gửi được
   feedback vòng 2, mà đó là cửa bắt buộc để duyệt idea. ĐỪNG VÁ LẠI BẰNG CSS.
   Đo 12/09 sau bản vá: hai selector đó khớp 0 phần tử ở CẢ BA trạng thái idea (bản cũ: 5 khi chốt
   một vòng, 10 khi chốt cả hai) — luật đã chết thật nên mới xoá. */
.fd-nhan-xong { font-size: .72rem; font-weight: 700; border-radius: var(--r-tron); padding: .05rem .45rem;
  background: var(--tt-duyet-nen); color: var(--tt-duyet-chu); text-transform: none; letter-spacing: 0; }
.fd-chan { margin-top: .7rem; border-top: 1px dashed var(--fb-vien); padding-top: .6rem; }
.fd-thieu { font-size: .86rem; color: var(--danger); margin: .4rem 0 0; }
/* ================= Phase 30b — ba nút chọn cột, ba màu cột, thanh thao tác dưới =================
   ⚠️ Cả khối này PHẢI nằm SAU `.fd-v1, .fd-v2 { background: var(--fb-nen) }` ở trên: cùng độ đặc
   hiệu thì luật khai SAU mới thắng. Khai trước là class có đủ trong HTML mà không ăn gì (L15 vế bổ
   sung, đã dính đúng lỗi này ở Phase 30a). */

/* --- Màu ba cột. Vạch 3px mép trên + chấm tròn trước tiêu đề, cùng màu `*-cham`. --- */
.fd-goc { background: var(--goc-nen); border-color: var(--goc-vien);
  box-shadow: inset 0 3px 0 var(--goc-cham); }
.fd-v1  { background: var(--fb1-nen); border-color: var(--fb1-vien);
  box-shadow: inset 0 3px 0 var(--fb1-cham); }
.fd-v2  { background: var(--fb2-nen); border-color: var(--fb2-vien);
  box-shadow: inset 0 3px 0 var(--fb2-cham); }
.fd-goc .fd-cot-ten { color: var(--goc-chu); }
.fd-v1  .fd-cot-ten { color: var(--fb1-chu); }
.fd-v2  .fd-cot-ten { color: var(--fb2-chu); }
.fd-cot-ten::before { content: ""; display: inline-block; vertical-align: middle;
  width: 10px; height: 10px; border-radius: 50%; margin: -2px .45rem 0 0; }
.fd-goc .fd-cot-ten::before { background: var(--goc-cham); }
.fd-v1  .fd-cot-ten::before { background: var(--fb1-cham); }
.fd-v2  .fd-cot-ten::before { background: var(--fb2-cham); }
/* Cột 2 chưa mở thì về lại kiểu "gạch đứt xám" — giữ nguyên ý cũ, chỉ cần thắng luật màu ở trên. */
.fd-chua-mo { background: var(--card-head); border-color: var(--border-dam); box-shadow: none; }
.fd-chua-mo .fd-cot-ten { color: var(--muted); }
.fd-chua-mo .fd-cot-ten::before { background: var(--muted); }

/* --- Ba nút chọn cột --- */
.fd-chuyen { display: flex; gap: .5rem; flex-wrap: wrap; margin: 0 0 .85rem; }
.fd-nut-cot { display: inline-flex; align-items: center; gap: .45rem; text-decoration: none;
  padding: .38rem .95rem; border-radius: var(--r-tron); font-size: .86rem; font-weight: 700;
  border: 1.5px solid var(--fd-nut-vien); background: var(--card); color: var(--text-2); }
.fd-nut-cot:hover { border-color: var(--muted); }
/* Chấm ĐẶC khi mở, RỖNG khi đóng: dấu hiệu KHÔNG PHẢI MÀU. Nút mở/đóng chỉ khác nhau ở nền, viền
   và chữ thì người mù màu không thấy nút nào đang mở — hình khối thì thấy, kể cả in đen trắng. */
.fd-nut-cham { flex: none; width: 9px; height: 9px; border-radius: 50%;
  border: 1.5px solid currentColor; background: transparent; }
.fd-nut-goc .fd-nut-cham { border-color: var(--goc-cham); }
.fd-nut-fb1 .fd-nut-cham { border-color: var(--fb1-cham); }
.fd-nut-fb2 .fd-nut-cham { border-color: var(--fb2-cham); }
.fd-nut-goc.fd-nut-mo { background: var(--goc-nen); border-color: var(--goc-vien); color: var(--goc-chu); }
.fd-nut-fb1.fd-nut-mo { background: var(--fb1-nen); border-color: var(--fb1-vien); color: var(--fb1-chu); }
.fd-nut-fb2.fd-nut-mo { background: var(--fb2-nen); border-color: var(--fb2-vien); color: var(--fb2-chu); }
.fd-nut-goc.fd-nut-mo .fd-nut-cham { background: var(--goc-cham); }
.fd-nut-fb1.fd-nut-mo .fd-nut-cham { background: var(--fb1-cham); }
.fd-nut-fb2.fd-nut-mo .fd-nut-cham { background: var(--fb2-cham); }
.fd-nut-khoa { opacity: .55; }

/* --- Cột nào hiện. `[data-mo]` ở điều kiện là CỐ Ý: máy chủ không đặt được thuộc tính (JS hỏng,
   template cũ trong cache…) thì cả ba cột hiện như trước Phase 30b, chứ không mất sạch nội dung. --- */
.fd-trang[data-mo]:not([data-mo~="goc"]) .fd-goc,
.fd-trang[data-mo]:not([data-mo~="fb1"]) .fd-v1,
.fd-trang[data-mo]:not([data-mo~="fb2"]) .fd-v2 { display: none; }
/* Số vệt lưới bám theo SỐ CỘT ĐANG MỞ, không bám theo bề rộng màn hình.
   `repeat(auto-fit, minmax(420px, 1fr))` đúng khi khung hẹp, nhưng Phase 31 nới khung lên 1600px thì
   nó đẻ ra vệt THỨ BA cho một lưới chỉ có hai cột: hai cột nội dung co về 2/3 chiều ngang, 1/3 còn
   lại bỏ trống. Đo ở 1920: lưới 1560px, 3 vệt, 2 cột hiện. Nới khung xong mới lộ ra.
   Chỉ có bốn tổ hợp thật (goc / goc+fb1 / goc+fb2 / fb1 / fb2) nên viết thẳng, khỏi đoán. */
.fd-trang[data-mo] .fd-luoi { grid-template-columns: 1fr; }
/* ⚠️ Luật hai cột PHẢI nằm trong @media rộng. Đặt ngoài thì nó thắng cả luật một-cột của khổ hẹp —
   hai selector thuộc tính làm độ đặc hiệu (0,4,0) cao hơn (0,3,0), và media query KHÔNG cộng thêm
   độ đặc hiệu nào. Đã dính: ở 390px lưới giữ 2 vệt trong khi chỉ 1 cột hiện, cột co còn 161px thay
   vì 335px. Bài "mỗi lần một cột" vẫn ĐẠT vì nó chỉ đếm số cột — bề rộng mới là thứ tố cáo. */
@media (min-width: 761px) {
  .fd-trang[data-mo~="goc"][data-mo~="fb1"] .fd-luoi,
  .fd-trang[data-mo~="goc"][data-mo~="fb2"] .fd-luoi { grid-template-columns: 1fr 1fr; }
}

/* --- Ba nút thao tác, luôn ở dưới, ở CẢ HAI khổ --- */
.fd-thao-tac { margin-top: 1rem; padding-top: .9rem; border-top: 1px solid var(--border);
  display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; }
.fd-thao-tac form { display: flex; align-items: center; gap: .5rem; margin: 0; }
.fd-thao-tac-chu { margin: .5rem 0 0; }
.fd-goc .image-grid figure { max-width: 110px; }
/* Nút vô hiệu PHẢI trông khác nút thường — L45(b) đã cắn đúng chỗ này một lần rồi. */
.btn:disabled, .btn[disabled] { opacity: .45; cursor: not-allowed; filter: grayscale(.4); }
@media (max-width: 900px) {
  /* Ba cột không vừa khổ hẹp: xếp DỌC theo đúng thứ tự đọc — Idea gốc → FB1 → FB2. */
  .fd-luoi { grid-template-columns: 1fr; }
  /* Khổ hẹp: mỗi lần MỘT cột (anh Tám 10/09). data-hep là cột người dùng vừa bấm — máy chủ đặt,
     nên đúng ngay lần vẽ đầu. Nó luôn nằm trong data-mo, vậy nên chỉ cần luật ẩn, không cần luật hiện. */
  .fd-trang[data-hep]:not([data-hep="goc"]) .fd-goc,
  .fd-trang[data-hep]:not([data-hep="fb1"]) .fd-v1,
  .fd-trang[data-hep]:not([data-hep="fb2"]) .fd-v2 { display: none; }
  .fd-trang[data-mo] .fd-luoi { grid-template-columns: 1fr; }
}

/* ---- Phase 26: màn Lưu trữ (bộ lọc kỳ + bốn thẻ + bảng gập) ---- */
/* KHÔNG dùng overflow:hidden ở đây: menu chọn kỳ là lớp phủ cao hơn thẻ, hidden thì nó bị CẮT mất
   mấy mục cuối (đúng "Tùy chỉnh…") — số đo báo sạch, chỉ ảnh chụp mới lộ. Bo góc cho hàng đầu riêng. */
.lt-khoi { padding: 0; }
.lt-dau { border-radius: var(--r-3) var(--r-3) 0 0; }
.lt-dau { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem;
  padding: .7rem .85rem; background: var(--card-head); border-bottom: 1px solid var(--border); }
.lt-nhan { font-size: .78rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--muted); padding-top: .5rem; }
/* Nút chọn kỳ: hai dòng — khoảng ngày trên, tên kỳ dưới (bản vẽ) */
.loc-ky { position: relative; }
.loc-ky-nut { list-style: none; cursor: pointer; background: var(--card); border: 1px solid var(--border-dam);
  border-radius: var(--r-2); padding: .4rem .75rem; display: flex; flex-direction: column; gap: .1rem;
  min-width: 15rem; text-align: right; }
.loc-ky-nut::-webkit-details-marker { display: none; }
.loc-ky-ngay { font-size: .76rem; color: var(--muted); }
.loc-ky-ten { font-size: .95rem; font-weight: 700; color: var(--text); }
.loc-ky-mui { color: var(--muted); font-size: .75rem; }
.loc-ky-menu { position: absolute; right: 0; top: calc(100% + .3rem); z-index: 30; width: 15rem;
  background: var(--card); border: 1px solid var(--border-dam); border-radius: var(--r-2);
  box-shadow: 0 8px 24px rgba(0,0,0,.14); overflow: hidden; }
.loc-ky-nhom { border-bottom: 1px solid var(--border); padding: .25rem 0; }
.loc-ky-nhom:last-child { border-bottom: 0; }
.loc-ky-muc { display: block; padding: .4rem .75rem; font-size: .92rem; color: var(--text-2); text-decoration: none; }
.loc-ky-muc:hover { background: var(--card-head); }
.loc-ky-muc.chon { font-weight: 700; color: var(--primary-dam); background: var(--primary-nhat); }
.loc-ky-ngay-o { display: flex; gap: .3rem; flex-wrap: wrap; margin-top: .3rem; }
.loc-ky-ngay-o input { min-width: 0; flex: 1 1 6rem; }
/* Bốn thẻ số — mỗi thẻ là LINK tới danh sách đã lọc */
.lt-the { display: grid; grid-template-columns: repeat(4, 1fr); gap: .7rem; padding: 1rem .85rem 0; }
.lt-o { display: block; border: 1px solid var(--border); border-left: 3px solid var(--border-dam);
  border-radius: var(--r-2); padding: .7rem .8rem; background: var(--card-head); text-decoration: none;
  color: inherit; min-width: 0; }
.lt-o:hover { border-color: var(--primary); }
.lt-ten { display: block; font-size: .74rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--muted); }
.lt-so { display: block; font-size: 1.7rem; font-weight: 800; line-height: 1.1;
  font-variant-numeric: tabular-nums; color: var(--text); }
.lt-ghi { display: block; font-size: .76rem; color: var(--muted); }
.lt-chip { margin: .1rem 0 0; display: flex; gap: .3rem; flex-wrap: wrap; }
.lt-tong { border-left-color: var(--primary); }
.lt-cho_duyet { border-left-color: var(--tt-cho-chu); background: var(--tt-cho-nen); }
.lt-cho_duyet .lt-so { color: var(--tt-cho-chu); }
.lt-da_duyet { border-left-color: var(--tt-duyet-chu); background: var(--tt-duyet-nen); }
.lt-da_duyet .lt-so { color: var(--tt-duyet-chu); }
.lt-loai { border-left-color: var(--tt-loai-chu); background: var(--tt-loai-nen); }
.lt-loai .lt-so { color: var(--tt-loai-chu); }
/* Bảng gập: Kênh → Người tạo → mã */
.lt-cay { padding: 1rem .85rem 1.1rem; }
.lt-kenh { border: 1px solid var(--border); border-radius: var(--r-2); margin-bottom: .5rem; overflow: hidden; }
.lt-kenh > summary, .lt-nguoi > summary { display: flex; align-items: center; gap: .45rem;
  padding: .55rem .7rem; cursor: pointer; font-weight: 600; }
.lt-kenh > summary { background: var(--card-head); }
.lt-kenh[open] > summary { background: var(--primary-nhat); }
.lt-nguoi > summary { font-weight: 500; color: var(--text-2); padding-left: 1.6rem;
  border-top: 1px solid var(--border); }
.lt-day { flex: 1; }
.lt-ten-kenh { font-weight: 700; }
.lt-dem { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--primary-dam);
  background: var(--primary-nhat); border-radius: var(--r-tron); padding: .05rem .5rem; font-size: .82rem; }
.lt-dem.nho { font-size: .78rem; }
.ma-k { font-size: .72rem; font-weight: 700; letter-spacing: .04em; color: var(--muted);
  border: 1px solid var(--border-dam); border-radius: var(--r-1); padding: .02rem .35rem; }
.mini { font-size: .74rem; font-weight: 700; border-radius: var(--r-1); padding: .05rem .4rem;
  font-variant-numeric: tabular-nums; }
.mini.cho { background: var(--tt-cho-nen); color: var(--tt-cho-chu); }
.mini.duyet { background: var(--tt-duyet-nen); color: var(--tt-duyet-chu); }
.mini.loai { background: var(--tt-loai-nen); color: var(--tt-loai-chu); }
.lt-ma { margin: 0; padding: .2rem 0 .5rem 2.6rem; list-style: none; font-size: .9rem; }
.lt-ma li { display: flex; align-items: center; gap: .45rem; padding: .2rem 0; flex-wrap: wrap; }
.ma-idea { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .86rem;
  color: var(--muted); border: 1px dashed var(--border-dam); border-radius: var(--r-1); padding: .02rem .35rem;
  text-decoration: none; }
.lt-ten-idea { color: var(--text-2); text-decoration: none; }
.lt-ten-idea:hover { text-decoration: underline; }
.tt { font-size: .73rem; font-weight: 700; border-radius: var(--r-tron); padding: .05rem .45rem; }
.tt.cho { background: var(--tt-cho-nen); color: var(--tt-cho-chu); }
.tt.duyet { background: var(--tt-duyet-nen); color: var(--tt-duyet-chu); }
.tt.loai { background: var(--tt-loai-nen); color: var(--tt-loai-chu); }
/* Cửa sổ "chọn mã" (Phase 26). Là LỚP NÂNG CẤP — con số vẫn là link thật, xem luu_tru.js. */
.lt-hop { border: 1px solid var(--border-dam); border-radius: var(--r-3); padding: 0; max-width: min(46rem, 92vw);
  width: 100%; background: var(--card); color: var(--text); box-shadow: 0 12px 40px rgba(0,0,0,.28); }
.lt-hop::backdrop { background: rgba(20, 16, 28, .45); }
.lt-hop-dau { display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: .6rem .85rem; background: var(--card-head); border-bottom: 1px solid var(--border); }
.lt-hop-ten { font-size: .95rem; }
.lt-hop-than { padding: .3rem .85rem; max-height: 60vh; overflow: auto; }
.lt-hop-than tbody tr { cursor: pointer; }
.lt-hop-than tbody tr:hover { background: var(--primary-nhat); }
.lt-hop-chan { margin: 0; padding: .3rem .85rem .8rem; }

/* Bảng tuần ở màn Giao Idea tuần */
.bang-tuan tr.tuan-nay { background: var(--primary-nhat); }
.bang-tuan td { white-space: nowrap; }
@media (max-width: 760px) {
  .lt-the { grid-template-columns: repeat(2, 1fr); }
  .lt-dau { flex-direction: column; align-items: stretch; }
  .loc-ky-nut, .loc-ky-menu { min-width: 0; width: 100%; }
  .loc-ky-nut { text-align: left; }
}

/* ---- Phase 24: lưới hai cột Idea gốc | Feedback (trang chi tiết) ---- */
.fb-luoi { display: grid; grid-template-columns: 1fr 1fr; border: 1px solid var(--border);
  border-radius: var(--r-3); overflow: hidden; margin: .8rem 0; }
/* Idea nháp: lưới chỉ còn cột nội dung. PHẢI khai SAU `.fb-luoi`, cùng độ đặc hiệu — khai trước
   thì luật hai cột ghi đè và class này có trong HTML mà không ăn gì (L15). Ảnh chụp lộ ra, còn phép
   đo "class có trong trang" thì vẫn xanh. */
.fb-luoi--mot { grid-template-columns: 1fr; }
.fb-dau { padding: .5rem .85rem; font-size: .78rem; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--muted); background: var(--card-head);
  border-bottom: 1px solid var(--border); }
.fb-dau.fb { color: var(--fb-chu); background: var(--fb-nen); border-left: 1px solid var(--border); }
.fb-o { padding: .9rem .85rem; min-width: 0; border-bottom: 1px solid var(--border); }
.fb-o.fb { background: var(--fb-nen); border-left: 1px solid var(--border); }
.fb-o > h2:first-child, .fb-o > h3:first-child { margin-top: 0; }
.fb-ten { font-size: .74rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--fb-chu); margin: 0 0 .5rem; }
.fb-ds { list-style: none; padding: 0; margin: 0 0 .6rem; }
.fb-ds > li { border-bottom: 1px dashed var(--fb-vien); padding: .4rem 0; }
.fb-ds > li:last-child { border-bottom: 0; }
.fb-ai { margin: 0 0 .2rem; display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.fb-ai small { color: var(--muted); }
.fb-chu-link { color: var(--text-2); font-size: .9rem; }
.fb-nhap, .fb-file { display: block; margin-top: .5rem; }
.fb-nhap-nhan { display: block; font-size: .8rem; color: var(--muted); margin-bottom: .2rem; }
.fb-nhap textarea { width: 100%; }
.fb-anh { margin: .4rem 0 0; }
.fb-anh figure { max-width: 120px; }
/* Ảnh trong lưới hai cột nhỏ hơn ở trang thường: cột chỉ rộng ~450px, để 220px thì mỗi hàng nhét
   được 1 ảnh rưỡi ⇒ ba ảnh xếp thành ba dòng và hàng đầu cao lêu nghêu, đẩy ba hàng còn lại xuống
   dưới màn. Bản vẽ xếp ảnh NGANG — 132px cho đúng ba ảnh một hàng. */
.fb-luoi .image-grid figure { max-width: 132px; }
.fb-form { display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; margin-bottom: 1rem; }
/* Chấm màu đọc từ mã #RRGGBB trong chữ (xem filter mau_trong_chu) — viền để màu trắng/nhạt vẫn thấy */
.mau-cham { display: inline-block; width: 14px; height: 14px; border-radius: var(--r-1); margin-left: .35rem;
  border: 1px solid var(--border-dam); vertical-align: -2px; }
@media (max-width: 760px) {
  /* Một cột: thứ tự DOM trái-phải xen kẽ nên feedback rơi ngay dưới đúng khối nó nói tới. */
  .fb-luoi { grid-template-columns: 1fr; }
  .fb-o.fb, .fb-dau.fb { border-left: 0; }
}

/* ---- Phase 23: nút giờ (thanh trên) + ảnh đại diện ---- */
.gio-tool { position: relative; }
.gio-tool > summary { list-style: none; cursor: pointer; font-variant-numeric: tabular-nums; white-space: nowrap; }
.gio-tool > summary::-webkit-details-marker { display: none; }
.gio-than { position: absolute; right: 0; top: calc(100% + .35rem); z-index: 20; min-width: 15rem; max-width: 20rem;
  padding: .6rem .8rem; background: var(--card); border: 1px solid var(--border-dam); border-radius: var(--r-3);
  box-shadow: 0 8px 24px rgba(0,0,0,.12); font-size: .86rem; display: flex; flex-direction: column; gap: .3rem; }
@media (max-width: 480px) { .gio-mui { display: none; } }   /* giữ HH:MM, cắt phần giải thích */
.avatar-anh { object-fit: cover; }
/* `hidden` THUA `display:inline-flex` của .avatar-tron (L15/L45 tái phạm 08/09: ảnh thật + chữ dự phòng hiện CẠNH
   nhau ở cả 3 chỗ, số đo "có thuộc tính hidden" vẫn xanh, ảnh chụp mới lộ). Trạng thái phải có luật CSS riêng. */
.avatar-tron[hidden] { display: none !important; }
.avatar-tron--nho { width: 26px; height: 26px; font-size: .75rem; margin-right: .4rem; vertical-align: middle; }
.avatar-tron--to { width: 96px; height: 96px; font-size: 2.2rem; }
.av-hang { display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; margin-bottom: .6rem; }
.av-form { display: flex; flex-direction: column; gap: .4rem; }
.av-form .inline-form { gap: .4rem; }

/* ---- Phase 21: dải băng bổ sung hồ sơ (cùng chỗ với .impersonate-banner, tông nhẹ hơn) ---- */
.bang-ho-so {
  display: flex; align-items: center; justify-content: center; gap: .6rem; flex-wrap: wrap;
  padding: .45rem 1rem; font-size: .92rem;
  background: var(--primary-nhat); color: var(--text); border-bottom: 1px solid var(--border-dam);
}
.cd-de-nghi { margin-top: .6rem; }

/* ---- Phase 20: đề nghị sửa hồ sơ chờ duyệt + lịch sử ---- */
.dn-cho { border-color: var(--primary); }
.dn-canh-bao { color: var(--danger); font-weight: 600; margin: .4rem 0; }
.dn-thay-doi { margin: .4rem 0 .6rem; padding-left: 1.2rem; }
.dn-thay-doi li { margin: .15rem 0; }
.dn-dau { display: flex; flex-wrap: wrap; gap: .4rem .6rem; align-items: baseline; }
.dn-lech { border: 1px solid var(--danger); border-radius: var(--r-2); padding: .6rem .8rem; margin: .5rem 0; }
.dn-lech ul { margin: .3rem 0; padding-left: 1.2rem; }
.dn-hanh-dong { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin-top: .6rem; }
.dn-hanh-dong input[type="text"] { max-width: 18rem; }
/* Chuyển bộ phận (15/09/2026): tiến độ hai phần duyệt; thẻ TBP đã duyệt phần mình thì mờ và không có nút. */
.dn-chuyen { margin: .45rem 0 .15rem; }
.dn-phan { margin: .1rem 0 .5rem; padding-left: 1.2rem; }
.dn-phan li { margin: .15rem 0; }
.dn-phan--xong { color: var(--muted); }
.dn-mot--da-duyet { opacity: .62; }
.dn-da-duyet { margin: .6rem 0 0; font-weight: 600; }
.ls-ds { list-style: none; margin: .3rem 0 0; padding: 0; }
.ls-hang { display: flex; flex-wrap: wrap; gap: .3rem .6rem; align-items: center; padding: .35rem 0; border-top: 1px dashed var(--border); font-size: .9rem; }
.ls-luc { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.nd-lich-su { margin-top: .6rem; }
.nd-lich-su > summary { cursor: pointer; color: var(--muted); font-size: .9rem; }

/* Cột QTV (Phase 18e): mỗi người MỘT DÒNG và không vỡ — tên + chip + "(đã khoá)" luôn cùng hàng
   (phiên prompt đọc ảnh 07/09: "Thanh / Huyền" vỡ đôi như hai người, chip rơi xa tên nó mô tả).
   nowrap cũng tự định bề rộng cột theo người dài nhất (đo 269px ở 390), nên không cần min-width;
   ô hẹp thì bảng cuộn ngang trong .table-scroll chứ không bẻ tên. */
.o-qtv .pt-nguoi { display: block; white-space: nowrap; }
/* Ô trống "— chưa gán ai —" cũng không bẻ: ca MỌI kênh trống (production 07/09) đo ở 390px cột co còn
   53px, chữ đó gãy 3–4 dòng trong một cột vốn rỗng. */
.o-qtv .qtv-trong { white-space: nowrap; }

/* ---------- Dòng Chuyển tài khoản — mẫu B, hai dòng (anh Tám duyệt 07/09/2026) ----------
   Avatar 40px + viền nhạt CHỈ ở đây (.dong-tk) — màn Người dùng giữ 34px. Dòng 1 tên + chip
   chức danh; dòng 2 tên đăng nhập + chấm bộ phận. Ghi đè .dong-tk-chu b/small (display:block)
   bằng selector đặc hiệu hơn, không sửa luật cũ. */
.dong-tk .avatar-tron { width: 40px; height: 40px; font-size: 1rem; box-shadow: 0 0 0 3px var(--primary-nhat); }
.dong-tk-chu .dong-tk-1 { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.dong-tk-chu .dong-tk-1 b { display: inline; }
.dong-tk-chu .dong-tk-2 { display: flex; align-items: center; gap: .3rem; margin-top: .15rem; }

/* Phase 30b (bổ sung 10/09) — cột "Feedback lần 2" lúc CHƯA MỞ: xem trước các ô sẽ gõ, dạng mờ.
   Đây là thẻ TRƠ, không phải ô nhập: con trỏ không nháy, không chọn được chữ, không gõ được gì.
   `user-select:none` là để cả cú bấm-kéo cũng không tạo cảm giác đây là ô nhập thật. */
.fd-xem-truoc { margin-top: .6rem; opacity: .5; user-select: none; }
.fd-o-mo { margin-bottom: .7rem; }
.fd-o-mo .fb-ten { margin: 0 0 .3rem; }
.fd-o-mo-hop {
  border: 1px dashed var(--border-dam); border-radius: var(--r-2); background: var(--card);
  padding: .55rem .7rem; min-height: 3.2rem; color: var(--muted); font-size: .92rem;
}

/* Phase 31 — giữ nội dung đang gõ dở. Dải băng chỉ hiện khi THẬT SỰ có bản được khôi phục, và nói
   rõ ba điều người dùng cần: gõ từ bao giờ, trên máy nào, và ảnh thì phải chọn lại.
   KHÔNG có danh từ "nháp"/"draft" ở đây — chữ đó đã thuộc về `Idea.status == "nhap"`. */
.go-do-bang {
  display: flex; align-items: center; justify-content: space-between; gap: .8rem; flex-wrap: wrap;
  background: var(--primary-nhat); border: 1px solid var(--primary); border-radius: var(--r-2);
  padding: .6rem .9rem; margin: 0 0 1rem; font-size: .92rem; color: var(--text-2);
}
.go-do-chi-bao { color: var(--muted); font-size: .86rem; }
.go-do-chi-bao[hidden] { display: none !important; }   /* L45: hidden phải thắng luật display */

/* Nút "Đổi ảnh đại diện" bị JS giấu sau khi gắn được sự kiện chọn ảnh. `.btn` khai
   `display:inline-block`, mà `hidden` chỉ là luật UA `display:none` nên nó THUA — đúng cơ chế L15,
   và L45 đã dính đúng kiểu này hai lần. Phải !important. */
.av-form [hidden] { display: none !important; }

/* ---------- Xu hướng: MỘT ô thời lượng + ba nút đổi mức (22/09/2026, bản 00003.7) ----------
   Anh Tám: "ở bên phải sẽ có 3 nút: 3-4p, 4-20p, Tren 20p. Mặc định hiển thị video trên 20p".
   Trước bản này thẻ chủ đề có ba ô <details> xếp dọc; nay chỉ còn ô của mức đang chọn nên ô KHÔNG gập
   nữa (một ô gập sẵn là một ô trông như rỗng). Ba nút là LINK THẬT, JS chỉ đỡ cho khỏi tải lại trang. */
.o-muc { border-top: 1px solid var(--border); padding-top: .6rem; margin-top: .6rem; }
.o-dau { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
.o-so { font-weight: 700; }      /* số video là chữ dẫn của hàng từ 22/09 — tên mức đã nằm trên nút */
.o-luc { color: var(--muted); font-size: .82rem; }
.o-cho { color: var(--muted); font-size: .82rem; font-style: italic; }
/* Cụm nút đẩy sang phải, và LUÔN là con cuối của .o-dau — giữ hàng đúng hai cụm (L50). */
.o-nut { margin-left: auto; }
.o-nut form { margin: 0; }
.o-tin { margin: .5rem 0 0; }
/* Ô chưa có dữ liệu: nhạt đi cho khác ô đã có, nhưng vẫn đọc được chữ báo bên trong. */
.o-dang_lay .o-so, .o-cho_bam .o-so, .o-het_luot .o-so { color: var(--muted); font-weight: 400; }
/* Ba nút mức: cụm con thứ hai của .khoi-head, nên .khoi-head giữ đúng 2 con (L50). margin-left:auto để
   khi gãy dòng cụm vẫn bám mép PHẢI — space-between với một phần tử thì nó dính trái. min-width:0 cho
   cụm tên chủ đề: từ khoá dài tới 120 ký tự, không có nó là cụm nút bị đẩy tràn ra ngoài thẻ. */
.khoi-ten { min-width: 0; flex: 1 1 14rem; }
.nut-muc { display: flex; gap: .35rem; flex-wrap: wrap; justify-content: flex-end; margin-left: auto; }
.nut-muc-1 { white-space: nowrap; }
.khoi-chu-de .video-grid:empty { display: none; }

/* ---------- Khoá YouTube: NHIỀU KHE cho một bộ phận (20/09/2026, đợt 2) ----------
   Anh Tám: "mỗi bộ phận anh cũng cho anh 2 API". Tool xoay sang khe sau khi khe trước hết lượt, nên
   từng khe phải thấy được đang thế nào — khe bị bỏ qua thì nhạt đi NHƯNG câu giải thích vẫn đọc rõ
   (tô mờ mà không nói vì sao là trạng thái vô hình, L45). */
.khoa-khe { list-style: none; margin: .75rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .75rem; }
.khoa-khe .khe { border: 1px solid var(--border); border-radius: var(--r-3); padding: .75rem .9rem; }
.khoa-khe .khe-bo-qua { border-style: dashed; opacity: .85; }
.khoa-khe .khe-bo-qua .khe-tren b { color: var(--muted); }
.khe-tren { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
.khe-ly-do { color: var(--muted); }
.khe-nut { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin-top: .5rem; }
.khe-nut form { margin: 0; }

/* ---------- Video tương tự (Nexlev, 21/09/2026) ----------
   Khối nằm ngay dưới nút của từng video trong lưới Xu hướng. Một lời gọi mất ≈15 giây nên nút phải
   nói ra là đang chờ — CSS chỉ lo phần nhìn, chữ do JS đổi. */
.tt-nut { margin-top: .4rem; }   /* 23/09: là <a> sang trang riêng, không còn <button> nên bỏ luật [disabled] */
/* Dấu hiệu "sắp hết quota Nexlev" NGAY TRÊN NÚT TIÊU LƯỢT (29/09). Cảnh báo cũ chỉ có ở trang Video
   tương tự — mà mở trang ấy là đã tiêu 10 đơn vị rồi, tức cảnh báo tới SAU cú tiêu. Màu mượn đúng
   biến cảnh báo sẵn có, không đẻ bộ màu mới. */
.tt-nut-sap-het { border-color: var(--ve-vien); background: var(--ve-nen); color: var(--ve-chu); }
.tt-khoi { margin-top: .5rem; border-top: 1px dashed var(--border); padding-top: .5rem; }
.tt-nguon { font-style: italic; }
.tt-ds { margin: .4rem 0 0; padding-left: 1.2rem; display: flex; flex-direction: column; gap: .35rem; }
.tt-ds li { font-size: .9rem; }
.tt-meta { display: block; color: var(--muted); font-size: .82rem; }
.tt-uoc, .tt-tin { color: var(--muted); }

/* ---------- Khoá dịch vụ cấp công ty (22/09/2026, bản 00003.8) ----------
   Trang chỉ admin. Điều quan trọng nhất của màn này là NÓI RA đang dùng nguồn khoá nào, nên câu nguồn
   dùng đúng khuôn .flash đang có (không đẻ giọng thứ hai), còn từng khe là một khối có viền. */
.khoa-dv .kdv-nguon { margin: 0 0 .8rem; }
.kdv-khe { border: 1px solid var(--border); border-radius: var(--r-2); padding: .7rem .8rem; margin-bottom: .7rem; }
.kdv-khe.kdv-loi { border-color: var(--danger); }
.kdv-dau { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
.kdv-duoi { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 700; }
.kdv-luc, .kdv-trong { color: var(--muted); font-size: .82rem; }
.kdv-ok { border-color: var(--primary); color: var(--primary); }
.kdv-the-loi { border-color: var(--danger); color: var(--danger); }
/* Cụm nút LUÔN là con cuối của hàng đầu — giữ hàng đúng hai cụm (L50) */
.kdv-nut { margin-left: auto; }
.kdv-nut form { margin: 0; }
.kdv-tin { margin: .5rem 0 0; }
/* Form dán khoá: xuống hàng riêng, ô khoá co giãn. min-width:0 để ô không nong khối ra ngoài thẻ. */
.kdv-form { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin: .6rem 0 0; }
.kdv-nhan { color: var(--muted); font-size: .82rem; }
.kdv-o { flex: 1 1 14rem; min-width: 0; }
.kdv-o-nhan { flex: 1 1 10rem; min-width: 0; }

/* ═══ ĐỢT C2 — khối "Gợi ý SEO" trên thẻ video ══════════════════════════════════════════════════
   Chỉ dùng biến ĐÃ KHAI: một biến CSS chưa khai thì im lặng không ăn — không lỗi, không cảnh báo,
   chỉ mất hiệu ứng (L38; đã dính ba lần với `--vien`, `--chu-mo`, `--nen-the`).
   ⚠️ CỐ Ý KHÔNG viết mẫu `var(` + tên biến ở đây: `tests/test_hinh_trong.py` quét CHÍNH file này bằng
   regex `var\((--[a-z0-9-]+)` và so với tập đã khai, nên một cái tên ví dụ nằm trong CHÚ THÍCH cũng
   bị đếm là "đang dùng" ⇒ bài kiểm ĐỎ OAN. Bản đầu tôi viết một ví dụ như thế và nó làm đỏ thật.
   ⇒ Và đáng nhớ hơn bản vá: bộ dò TAY của tôi lúc ấy CÓ báo tên ví dụ đó là "thiếu", tôi **gạt đi**
     vì "chỉ là chữ trong chú thích". Nó báo ĐÚNG. Một cảnh báo bị dán nhãn báo-oan thì im lặng y hệt
     một cảnh báo không tồn tại — mà ở đây tôi là người dán nhãn. */
.seo-khoi { margin-top: .35rem; }

/* Nút mở. Cùng cỡ 28px với hàng nút cỡ thumbnail để hai hàng nút trên một thẻ không lệch nhau. */
.seo-nut { padding: .18rem .5rem; font-size: 0.78rem; line-height: 1.2; }

/* ⚠️ BẮT BUỘC: `hidden` chỉ là luật UA `display:none`, nó THUA `display` mà `.btn` khai — đúng cơ
   chế L15, và đã tái phạm ở L45 (ảnh đại diện hiện cạnh chữ dự phòng). Thiếu dòng này thì nút "Gợi ý
   SEO" vẫn nằm đó sau khi bấm, người dùng bấm lần nữa và tiêu thêm một lượt TIỀN. */
.seo-nut[hidden], .seo-lai[hidden], .seo-chep[hidden] { display: none !important; }

.seo-ket { margin-top: .4rem; font-size: 0.82rem; }
.seo-tin { margin: .2rem 0; color: var(--muted); }

/* Câu KHAI (dữ liệu không đủ mà máy vẫn phải trả lời). Đặt TRƯỚC kết quả và cho nó màu cảnh báo
   nhạt: người đọc phải thấy giới hạn TRƯỚC khi tin mấy dòng gợi ý, không phải sau. */
.seo-khai { margin: .2rem 0 .3rem; padding-left: 1.1rem; color: var(--muted); font-size: 0.78rem; }
.seo-khai li { margin: .1rem 0; }

.seo-kq { border: 1px solid var(--border); border-radius: 6px; padding: .4rem .5rem;
          background: var(--card-head); }
.seo-dau { margin: 0 0 .3rem; font-weight: 600; }

/* Nhãn "Máy viết" — BẮT BUỘC theo yêu cầu C2 §4: người đọc phải biết đây là máy gợi ý, KHÔNG phải
   số liệu đo được. Đừng ai gỡ nó đi cho gọn. */
.seo-nhan { display: inline-block; margin-left: .3rem; padding: .05rem .35rem; border-radius: 999px;
            border: 1px solid var(--border-dam); background: var(--bg); color: var(--muted);
            font-size: 0.7rem; font-weight: 500; vertical-align: middle; }

/* Một mục = nhãn · chữ · nút chép. Xuống dòng được ở khổ hẹp (390px) thay vì tràn ngang (L33/L55). */
.seo-muc { display: flex; flex-wrap: wrap; align-items: baseline; gap: .3rem; margin: .22rem 0; }
.seo-nhan-muc { flex: 0 0 auto; min-width: 3.6rem; color: var(--muted); font-size: 0.75rem; }
.seo-chu { flex: 1 1 12rem; min-width: 0; overflow-wrap: anywhere; }
.seo-chep { flex: 0 0 auto; padding: .1rem .38rem; font-size: 0.7rem; }

/* Ô "từ khoá riêng của bạn" + nút hỏi sâu hơn. `type=text` nằm trong danh sách selector chung của
   repo nên không dính L35 (kiểu input mới rơi ra ngoài danh sách → trắng bốp ở nền tối). */
.seo-hang { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .35rem; }
.seo-o { flex: 1 1 11rem; min-width: 0; height: 1.9rem; padding: .1rem .4rem; }
/* 🔴 CỠ CHỮ PHẢI Ở MỘT LUẬT RIÊNG, ĐẶC HIỆU CAO HƠN — và vì sao thì đáng đọc hết (01/10/2026):
   `.seo-o` từng khai `font-size: .78rem` NGAY TRONG luật trên, và nó **CHƯA TỪNG ĂN MỘT LẦN NÀO**.
   Luật dùng chung ở dòng ~479 (`input[type="text"], … { font: inherit; }`) có độ đặc hiệu (0,1,1),
   thắng `.seo-o` (0,1,0); mà `font:` là shorthand nên `inherit` **đặt lại cả cỡ chữ** về 16px.
   ⇒ Hai nửa đều tồn tại, đều đúng chính tả, chỉ KHÔNG THẮNG NHAU — họ L15, và nó im lặng tuyệt đối:
     không lỗi, không cảnh báo, chỉ là một con số trong file không bao giờ tới màn hình.
   ⚠️ Lộ ra thế nào: anh Tám xin *"giảm cỡ chữ để ghi đủ"* ô từ khoá. Phiên nghiệm thu ĐỌC CSS rồi
     kết luận *"đã 0.78rem rồi, chắc không cần giảm"*. Đo thật ở 390px thì `getComputedStyle` trả
     **16px**, và chữ gợi ý cần 313px trong một ô rộng 303px ⇒ **đang bị cắt thật**.
     ⇒ Đúng L15 vế đo: **đo HIỆU LỰC (`getComputedStyle`), đừng đọc khai báo.**
   ⇒ Nên bản vá cho yêu cầu của anh Tám KHÔNG phải "chọn một cỡ chữ nhỏ hơn" — mà là **làm cho cỡ
     chữ đã chọn từ đầu thật sự có hiệu lực**. Giữ nguyên .78rem, chỉ nâng đặc hiệu lên (0,2,1).
   ⚠️ ĐỪNG hạ lại thành `.seo-o` một lớp "cho gọn": gọn xong là nó im lặng thua tiếp. */
.seo-hang input.seo-o { font-size: 0.78rem; }
.seo-lai { flex: 0 0 auto; padding: .18rem .5rem; font-size: 0.76rem; }

.seo-con { margin: .3rem 0 0; font-size: 0.75rem; }

/* ── Đợt D1: tab "Kiểm tra Network" (30/09/2026) ─────────────────────────────────────────────────
   Mọi biến dưới đây phải có trong danh sách đã khai — biến chưa khai thì trình duyệt IM LẶNG không
   vẽ gì, và thứ mất đi là một đường kẻ mảnh nên mắt không bắt được (L38). Có bài kiểm so hai tập.

   ⛔ ĐỪNG VIẾT CHUỖI `v a r ( - - x )` (liền, không cách) VÀO BẤT KỲ CHÚ THÍCH NÀO TRONG FILE NÀY.
   `test_moi_bien_css_dung_deu_da_khai` của repo dò bằng regex trên **toàn văn**, **KHÔNG bỏ chú
   thích trước khi dò** ⇒ một cái tên biến ví dụ nằm trong chú thích bị đọc thành *"biến đang dùng
   mà chưa khai"*, và bài ấy ĐỎ. Đã dính **HAI LẦN**: đợt C2, rồi lại đợt D1 ngay trong chú thích
   viết ra để nhắc chính luật này.
   ⇒ CÁCH VIẾT THAY THẾ, dùng cái nào cũng được — regex của bộ dò đòi dấu `(` DÍNH LIỀN sau `var`:
         var( --ten-bien )        ← thêm khoảng trắng
         "biến `--ten-bien`"      ← bỏ hẳn chữ `var`
     ⚠️ Một lệnh cấm KHÔNG KÈM ĐƯỜNG ĐI thì người sau **vẫn cần diễn đạt ý đó** và sẽ tự nghĩ ra một
     cách — có thể là cách vẫn dính. Đúng L36 ở tầng tài liệu: *cấm một ô mà không cho giá trị hợp lệ
     nào là một ngõ cụt.*

   ⚠️ VÀ GHI ĐÚNG LÝ DO, vì bản đầu của chính chú thích này ghi sai họ: chữa ở phía bộ dò (cho nó bỏ
     chú thích trước khi dò) **KHÔNG phải "nới bộ dò"**. Phiên nghiệm thu đo:
         bộ dò hiện tại (toàn văn)   dùng 95 · khai 95 · THIẾU ['--x']   ← đỏ vì chú thích
         sau khi bỏ chú thích        dùng 94 · khai 95 · THIẾU []
         biến chỉ KHAI trong chú thích: 0   ⇒ bỏ chú thích không mất một khai báo nào
         đối chứng: tiêm một biến bịa ⇒ VẪN KÊU đúng tên
     ⇒ Tức bộ dò hiện tại đang **đo SAI ĐỐI TƯỢNG**: nó tự nhận đo *"CSS đang chạy"* nhưng đo *"toàn
       bộ ký tự trong file"*. Chú thích không ăn, không vẽ, trình duyệt không thấy.
     ⇒ Và CHIỀU NGƯỢC là một lỗ THẬT: một biến khai trong một khối CSS **đã bị comment out** hôm nay
       vẫn tính là "đã khai" ⇒ một `var()` thiếu thật có thể LỌT. Hôm nay 0 ca — nhưng "hôm nay 0" là
       thứ đổi ngay khi ai đó comment out một khối, và lúc ấy **không gì kêu** (L42 vế 3).
     ⇒ Lý do KHÔNG chữa ở đây là lý do **QUY TRÌNH**, không phải lý do kỹ thuật: (1) đổi một bộ dò của
       repo bên trong một đợt tính năng là mở phạm vi (quy tắc 2); (2) **phía có câu văn làm bộ dò kêu
       không nên là phía quyết định đổi bộ dò** (giao thức 🔢 vế b). Đã ghi nợ kèm nguyên bảng đo. */
.ktn-hop { display: grid; gap: .5rem; }
/* Lưới ô nhập + nút. `1fr auto` ở khổ rộng; ở khổ hẹp xuống một cột — và luật một-cột phải nằm TRONG
   media query của khổ đó, không viết ngoài rồi tin là "ở khổ kia vô hại": `@media` KHÔNG cộng thêm
   độ đặc hiệu nào, nên luật ngoài vẫn thắng luật trong ở MỌI khổ (L55). */
.ktn-form { display: grid; grid-template-columns: 1fr auto; gap: .4rem .5rem; align-items: end; }
.ktn-form label { grid-column: 1 / -1; font-size: .86rem; color: var(--text-2); }
.ktn-o { width: 100%; }
.ktn-vd { margin: 0; color: var(--muted); font-size: .8rem; }
.ktn-vd code { font-size: .95em; }
.ktn-luot { margin: 0; color: var(--muted); font-size: .8rem; }
.ktn-tin { margin: .2rem 0 0; color: var(--muted); }

.ktn-ket { display: grid; gap: .45rem; margin-top: .6rem; }
.ktn-cau-tra-loi { margin: 0; font-size: 1.05rem; }
/* Tên Network dài là ca THẬT, không phải ca dựng ra: "HTV Technology and Media Services" = 33 ký tự.
   `overflow-wrap` để nó ngắt được trong cột 390px thay vì đẩy cả thẻ tràn ngang (L33). */
/* ⚠️ `--primary`, KHÔNG PHẢI `--primary-text` — đã vấp thật 30/09/2026, và mắt mới bắt được.
   `--primary-text` là **màu chữ NẰM TRÊN nền primary** (nút, chip đang chọn), không phải một màu chữ
   đứng một mình. Dùng nó trên nền thẻ trắng cho tương phản **1.00** — chữ trắng trên nền trắng:
        sáng  #ffffff trên #ffffff → 1.00        tối  #1a1024 trên #1e1a25 → 1.08
   ⇒ Nhãn hiện ra thành *"Thuộc Network:"* rồi **để trống**, còn tên Network thì **có trong DOM**.
   ⇒ 🔴 VÀ ĐÂY LÀ HỌ L38 Ở CHIỀU KHÓ HƠN: L38 là biến **CHƯA KHAI** (im lặng không vẽ gì). Ca này là
     biến **ĐÃ KHAI nhưng MANG NGHĨA KHÁC** — nên bộ dò "mọi biến phải có trong danh sách đã khai"
     **cho nó qua**, và 21 con số của phép đo giao diện **đều báo sạch** (phép đo đọc `textContent`,
     mà `textContent` thì không biết màu). Chỉ **ẢNH CHỤP** lộ ra (L30).
   ⇒ Chọn `--primary` vì repo đã dùng nó làm MÀU CHỮ thật (`a { color: var(--primary) }`), và đo được
     5.01 (sáng) / 9.59 (tối) — đạt 4.5 ở cả hai chế độ, đo trên nền thẻ THẬT chứ không trên nền suy ra. */
.ktn-net { color: var(--primary); overflow-wrap: anywhere; }
.ktn-duong { margin: 0; color: var(--muted); font-size: .82rem; }
.ktn-moc { margin: 0; color: var(--muted); font-size: .78rem; }
/* Bảng số liệu: nhãn trái, giá trị phải. `dl` chứ không `table` — không có hàng nào cần cuộn ngang,
   và `table` trong cột hẹp là đúng chỗ đã phải bọc `.table-scroll` khắp nơi. */
.ktn-so { display: grid; grid-template-columns: auto 1fr; gap: .15rem .6rem; margin: 0;
          font-size: .86rem; }
.ktn-so dt { color: var(--muted); }
.ktn-so dd { margin: 0; overflow-wrap: anywhere; }

@media (max-width: 560px) {
  .ktn-form { grid-template-columns: 1fr; }
  .ktn-form .btn { justify-self: start; }
}

/* Đợt D2 — nút "Vẫn hỏi Nexlev" dưới câu báo YouTube-không-có. Hàng ngang, nút rồi tới ghi chú. */
.ktn-bo-qua { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-top: .3rem; }

/* ═══ ĐỢT F1 — Lịch sử tra cứu (01/10/2026) ═══════════════════════════════════════════════ */
/* 🔴 MỘT BIẾN MÀU RIÊNG, và lý do là một SỰ THẬT ĐO ĐƯỢC về chính file này, không phải ý thích:
     --ok (#15803d) trên nền xanh nhạt (#eaf4ec) ở cỡ chữ .73rem  ->  4.45   (ngưỡng 4.5)
   Dưới ngưỡng 0,05. Thẻ "Có kết quả" là chữ NHỎ trên nền nhạt nên nó rơi đúng vào ca ấy.
   ⚠️ VÀ TÔI SUÝT KẾT LUẬN NGƯỢC: bản đầu tôi dựng thẻ KHÔNG NỀN ⇒ nó nằm trên `--card` trắng ⇒
     `--ok` đo ra **5.02, ĐẠT** ⇒ token mới hoá ra không cần. Nhưng bản vẽ anh Tám DUYỆT có nền
     (`.tt-ok{background:var(--ok-nen)…}`), tức tôi đã lệch khỏi bản đã duyệt mà không nói.
     ⇒ Dựng đúng bản duyệt thì nền là `--ok-nen` và `--ok` tụt về 4.45 — token mới CÓ việc thật.
     ⇒ Bài học: con số tương phản chỉ có nghĩa kèm theo NỀN THẬT. Đổi nền là đổi kết luận (L39).
   ⛔ ĐỪNG ĐỔI `--ok`: nó đang dùng ở chỗ khác với cỡ chữ khác, và đổi một biến DÙNG CHUNG để chữa
     MỘT chỗ là đúng hình dạng L62. Khai một biến có TÊN, sẫm hơn, cho đúng việc này.
   ⚠️ Khai CẢ HAI chế độ. Ở chế độ tối `--ok` hiện tại (#8fe6bc) đã đạt 10.44 nên biến mới bằng
     chính nó — nhưng vẫn phải KHAI, vì một token chỉ có trong khối tối thì ở trạng thái
     không-dán-nhãn nó KHÔNG áp. */
/* ⚠️ MÀU LỖI DÙNG LẠI `--danger` / `--danger-nhat` ĐÃ CÓ, không đẻ bộ token song song.
     Bản đầu tôi gõ một biến tên `-` `-loi` (viết tách ở đây để bộ dò biến-chưa-khai không trúng
     chính câu kể về lỗi) cùng hai biến nền/viền tự chế — cái tên ấy KHÔNG TỒN TẠI
     (đúng L38: biến chưa khai thì im lặng không ăn, không lỗi, chỉ mất hiệu ứng), và hai biến kia
     là một bộ màu lỗi THỨ HAI cạnh bộ đã có — đúng cái L62 cảnh báo ở chiều ngược.
     ⇒ Biến MỚI chỉ còn ĐÚNG MỘT: `--ok-chu`, vì chỗ này thật sự không có token nào đủ sẫm. */
/* Ba token, lấy đúng bộ của bản vẽ anh Tám đã duyệt. KHAI ĐỦ BA CHỖ (`:root` trần · `@media`
   · `[data-theme]`): token chỉ khai trong khối tối thì ở trạng thái KHÔNG-DÁN-NHÃN nó không áp. */
:root { --ok-chu: #115c2b; --ok-nen: #eaf4ec; --ok-vien: #8fbf9d; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --ok-chu: #9ce0b4; --ok-nen: #13291c; --ok-vien: #3f7a52; }
}
:root[data-theme="dark"] { --ok-chu: #9ce0b4; --ok-nen: #13291c; --ok-vien: #3f7a52; }

.ls-tien { display: flex; flex-wrap: wrap; gap: .6rem; margin: .6rem 0 1rem; }
.ls-o { flex: 1 1 13rem; min-width: 0; display: flex; flex-direction: column; gap: .15rem;
        padding: .6rem .75rem; border: 1px solid var(--border); border-radius: var(--r-2);
        background: var(--card); }
/* Ô GIỮA mang áo khác hai ô kia — nó là con số duy nhất để quyết "có đáng tiêu tiếp không".
   Ba ô cùng áo thì nó chìm, và chìm đúng chỗ không được phép chìm. */
.ls-o--loi { border-color: var(--danger); background: var(--danger-nhat); }
.ls-nhan { font-size: .78rem; color: var(--muted); }
.ls-so { font-size: 1.15rem; font-weight: 700; }

.ls-bang { width: 100%; border-collapse: collapse; font-size: .82rem; }
.ls-bang th, .ls-bang td { padding: .35rem .5rem; border-bottom: 1px solid var(--border);
                           text-align: left; vertical-align: top; }
.ls-bang th { font-size: .74rem; color: var(--muted); font-weight: 600; white-space: nowrap; }
.ls-goc { word-break: break-all; max-width: 18rem; }
/* Ô SỐ và ô TIỀN không được vắt dòng giữa con số và đơn vị ("1.655" xuống dòng rồi "đ") — đọc ra
   hai thứ thay vì một. Cùng ca với thẻ trạng thái ở trên, cùng chỉ lộ ra trên ảnh. */
.ls-bang td.ls-so-o { white-space: nowrap; }
/* Ô nội dung gợi ý: một dòng, cắt bằng dấu ba chấm, chữ đủ nằm ở `title`.
   `max-width` CÓ ăn ở đây vì `td` là ô bảng, không phải phần tử inline. */
.ls-bang td.ls-nd { max-width: 16rem; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; }

/* ⚠️ `white-space: nowrap` KHÔNG phải để đẹp. Thiếu nó, thẻ "Không đọc được" vỡ thành BA DÒNG
   trong một viên bo tròn — nhìn ra một ô hỏng, không ra một nhãn. Bản vẽ anh Tám duyệt có vế này
   (`.tt{…;white-space:nowrap}`); tôi dựng thiếu, và MỌI SỐ ĐO ĐỀU SẠCH (`du = 0`, bảng trong khung,
   không tràn trang) — chỉ ẢNH mới lộ. L30 lần nữa: số đo trả lời đúng câu nó được hỏi, mà câu đó
   không phải câu người dùng hỏi khi nhìn màn hình.
   Thẻ dài ra thì bảng rộng ra, và bảng đã nằm trong `.table-scroll` nên nó cuộn, không tràn trang. */
.ls-the { display: inline-block; padding: .05rem .4rem; border-radius: 999px; font-size: .73rem;
          border: 1px solid var(--border); white-space: nowrap; }
.ls-the--ok { background: var(--ok-nen); color: var(--ok-chu); border-color: var(--ok-vien); }
.ls-the--loi { background: var(--danger-nhat); color: var(--danger); border-color: var(--danger); }

/* Dòng "Xem lại" trải HẾT chiều ngang, không nằm trong ô cuối của dòng dữ liệu. Ở 390px ô cuối
   trôi ra ngoài màn ⇒ khối mở ra nằm chỗ không ai thấy, và dòng dữ liệu cao vọt lên vài trăm px
   với một khoảng trống khổng lồ. Mọi số đo vẫn sạch — chỉ ảnh lộ (L30). */
.ls-xem-dong > td { padding-top: 0; }
.ls-ban-ghi > tr:first-child > td { border-bottom: none; }
.ls-ban-ghi > tr.ls-xem-dong > td { border-bottom: 1px solid var(--border); }
.ls-xem > summary { cursor: pointer; display: inline-block; }
.ls-xem[open] > summary { margin-bottom: .4rem; }
.ls-moc { margin: .2rem 0 .4rem; color: var(--danger); font-size: .8rem; }
.ls-dl { display: grid; grid-template-columns: auto 1fr; gap: .15rem .6rem; margin: 0 0 .4rem;
         font-size: .82rem; }
.ls-dl dt { color: var(--muted); white-space: nowrap; }
.ls-dl dd { margin: 0; }
.ls-gioi-han { margin: .4rem 0 0; padding-left: 1.1rem; }
.ls-gioi-han li { margin-bottom: .3rem; }

@media (max-width: 760px) {
  .ls-dl { grid-template-columns: 1fr; gap: 0 0; }
  .ls-dl dt { margin-top: .3rem; }
  /* 🔴 Ô trải ngang nằm TRONG bảng, nên nó rộng bằng BẢNG — mà bảng rộng hơn màn (nó cuộn).
     ⇒ Chữ trong đó vắt dòng theo bề rộng BẢNG, và phần đuôi nằm ngoài màn: người dùng đọc được
       nửa câu rồi phải cuộn ngang để đọc nốt, trong khi dòng dữ liệu bên trên thì không cần.
     ⇒ `sticky left:0` ghim ô lại mép trái khung cuộn, và kẹp bề rộng theo MÀN chứ không theo bảng.
     Đo được sau khi vá: chữ nằm trọn trong 390px, không phần nào ra ngoài. */
  .ls-xem-dong > td { position: sticky; left: 0; max-width: 100vw; }
  /* ⚠️ `display: block` BẮT BUỘC, không phải cho gọn: `max-width` **không áp** cho phần tử
     INLINE không-thay-thế. Câu "không có gì để xem lại · …" nằm trong một `<span>` ⇒ nó làm ngơ
     `max-width` và vẫn vắt dòng theo bề rộng BẢNG. Đo được: 4/6 khối vừa (chúng là `<details>`,
     vốn là block), đúng 2 cái `<span>` tràn 339px và 376px. */
  .ls-xem-dong > td > * { display: block; max-width: calc(100vw - 4.5rem); }
}

/* ═══ ĐỢT H1 — hai nút "Đã dùng / Không dùng", màn chặn, ô dán link ═══════════════════════════ */
/* ⚠️ `display: inline-flex` chứ không `block`: form nằm CẠNH nội dung mục, không xuống dòng riêng
   — ba mục liền nhau mà mỗi mục đẩy một form xuống dòng thì khối cao gấp đôi. */
.seo-tl-form { display: inline-flex; gap: .3rem; margin-left: .4rem; }
.seo-tl { white-space: nowrap; }
/* Nút ĐANG CHỌN phải trông KHÁC — và khác bằng MÀU NỀN, không chỉ bằng viền.
   L45 vế (b): một trạng thái không có luật CSS thì nó vô hình, người ta bấm rồi tưởng tool hỏng.
   Ở đây còn nặng hơn: không thấy mình đã chọn gì thì sẽ bấm lại, và lần bấm lại ấy ghi đè dữ liệu. */
.seo-tl--chon { background: var(--primary); color: var(--primary-text); border-color: var(--primary); }

.seo-chan { border: 1px solid var(--danger); background: var(--danger-nhat);
            border-radius: var(--r-2); padding: .6rem .75rem; margin-bottom: .6rem; }
.seo-chan-luot { margin-top: .5rem; padding-top: .5rem; border-top: 1px solid var(--border); }
.seo-chan-luot:first-of-type { border-top: none; padding-top: 0; }
.seo-da-tl { margin-top: .4rem; padding-top: .4rem; border-top: 1px dashed var(--border); }

.seo-link-form { margin-top: .5rem; }
.seo-link-hang { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .2rem; }
/* Cùng bẫy đã vấp ở `.seo-o`: luật dùng chung `input[type="text"] { font: inherit }` có đặc hiệu
   (0,1,1) và THẮNG một luật một-lớp ⇒ cỡ chữ ở đây phải gắn vào selector ≥ 2 lớp. */
.seo-link-hang input.seo-o { font-size: 0.78rem; flex: 1 1 14rem; }

@media (max-width: 760px) {
  /* Ở khổ hẹp, form nút xuống dòng riêng — đứng cạnh thì nội dung mục bị bóp còn vài chữ. */
  .seo-tl-form { display: flex; margin-left: 0; margin-top: .25rem; }
}

/* ════════════════════════════════════════════════════════════════════════════════════════════════
   ĐỢT J1 (07/10/2026) — DẢI ĐẦU KÊNH · BẢNG THEO NGÀY · TRANG VIDEO RIÊNG
   ════════════════════════════════════════════════════════════════════════════════════════════════
   ⚠️ MỌI `var(--x)` dưới đây phải có trong danh sách đã khai ở `:root` — biến chưa khai thì trình
      duyệt **im lặng không vẽ gì**, không lỗi, không cảnh báo, và thiếu một đường kẻ mảnh thì nhìn
      ảnh không thấy (L38: nghiệm thu bằng mắt bắt được cái SAI, không bắt được cái THIẾU).
      Đã đối chiếu: --border --muted --card --text --danger --primary --primary-dam --primary-nhat. */

/* ---- §1 dải đầu kênh ---- */
.tdk-dau { display: flex; gap: .9rem; align-items: center; flex-wrap: wrap; margin-bottom: .8rem; }
.tdk-dau-chu { min-width: 0; }            /* min-width:0 để tên kênh dài cắt được trong flex */
.tdk-dau-chu h2 { margin: 0; }
.tdk-handle { margin: .15rem 0 0; }
/* Ảnh đại diện kênh là ảnh XA (YouTube): cho nền giữ chỗ để lúc ảnh chưa tải xong bố cục không nhảy,
   và `object-fit` để ảnh không méo nếu YouTube trả khung khác 1:1. */
.avatar-tron.avatar-anh[src] { object-fit: cover; background: var(--border); }

/* 4 ô đỏ. `auto-fit` + `minmax` để ở 390px nó tự xuống 2 ô mỗi hàng, ⛔ không cần media query riêng
   (và ⛔ không ghim 4 cột: ở khổ hẹp 4 cột làm mỗi ô còn ~80px, con số 5 chữ số vỡ hai dòng). */
.tdk-o-hang {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
  gap: .5rem; margin-bottom: .8rem;
}
.tdk-o {
  display: flex; flex-direction: column; gap: .15rem;
  padding: .55rem .7rem; border-radius: var(--r-1);
  background: var(--danger-nhat); border: 1px solid var(--danger);
}
.tdk-o-nhan { font-size: .72rem; color: var(--muted); }
.tdk-o-so { font-size: 1.05rem; color: var(--danger); line-height: 1.2; }
.tdk-o-so--nho { font-size: .9rem; }
/* "kênh ẩn" KHÔNG phải một con số — cho nó cỡ chữ và màu của chữ thường, để mắt không đọc nó như
   một giá trị đo được. Hai thứ khác nhau thì phải TRÔNG khác nhau. */
.tdk-o-an { font-size: .82rem; font-weight: 400; color: var(--muted); }

/* ---- §3/§4 cụm nút ---- */
/* Cụm nút bọc trong MỘT thẻ, tự xuống dòng ở khổ hẹp. ⛔ Đừng thả rời các nút này vào một flex
   `space-between` — thêm con thứ ba là hai thứ đang cạnh nhau bị dàn ra hai đầu (L50, đo 329px). */
.tdk-nut { display: flex; gap: .4rem; flex-wrap: wrap; align-items: center; margin-bottom: .9rem; }
.tdk-nut .inline-form { margin: 0; }

/* ---- §2 bảng theo ngày ---- */
.tdk-h3 { margin: 1.1rem 0 .5rem; font-size: .95rem; }
/* "so với 23/09" đứng cạnh một con số tăng — phải NHỎ và MỜ hơn con số, vì nó là chú thích cho con
   số ấy chứ không phải một số thứ hai. `display:block` để nó xuống dòng trong ô, không nong cột. */
.tdk-so-voi { display: block; font-size: .68rem; font-weight: 400; color: var(--muted); }

/* 🔺 §2.3 + L45(b) — CHIP VÔ HIỆU PHẢI TRÔNG KHÁC CHIP THƯỜNG.
   Vế này không phải trang trí: thêm một TRẠNG THÁI mới cho phần tử mà CSS không có luật cho nó thì
   trạng thái ấy **vô hình** — người dùng bấm, không thấy gì xảy ra, và kết luận là tool hỏng. Đã trả
   giá đúng thế ở Phase 18b với nút "Lấy lại tên từ YouTube" (`disabled` trong HTML, test xanh, mà
   nút vô hiệu trông y hệt nút thường).
   ⚠️ Khai NGAY SAU `.chip`/`.chip-chon` mà nó ghi đè: `.chip-mo` cùng độ đặc hiệu với `.chip`, nên
      cái khai SAU thắng (L15 vế bổ sung — `.fb-luoi--mot` đặt TRƯỚC `.fb-luoi` thì không ăn gì).
      Ở đây file app.css nối thêm vào cuối nên `.chip-mo` luôn đứng sau — nhưng ai mai này DỜI khối
      này lên trên khối `.chip` ở dòng 523 là nó mất hiệu lực trong im lặng. */
.chip-mo {
  opacity: .45; cursor: not-allowed; filter: grayscale(.5);
  background: var(--card); color: var(--muted); border-color: var(--border);
}
.chip-mo:hover { border-color: var(--border); color: var(--muted); }

/* ---- §3 trang video riêng ---- */
.vk-dau { display: flex; gap: .9rem; align-items: center; flex-wrap: wrap; margin-bottom: .3rem; }
.vk-dau h2 { margin: 0; }
