/* Trang /video công khai - khách xem, KHÔNG phải màn quản trị.
   Tự đứng một mình (không kéo tokens.css/components.css của app ql):
   khách không cần tải theme của bàn làm việc, và trang này phải sống
   sót cả khi token app đổi. Bảng màu + thang chữ dưới đây LÀ CỦA
   RIÊNG trang video - mockup v3 (chủ shop duyệt 23/08, "Thép & Ô-liu"
   bản tối, không đụng token app ql).

   Ba màn (trang chủ / danh sách / chi tiết) sống trong CÙNG một trang
   - video_public.js chuyển màn bằng JS + history API, không tải lại.
   Lớp .an/.hien điều khiển màn nào đang hiện, y hệt cơ chế mockup. */

/* Font tự host (mockup v3, 23/08) - tải về từ Google Fonts,
   KHÔNG nạp qua CDN của họ trong trang chạy thật. Giấy phép +
   nguồn: admin_web/static/fonts/LICENSE.txt.

   Inter là font BIẾN THIÊN (trục wght 100-900, đã xác nhận bằng
   fontTools) - một tệp phủ hết 400-700 nên khai `font-weight:
   400 700` (một KHOẢNG, không phải bốn khai riêng) trên đúng MỘT
   @font-face mỗi subset. Barlow Condensed là font TĨNH - Google
   trả ba tệp khác hẳn nhau cho 500/600/700, khai riêng từng cái.

   Thứ tự nạp: vietnamese trước rồi latin sau KHÔNG quan trọng vì
   unicode-range của hai subset không chồng nhau - trình duyệt tự
   chọn đúng tệp theo ký tự cần vẽ, không tải tệp không cần. */

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/admin/static/fonts/inter-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: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/admin/static/fonts/inter-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: 'Barlow Condensed';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/admin/static/fonts/barlow-condensed-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: 'Barlow Condensed';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/admin/static/fonts/barlow-condensed-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: 'Barlow Condensed';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/admin/static/fonts/barlow-condensed-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: 'Barlow Condensed';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/admin/static/fonts/barlow-condensed-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: 'Barlow Condensed';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/admin/static/fonts/barlow-condensed-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;
}

@font-face {
  font-family: 'Barlow Condensed';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/admin/static/fonts/barlow-condensed-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;
}

/* ===========================================================================
   BẢNG MÀU HAI CHẾ ĐỘ SÁNG + TỐI (24/09, lô "theme-sang-video", Bruno duyệt
   mockup + bảng mã màu đích danh). Đọc trước khi thêm một màu nào.

   BA TẦNG, mỗi giá trị hex chỉ viết MỘT LẦN trong cả tệp:
     1. BẢNG GỐC  `--D-*` (tối) / `--S-*` (sáng) - mã màu thật, không ai
        dùng thẳng trong component.
     2. TOKEN NGỮ NGHĨA  `--nen`, `--tam`, `--chu`... - component chỉ đọc
        tầng này. Mặc định trỏ bảng TỐI; khối "CHỌN BẢNG" ngay dưới
        `:root` đổi chúng sang bảng SÁNG.
     3. TOKEN "TRÊN ẢNH"  `--ta-*` - trỏ CỐ ĐỊNH bảng tối ở cả hai chế độ.
        Mọi lớp nằm đè lên ảnh bìa/player (nút play, nhãn thời lượng,
        huy hiệu REVIEW, dấu ghim, gradient phủ, bút chì quản trị, khung
        đen player dọc) dùng tầng này: ảnh không đổi theo theme, nên chữ
        trên ảnh cũng không được đổi.

   CHỌN BẢNG: "Theo máy" = không đặt `data-theme`, `@media
   (prefers-color-scheme)` tự lo. Chọn tay = `data-theme="light|dark"` trên
   <html> (đặt bởi `video_theme.js`, script CHẶN trong <head> - không chớp).

   ĐỔI THEME CHỈ ĐỔI MÀU: không token nào ở đây mang kích thước/khoảng
   cách/font. Có bài canh so hộp bao từng phần tử trước/sau khi đổi.
   =========================================================================== */
:root {
  color-scheme: dark;

  /* ---- 1. BẢNG GỐC ---- */
  --D-nen: #14171c;      --S-nen: #e4e3de;       /* nền trang */
  --D-the: #1c2027;      --S-the: #ffffff;       /* bề mặt thẻ */
  --D-phu: #252a33;      --S-phu: #efeee9;       /* bề mặt phụ: ô nhãn trục lọc, ô số đếm, khung đang tải */
  --D-vien: #343b45;     --S-vien: #cfcdc4;      /* đường kẻ */
  --D-chu: #e8e6df;      --S-chu: #1b1e23;       /* chữ chính */
  --D-chu-mo: #a0a6ae;   --S-chu-mo: #575c63;    /* chữ phụ */
  --D-oliu: #a3b06a;     --S-oliu: #6a7a3a;      /* ô-liu */
  --D-oliu-ro: #b8c47f;  --S-oliu-ro: #55622e;   /* ô-liu rê chuột */
  --D-oliu-nen: rgba(163, 176, 106, .14);
  --S-oliu-nen: rgba(106, 122, 58, .12);         /* nền ô-liu nhạt */
  --D-con: #7cc47f;      --S-con: #2e7031;       /* còn hàng */
  --D-order: #e0b24a;    --S-order: #8a5a00;     /* hàng order */
  --D-het: #f08a80;      --S-het: #b3261e;       /* hết hàng */
  --S-bong-the: 0 1px 2px rgba(20, 23, 28, .07), 0 3px 10px rgba(20, 23, 28, .05);
  --D-bong-the: 0 0 0 0 transparent;             /* tối: không bóng */

  /* Màu ĐÍCH DANH có từ trước (Bruno chỉ định, lý do ở hồ sơ git):
     `--c-mac-san` nền mác "HÀNG SẴN" (nằm trên ảnh - cố định),
     `--c-sao-do` dấu ★, `--c-tti-cam` dòng phụ TTI, `--vk-quan-tri` cam
     chế độ quản trị. Bảng SÁNG không thêm màu ngoài bảng: ba màu chữ
     cuối trượt ngưỡng 4.5:1 trên nền sáng nên ở chế độ sáng chúng mượn
     màu trạng thái gần nghĩa nhất (đỏ -> hết hàng, cam -> hàng order). */
  --c-mac-san: #23994f;
  /* `--mac-*` (hai nút đầu khung chat màu macOS) dời sang `:root` của
     `khung_chat.css` ngày 28/09 - chỉ khung chat dùng, và /timkiem cần chúng. */
  --D-sao-do: #e0524a;
  --D-tti-cam: #e8843a;
  --D-quan-tri: #f0a53a;
  --phat-nen: #000;

  /* ---- 2. TOKEN NGỮ NGHĨA (mặc định TỐI) ---- */
  --nen: var(--D-nen);
  --tam: var(--D-the);
  --tam-cao: var(--D-phu);
  --vien: var(--D-vien);
  --chu: var(--D-chu);
  --chu-mo: var(--D-chu-mo);
  --oliu: var(--D-oliu);            /* NỀN/VIỀN ô-liu */
  --oliu-sang: var(--D-oliu-ro);    /* ô-liu rê chuột - và CHỮ ô-liu nhấn */
  /* CHỮ ô-liu thường. Tách khỏi `--oliu` vì ở bảng SÁNG `#6a7a3a` làm chữ
     nhỏ chỉ đạt 3.67:1 trên nền trang - chữ phải lên bậc rê chuột. */
  --oliu-chu: var(--D-oliu);
  --oliu-nen: var(--D-oliu-nen);
  --chu-tren-oliu: var(--D-nen);
  --c-con-hang: var(--D-con);
  --c-hang-order: var(--D-order);
  --c-het-hang: var(--D-het);
  --c-sao-do: var(--D-sao-do);
  --c-tti-cam: var(--D-tti-cam);
  --vk-quan-tri: var(--D-quan-tri);
  --bong-the: var(--D-bong-the);
  /* Suy từ token trên bằng color-mix - tự đổi theo chế độ, không mã màu. */
  --oliu-dam: color-mix(in srgb, var(--oliu) 70%, var(--nen));
  --vien-oliu: color-mix(in srgb, var(--oliu) 45%, transparent);
  --vien-chip: color-mix(in srgb, var(--chu) 42%, transparent);
  --dau-nen: color-mix(in srgb, var(--nen) 88%, transparent);
  --mui-ten-nen: color-mix(in srgb, var(--nen) 85%, transparent);
  --bong: rgba(0, 0, 0, .4);
  --bong-noi: rgba(0, 0, 0, .5);
  --so-loai: var(--oliu-chu);
  --vk-quan-tri-vien: color-mix(in srgb, var(--vk-quan-tri) 50%, transparent);
  --vk-quan-tri-nen: color-mix(in srgb, var(--vk-quan-tri) 12%, transparent);
  /* Mép TRÊN của gradient nút thanh đáy (27/09) - tối sáng hơn nền nút một
     bậc, sáng là trắng thẻ; mép dưới là `--tam-cao`. */
  --nut-day-tren: color-mix(in srgb, var(--D-chu) 22%, var(--D-phu));

  /* Bộ lọc dùng chung hai cấp (18/09) - nay chỉ là TÊN trỏ về token
     ngữ nghĩa, không còn giá trị riêng (16 hex cũ đã gỡ 24/09). */
  --bl-khung-nen: var(--tam);
  --bl-nut-nen: var(--tam-cao);
  --bl-nut-vien: var(--vien);
  --bl-vach: var(--vien);
  --bl-nhan-chu: var(--chu);
  --bl-meta-chu: var(--chu-mo);
  --bl-ten-chu: var(--chu);
  --bl-chip-nen: var(--nen);
  --bl-chip-vien: var(--vien);
  --bl-chip-chu: var(--chu);
  --bl-dem-nen: var(--tam-cao);
  --bl-dem-chu: var(--chu-mo);
  --bl-chon-nen: var(--oliu);
  --bl-chon-chu: var(--chu-tren-oliu);
  --bl-chon-dem-nen: rgba(0, 0, 0, .18);
  --bl-chon-dem-chu: var(--chu-tren-oliu);

  /* ---- 3. TRÊN ẢNH - cố định bảng tối ở CẢ HAI chế độ ---- */
  --ta-nen: var(--D-nen);
  --ta-khung: var(--D-phu);         /* nền chờ của ô ảnh bìa */
  --ta-chu: var(--D-chu);
  --ta-chu-mo: var(--D-chu-mo);
  --ta-oliu: var(--D-oliu);
  --ta-oliu-ro: var(--D-oliu-ro);
  --ta-vien: var(--D-vien);
  --khan-toi: rgba(20, 23, 28, .75);
  --nhan-nen: rgba(20, 23, 28, .8);
  --ta-vien-sang: color-mix(in srgb, var(--D-chu) 42%, transparent);
  /* Dấu khắc số mẫu trên vùng ảnh TRẮNG của thẻ loại (ảnh studio nền
     trắng, `.tlc-anh-vung` giữ #ffffff ở cả hai chế độ) - olive đậm
     7.08:1 trên trắng, lý do đầy đủ ở chính luật `.tlc-khac`. */
  --ta-oliu-khac: #49502a;

  --le: 12px;
  --f-nhan-goc: .74rem;
  /* Ô nút ghim ở góc trên-phải thẻ clip; vùng CHẠM 44px (Apple HIG,
     WCAG 2.5.5) tách khỏi ô vẽ. */
  --o-ghim: 28px;
  --cham-ghim: 44px;
  --cao-phat-doc: 85vh;
  --bk: 6px;
  --f1: .78rem; --f2: .86rem; --f3: .95rem;
  --f4: 1.05rem; --f5: 1.35rem; --f6: 1.6rem;
}

/* ---- CHỌN BẢNG SÁNG: hai khối CÙNG NỘI DUNG (một cho "Theo máy" khi máy
   sáng, một cho chọn tay "Sáng"). CSS không gộp được @media với bộ chọn
   thuộc tính vào một luật, nên sửa một khối thì sửa cả khối kia - có bài
   canh so hai khối phải giống hệt nhau. ---- */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;
    --nen: var(--S-nen); --tam: var(--S-the); --tam-cao: var(--S-phu);
    --vien: var(--S-vien); --chu: var(--S-chu); --chu-mo: var(--S-chu-mo);
    --oliu: var(--S-oliu); --oliu-sang: var(--S-oliu-ro); --oliu-chu: var(--S-oliu-ro);
    --oliu-nen: var(--S-oliu-nen); --chu-tren-oliu: var(--S-the);
    --c-con-hang: var(--S-con); --c-hang-order: var(--S-order); --c-het-hang: var(--S-het);
    --c-sao-do: var(--S-het); --c-tti-cam: var(--S-order); --vk-quan-tri: var(--S-order);
    --bong-the: var(--S-bong-the);
    --bong: color-mix(in srgb, var(--D-nen) 16%, transparent);
    --bong-noi: color-mix(in srgb, var(--D-nen) 18%, transparent);
    --nut-day-tren: var(--S-the);
  }
}
:root[data-theme="light"] {
    color-scheme: light;
    --nen: var(--S-nen); --tam: var(--S-the); --tam-cao: var(--S-phu);
    --vien: var(--S-vien); --chu: var(--S-chu); --chu-mo: var(--S-chu-mo);
    --oliu: var(--S-oliu); --oliu-sang: var(--S-oliu-ro); --oliu-chu: var(--S-oliu-ro);
    --oliu-nen: var(--S-oliu-nen); --chu-tren-oliu: var(--S-the);
    --c-con-hang: var(--S-con); --c-hang-order: var(--S-order); --c-het-hang: var(--S-het);
    --c-sao-do: var(--S-het); --c-tti-cam: var(--S-order); --vk-quan-tri: var(--S-order);
    --bong-the: var(--S-bong-the);
    --bong: color-mix(in srgb, var(--D-nen) 16%, transparent);
    --bong-noi: color-mix(in srgb, var(--D-nen) 18%, transparent);
    --nut-day-tren: var(--S-the);
}

* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

/* Lớp nền BẢO HIỂM chống trình xem/PWA ép nền sáng - trả giá ở mockup
   v1: `<html>`/`<body>` không đặt nền thì một số trình duyệt tự vẽ
   nền trắng NGOÀI vùng `.trang` (thanh cuộn iOS kéo quá đà, thanh địa
   chỉ ẩn/hiện...) và chữ sáng hoà luôn vào đó. `!important` vì đây là
   hàng rào cuối, không phải chỗ để ai "tinh chỉnh" đè lên. */
/* ⚠ MÀU NỀN Ở TẦNG GỐC GHI MÃ THẲNG, KHÔNG QUA BIẾN.
   Biến CSS ở `html`/`body` là chỗ dễ bị ghi đè nhất: chế độ tối của
   hệ thống, trình đọc/tiết kiệm dữ liệu, hay một tiện ích mở rộng đều
   có thể chen vào `:root` và làm nền trắng bệch trong một tích tắc
   trước khi CSS của mình kịp nạp. Mã màu thẳng thì không ai chen được.
   Bên TRONG trang vẫn dùng `var(--nen)` như thường - luật này CHỈ áp
   cho hai dòng gốc này. Giữ giá trị KHỚP `--nen` (#14171c). */
html, body { background: #14171c !important; }
body { color: var(--chu); margin: 0; }
/* Bảng SÁNG ở tầng gốc: cùng lý do ghi mã thẳng. Hai luật vì CSS không
   gộp @media với bộ chọn thuộc tính - giữ giá trị KHỚP `--S-nen`. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]), :root:not([data-theme="dark"]) body { background: #e4e3de !important; }
}
:root[data-theme="light"], :root[data-theme="light"] body { background: #e4e3de !important; }

.an { display: none !important; }
.hien { display: block; }

body {
  background: var(--nen);
  color: var(--chu);
  font-family: 'Inter', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-size: var(--f3);
  line-height: 1.45;
  padding-bottom: calc(64px + env(safe-area-inset-bottom));
}

.tem {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .14em;
  font-size: var(--f1);
  color: var(--chu-mo);
}
h1, h2 {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--chu);
}

/* ---- header ---- */
.dau {
  padding: 16px var(--le) 12px;
  display: flex; align-items: center; gap: 12px;
  border-bottom: 1px solid var(--vien);
  position: sticky; top: 0; background: var(--dau-nen);
  backdrop-filter: blur(8px); z-index: 20;
}
/* Chiều cao 70px + khoảng cách 22px CHỈ áp cho header TRANG CHỦ (06/09,
   tên hiệu một dòng) - `#man-ds`/`#man-ct` dùng CHUNG lớp `.dau` cho
   nút "Quay lại", đụng chung `.dau` sẽ đổi luôn hai màn đó, ngoài
   phạm vi lô này (CẤM đụng trang chi tiết/danh sách). */
#man-chu .dau { min-height: 70px; gap: 22px; }
.dau-chu { min-width: 0; }
/* Logo trong `#man-ds`/`#man-ct` KHÔNG bọc `.dau-chu` (bỏ luôn nút
   "Quay lại" 11/09, #10 Việc 1) - `.ten-hieu` đứng THẲNG làm con của
   `.dau` (flex row), cần tự co như `.dau-chu` đã lo cho màn trang chủ. */
.dau > .ten-hieu { min-width: 0; }
/* ⚠ `.dau-chu--lui` (đẩy tiêu đề khỏi nút "Quay lại" ở màn danh sách)
   ĐÃ GỠ 04/09 - `#ds-ten`/`#ds-phu` chuyển ra khỏi `.dau-chu`/header
   dính, xem `.ds-dau-trang`. Không còn chỗ dùng. */
/* TÊN HIỆU MỘT DÒNG (06/09) - thay khối vuông "ST" + hai dòng
   "Sói Tuyết Airsoft"/"Kho video" cũ (Bruno duyệt bản giao diện mới).
   `.logo`/`.dau-chu .ten`/`.dau-chu .phu` ĐÃ GỠ HẲN - không còn khối
   huy hiệu vuông nào ở topbar trang chủ. */
.ten-hieu {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 700; font-size: 19px; letter-spacing: .16em; line-height: 1;
  text-transform: uppercase; color: var(--chu);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  /* `display:block` BẮT BUỘC (11/09, #10 Việc 1) - `.ten-hieu` nay còn
     là `<a>` ở `#man-ds`/`#man-ct` (logo = liên kết thật, mục 2 nhiệm
     vụ). `<a>` mặc định `inline`, mà `text-overflow:ellipsis` KHÔNG ăn
     trên inline - thiếu dòng này thì chữ dài tràn thẳng ra `.dau-chu`
     thay vì cắt ba chấm (đo thật: `test_KHONG_TRAN_NGANG...` đỏ ở
     320/360px). `<div>` cũ ở trang chủ không cần dòng này (đã block
     sẵn) nhưng khai chung không hại gì. */
  display: block; text-decoration: none;
}
@media (max-width: 899px) {
  .ten-hieu { font-size: 15px; letter-spacing: .12em; }
}
.nut-fb {
  flex: none;
  /* Vùng chạm ≥44px (xem giải thích tại `.nut-tim`) - áp cho CẢ dạng
     chữ (đây) lẫn dạng icon vuông (`.nut-fb--icon` bên dưới đặt lại
     width/height, `min-height` ở đây vẫn giữ nguyên vô hại). */
  min-height: 44px;
  background: var(--oliu); color: var(--chu-tren-oliu);
  border: none; border-radius: var(--bk);
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif; font-weight: 700; font-size: var(--f2);
  text-transform: uppercase; letter-spacing: .1em;
  padding: 8px 12px; display: flex; align-items: center; gap: 8px;
  cursor: pointer; text-decoration: none;
}
.nut-fb svg { width: 14px; height: 14px; flex: none; }
/* "Tư vấn sản phẩm" -> "Tư vấn" dưới 600px (việc 4a, 26/08). Đổi bằng
   CSS chứ KHÔNG bằng JS: đổi bằng JS thì lúc xoay máy phải nghe sự
   kiện resize, mà giữa hai nhịp ấy nút hiện sai chữ. CSS đổi theo
   media query là tức thì và không cần một dòng mã nào chạy. */
.fb-chu-gon { display: none; }
@media (max-width: 599px) {
  .fb-chu-day { display: none; }
  .fb-chu-gon { display: inline; }
}
/* Dưới 420px (24/09, Bruno chốt B): nút tư vấn topbar CHỈ CÒN ICON vuông
   44px như `.nut-fb--icon` - nhường chỗ cho tên hiệu hiện ĐỦ ở 390px sau
   khi topbar có thêm nút giao diện. Nhãn đọc máy nằm ở `aria-label` của
   chính thẻ <a> (video.html). */
@media (max-width: 439px) {
  .nut-fb:not(.nut-fb--icon) { padding: 0; width: 44px; height: 44px; justify-content: center; }
  .nut-fb:not(.nut-fb--icon) svg { width: 18px; height: 18px; }
  .nut-fb .fb-chu-day, .nut-fb .fb-chu-gon { display: none; }
  /* Trang chủ khe hàng 22px: khe giữa tên hiệu và cụm icon thu về 12px
     (bằng khe của hai màn kia) - đủ 2px còn thiếu ở 390px. Khe GIỮA các
     icon giữ nguyên. */
  #man-chu .dau-chu { margin-right: -12px; }
}
/* Dưới 380px (24/09, Bruno chốt): thu KHOẢNG CÁCH CHỮ của tên hiệu để
   "SOI TUYET CONTINENTAL" hiện trọn ở 360px trên cả ba topbar - KHÔNG
   đổi cỡ chữ/font/bố cục. Đo 360px trang chủ: .12em cắt 22px, .05em vừa
   khít 0px, .04em còn dư ~3px phòng font Safari thật rộng hơn Chromium. */
@media (max-width: 379px) {
  .ten-hieu { letter-spacing: .04em; }
}
/* `.quay` (nút "Quay lại" history.back) ĐÃ GỠ HẲN 11/09, #10 Việc 1 -
   xem `.crumb` phía trên. */

/* ---- tìm kiếm ---- */
/* ⚠ `.o-tim`/`.o-tim-xoa` ĐÃ GỠ (04/09) cùng cái ô chúng tô: trang chủ
   bày hai cửa vào tìm kiếm sát nhau, giữ lại nút topbar. Đừng dựng lại
   lớp này - hai cửa vào cho cùng một overlay là thứ vừa dọn đi. Cửa
   vào theo bề ngang: >760px `.o-tim-desktop`, <=760px `.nut-tim`.
   Ô nhập THẬT của máy tìm là `.o-tim-lon` (#tim-nhap) trong overlay,
   khai ở phần dưới tệp - KHÔNG liên quan tới `.o-tim` vừa gỡ. */

/* ---- khối / tiêu đề mục ---- */
.khoi { padding: 16px var(--le) 4px; }
.khoi-dau { display: flex; align-items: baseline; gap: 8px; margin-bottom: 12px; }
.khoi-dau .gach { width: 3px; height: 15px; background: var(--oliu); flex: none; align-self: center; }
.khoi-dau .dem { margin-left: auto; font-size: var(--f1); color: var(--chu-mo); }
/* Tiêu đề mục DÙNG CHUNG (04/09, v2) - vạch olive 3px + chữ IN HOA
   giãn .09em, cho MỌI mục: loại/chủ đề (`.khoi-dau h2`) và các
   hàng ngang trang chủ/chi tiết (`.hang-dau h2`) - một quy tắc, không
   hai bản lệch nhau giữa hai nơi bày tiêu đề mục. 19px dưới 600px
   (mốc hẹp GIỮ NGUYÊN 19px - Bruno không cho số mới cho mốc này, chỉ
   nêu bậc mặc định 25px, 06/09 "chữ to lên toàn trang"). */
.khoi-dau h2, .hang-dau h2 { font-size: 25px; letter-spacing: .09em; }
@media (max-width: 599px) {
  .khoi-dau h2, .hang-dau h2 { font-size: 19px; }
}

/* ---- tầng 1 trang chủ: thẻ LOẠI, v3 (05/09, mockup lưới tự giãn) --
   ĐỔI từ hàng CUỘN NGANG (v2, 04/09) sang LƯỚI TỰ GIÃN
   (`repeat(auto-fill, minmax(168px,1fr))`) - Bruno duyệt mockup mới:
   kéo rộng trình duyệt trước đây vẫn chừa trắng bên phải và phải cuộn
   mới thấy hết 9 loại; lưới tự giãn trải hết bề ngang, màn hẹp tự
   xuống hàng, không còn cuộn ngang. Thẻ `.the-loai-chu` GIỮ NGUYÊN mọi
   bất biến đã chốt (ảnh nền trắng contain, dấu khắc, vạch olive, tên
   một dòng...) - CHỈ đổi cách xếp CONTAINER, không đụng bên trong thẻ. */
.hang-loai-cuon {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 14px; padding: 4px var(--le) 8px;
}
@media (max-width: 640px) {
  .hang-loai-cuon { grid-template-columns: repeat(2, 1fr); gap: 10px; }
}
/* ===== BẢN B (04/09) - BỎ HẲN KIỂU ĐÈ CHỮ LÊN ẢNH ==================
   Hai lô trước phải vá gradient HAI LẦN (đặc .75 -> ba điểm dừng theo
   % -> mốc px tuyệt đối) mà vẫn hoặc chữ mờ hoặc ảnh chìm - vì cả hai
   lần đều chữa TRIỆU CHỨNG của cùng một quyết định gốc: đặt chữ TRÊN
   ảnh thì buộc phải phủ tối, mà phủ tối thì ảnh súng thành mảng xám.
   Bruno duyệt mockup mới: TÁCH HẲN hai vùng, ảnh không bị phủ gì.

   Hệ quả: `.tlc-phu` (lớp gradient) và hai token `--tlc-toi`/
   `--tlc-nhat` ĐÃ GỠ SẠCH - không còn chỗ nào cần chúng. */
.the-loai-chu {
  position: relative; overflow: hidden;
  aspect-ratio: 4 / 5;
  display: flex; flex-direction: column;
  background: var(--tam); border: none; border-radius: var(--bk);
  /* Viền vẽ bằng `box-shadow: inset` chứ không `border`: `border`
     chiếm chỗ trong layout và đẩy hai vùng con lùi vào 1px mỗi cạnh -
     vùng ảnh phải chạm đúng mép ngoài thẻ. */
  box-shadow: inset 0 0 0 1px var(--vien), var(--bong-the);
  text-align: left; color: inherit; font: inherit; cursor: pointer;
  padding: 0;
  transition: transform .16s, box-shadow .16s;
}
.the-loai-chu:active { box-shadow: inset 0 0 0 1px var(--oliu-dam); }

/* VÙNG ẢNH. TÔN TRỌNG ẢNH GỐC: không gradient, không lớp
   phủ, không vân, không blur, không đổi độ sáng. `contain` để ảnh
   hiện TRỌN (không cắt) - khác hẳn `cover` của bản đè chữ cũ, vốn
   phải cắt để lấp kín khung. Nền sáng nhạt cho hợp ảnh sản phẩm chụp
   nền trắng: phần thừa quanh ảnh hoà vào nền ảnh thay vì kẻ một
   khung tối quanh nó.
   ⚠ Tỉ lệ ĐỔI từ CỐ ĐỊNH 58% sang `flex: 1 1 auto` (06/09, Bruno
   duyệt "khối chữ bó sát lại, ảnh chiếm phần lớn thẻ") - vùng chữ
   `.tlc-chu` nay `flex: 0 0 auto` (hugs đúng nội dung), vùng ảnh
   giãn nuốt hết phần còn lại thay vì một tỉ lệ phần trăm cứng. */
.the-loai-chu .tlc-anh-vung {
  flex: 1 1 auto;
  /* ⚠ `min-height: 0` KHÔNG THỪA dù tỉ lệ nay ĐỘNG chứ không còn CỐ
     ĐỊNH - vẫn cần để flex item chịu co dưới kích thước NỘI DUNG.
     Flex item mặc định `min-height: auto` tức KHÔNG co xuống dưới
     kích thước nội dung; ảnh loại thật (400x300 trở lên) vì thế đẩy
     vùng ảnh phình quá `flex-basis` nếu thiếu dòng này. */
  min-height: 0;
  position: relative;
  /* ⚠ TRẮNG TINH, KHÔNG gradient (05/09). Ảnh loại súng là ảnh sản
     phẩm chụp nền TRẮNG; nền gradient xám cũ (#eceae4 -> #c9c6bf) là
     một sắc trắng KHÁC, nên hai mảng trắng cạnh nhau lộ thành hình
     chữ nhật lồng trong hình chữ nhật - Bruno thấy rõ trên ảnh
     production thẻ "Súng máy". Cùng màu thì ranh giới biến mất.
     Đổi này còn GIẢM một hex (2 đầu gradient -> 1 màu), ratchet hạ
     18 -> 17. */
  background: #ffffff;
  display: flex; align-items: center; justify-content: center;
  /* Đệm 14/12 -> 5px: viền trắng thừa quanh ảnh mỏng đi, ảnh to lên.
     `contain` GIỮ NGUYÊN - ảnh không được cắt. */
  padding: 5px;
}
/* Loại CHƯA có ảnh: gunmetal trơn, khung không vỡ. */
.the-loai-chu--trong .tlc-anh-vung { background: var(--tam-cao); }
.the-loai-chu .tlc-anh {
  width: 100%; height: 100%;
  object-fit: contain; display: block;
  transition: transform .32s;
}

/* DẤU KHẮC số mẫu - thứ DUY NHẤT được chèn lên vùng ảnh.
   ⚠ MÀU: `--oliu`(#a3b06a) và `--oliu-dam`(#7f8c4d) ĐỀU TRƯỢT ngưỡng
   đọc được trên nền sáng này - đo thật 04/09: `--oliu` 1.94:1 ở đỉnh
   gradient / 1.37:1 ở đáy, `--oliu-dam` 3.03:1 / 2.14:1, đều dưới
   4.5:1. Nên phải có một sắc olive ĐẬM HƠN NỮA, và nó GIỮ NGUYÊN hệ
   màu olive (cùng hue 71.1deg, cùng saturation 30.7% với `--oliu`,
   chỉ hạ lightness 55.3% -> 24%) chứ không đổi sang màu ngoài bảng.
   Đo bản chốt `--oliu-khac` #49502a: 7.08:1 ở đỉnh gradient, 5.00:1
   ở đáy - đạt cả hai đầu, còn dư biên. KHÔNG thêm nền đặc sau dấu
   khắc (đề bài cấm, và cũng không cần khi chữ đã đủ đậm). */
.the-loai-chu .tlc-khac {
  position: absolute; top: 8px; left: 8px;
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 700; font-size: 11.5px; letter-spacing: .16em;
  text-transform: uppercase; line-height: 1.25;
  color: var(--ta-oliu-khac);
  border: 1.5px solid var(--ta-oliu-khac);
  border-radius: 3px;
  padding: 1px 6px;
  transform: rotate(-3deg);
}

/* VÙNG CHỮ, nền ĐẶC nên không cần gradient nào.
   ⚠ `flex: 0 0 auto` (06/09, trước là `1 1 auto`) - khối chữ nay HUG
   đúng nội dung của nó thay vì chia tỉ lệ cố định, bó sát khoảng
   thừa trên dưới Bruno chỉ ra trên điện thoại; vùng ảnh
   (`.tlc-anh-vung`) giãn nuốt phần còn lại. */
.the-loai-chu .tlc-chu {
  flex: 0 0 auto; min-width: 0;
  background: var(--tam);
  border-top: 2px solid var(--oliu-dam);
  display: flex; flex-direction: column; justify-content: center; gap: 3px;
  padding: 9px 11px 10px;
}
/* ⚠ KHOÁ MỘT DÒNG. Tên dài nhất ("SÚNG LỤC Ổ QUAY") phải cắt đuôi ba
   chấm chứ TUYỆT ĐỐI không xuống dòng - hai dòng thì đáy thẻ trong
   cùng một hàng so le, đúng cái bệnh lô đồng cao vừa chữa xong. */
/* Việc 1 (14/09): `.tlc-ten` nay là HÀNG chứa tên Việt (co giãn, cắt
   đuôi ba chấm - `.tlc-ten-txt`) + chú thích tiếng Anh ĐỨNG SAU, không
   bao giờ co (`.tlc-chu-phu`). Tách hai `<span>` thay vì để cả chuỗi
   trong một node để chú thích không bao giờ mất - trước đây "KHOÁ MỘT
   DÒNG" cắt cả cụm bằng `text-overflow: ellipsis` trên toàn bộ text,
   nay chỉ phần TÊN co lại nhường chỗ. */
.tlc-ten {
  display: flex; align-items: baseline; gap: 6px; min-width: 0;
  line-height: 1.05;
}
.tlc-ten-txt {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 600; font-size: 15px; text-transform: uppercase;
  letter-spacing: .05em; color: var(--chu);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  min-width: 0; flex: 1 1 auto;
  transition: color .16s;
  /* ⚠ DẤU CHỒNG TIẾNG VIỆT IN HOA (17/09): "Ắ Ẩ Ẫ Ỗ" cao hơn dòng 1,05
     tới ~2,9px, và `overflow: hidden` (để cắt "…") XÉN MẤT phần ấy -
     "SÚNG NGẮN KHÁC" hiện "SÚNG NGĂN KHÁC". Nới vùng xén LÊN TRÊN bằng
     đệm trên, rồi trả lại đúng bấy nhiêu bằng lề âm - chữ đứng yên.
     ⚠⚠ NÂNG .25em -> .3em (24/09, lô "don-no-video", đỏ SẴN trên
     origin/main) - đo bằng canvas.measureText THẬT ở khổ điện thoại
     (font-size 15px): `.25em` = 3,75px đệm, dấu "Ẩ" cần 3,95px ->
     THIẾU ĐÚNG 0,2px, xén một sợi tóc không thấy bằng mắt nhưng đo ra.
     `.3em` (4,5px) dư 0,55px - đã thử `.27em`/`.28em` đều đủ, chọn
     `.3em` để còn biên cho hinting font khác Chromium. Lề âm đi cùng
     nên VỊ TRÍ CHỮ không đổi, chỉ đổi bề cao vùng đệm vô hình. */
  padding-top: .3em; margin-top: -.3em;
}
/* Chú thích tiếng Anh (vd "PISTOL", "REVOLVER") - Barlow Condensed,
   NHỎ HƠN tên chính, olive, hoa toàn bộ, KHÔNG BAO GIỜ xuống dòng.
   `--oliu` (không phải `--oliu-khac`) vì nền ở đây là `.tlc-chu`
   (gunmetal `--tam`, tối) chứ không phải vùng ảnh sáng - khác bối
   cảnh với dấu khắc `.tlc-khac` ngay phía trên. */
.tlc-chu-phu {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 600; font-size: 10.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--oliu-chu);
  white-space: nowrap; flex: 0 0 auto;
}
.tlc-so {
  margin-top: 3px; font-size: 12.5px; line-height: 1.2; color: var(--chu-mo);
  min-width: 0;
  font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Số VIDEO đậm hơn một bậc so với phần còn lại của dòng. */
.tlc-so b { color: var(--chu); font-weight: 600; }
/* Thẻ 0 video vẫn hiện, chỉ mờ đi - Bruno chốt "đang cập nhật" chứ
   không ẩn hẳn: chủ đề mới thêm chưa kịp có video gắn vẫn cần một chỗ
   đứng để biết nó tồn tại. */
.the-loai-chu--mo { opacity: .55; }
.the-loai-chu--mo .tlc-so { color: var(--chu-mo); }
@media (min-width: 600px) {
  .tlc-ten-txt { font-size: 19px; }
}

/* ==================================================================
   KHỐI CHỌN DÒNG SÚNG - trang LOẠI (06/09, Việc 1/3, Bruno duyệt
   mockup). Thẻ DÒNG dùng LẠI NGUYÊN `.the-loai-chu` (root + `.tlc-anh`/
   `.tlc-ten` + hover ở cuối tệp) - CẤM viết khối hover mới. Chỉ ảnh
   (contain trắng -> cover + gradient tối, ảnh sản phẩm chụp rời khác
   ảnh đại diện thẻ loại) đổi qua modifier `.the-dong`, thêm-vào chứ
   KHÔNG sửa một dòng nào của `.the-loai-chu`/`.tlc-*` gốc (trang chủ
   vẫn dùng nguyên, CẤM đụng trang chủ). ================================== */
.dong-luoi {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
  gap: 14px; padding: 4px var(--le) 8px;
}
@media (max-width: 640px) {
  .dong-luoi { grid-template-columns: repeat(3, 1fr); gap: 10px; }
}
/* Card dòng KHÔNG ép tỉ lệ TOÀN THẺ (`.the-loai-chu` gốc dùng
   `aspect-ratio: 4/5`) - ảnh dòng tự có tỉ lệ 4:3 riêng, khối chữ hug
   nội dung của nó (`.tlc-chu` vốn đã `flex: 0 0 auto`), tổng chiều cao
   là CỘNG của hai phần, không phải một hộp cố định trước rồi chia. */
.the-dong.the-loai-chu { aspect-ratio: unset; }
/* bo-loc-web-phase2-va-giao-dien, Lỗi 1 - VÙNG ẢNH KHOÁ tỉ lệ, KHÔNG
   còn `flex: 1 1 auto` (thừa kế từ gốc `.tlc-anh-vung`) hút hết khoảng
   trống thừa/thiếu của khối chữ bên dưới. Đo thật trên production
   (rifle, 1180px): trước khi vá, `anhCao` dao động 129,9-167,9px (lệch
   38px) tuỳ thẻ có "dòng phụ" 2 dòng hay không - đúng vạch ô-liu răng
   cưa Bruno chỉ ra. `aspect-ratio` một mình (không `flex:0 0 auto`)
   KHÔNG đủ: flex item vẫn `flex-grow` theo tỉ lệ đã khai ở lớp gốc trừ
   khi ép lại `flex-shrink`/`flex-grow` về 0 tại đây. */
.the-dong .tlc-anh-vung {
  aspect-ratio: 4 / 3;
  flex: 0 0 auto;
  background: var(--ta-khung);   /* KHÔNG ảnh -> gunmetal trơn, cùng cỡ mọi thẻ khác (Việc "Súng trường khác") */
  padding: 0;                   /* cover chạm mép, không viền trắng như .tlc-anh-vung gốc */
}
.the-dong .tlc-anh { object-fit: cover; }
/* KHỐI CHỮ chiều cao CỐ ĐỊNH, đủ chứa tên (1 dòng) + số video (1 dòng)
   + dòng phụ (TỐI ĐA 2 dòng, `-webkit-line-clamp: 2` đã khoá) - đo
   thật chiều cao khối chữ khi ĐẦY (dòng phụ 2 dòng) ở cả hai bậc chữ
   (15px <600px / 19px ≥600px): 99,97px tại 1180px là số đo thật, chốt
   102px để dư biên an toàn (bo tròn phông chữ khác trình duyệt/hệ
   điều hành). Thẻ KHÔNG có dòng phụ thì CHỪA CHỖ TRỐNG dưới đáy (đúng
   đề bài), không kéo ảnh cao lên bù - `justify-content: flex-start`
   neo nội dung lên đỉnh khối thay vì `center` gốc (center sẽ đẩy
   khoảng trống chia đều trên/dưới, trông như tên/số bị "trôi" giữa
   khối rỗng ở thẻ ít chữ). */
/* ⚠ 17/09: dòng phụ nay nằm CHUNG hàng "N video" (xem `veTheDong`), nên
   khung chữ tối đa BA hàng (tên · tên đầy đủ hãng nổi bật · số video) -
   đủ cao cho thẻ nhiều hàng nhất, mọi thẻ cùng một chiều cao. */
.the-dong .tlc-chu {
  flex: 0 0 auto;
  height: 74px;
  justify-content: flex-start;
  overflow: hidden;
}
@media (min-width: 600px) {
  .the-dong .tlc-chu { height: 78px; }
}
/* Lớp phủ tối dần đáy ảnh - CHỈ chèn bằng JS khi CÓ ảnh thật (rơi về
   gunmetal trơn thì không có gì để tôn chữ lên, gradient trên nền
   trơn chỉ làm tối vô cớ). Đứng SAU ảnh, TRƯỚC dấu khắc "N mẫu". */
.the-dong .tlc-phu-dong {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to top, var(--khan-toi), transparent 55%);
}
/* Dấu khắc "N mẫu" của dòng cần nền mờ để đọc được TRÊN ẢNH THẬT
   (khác thẻ loại: nền luôn trắng nên chữ đậm là đủ) - viền/chữ GIỮ
   NGUYÊN token `.tlc-khac` gốc, chỉ thêm nền. */
.the-dong .tlc-khac {
  background: var(--khan-toi);
  color: var(--ta-oliu-ro);
  border-color: color-mix(in srgb, var(--ta-oliu) 70%, var(--ta-nen));
}

/* "DÒNG PHỤ" olive (Việc 3, 14/09) - TỐI ĐA 4 tên mẫu (server đã xếp),
   MAX 2 DÒNG rồi cắt đuôi ba chấm (`-webkit-line-clamp`, hỗ trợ mọi
   engine trình duyệt hiện đại kể cả không tiền tố `-webkit-` từ lâu -
   không cần fallback JS đo chiều cao). */
.tlc-dong-phu { color: var(--oliu-chu); }
/* "★" đỏ - dấu Bruno gắn riêng cho MỘT mẫu, KHÁC nghĩa "nổi bật"
   (nổi bật chỉ quyết mẫu có mặt trong danh sách hay không). */
.tlc-sao-do { color: var(--c-sao-do); }
/* "Cũng ở <loại khác>" (Việc 5, 14/09) - gợi ý chéo loại cho thẻ MẪU
   trang sniper, màu MỜ (khác `.tlc-dong-phu` olive - đây không phải
   thành viên của dòng, chỉ là một ghi chú phụ). */
.tlc-cung-o { color: var(--chu-mo); font-style: italic; }

/* THẺ HÃNG NỔI BẬT (Việc 4, 14/09 - TTI/Novritsch) - viền olive 2px
   ĐÈ lên viền `--vien` 1px mặc định của `.the-loai-chu`, tên đổi màu
   olive, phụ đề tên đầy đủ nhỏ ngay dưới tên. */
.the-dong-noi-bat.the-loai-chu { box-shadow: inset 0 0 0 2px var(--oliu); }
.the-dong-noi-bat .tlc-ten-txt { color: var(--oliu-chu); }
.tlc-ten-day-du {
  margin-top: 1px; font-size: 10.5px; line-height: 13px; color: var(--chu-mo);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Dòng phụ riêng của hãng nổi bật - "cam" (TTI, màu thương hiệu chỉ
   định đích danh) hoặc "oliu" (Novritsch, màu chuẩn của trang). */
.tlc-hang-phu { font-weight: 600; }
.dong-strip-hangnb .tlc-hang-phu { font-size: 11.5px; }
.tlc-hang-phu--cam { color: var(--c-tti-cam); }
.tlc-hang-phu--oliu { color: var(--oliu-chu); }

/* Tiêu đề khối "CHỌN DÒNG <LOẠI>" - dùng lại NGUYÊN `.khoi-dau`/`.gach`/
   `h2` (vạch olive 3px + chữ 25px/19px .09em, một quy tắc cho MỌI tiêu
   đề mục của trang này). Chỉ thêm nút "Xem tất cả" dồn phải. */
.dong-khu { padding: 16px var(--le) 4px; }

.dong-xemthem {
  margin-left: auto; flex: none;
  background: none; border: none; cursor: pointer; font-family: inherit;
  color: var(--oliu-sang); font-size: var(--f1);
  text-decoration: underline; text-underline-offset: 2px;
}
.dong-xemthem[hidden] { display: none; }

/* ---- DẢI "ĐANG XEM DÒNG" (Việc 3) - thu gọn lưới thành một dải gọn
   + hai hàng chip Mẫu/Hãng khi đã chọn một dòng. ------------------- */
.dong-strip[hidden] { display: none; }
/* Khung lọc DÙNG CHUNG hai cấp trang (18/09, Việc 2 lô dọn trang
   khách - quy cách Bruno duyệt): nền riêng, bo 14px, đệm rộng, và
   BỎ HẲN viền ô-liu bao ngoài (viền ấy đóng khung một vùng vốn đã
   tách khỏi nền bằng chính màu nền, thành ra kẻ hai lần). */
.dong-strip {
  margin: 4px var(--le) 12px;
  background: var(--bl-khung-nen); box-shadow: var(--bong-the); border: none; border-radius: 14px;
  padding: 24px 26px;
}
.dong-strip-hang1 { display: flex; align-items: flex-start; gap: 8px 10px; }
/* Đầu khung lọc GỘP tên dòng (18/09, thiết kế lại) - `.dong-strip-ten`
   ("GLOCK", 28px) + `.dong-strip-meta` ("N video"...) nay XẾP DỌC
   trong một cụm riêng thay vì nằm chung một hàng ngang với nút thu
   gọn. Bọc bằng `.dong-strip-headtext` để hai span giữ nguyên id/JS
   (không đổi một dòng script nào) mà vẫn xếp được thành cột. */
.dong-strip-headtext {
  display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto;
}
.dong-strip-nhan {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 600; font-size: 14px; text-transform: uppercase; letter-spacing: .12em;
  color: var(--chu-mo); flex: none;
}
/* ⚠ CỠ CHỮ CO THEO BỀ NGANG (Bruno chốt 19/09: "quá to và rất xấu").
   Trước đó ghim CỨNG 40px - mà chú thích ngay trên đây vẫn ghi "28px",
   tức con số đã phình lên ở một lô nào đó mà chữ mô tả không đi theo.
   40px in hoa Barlow Condensed đứng cạnh dòng meta 14px là lệch bậc
   quá xa; tên dài thật ("DMR (BÁN TỰ ĐỘNG)", "AR-15 / M4 CUSTOM CQB")
   ăn gần trọn hàng và đẩy "N video · M hãng" ra sát mép.
   `clamp()` giữ 28px như thiết kế gốc ở màn rộng và tự co xuống 22px ở
   điện thoại - KHÔNG cần thêm một @media mới (thang breakpoint của
   trang này đã khai đủ bốn mốc, đẻ thêm mốc là phải khai ngoại lệ). */
.dong-strip-ten {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 700; font-size: clamp(22px, 4.6vw, 28px);
  text-transform: uppercase; color: var(--bl-ten-chu);
  line-height: 1.1;
}
/* `.dong-strip-so` (đếm "N video · M mẫu · P hãng" cũ) đổi tên thành
   `.dong-strip-meta` (11/09, #12 mục C - dòng số nay đổi theo ngữ cảnh
   lọc, không còn cố định ba phần). `.dong-strip-doi`/`.dong-strip-bo`
   (nút "Đổi dòng khác"/"Bỏ lọc") ĐÃ GỠ HẲN - đường dẫn (cấp dòng) và
   chip "Tất cả" đã thay việc, xem `veStripDong()`. */
.dong-strip-meta { font-size: 14px; color: var(--bl-meta-chu); }
/* Tóm tắt "Đang lọc: ..." khi thu gọn - nay là MỘT SPAN trong hàng
   tiêu đề (mục A nhiệm vụ), không còn khối thay thế toàn bộ nội dung
   như bản 08/09 cũ. */
.dong-strip-tomtat[hidden] { display: none; }
.dong-strip-tomtat {
  margin-left: auto; font-size: var(--f2); font-weight: 600; color: var(--oliu-sang);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
/* Hai hàng chip Mẫu/Hãng - nhãn 62px cố định + băng cuộn ngang (tái
   dùng ĐÚNG `.hang-chip`/`.chip` đã có, không dựng khuôn chip thứ hai). */
/* bo-loc-web-phase3 (Việc 1-3) - ba trang chủ đề riêng dùng LẠI class
   này TRỰC TIẾP trên một khối cấp trang (`#ds-phukien-chip-khu`/
   `#ds-saleoff-chip-khu`/`#ds-thaolap-chip-khu`), ẩn/hiện qua thuộc
   tính `hidden` - trước lô này `.dong-strip-chiphang` chỉ từng đứng
   BÊN TRONG `#ds-dong-strip-than` (ẩn/hiện qua CHA, không tự mang
   `hidden`), nên chưa ai cần tới luật này. `display: flex` của lớp
   THẮNG `[hidden]` mặc định trình duyệt (bẫy đã ghi nhiều lần trong
   CLAUDE.md) - thiếu dòng dưới thì `show(el,false)` không ẩn được gì,
   sabotage/bài canh `TestKhuonChungBonChuDeDon` đã bắt được. */
.dong-strip-chiphang[hidden] { display: none; }
.dong-strip-chiphang { display: flex; align-items: center; gap: 8px; margin-top: 10px; }
.dong-strip-chiphang .dong-strip-nhan { width: 62px; font-size: 12px; }
.dong-strip-chiphang .hang-chip { padding-right: 4px; }
/* ⚠ 24/09 (lô "don-no-video") - VÁ LỀ CHO BA KHỐI ĐỨNG LẺ đúng chú
   thích trên đầu mục này: trước lô "bo-loc-web-phase3" lớp này CHỈ
   từng đứng BÊN TRONG `.dong-strip` (đã có `padding: 24px 26px`, tự lo
   lề), nên bản gốc chưa từng cần lề của riêng nó. Ba khối dưới đây là
   CON TRỰC TIẾP của `<section id="man-ds">`, không cha nào đệm lề cho
   chúng - nhãn "NHÓM"/"SÚNG" và hàng chip nằm ÉP SÁT mép trái màn hình
   (đo thật 390px: `x=0`), khác hẳn mọi khối khác trên trang (đều có
   `var(--le)`). Bằng chứng: chụp lại trang Phụ kiện TRƯỚC/SAU vá,
   xem `tests/test_video_rendering.py::TestBaChuDeDonCoLeTrangHang`. */
#ds-phukien-chip-khu, #ds-saleoff-chip-khu, #ds-thaolap-chip-khu {
  margin-left: var(--le); margin-right: var(--le);
}
#ds-dong-strip-than[hidden] { display: none; }

/* bo-loc-web-phase2, Việc 4/5 - phụ đề hãng nổi bật + "cũng nằm ở
   <loại khác>" trên strip, ngay dưới hàng tiêu đề. */
.dong-strip-hangnb[hidden], .dong-strip-cheo-loai[hidden] { display: none; }
.dong-strip-hangnb, .dong-strip-cheo-loai {
  margin: 6px 0 0; font-size: var(--f1); color: var(--chu-mo);
}

/* ⚠ Ô GÕ TÌM RIÊNG CỦA MỘT HÀNG CHIP: ĐÃ BỎ HẲN (16/09, lô
   "trang-khach-cay" Việc 4, Bruno chốt) - `.chip-tim`/`.chip-tim-trong`
   không còn nơi nào sinh ra. Ô tìm CHUNG trên đầu trang
   (`.o-tim`/`#tim-nhap`) KHÔNG đụng tới - đó vẫn là đường tìm duy nhất.

   ⚠⚠ LUẬT XẾP DỌC THÌ Ở LẠI, chỉ ĐỔI TÊN `--co-tim` -> `--nhieu-chip`.
   Lượt gỡ đầu tiên bỏ luôn cả nó (tưởng là mã chết đi kèm ô tìm) và
   đỏ ngay: `.hang-chip` mang `overflow-x: auto` (cuộn ngang, KHÔNG
   wrap), nên khi đứng CÙNG HÀNG với nhãn 62px thì từ chip thứ chín trở
   đi nằm ngoài vùng nhìn thấy và không bấm được - Playwright báo đúng
   triệu chứng "hang-chip intercepts pointer events" ở trang TTI.
   Xếp dọc cho hàng nhiều chip là thứ giữ cho dải rộng TRỌN khung. */
.dong-strip-chiphang--nhieu-chip {
  flex-direction: column; align-items: flex-start; gap: 4px;
}
.dong-strip-chiphang--nhieu-chip .dong-strip-nhan { width: auto; padding-top: 0; }
/* `flex: 1` gốc của `.hang-chip` là cho HÀNG NGANG (chiếm chỗ CÒN LẠI
   cạnh nhãn) - vô nghĩa khi cha đã đổi sang CỘT DỌC (trục flex xoay
   90°). Ép `align-self: stretch` để nó rộng ĐỦ CẢ CỘT thay vì chỉ ôm
   khít nội dung (`align-items: flex-start` của cha không tự giãn con). */
.dong-strip-chiphang--nhieu-chip .hang-chip {
  align-self: stretch; flex: 0 1 auto; width: 100%;
}

/* BỎ tiêu đề tên dòng TRÙNG phía trên khung lọc (18/09, thiết kế lại
   khung lọc theo mockup) - đầu khung lọc (`.dong-strip-hang1`) nay tự
   mang tên dòng/mẫu + số video, nên `.ds-dau-trang` (h1 `#ds-ten` +
   `#ds-phu`) là bản chép thừa CẢ Ở DESKTOP, không chỉ điện thoại. Trước
   lô này luật ẩn CHỈ nằm trong `@media (max-width:599px)` (#14, 11/09)
   - nay bỏ điều kiện màn hình, nhưng GIỮ đúng bất biến "H1 - ẩn CHỈ khi
   có khối lọc thật sự thay thế nó": `:has(#ds-dong-strip:not([hidden]))`
   - dòng "1 mẫu·1 hãng·1 hệ" (Lỗi 3a) tự BỎ HẲN `#ds-dong-strip`, nếu
   ẩn `.ds-dau-trang` VÔ ĐIỀU KIỆN theo `body.vk-trang-dong` (không kèm
   `:has`) thì trang mất sạch tiêu đề - không H1, không khung lọc, không
   gì cả. `TestBoLocGiaoDienIpad::test_khoi_loc_rong_thi_bo_han_khung`
   canh đúng ca này. `#ds-phu` vốn đã tự ẩn qua `anDongPhuVi()` khi dải
   có số riêng; dòng dưới đây chỉ còn cần lo cho `#ds-ten`. */
.ds-dau-trang[hidden],
body.vk-trang-dong:has(#ds-dong-strip:not([hidden])) .ds-dau-trang {
  display: none;
}

/* ===================================================================
   BA (BỐN) KHỐI Mẫu/Hãng/Hệ/Màu - thiết kế lại (18/09, mockup Bruno
   duyệt). `.dong-tang` là lớp THÊM VÀO bên cạnh `.dong-strip-chiphang`
   sẵn có trên 4 hàng chip trong `#ds-dong-strip-than` - JS
   (`veHangChipLoc`/`hienKhoi`) và các trang khác dùng chung
   `.dong-strip-chiphang` (Phụ kiện/Sale off/Tháo lắp/trang Hãng/
   `#ds-sniper-strip`) KHÔNG mang lớp này nên không đụng gì tới chúng.
   Selector CỐ Ý ghép hai lớp (`.dong-strip-chiphang.dong-tang`,
   đặc trưng 0,2,0) để LUÔN thắng `.dong-strip-chiphang` một lớp
   (0,1,0) bất kể khối CSS này đặt trước hay sau trong tệp - không dựa
   vào thứ tự nguồn.
   MÀU: không một hex/rgba mới - ba biến `--tl-*` khai ở khối `:root`
   đầu tệp đều suy từ token nền/ô-liu sẵn có qua `color-mix()`; phần
   còn lại dùng thẳng `--tam`/`--tam-cao`/`--vien`/`--oliu`/`--chu`/
   `--nen`/`--oliu-sang` đã có. Dựng bảng sáng (lô riêng, CHƯA làm) chỉ
   cần đổi giá trị NHỮNG TOKEN GỐC đó, không phải sửa CSS dưới đây. */
.dong-strip-chiphang.dong-tang {
  display: grid;
  grid-template-columns: 84px 1fr;
  align-items: stretch;
  background: none;
  border: none;
  border-radius: 0;
  /* ⚠ PHẢI trả `margin-top` về 0: lớp gốc `.dong-strip-chiphang` đặt
     10px cho kiểu CŨ (các khối bo góc RỜI NHAU). Quy cách 18/09 là các
     trục LIỀN nhau, ngăn bằng vạch 1px - để nguyên 10px thì có CẢ khe
     hở LẪN vạch, và vạch trông như treo lơ lửng giữa hai khối. */
  margin-top: 0;
}
/* Vạch ngăn GIỮA các trục (18/09, quy cách Bruno duyệt) - đặt trên
   trục thứ HAI trở đi bằng `+`, nên trục đầu không có vạch thừa ở
   đỉnh và trục cuối không có vạch treo ở đáy. Dùng `+` thay vì
   `:not(:first-child)` vì các trục bị ẨN bằng cách GỠ KHỎI DOM
   (`hienKhoi`), nên "con đầu tiên" đổi theo dữ liệu - `+` luôn đúng
   với đúng những trục ĐANG hiện. */
.dong-strip-chiphang.dong-tang + .dong-strip-chiphang.dong-tang {
  border-top: 1px solid var(--bl-vach);
}
/* Ô nhãn - đậm hơn thân khối (`--tam`, một bậc TỐI hơn `--tam-cao`),
   kẻ dọc ngăn vùng chip. `align-self:stretch` (kế thừa mặc định của
   grid) khiến nó cao ĐÚNG BẰNG cột chip dù chip tràn 1 hay 2 hàng;
   flex column + `justify-content:center` bên trong tự căn GIỮA cụm
   chữ theo chiều cao thật đó - không cần biết trước số hàng chip. */
.dong-tang-nhan {
  background: none;
  border-right: none;
  padding: 14px 10px 14px 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;      /* CĂN GIỮA trong cột nhãn - quy cách 18/09 */
  text-align: center;
  gap: 3px;
  min-width: 0;
}
.dong-tang-nhan-chu {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 700;
  font-size: 20px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--bl-nhan-chu);
  line-height: 1.1;
}
.dong-tang-nhan-dem {
  font-size: 11px;
  color: var(--chu-mo);
  line-height: 1.25;
}
/* Trống (chưa kịp JS điền, hoặc tầng không có đơn vị) - đừng để một
   dòng rỗng chiếm chỗ và lệch canh giữa. */
.dong-tang-nhan-dem:empty { display: none; }

.dong-tang .hang-chip { padding: 14px 0 14px 12px; gap: 8px; }

/* ---- Chip RIÊNG của bốn khối - KHÔNG đụng `.chip` gốc (dùng chung
   cho `.dai-loc`/`.loc-panel`/Phụ kiện/Sale off/Tháo lắp/trang Hãng/
   `#ds-sniper-strip`, vẫn giữ pill 44px cũ). Geometry áp cho MỌI chip
   kể cả `.chip--vet` (0 video) - hình dạng chung, chỉ MÀU mới phân
   biệt trạng thái. */
.dong-tang .chip {
  height: 44px;
  min-height: 44px;
  padding: 0 16px;
  border-radius: 8px;
  font-size: 15px;
  font-weight: 500;
  transition: background-color .13s, border-color .13s, color .13s;
}
/* Màu MẶC ĐỊNH - tách khỏi geometry ở trên, và CỐ Ý loại CẢ `.chip--vet`
   (chip 0 video) LẪN `.chon` (đang chọn) bằng `:not()` thay vì dựa vào
   thứ tự nguồn thắng-thua với `.chip.chip--vet`/`.chip.chon` ở nơi
   khác trong tệp: đặc trưng (0,4,0) của hai `:not()` LUÔN thắng (0,2,0)
   của chúng, không phải chuyện may rủi ai đứng trước ai.
   ⚠ TRẢ GIÁ lúc dựng: thiếu `:not(.chon)` làm CHÍNH RULE NÀY (0,3,0 lúc
   đó) thắng luôn `.chip.chon` gốc (0,2,0) - mọi chip "Tất cả"/đang chọn
   bị sơn nhầm màu mặc định thay vì ô-liu, dù DOM đúng đã mang class
   `chon`. Bài canh `TestKhungLocBaKhoiThietKeLai::
   test_nam_trang_thai_chip_doi_mau_dung_token` bắt được ngay (so màu
   thật đọc qua token, không đoán bằng mắt). */
.dong-tang .chip:not(.chip--vet):not(.chon) {
  background: var(--bl-chip-nen);
  border-color: var(--bl-chip-vien);
  color: var(--bl-chip-chu);
}
/* Số đếm TÁCH khỏi tên vào một ô nền riêng BÊN TRONG chip (quy cách
   18/09) - không còn là chữ mờ đi cạnh tên. */
.dong-tang .chip .c-dem {
  border-radius: 6px;
  font-size: 13px;
  font-weight: 600;
  padding: 2px 8px;
  background: var(--bl-dem-nen);
  color: var(--bl-dem-chu);
  transition: background-color .13s, color .13s;
}
/* Đang chọn - nền kế thừa từ `.chip.chon` gốc (đã đúng "nền ô-liu đặc,
   chữ màu nền tối"), chỉ thêm riêng ô số "nền tối 22%" (khác bản gốc
   dùng nền tối ĐẶC cho `.dai-loc`/`.loc-panel`). */
.dong-tang .chip.chon {
  background: var(--bl-chon-nen);
  color: var(--bl-chon-chu);
  border-color: transparent;
}
.dong-tang .chip.chon .c-dem {
  background: var(--bl-chon-dem-nen);
  color: var(--bl-chon-dem-chu);
}
.dong-tang .chip-cham { width: 11px; height: 11px; }

@media (hover: hover) and (pointer: fine) {
  .dong-tang .chip:not(.chip--vet):not(:disabled):hover {
    background: var(--oliu-nen);
    border-color: var(--oliu);
    color: var(--chu);
  }
  .dong-tang .chip:not(.chip--vet):not(:disabled):hover .c-dem {
    color: var(--oliu-chu);
  }
  /* Đang chọn + rê chuột - ô-liu sáng thêm một bậc, báo cho biết bấm
     lại là bỏ lọc. Đặc trưng (0,4,0) thắng cặp rule ngay trên. */
  .dong-tang .chip.chon:not(.chip--vet):not(:disabled):hover {
    background: var(--oliu-sang);
    border-color: transparent;
  }
}
.dong-tang .chip:focus-visible {
  outline: 2px solid var(--oliu);
  outline-offset: 2px;
}
/* Chuyển động rút gọn cho hệ điều hành: luật `.dong-tang .chip
   { transition: none }` nằm trong khối `@media (prefers-reduced-motion)`
   ở CUỐI tệp, không mở khối riêng ở đây - một khối thứ hai cho cùng
   một truy vấn media chỉ làm người đọc phải tìm hai chỗ. (Khối ấy
   trước 18/09 còn chứa `.loc-panel`; dải + panel đã xoá hẳn, xem bia
   mộ ở cuối tệp.) */

/* ĐIỆN THOẠI (≤599px, ranh giới thiết bị sẵn có của trang - xem "BỐN
   MỐC BỀ NGANG" cuối tệp; đề bài ghi 768px nhưng 768 = iPad DỌC, ranh
   giới trang này CỐ Ý xếp iPad dọc vào dải "máy tính bảng", không phải
   dải điện thoại - dùng số 768 ở đây sẽ đẻ một mốc thứ năm cho riêng
   một component, đúng thứ `_NGOAI_LE` của test_chuan_giao_dien_shop.py
   sinh ra để chặn). Mỗi khối: nhãn nằm TRÊN, dải chip trượt ngang MỘT
   hàng bên dưới (kế thừa `overflow-x:auto` mặc định <600px của chính
   `.hang-chip`, không cần khai lại). */
@media (max-width: 599px) {
  /* ⚠⚠ ĐỔI BỐ CỤC 18/09 (mockup Bruno duyệt, lô "bộ lọc + rổ vét"
     Việc 4): nhãn trục KHÔNG còn nằm TRÊN dải chip và căn giữa nữa -
     nó xuống ĐẦU HÀNG BÊN TRÁI, cùng dòng với dải chip.

     Giữ nguyên GRID của desktop, chỉ hẹp cột nhãn 84px -> 52px: ba
     trục vì thế tự thẳng cột với nhau (cùng một `grid-template-columns`),
     không cần một luật canh hàng riêng. Và vì nhãn là MỘT Ô GRID khác
     còn `overflow-x: auto` chỉ nằm trên `.hang-chip`, nhãn ĐỨNG YÊN
     khi khách vuốt chip - không cần `position: sticky` nào.

     Bản cũ dùng `display: block` (nhãn trên, chip dưới) + một vạch
     `border-bottom` ngăn nhãn với chip; cả hai đi theo bố cục ấy. */
  .dong-strip-chiphang.dong-tang {
    grid-template-columns: 52px 1fr;
  }
  .dong-tang-nhan {
    border-right: none;
    border-bottom: none;
    /* Căn TRÁI, dồn lên đầu cụm chữ - quy cách 18/09 (desktop vẫn căn
       giữa, khai ở khối gốc). */
    align-items: flex-start;
    text-align: left;
    padding: 14px 8px 14px 0;
  }
  .dong-tang-nhan-chu {
    font-size: 16px;
    letter-spacing: 0.12em;
  }
  /* Dòng đếm phụ ("13 mẫu") xuống 10px cho vừa cột 52px - cột hẹp hơn
     desktop 32px, giữ nguyên cỡ thì nó tràn sang ô chip. */
  .dong-tang-nhan-dem { font-size: 10px; }
  /* Vệt mờ mép phải - báo còn trượt được. Phai vào ĐÚNG màu thân khối
     (`--bl-khung-nen`) nên liền mạch, không viền cứng. `pointer-events:none`
     để không nuốt cú chạm vào chip nằm dưới nó.
     ⚠ VỆT ĐỨNG TRÊN HÀNG (không cuộn), KHÔNG trên `.hang-chip` (10/10, lô
     soizz-loc-dai-toi): bản cũ đặt `::after` absolute bên TRONG chính khung
     cuộn `.hang-chip` nên vệt TRÔI theo nội dung - cuộn 100px là nó nằm ở
     60-67% bề ngang, đè lên chữ chip (Bruno chụp "Hi-Capa" bị che). */
  .dong-strip-chiphang.dong-tang { position: relative; }
  .dong-strip-chiphang.dong-tang::after {
    content: "";
    position: absolute;
    top: 0; right: 0; bottom: 0;
    width: 28px;
    background: linear-gradient(to right, transparent, var(--bl-khung-nen));
    pointer-events: none;
  }
  /* Ô đệm cuối dải = bề ngang vệt: chip CUỐI cuộn được ra khỏi vùng vệt nên
     đọc trọn. Dùng phần tử flex (không dùng `padding-right` - WebKit cũ bỏ
     qua lề cuối của khung cuộn flex). */
  .dong-tang .hang-chip::after {
    content: "";
    flex: 0 0 28px;
  }
  .dong-tang .chip {
    height: 44px;
    min-height: 44px;
    font-size: 14px;
  }
  .dong-tang .chip-cham { width: 10px; height: 10px; }
}

/* ĐÓNG/MỞ dải (08/09, Phase 2 Việc 2; đổi kiểu dáng 11/09, #12 mục A) -
   nút TRÒN CHỈ ICON (không chữ), mũi tên xoay theo trạng thái. Không
   có `.dong-strip-tomtat` nữa mang tên nút thu gọn bên trong nó - tóm
   tắt nay đứng NGAY trong hàng tiêu đề (span ở trên). */
/* Nút thu gọn CHỈ CÓ ICON (18/09, Việc 2 - quy cách Bruno duyệt):
   ô VUÔNG bo 10px 44px (đủ vùng chạm), nền/viền riêng, mũi tên ô-liu.
   Nhãn chữ nằm ở `aria-label` trong template - bỏ chữ trên mặt nút
   chứ không bỏ tên gọi cho trình đọc màn hình. */
.dong-strip-thugon {
  flex: none; margin-left: auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;
  background: var(--bl-nut-nen); border: 1px solid var(--bl-nut-vien);
  border-radius: 10px;
  color: var(--oliu-chu); cursor: pointer; padding: 0;
  transition: border-color .13s, background-color .13s;
}
@media (hover: hover) and (pointer: fine) {
  .dong-strip-thugon:hover { border-color: var(--oliu); }
}
.dong-strip-thugon:focus-visible { outline: 2px solid var(--oliu); outline-offset: 2px; }
.dong-strip-thugon svg { width: 20px; height: 20px; transition: transform .15s; }
.dong-strip-thugon--dong svg { transform: rotate(180deg); }

/* ---- TRANG SNIPER - hai khu DMR/Bolt-action (Việc 4), mẫu KHÔNG
   dòng - thẻ mẫu dùng chung KHUÔN `.the-dong`, chỉ KHÔNG có dấu khắc
   "N mẫu" (mẫu là đơn vị lá, không gom gì bên dưới nó nữa). --------- */
.sniper-khu { padding: 4px 0 0; }
.sniper-khu-tieu { padding: 16px var(--le) 4px; }
.sniper-khu-phu { color: var(--chu-mo); font-size: var(--f1); }
/* Nghĩa tiếng Việt của cơ chế bắn (Việc 5, 14/09) - đứng TRONG `h2` nên
   thừa hưởng hoa/giãn chữ của nó, chỉ giảm độ đậm/độ sáng cho phân bậc
   rõ với tên cơ chế chính đứng trước. */
/* 24/09: chữ mờ bằng TOKEN chữ phụ thay cho `opacity: .62` - độ mờ nhân
   lên màu chữ chính ra 4.3:1 trên nền sáng (trượt 4.5). */
.sniper-khu-nghia { font-weight: 500; color: var(--chu-mo); }

/* ---- tầng 2 trang chủ: chip CHỦ ĐỀ, v2 (04/09) -------------------
   Viền trái olive 3px + số đếm, thay `.the-loai` (ảnh) cũ. */
.hang-chip-cuon {
  display: flex; flex-wrap: wrap; gap: 8px; padding: 4px var(--le) 8px;
}
/* NÂNG CẤP 04/09 - chip chủ đề trước đây chữ bé + số xám mờ nên chìm
   hẳn so với thẻ loại súng ngay trên nó. Nay ngang tầm: tên IN HOA
   Barlow Condensed, số nằm trong VIÊN ô-liu đặc thay vì trôi lơ lửng.
   ⚠ Tên token: đề bài viết `--vd-surface2`/`--vd-line`/`--vd-ink`/
   `--vd-olive*` - bộ `--vd-*` KHÔNG tồn tại trong tệp này (đã trả giá
   hai lần trước ở `--vd-bg` và `--vd-olive-deep`). Ánh xạ sang token
   THẬT: `--tam-cao` (nền nổi hơn `--tam` một bậc), `--vien`, `--chu`,
   `--oliu`, `--oliu-dam`, và `--nen` làm chữ trên viên ô-liu. */
.chip-cd {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--tam-cao); border: 1px solid var(--vien);
  border-left: 3px solid var(--oliu-dam); border-radius: 6px;
  padding: 10px 14px; font-family: inherit; cursor: pointer;
  transition: border-color .16s, background-color .16s, transform .16s;
}
.chip-cd-ten {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 600; font-size: 14.5px; text-transform: uppercase;
  letter-spacing: .07em; color: var(--chu);
}
@media (min-width: 600px) {
  .chip-cd-ten { font-size: 17.5px; }
}
/* Số đếm trong VIÊN ô-liu đặc - chữ dùng `--nen` (nền trang, gần đen)
   nên tương phản mạnh trên nền ô-liu sáng. Font THÂN (không Barlow)
   theo đúng đề bài: con số cần dễ đọc hơn là cần hẹp. */
.chip-cd-so {
  font-size: 12.5px; font-weight: 700;
  background: var(--oliu); color: var(--chu-tren-oliu);
  border-radius: 999px; padding: 1px 7px;
  font-variant-numeric: tabular-nums;
}
/* ⚠ Chip 0 video nay ẨN HẲN ở tầng JS (không dựng phần tử) chứ không
   phải làm mờ - `.chip-cd--mo` GIỮ LẠI làm lưới an toàn phòng khi một
   đường dựng khác còn gắn lớp này, nhưng đường chính đã không đẻ ra
   chip rỗng nữa. Xem `veChipTang2` trong video_public.js. */
.chip-cd--mo { display: none; }

/* ---- nút "xem thêm" cuối mục ---- */
/* `display` của lớp THẮNG luật [hidden] mặc định của trình duyệt -
   thiếu dòng dưới đây thì nút ẩn (JS đặt thuộc tính `hidden`) vẫn hiện
   nguyên, chỉ mất tác dụng bấm. Bẫy y hệt CLAUDE.md đã ghi cho
   `.vp-ke`/`.vp-man-phat` ở bản trang video cũ. */
.nut-xem-them[hidden] { display: none; }
.nut-xem-them {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin: 4px var(--le) 4px; width: calc(100% - var(--le) * 2);
  background: none; border: 1px solid var(--oliu-dam); border-radius: var(--bk);
  color: var(--oliu-sang);
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif; font-weight: 600; font-size: var(--f2);
  text-transform: uppercase; letter-spacing: .12em;
  padding: 12px; cursor: pointer;
}
.nut-xem-them svg { width: 13px; height: 13px; stroke: var(--oliu-sang); fill: none; stroke-width: 2.2; }

/* ---- hàng video trang chủ (video mới nhất / xem nhiều / mỗi loại /
   đã ghim) - v3 (05/09, mockup lưới tự giãn) ------------------------
   ĐỔI từ cuộn ngang (flex + overflow-x, 26/08) sang LƯỚI TỰ GIÃN
   (`repeat(auto-fill, minmax(186px,1fr))`), cùng lý do và cùng lô với
   `.hang-loai-cuon` ở trên - Bruno duyệt mockup mới. `.cuon-ngang` là
   MỘT lớp dùng chung cho CẢ BỐN hàng trang chủ (mới nhất/xem nhiều/
   mỗi loại/đã ghim, đều qua `veHangNgang()`), nên cả bốn cùng đổi -
   không có cơ chế tách riêng "hai dải" khỏi "mỗi loại" mà không sửa
   JS thêm tham số, và đằng nào bài toán "chừa trắng bên phải" cũng
   giống hệt nhau ở cả bốn.
   ⚠ Trang CHI TIẾT (mockup V8) KHÔNG đụng - nó dùng `.lq-luoi`, một
   lớp HOÀN TOÀN riêng, không hề gọi `veHangNgang()`/`.cuon-ngang`. */
.cuon-ngang {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(186px, 1fr));
  /* `align-items: start` (KHÔNG mặc định `stretch` của grid) - giữ
     đúng tinh thần `align-items: flex-start` của bản flex cũ: thẻ
     ngang/dọc cao khác nhau vài px thì mép TRÊN vẫn khớp, phần chênh
     dồn xuống DƯỚI chứ không kéo dãn/đẩy lệch nội dung bên trong. */
  align-items: start;
  gap: 22px 16px; padding: 4px var(--le) 8px;
}
@media (max-width: 640px) {
  .cuon-ngang { grid-template-columns: repeat(3, 1fr); gap: 14px 9px; }
}

/* ================= HAI DẢI VIDEO: TRƯỢT NGANG (06/09) ==============
   Bruno duyệt bản giao diện mới - MỌI mục video ("Video mới nhất",
   "Video xem nhiều", VÀ CẢ 9 hàng theo LOẠI SÚNG,
   `data-kieu="moi-nhat"`/`"xem-nhieu"`/`"loai"`, gắn sẵn từ
   `veHangNgang()`) đổi sang MỘT HÀNG cuộn ngang thật (mở rộng 06/09 -
   lô đầu chỉ hai hàng cố định). CHỈ hàng ĐÃ GHIM (`data-kieu="da-ghim"`)
   còn giữ `.cuon-ngang` lưới tự giãn - KHÔNG đụng. ⚠ ĐỪNG NHẦM với
   khối thẻ ẢNH chọn danh mục ở đầu trang (`.hang-loai-cuon`, lớp
   HOÀN TOÀN khác, không qua `[data-kieu]`/`veHangNgang()`) - khối đó
   vẫn là lưới tự giãn như cũ, không nằm trong phạm vi khối CSS này.
   Lý do đổi: lưới nhiều hàng trộn thẻ ngang (rộng gấp 3 thẻ dọc) với
   thẻ dọc luôn để lại lỗ trống lớn ở cuối hàng lẻ; một hàng cuộn thì
   không bao giờ có lỗ - thẻ nào cũng nối đuôi thẻ kia.

   Chọn lọc bằng ATTRIBUTE SELECTOR trên `[data-kieu]` (đã có sẵn từ
   26/08, không cần thêm lớp JS) - `.cuon-ngang` gốc vẫn là NỀN TẢNG
   dùng chung (align-items, v.v.), khối này chỉ GHI ĐÈ display/scroll
   cho đúng các hàng cần đổi. */
.hang-ngang[data-kieu="moi-nhat"] .cuon-ngang,
.hang-ngang[data-kieu="xem-nhieu"] .cuon-ngang,
.hang-ngang[data-kieu="loai"] .cuon-ngang,
.hang-ngang[data-kieu="co-san"] .cuon-ngang,
.hang-ngang[data-kieu="sap-ve"] .cuon-ngang {
  display: flex; flex-wrap: nowrap; gap: 16px;
  overflow-x: auto; overflow-y: hidden;
  scroll-behavior: smooth; scroll-snap-type: x proximity;
  /* Ẩn thanh cuộn - vuốt tay vẫn hoạt động, chỉ giấu thanh xám xấu. */
  scrollbar-width: none; -ms-overflow-style: none;
}
.hang-ngang[data-kieu="moi-nhat"] .cuon-ngang::-webkit-scrollbar,
.hang-ngang[data-kieu="xem-nhieu"] .cuon-ngang::-webkit-scrollbar,
.hang-ngang[data-kieu="loai"] .cuon-ngang::-webkit-scrollbar,
.hang-ngang[data-kieu="co-san"] .cuon-ngang::-webkit-scrollbar,
.hang-ngang[data-kieu="sap-ve"] .cuon-ngang::-webkit-scrollbar {
  display: none; width: 0; height: 0;
}
/* Thẻ dọc rộng CỐ ĐỊNH 186px (khớp `minmax(186px,...)` của lưới, cùng
   một con số cho quen mắt). `.the-cuoi` đi CÙNG bề ngang thẻ dọc - nó
   là một ô dọc bình thường trong dải. `flex: 0 0 …` khoá cứng bề
   ngang, không co giãn theo khoảng trống còn lại.

   ⚠ BỀ NGANG THẺ NGANG DÙNG TỈ LỆ CHÍNH XÁC (256/81), KHÔNG PHẢI "3
   thẻ dọc + 2 khe hở" (06/09, tự sửa sau khi đo). Đề bài gốc tả công
   thức "3× + 2 khe" cho cả hai mốc - ở mốc RỘNG (186px/16px) nó tình
   cờ chỉ lệch 1,2px (186×16/9=330,67 so với (186×3+16×2)×9/16=331,88),
   nhưng ở mốc HẸP theo vw thì lệch tới 7px giữa 434-640px (đo thật ở
   600px: 331 so với 324) - vượt hẳn bất biến "sai số ≤2px" mà chính
   đề bài liệt trong mục BÀI CANH. Suy ra công thức đúng từ định nghĩa
   "cao bằng nhau": cao_dọc = W_dọc×16/9, cao_ngang = W_ngang×9/16;
   cho hai vế bằng nhau ra W_ngang = W_dọc×(16/9)² = W_dọc×256/81 -
   ĐÚNG ở MỌI bề ngang màn, không chỉ tình cờ đúng ở một mốc. Ưu tiên
   giữ đúng bất biến chiều cao (có bài canh cứng số `TestDongCaoThe
   TrongMotHang`) hơn giữ đúng chữ công thức minh hoạ trong đề bài. */
.hang-ngang[data-kieu="moi-nhat"] .cuon-ngang,
.hang-ngang[data-kieu="xem-nhieu"] .cuon-ngang,
.hang-ngang[data-kieu="loai"] .cuon-ngang,
.hang-ngang[data-kieu="co-san"] .cuon-ngang,
.hang-ngang[data-kieu="sap-ve"] .cuon-ngang {
  --rong-doc-truot: 186px;
}
.hang-ngang[data-kieu="moi-nhat"] .cuon-ngang > .the-nho,
.hang-ngang[data-kieu="xem-nhieu"] .cuon-ngang > .the-nho,
.hang-ngang[data-kieu="loai"] .cuon-ngang > .the-nho,
.hang-ngang[data-kieu="co-san"] .cuon-ngang > .the-nho,
.hang-ngang[data-kieu="sap-ve"] .cuon-ngang > .the-nho,
.hang-ngang[data-kieu="moi-nhat"] .cuon-ngang > .the-cuoi,
.hang-ngang[data-kieu="xem-nhieu"] .cuon-ngang > .the-cuoi,
.hang-ngang[data-kieu="loai"] .cuon-ngang > .the-cuoi,
.hang-ngang[data-kieu="co-san"] .cuon-ngang > .the-cuoi,
.hang-ngang[data-kieu="sap-ve"] .cuon-ngang > .the-cuoi {
  flex: 0 0 var(--rong-doc-truot); width: var(--rong-doc-truot);
  scroll-snap-align: start;
}
.hang-ngang[data-kieu="moi-nhat"] .cuon-ngang > .the-nho--ngang,
.hang-ngang[data-kieu="xem-nhieu"] .cuon-ngang > .the-nho--ngang,
.hang-ngang[data-kieu="loai"] .cuon-ngang > .the-nho--ngang,
.hang-ngang[data-kieu="co-san"] .cuon-ngang > .the-nho--ngang,
.hang-ngang[data-kieu="sap-ve"] .cuon-ngang > .the-nho--ngang {
  flex-basis: calc(var(--rong-doc-truot) * 256 / 81);
  width: calc(var(--rong-doc-truot) * 256 / 81);
}
@media (max-width: 640px) {
  .hang-ngang[data-kieu="moi-nhat"] .cuon-ngang,
  .hang-ngang[data-kieu="xem-nhieu"] .cuon-ngang,
  .hang-ngang[data-kieu="loai"] .cuon-ngang,
  .hang-ngang[data-kieu="co-san"] .cuon-ngang,
  .hang-ngang[data-kieu="sap-ve"] .cuon-ngang {
    gap: 8px; --rong-doc-truot: 31vw;
  }
}

/* ================= KỆ "SẢN PHẨM ĐANG CÓ SẴN / SẮP VỀ" (23/09) ===========
   Mockup Bruno duyệt 23/09 (`mockup/mockup-san-pham-co-san-v2.html`): MỌI
   thẻ cùng một cỡ 16:9, tên mã ql, mác treo HÀNG SẴN/SẮP VỀ góc phải ảnh,
   giá đã che (chữ thường, không đậm) + nút chat cùng hàng. Thẻ dựng ở JS
   `veTheKe` - ghi đè bề ngang thẻ dọc/ngang của dải trượt chung phía trên. */
.hang-ngang[data-kieu="co-san"] .cuon-ngang,
.hang-ngang[data-kieu="sap-ve"] .cuon-ngang { --rong-ke: 260px; }
.hang-ngang[data-kieu="co-san"] .cuon-ngang > .the-ke,
.hang-ngang[data-kieu="sap-ve"] .cuon-ngang > .the-ke {
  flex: 0 0 var(--rong-ke); width: var(--rong-ke);
  scroll-snap-align: start;
}
@media (max-width: 640px) {
  /* Thẻ thứ hai LÓ MÉP ở màn điện thoại = còn vuốt được. */
  .hang-ngang[data-kieu="co-san"] .cuon-ngang,
  .hang-ngang[data-kieu="sap-ve"] .cuon-ngang { --rong-ke: 64vw; }
}
.the-ke {
  position: relative; display: flex; flex-direction: column;
  background: var(--tam); box-shadow: var(--bong-the); border: 1px solid var(--vien);
  border-radius: 12px; overflow: hidden;
}
.ke-khung { position: relative; aspect-ratio: 16 / 9; background: var(--ta-khung); }
.ke-hinh {
  position: absolute; inset: 0; display: block; width: 100%;
  padding: 0; margin: 0; border: 0; background: none; cursor: pointer;
}
.ke-hinh .hinh { position: absolute; inset: 0; overflow: hidden; }
.ke-hinh img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Ghim dời xuống góc TRÁI DƯỚI ảnh - góc phải trên là chỗ của mác treo. */
.the-ke .ghim { top: auto; right: auto; left: 8px; bottom: 8px; }
/* MÁC TREO: đầu nhọn có khoen áp cạnh phải, xoay quanh chính đầu khoen
   (`transform-origin` 90%) cho thân mác rủ xuống như đang treo. Màu tô ở
   đây bằng token, SVG trong JS chỉ mang hình. */
.ke-mac {
  position: absolute; right: 4px; top: 8px; z-index: 2;
  display: block; line-height: 0; pointer-events: none;
  transform: rotate(-7deg); transform-origin: 90% 50%;
  filter: drop-shadow(0 2px 3px var(--bong));
}
.ke-mac svg { display: block; }
.ke-mac .than { fill: var(--c-mac-san); }
.ke-mac .sang { fill: var(--ta-chu); fill-opacity: .14; }
.ke-mac .chi {
  fill: none; stroke: var(--ta-chu); stroke-opacity: .55;
  stroke-width: .9; stroke-dasharray: 2.2 1.8;
}
.ke-mac .khoen { fill: var(--ta-chu); fill-opacity: .85; }
.ke-mac .lo { fill: var(--ta-nen); }
.ke-mac text {
  fill: var(--ta-chu); font-family: 'Barlow Condensed', 'Arial Narrow', sans-serif;
  font-weight: 700; font-size: var(--f3); letter-spacing: .06em;
}
.ke-mac--ve .than { fill: var(--D-order); }
.ke-mac--ve .chi { stroke: var(--ta-nen); stroke-opacity: .4; }
.ke-mac--ve text { fill: var(--ta-nen); }
.ke-ten {
  display: block; width: 100%; padding: 8px 12px 0; margin: 0;
  background: none; border: 0; text-align: left; color: var(--chu); cursor: pointer;
}
.ke-ten-chu {
  font-size: var(--f3); font-weight: 600; line-height: 1.3;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; min-height: 2.6em;
}
.ke-duoi {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 4px 12px 12px; margin-top: auto;
}
.ke-gia {
  min-width: 0; font-size: var(--f3); font-weight: 500;
  color: var(--oliu-sang); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.ke-gia-phu { margin-left: 8px; font-size: var(--f1); font-weight: 400; color: var(--chu-mo); }
/* Nút chat = CHỈ ICON, không nền không viền tròn (Bruno 27/09: "chỉ icon
   không thôi không có nút tròn, icon to một chút cho nổi bật"). Icon 28px,
   rồi hạ còn 90% = 25,2px cùng ngày (bản cũ 18px trong vòng tròn 36px). */
.ke-chat {
  flex: none; position: relative; width: 32px; height: 32px; padding: 0;
  display: grid; place-items: center; cursor: pointer;
  background: none; border: 0; color: var(--oliu-sang);
  transition: transform .15s ease;
}
/* 44px vùng chạm, bung bằng `::before` (cùng cách `.ghim`/`.the-ma-sua`). */
.ke-chat::before {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
}
.ke-chat svg { width: 25.2px; height: 25.2px; transform: translateY(2.3px); }
/* ↑ NGANG HÀNG GIÁ (Bruno 27/09): khung icon đã căn giữa theo hàng, nhưng hai
   đuôi bong bóng kéo khung xuống - THÂN bong bóng (y 1→18,55 của viewBox 24)
   có tâm cao hơn tâm khung 2,22/24 × 25,2px ≈ 2,3px, trông như nổi cao hơn
   chữ giá. Hạ đúng ngần ấy để tâm THÂN trùng tâm chữ giá; đuôi thò xuống dưới. */
.ke-chat:focus-visible { outline: 2px solid var(--oliu-sang); outline-offset: 2px; border-radius: 6px; }
@media (hover: hover) and (pointer: fine) {
  .ke-chat:hover { transform: scale(1.12); }
}
.the-ke .the-ma { margin: 0 12px 12px; }
/* Thẻ "Xem tất cả" cuối hai hàng kệ: cao ĐÚNG bằng thẻ kệ. Dáng mặc định của
   nó là thẻ dọc 9:16 (331px ở 186px ngang) - đo production 23/09 sau deploy:
   thẻ kệ 247px, hàng dư ~85px trống dưới đáy. */
.hang-ngang[data-kieu="co-san"] .cuon-ngang > .the-cuoi,
.hang-ngang[data-kieu="sap-ve"] .cuon-ngang > .the-cuoi {
  aspect-ratio: auto; align-self: stretch; border-radius: 12px;
}
/* Màn "Xem tất cả" của hai hàng: MỘT lưới thẻ kệ (`napCoSanDs`). */
.lq-nhom--ke .lq-nhom-dau { display: none; }
.lq-luoi.luoi-ke { grid-template-columns: repeat(auto-fill, minmax(236px, 1fr)); gap: 16px; }
@media (max-width: 640px) {
  .lq-luoi.luoi-ke { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
}

/* ---- Bọc dải + MŨI TÊN TRƯỢT (Việc 3) ---------------------------
   CẤM nút tròn nền đen, CẤM vệt mờ cố định hai mép - mũi tên là SVG
   nét mảnh trong suốt, chỉ tối góc đó lúc RÊ CHUỘT vào đúng vùng bấm.
   `.dai-truot-boc` chỉ được JS chèn cho hai hàng trượt (xem
   `veHangNgang`), không tồn tại ở hàng loại/ghim. */
.dai-truot-boc { position: relative; }
.mui-ten {
  position: absolute; top: 0; bottom: 34px; width: 84px;
  background: transparent; border: none; padding: 0; margin: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--chu); cursor: pointer; z-index: 5;
  transition: background .16s;
}
.mui-ten--trai { left: 0; }
.mui-ten--phai { right: 0; }
.mui-ten svg {
  width: 35px; height: 35px; opacity: .5;
  transition: opacity .16s;
}
@media (hover: hover) and (pointer: fine) {
  .mui-ten--trai:hover {
    background: linear-gradient(to right, var(--mui-ten-nen), transparent);
  }
  .mui-ten--phai:hover {
    background: linear-gradient(to left, var(--mui-ten-nen), transparent);
  }
  .mui-ten:hover svg { opacity: 1; }
}
/* Đầu dải: ẩn mũi tên trái. Cuối dải: ẩn mũi tên phải. JS đo
   `scrollLeft` rồi gắn/gỡ lớp này (xem `capNhatMuiTen`). */
.mui-ten.an { display: none; }
@media (max-width: 640px) {
  /* Vuốt tay như thường, không cần mũi tên ở màn hẹp. */
  .mui-ten { display: none; }
}

/* ---- THẺ CLIP HAI HƯỚNG (26/08, thích nghi lưới 05/09) -----------
   Kho có HAI loại video, gần 50/50 (đo thật: 1044 dọc / 1111 ngang).
   Luật CŨ "cùng chiều cao, khác bề ngang" nay đổi cách đạt tới: trong
   lưới, MỌI cột cùng bề ngang (`1fr` chia đều) nên thẻ DỌC tự nhiên
   cùng cao (bề ngang x 16/9 qua `aspect-ratio` của `.hinh`) - không
   cần biến `--cao-thumb`/`--rong-clip` neo tay nữa, GỠ CẢ HAI (xem
   `:root` và bốn mốc bề ngang cuối tệp). Thẻ NGANG chiếm ĐÚNG 3 CỘT
   (`grid-column: span 3`) - ba cột cộng hai khe hở, đưa qua tỉ lệ
   16:9, ra xấp xỉ đúng chiều cao một thẻ dọc ở bề ngang cột quanh
   186-200px (khoảng cột thực tế của lưới `minmax(186px,1fr)`). */
.the-nho {
  width: 100%;
  transition: transform .16s, box-shadow .16s;
  /* Mốc cho `.the-sua`/`.ghim` đặt tuyệt đối (12/09) - hai nút là ANH
     EM của `.the-nho-hit`, KHÔNG lồng trong nó (bài học 2534bb4, xem
     chú thích đầy đủ ở JS `veTheNho`/`veTheVideo`), nên phải neo vào
     thẻ ngoài này - `.hinh` nằm khít mép trên của `.the-nho-hit`
     (không padding/border chen giữa) nên vị trí số liệu giữ NGUYÊN,
     không cần đổi bất kỳ top/left/right nào. */
  position: relative;
}
.the-nho-hit {
  display: block; width: 100%;
  text-align: left; color: inherit; font: inherit;
  background: none; border: none; padding: 0; margin: 0; cursor: pointer;
}
.the-nho--ngang { grid-column: span 3; }
@media (max-width: 640px) {
  /* Thẻ ngang trải trọn bề ngang hàng ở mốc điện thoại - 3 cột dọc
     hẹp không đủ chỗ chia ba cho một thẻ ngang mà không vỡ tỉ lệ. */
  .the-nho--ngang { grid-column: 1 / -1; }
}
.the-nho .hinh {
  width: 100%; aspect-ratio: 9 / 16;
  border-radius: var(--bk); border: 1px solid var(--vien);
  position: relative; overflow: hidden; background: var(--ta-khung);
  transition: border-color .16s;
}
.the-nho--ngang .hinh { aspect-ratio: 16 / 9; }
.the-nho .hinh img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* Vùng chữ CỐ ĐỊNH chiều cao (2 dòng) để ĐÁY thẻ thẳng hàng - tựa một
   dòng và tựa hai dòng mà để tự co thì đáy so le, nhìn như hàng bị lỗi. */
/* ⚠ FONT TIÊU ĐỀ THẺ - GỘP VỀ MỘT KHUÔN VỚI `.the-video .tv` (04/09).
   GỐC LỖI của lô trước: Barlow Condensed CHỈ được áp cho `.the-video
   .tv` (lưới màn danh sách + tìm kiếm), còn `.the-nho .ten-v` (hàng
   cuộn trang chính + hai dải trang chi tiết) KHÔNG hề khai
   `font-family` nên thừa kế font THÂN (Inter) của `body`. Không phải
   bị lớp khác đè, không phải sai tên lớp, không cần `!important` -
   chỉ là áp thiếu MỘT trong HAI thành phần thẻ. Bruno soi production
   trang chủ (hàng cuộn) nên thấy đúng chỗ chưa được áp.
   Nay hai lớp dùng CÙNG bộ giá trị; sửa một chỗ thì sửa cả hai. */
.the-nho .ten-v {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 500;
  font-size: 19px; line-height: 1.22; letter-spacing: .015em;
  color: var(--chu); margin-top: 8px; transition: color .16s;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  /* `min-height` (không phải `height` cố định như bản cũ) - cùng cơ
     chế giữ đáy thẻ thẳng hàng mà `.the-video .tv` đang dùng: tựa một
     dòng và tựa hai dòng đều chiếm đúng 2.44em. */
  min-height: 2.44em;
}
@media (max-width: 640px) {
  .the-nho .ten-v { font-size: 16.5px; }
}

/* nhãn lượt xem (góc trái dưới) - chỉ hiện khi có số (mục 5, Việc 2).
   ⚠ TÁCH KHỎI NHÃN THỜI LƯỢNG, KHÔNG BAO GIỜ CHẠM NHAU (26/08) - xem
   giải thích công thức đầy đủ tại chỗ tạo ra hai nhãn này trong
   `video_public.js` (`veTheNho`).

   ⚠ ĐO THẬT TRƯỚC KHI CHỐT SỐ (bẫy tự bắt được lúc dựng): bản đầu chỉ
   thêm `max-width: calc(50% - 9px)`, GIỮ NGUYÊN cỡ chữ/đệm cũ (`--f1`,
   `padding: 4px 8px`, `gap: 4px`). Hai nhãn HẾT CHẠM NHAU thật, nhưng
   đo lại thì khoảng còn cho CHỮ chỉ 13px trong khi "5,5M" cần ~30px -
   MỌI số bình thường bị cắt còn "5..". `.textContent` vẫn đúng
   ("5,5M") nên bài test đầu tiên (đọc `.textContent`) XANH mà không hề
   canh cái mắt nhìn thấy - phải đo `scrollWidth` của CHÍNH `.xem-so`
   mới bắt được.
   Card dọc ở 390px chỉ rộng 108px - không đủ chỗ cho cả hai nhãn ở cỡ
   chữ/đệm gốc mà không chạm. Phải THU NHỎ CẢ HAI (đệm, khe hở icon, cỡ
   icon, cỡ chữ - xem `--f-nhan-goc`) để nội dung THẬT SỰ vừa, không
   chỉ ép một cái trần rồi cắt chữ cho vừa cái trần đó.
   Đo lại sau khi thu nhỏ: "5,5M"/"726K"/"367K" tự nhiên rộng 51-53px,
   còn dư 8-10px hở với `.dai` mà KHÔNG cần chạm ngưỡng `max-width`. */
.hinh .xem {
  position: absolute; left: 4px; bottom: 4px;
  max-width: calc(60% - 5px);
  background: var(--nhan-nen); border-radius: var(--bk);
  font-size: var(--f-nhan-goc); padding: 2px 5px; color: var(--ta-chu);
  display: inline-flex; align-items: center; gap: 2px; font-variant-numeric: tabular-nums;
}
.hinh .xem svg { width: 9px; height: 9px; flex: none; fill: none; stroke: var(--ta-chu); stroke-width: 2; }
/* Chữ số MỚI co lại (ellipsis) khi hết chỗ - `min-width: 0` bắt buộc
   để flex item chịu co dưới kích thước nội dung tự nhiên của nó.
   Đây là LƯỚI AN TOÀN cho dữ liệu bất thường (sổ hỏng ra một con số
   khổng lồ), KHÔNG PHẢI cơ chế chính để hai nhãn tách nhau - cơ chế
   chính là thu nhỏ đệm/chữ ở trên, để số bình thường không bao giờ
   chạm tới ngưỡng này. */
.hinh .xem-so {
  min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}

/* ================= HÀNG NGANG TRANG CHỦ (26/08) ==================
   Trang chủ nay là một CHỒNG hàng ngang cùng khuôn: "mới nhất",
   "xem nhiều", rồi mỗi loại đủ 10 clip một hàng. Tất cả dùng chung
   `.hang-ngang` + `.cuon-ngang` + `.the-nho` đã có sẵn - hàng ghim
   của lô sau chỉ việc chèn thêm MỘT `.hang-ngang` nữa, không phải
   thêm lớp nào.                                                    */

.hang-ngang { padding-bottom: 4px; }
/* Vạch ngăn MẢNH giữa hai hàng. Dùng `+` chứ không phải viền dưới
   trên từng hàng: hàng cuối không có vạch thừa, và hàng ghim chèn
   vào giữa cũng tự có vạch mà không sửa gì. */
.hang-ngang + .hang-ngang { border-top: 1px solid var(--vien); }
.hang-khoi { padding-bottom: 0; }
.hang-dau { gap: 8px; }

/* Ảnh loại 38x29 thay chỗ vạch ô-liu. Hai hàng cố định (mới nhất /
   xem nhiều) không có ảnh nên vẫn đeo `.gach` như cũ. */
.hang-dau .hang-anh {
  width: 38px; height: 29px; flex: none; align-self: center;
  border-radius: var(--bk); border: 1px solid var(--vien);
  object-fit: cover; display: block; background: var(--ta-khung);
}
.hang-dau h2 { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hang-dau .hang-phu-en { font-size: var(--f1); color: var(--chu-mo); flex: none; }
/* Số clip dồn phải, màu ô-liu (khác `.khoi-dau .dem` xám của khối cũ).
   `font-size` khai THẲNG (không qua `--f1` dùng chung 19 chỗ khác
   trong tệp) - 06/09 "chữ to lên toàn trang" chỉ nhắm đúng con số cạnh
   tiêu đề mục, đổi `--f1` sẽ kéo theo 18 chỗ khác không được giao. */
.hang-dau .hang-so { margin-left: auto; flex: none; color: var(--so-loai); font-size: 13.5px; }
/* "Xem thêm 22 ›" ở hàng "Sản phẩm đang có sẵn"/"Sắp về" (Bruno duyệt mockup
   24/09): CHỮ TRƠN, không viền không bo tròn; SỐ khác màu, lấy đúng màu mác
   trên thẻ của hàng ấy (xanh "HÀNG SẴN", vàng "SẮP VỀ") - không đẻ màu mới.
   Đệm dọc + lề âm cùng cỡ: vùng chạm cao hơn chữ mà hàng tiêu đề không cao
   thêm một điểm ảnh. */
.hang-dau .hang-xem-them {
  margin-left: auto; flex: none; display: inline-flex; align-items: center; gap: 4px;
  padding: 8px 0; margin-block: -8px;
  color: var(--oliu-sang); font-size: 14.5px; font-weight: 600;
  white-space: nowrap; text-decoration: none;
}
.hang-dau .hang-xem-so { font-weight: 700; }
/* 24/09: số "Xem thêm" của hàng "có sẵn" dùng màu CÒN HÀNG theo chế độ -
   `--c-mac-san` là nền mác đè trên ảnh, làm chữ trên nền sáng chỉ 2.85:1. */
.hang-ngang[data-kieu="co-san"] .hang-xem-so { color: var(--c-con-hang); }
.hang-ngang[data-kieu="sap-ve"] .hang-xem-so { color: var(--c-hang-order); }
.hang-dau .hang-xem-them svg {
  width: 15px; height: 15px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 2.4;
}

/* ---- THẺ CUỐI "XEM TẤT CẢ" ----
   Cố ý KHÁC hẳn thẻ clip: viền đứt ô-liu, không ảnh, mũi tên trong
   vòng tròn.

   v3 (05/09): trong lưới, thẻ này là MỘT Ô DỌC bình thường (không
   span) - bề ngang tự bằng cột lưới như mọi thẻ dọc khác,
   `aspect-ratio: 9/16` tự suy chiều cao, không cần neo `--cao-thumb`
   (đã gỡ, xem `.cuon-ngang`/`.the-nho` ở trên). */
.the-cuoi {
  width: 100%; aspect-ratio: 9 / 16;
  /* Hàng lưới không có khái niệm "dãn theo ô cao nhất" như flex, nhưng
     giữ `align-self: start` cho chắc nếu sau này có hàng trộn nhiều
     hàng lưới (grid-row tự động không đều). */
  align-self: start;
  border: 1px dashed var(--vien-oliu); border-radius: var(--bk);
  background: var(--oliu-nen); color: var(--oliu-sang); text-decoration: none;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  /* Đệm NGANG hẹp hơn đệm dọc: khổ mới chỉ 77px, mà con số thật của
     hai hàng cố định là "2.155 video" - đo được cần 66px, còn đệm 6px
     hai bên chỉ chừa 63px nên nó bị cắt bằng dấu ba chấm. Đo rồi mới
     chọn 4px, không gõ bừa. */
  gap: 6px; padding: 6px 4px; text-align: center;
}
/* Vòng 40px (06/09, đúng mockup Việc 2) - bình luận CŨ "khổ chỉ 77px
   nên phải co 36->28" đã LỖI THỜI: đó là số đo TRƯỚC khi dải video đổi
   sang trượt ngang (26/08), lúc `.the-cuoi` còn nằm trong lưới hẹp.
   Nay khổ thẻ neo theo `--rong-doc-truot` (186px desktop, 31vw mobile
   ~121px ở 390px) - dư sức cho vòng 40px, không còn ràng buộc cũ. */
.the-cuoi .tc-vong {
  width: 40px; height: 40px; flex: none; border-radius: 50%;
  border: 1px solid var(--vien-oliu);
  display: flex; align-items: center; justify-content: center;
}
.the-cuoi .tc-vong svg { width: 18px; height: 18px; stroke: var(--oliu-sang); }
.the-cuoi .tc-chu {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  /* 16.5px/.12em (06/09, "chữ to lên toàn trang" - trước 15px cùng ngày).
     Đổi CHUNG cho cả hai dải trượt lẫn hàng loại/ghim (grid): một thẻ
     "Xem thêm" dùng chung một kiểu chữ ở mọi nơi nó xuất hiện, chỉ BỀ
     NGANG khối bọc là khác theo bố cục (flex hay grid). */
  font-weight: 700; font-size: 16.5px;
  text-transform: uppercase; letter-spacing: .12em; line-height: 1.1;
}
/* Số video MỘT DÒNG - khổ hẹp mà để nó vỡ đôi thì thẻ cao lên và lại
   so le với vùng ảnh. `font-size` khai THẲNG 12.5px (không qua `--f1`
   dùng chung 19 chỗ khác) - cùng lý do đã ghi ở `.hang-dau .hang-so`. */
.the-cuoi .tc-so {
  font-size: 12.5px; color: var(--chu-mo);
  white-space: nowrap; max-width: 100%; overflow: hidden;
  text-overflow: ellipsis;
}

/* ================= NÚT GHIM (26/08) ================================
   Góc TRÊN-PHẢI ảnh clip đã chừa sẵn từ lô hàng ngang: nhãn thời lượng
   ở dưới-phải, nhãn lượt xem ở dưới-trái, không thứ gì chạm vào đây.

   MỘT bộ luật cho MỌI nơi có thẻ clip (hàng cuộn ngang, lưới màn danh
   sách, dòng kết quả tìm) - `veNutGhim()` bên JS cũng là MỘT hàm. Ba
   bản chép ra ba chỗ là ba chỗ lệch nhau, đúng bài học cây chính/cây
   phụ ở e3fa724.

   ⚠ VÙNG CHẠM >= 44px dù ô vẽ chỉ 28px: bung ra bằng `::before` phủ
   trong suốt, KHÔNG bằng cách phóng to nút - phóng to là che mất ảnh
   clip, mà cái người ta đang xem chính là ảnh ấy. */
.ghim {
  position: absolute; top: 6px; right: 6px; z-index: 2;
  width: var(--o-ghim); height: var(--o-ghim);
  border: none; border-radius: 50%; background: var(--nhan-nen);
  color: var(--ta-chu); display: flex; align-items: center; justify-content: center;
  padding: 0; cursor: pointer;
  transition: background-color .16s;
}
.ghim::before {
  content: ""; position: absolute;
  top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: var(--cham-ghim); height: var(--cham-ghim);
}
/* Chưa ghim: viền trắng RỖNG. Đã ghim: ĐẶC màu ô-liu. Khác nhau ở CẢ
   nét lẫn ruột nên phân biệt được kể cả khi nhìn lướt trên nền ảnh. */
.ghim svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2; }
.ghim.da-ghim { color: var(--ta-oliu-ro); }
.ghim.da-ghim svg { fill: currentColor; stroke: currentColor; }
.the-video .ghim { top: 10px; right: 10px; }

/* ---- hàng "Đã ghim" ---- */
/* Vạch ngăn: hàng ghim nằm ở khối RIÊNG (`#tc-hang-ghim`) nên luật
   `.hang-ngang + .hang-ngang` không với tới nó - tự khai một vạch dưới.
   Không sợ chồng đôi: hàng đầu của `#tc-cac-hang` không có anh em
   `.hang-ngang` đứng trước nên không ăn `border-top`. */
#tc-hang-ghim > * { border-bottom: 1px solid var(--vien); }
.hang-ghim-trong { padding-bottom: 4px; }
/* Dòng báo thoáng qua. `pointer-events: none` là phần QUAN TRỌNG:
   nó nổi ở đáy màn, ngay chỗ ngón cái hay chạm - bắt sự kiện chuột là
   nó nuốt mất cú chạm vào thẻ clip bên dưới. */
.bao-thoang {
  position: fixed; left: 50%; bottom: calc(16px + env(safe-area-inset-bottom));
  transform: translateX(-50%); z-index: 60; pointer-events: none;
  max-width: calc(100% - 32px);
  background: var(--tam-cao); color: var(--chu);
  border: 1px solid var(--vien-oliu); border-radius: var(--bk);
  padding: 12px 16px; font-size: var(--f1); line-height: 1.4;
  box-shadow: 0 4px 16px var(--bong); text-align: center;
}
.bao-thoang[hidden] { display: none; }

.ghim-loi-moi {
  color: var(--chu-mo); font-size: var(--f1); line-height: 1.5;
  padding: 0 var(--le) 16px;
}


/* ---- V5 (26/08): THẺ SẢN PHẨM ------------------------------------ */
.the-sp {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 12px var(--le) 0;
  padding: 10px;
  border: 1px solid var(--vien);
  border-radius: var(--bk);
  background: var(--tam);
  box-shadow: var(--bong-the);
}
.the-sp[hidden] { display: none; }

/* DẢI BÁO CHẾ ĐỘ XEM THỬ (04/09). Cố ý CHÓI và nằm trên cùng: mục
   đích duy nhất là không ai nhìn nhầm giá/thông số demo thành thật.
   Dùng `--c-hang-order` (vàng hổ phách) - đã có sẵn trong bảng, và
   vàng cảnh báo là đúng nghĩa ở đây. */
.dai-demo {
  position: sticky; top: 0; z-index: 60;
  background: var(--c-hang-order); color: var(--chu-tren-oliu);
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 700; font-size: 12.5px; letter-spacing: .14em;
  text-transform: uppercase; text-align: center;
  padding: 5px 12px;
}

.the-sp-anh {
  /* 64px -> 80px (Commit 4) -> 84px (04/09, Bruno chốt theo mockup V8).
     Hai lệnh cũ lệch nhau 4px, đã hỏi và Bruno chốt lấy 84 của V8. */
  width: 84px; height: 84px; flex: none;
  border-radius: var(--bk);
  border: 1px solid var(--vien);
  object-fit: cover;
  background: var(--ta-khung);
}

.the-sp-chu { min-width: 0; flex: 1; }

.the-sp-ten {
  color: var(--chu);
  font-size: 14px; font-weight: 600;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Giá và "Xem thêm" CÙNG MỘT HÀNG, đẩy hai đầu - hai thứ người ta liếc
   cùng lúc, "Xem thêm" LUÔN dạt phải dù giá ngắn/dài. */
.the-sp-hang {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 4px;
}

/* Giá LUÔN Ở DẠNG ĐÃ CHE (`the.gia_che` che sẵn ở máy chủ, xem
   `_thong_tin_san_pham`/`che_gia()`) - trang khách không bao giờ nhận
   số đầy đủ để mà lỡ hiện ra. */
.the-sp-gia {
  color: var(--oliu-sang);
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 700;
  font-size: 21px;
  font-variant-numeric: tabular-nums;
}

/* "Xem thêm" KHÔNG viền, màu ô-liu (khác nút tư vấn ở HÌNH DÁNG - chữ
   trần không nền, không phải ở màu). */
.the-sp-xem {
  display: inline-flex; align-items: center; gap: 2px;
  color: var(--oliu-chu);
  text-decoration: none;
  font-size: var(--f1);
  border: none;
  background: none;
  padding: 0;
  margin-left: auto;
}
.the-sp-xem svg { width: 13px; height: 13px; }

.the-sp-tt {
  display: flex; align-items: center; gap: 6px;
  margin-top: 6px;
  font-size: var(--f1);
}
/* Chấm tròn đầu dòng, màu THEO ĐÚNG màu chữ (currentColor) - đổi màu
   trạng thái thì chấm tự đổi theo, không cần khai lại ba lần. */
.the-sp-tt::before {
  content: ""; width: 7px; height: 7px; border-radius: 999px;
  background: currentColor; flex: none;
}
.the-sp-tt--con_hang { color: var(--c-con-hang); }
.the-sp-tt--hang_order { color: var(--c-hang-order); }
.the-sp-tt--het_hang { color: var(--c-het-hang); }

/* ---- V3 (26/08): nút tư vấn theo NGỮ CẢNH ------------------------
   Header màn chi tiết: thu thành ICON VUÔNG ngang cỡ nút tìm kiếm.
   Thân trang đã có một nút to full-rộng, để thêm một nút chữ trên
   header là hai lời mời giống hệt nhau tranh chỗ của tiêu đề video. */
.nut-fb--icon {
  /* VUÔNG thật, không phải "gần vuông": đặt cả `width` lẫn `height`
     và bỏ padding dọc thừa. Đo thật lần đầu ra 38x30 - trông như một
     nút bị bóp, không như icon cạnh nút tìm.
     44px (không phải 38px) - VÙNG CHẠM = chính hộp nút, khớp
     `.nut-tim` cạnh nó (xem lý do "đừng dùng lớp phủ" tại đó). */
  padding: 0;
  width: 44px;
  height: 44px;
  flex: none;
  justify-content: center;
}
.nut-fb--icon svg { width: 18px; height: 18px; }
/* ⚠ KHÔNG khai luật ẩn `.fb-chu-*` ở đây - nút icon KHÔNG CÓ span chữ
   nào để mà ẩn (xem `video.html`). Đã thử viết luật ấy: sabotage bỏ nó
   đi thì không bài nào đỏ, vì nó chưa từng chạm được vào phần tử nào.
   Một dòng CSS không làm gì thì sớm muộn cũng có người sửa nó rồi
   tưởng mình vừa đổi cái gì đó. */

/* Nút CHÍNH: nền ô-liu đặc, full rộng, chữ in đậm, icon chat bên trái. */
.nut-tv-chinh {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin: 12px var(--le) 0;
  min-height: 52px;
  padding: 12px 16px;
  border-radius: var(--bk);
  background: var(--oliu);
  color: var(--chu-tren-oliu);
  text-decoration: none;
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 700;
  font-size: var(--f3);
  text-transform: uppercase;
  letter-spacing: .1em;
}
.nut-tv-chinh svg { width: 18px; height: 18px; flex: none; }
.nut-tv-chinh:active { filter: brightness(1.12); }
.nut-tv-chinh[hidden] { display: none; }
/* NGỪNG BÁN (10/10): icon tư vấn đầu trang chi tiết + nút chat thẻ kệ ẩn được
   - `.nut-fb`/`.ke-chat` đặt `display` bằng lớp, thắng `[hidden]` mặc định. */
.nut-fb[hidden], .ke-chat[hidden] { display: none; }

/* ⚠ `.nut-tv-phu` ĐÃ GỠ (V8) cùng phần tử nó tô - xem `video.html`.
   Đừng dựng lại: câu ấy giải thích một việc nút đã tự làm, và ở bố cục
   hai-ô nó rơi xuống dưới ô phải làm lệch chiều cao hai ô. */

/* ================= V0: TẤM THÔNG SỐ (spec plate) ==================
   Kiểu tấm thép khắc quân sự. Dùng CHUNG cho màn chi tiết và màn lưới
   - một component, không phải hai bản gần giống nhau.

   v2 (04/09, mockup duyệt 03/09): DẢI NGANG MỘT HÀNG thay khối dọc cũ
   (tiêu đề kẹp vạch phía trên, các dòng khoá-giá trị xếp chồng phía
   dưới). ⚠ `.tam-dau`/`.tam-vach`/`.tam-tieu-de`/`.tam-day` GIỮ NGUYÊN
   CSS dù `veTamThongSo` (tấm 1 sản phẩm) không còn dùng - BẢNG SO SÁNH
   (`veBangSoSanh`, video >=2 sản phẩm) vẫn dùng nguyên bốn lớp này cho
   tiêu đề/chân bảng của NÓ, không đụng tới theo đúng phạm vi lô này.

   ⚠ Chỉ token "Thép & Ô-liu" của trang này, KHÔNG mượn token ql. */
/* ⚠ XẾP DỌC, không phải hàng ngang (04/09). Bản cũ là flex HÀNG
   (`.tts-ten` bên trái | `.tts-cap` bên phải) - hợp với dải ngang 5
   cặp. Khi `.tts-cap` đổi thành BẢNG DỌC 10 dòng mà cha vẫn là hàng
   thì khối tên chiếm bên trái và bảng bị ép vào một cột hẹp còn lại:
   giá trị vỡ chữ giữa từ ("Gree n Gas", "112 mm"). Đo số KHÔNG bắt
   được (vẫn đủ 10 dòng), chỉ lộ khi TỰ SOI ẢNH production.
   `overflow-x: auto` cũng bỏ - bảng dọc không tràn ngang, giữ lại chỉ
   tạo một thanh cuộn ma. */
.tam-ts {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 16px var(--le) 0;
  padding: 14px 16px;
  border: 1px solid var(--oliu-dam);
  border-radius: var(--bk);
  background: var(--tam);
  box-shadow: var(--bong-the);
}

/* Bốn đinh tán góc. Bé và mờ - nó là chi tiết chất liệu, không phải
   một thứ để nhìn vào. */
.tam-dinh {
  position: absolute;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--oliu-dam);
}
.tam-dinh--tl { top: 5px; left: 5px; }
.tam-dinh--tr { top: 5px; right: 5px; }
.tam-dinh--bl { bottom: 5px; left: 5px; }
.tam-dinh--br { bottom: 5px; right: 5px; }

.tam-dau {
  position: relative;   /* mốc neo cho dấu "Đã kiểm duyệt" - xem `.tts-dau` */
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-bottom: 12px;
}

/* Hai vạch ngắn kẹp tiêu đề. `flex: 1` để chúng tự dài ra cho cân,
   nhưng bó `max-width` để không thành hai đường kẻ dài ngoằng. */
.tam-vach {
  flex: 1;
  max-width: 28px;
  height: 1px;
  background: var(--oliu-dam);
}

.tam-tieu-de {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 700;
  font-size: var(--f2);
  text-transform: uppercase;
  letter-spacing: .22em;
  color: var(--oliu-sang);
  white-space: nowrap;
}

/* ---- v2: tên mẫu · hãng, GÓC TRÁI dải ngang --------------------- */
/* Khối tên nay nằm TRÊN bảng (không còn cột trái) - bỏ vạch ngăn dọc
   và trần bề ngang 108px của bố cục hàng cũ. */
.tts-ten {
  position: relative;   /* mốc neo cho dấu "Đã kiểm duyệt" - xem `.tts-dau` */
  flex: none;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--vien);
}
/* Chừa chỗ bên phải cho dấu nghiêng, để tên dài không chạy xuống dưới
   nó. Dưới 600px dấu ẩn nên không chừa. */
@media (min-width: 600px) {
  .tts-ten { padding-right: 112px; }
}
/* TÊN SẢN PHẨM đầu khối thông số - ĐỔI 09/10 (lô chi-tiet-tu-van, Bruno):
   chữ thân Inter (không còn Barlow Condensed hẹp), đậm 600, cỡ bậc --f3
   (.95rem = 15.2px, bậc gần 15px nhất của thang sáu bậc), màu chữ chính.
   Dòng hãng dưới tên (`.tts-ten-hang`) đã bỏ - hãng ở hàng "HÃNG SẢN XUẤT".
   Bảng so sánh nhiều mã (`.tam-bang-ten`) đi CÙNG kiểu này. */
.tts-ten-chinh {
  font-family: 'Inter', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 600;
  font-size: var(--f3);
  color: var(--chu);
  line-height: 1.3;
  overflow-wrap: anywhere;
}

/* ---- v2: 4-5 cặp khoá-giá trị GIỮA dải ngang -------------------- */
/* ⚠ ĐỔI HẲN KIỂU BÀY (04/09, mockup Bruno duyệt): DẢI NGANG -> BẢNG
   DỌC. Bản cũ xếp các cặp thành một hàng ngang và vì thế phải chặn ở
   5 cặp (dải một hàng không chứa nổi hơn); mockup mới là bảng dọc
   khoá-trái / giá-trị-phải, kẻ chấm ngăn dòng, bày ĐỦ 10 trường.
   Đổi kiểu bày cũng là thứ làm CỘT PHẢI CAO LÊN - điều kiện để player
   sticky có chỗ dính lại (xem bước bố cục). */
/* V8: 10 trường chia HAI CỘT, 5 mỗi bên. `grid-auto-flow: column` +
   `grid-template-rows: repeat(5, auto)` cho ra ĐÚNG 5 dòng mỗi cột và
   đổ theo CỘT (1-5 bên trái, 6-10 bên phải) - khác hẳn `columns: 2`
   của CSS multi-column, thứ cắt theo chiều cao nên hai cột lệch dòng
   nhau khi một giá trị vỡ hai dòng.
   ⚠ Dưới 760px về MỘT cột: hai cột trên màn hẹp thì mỗi ô chỉ còn
   ~160px và giá trị vỡ chữ giữa từ ("Gree n Gas") - đúng lỗi đã trả
   giá khi nhét bảng này vào cột 50/50, chỉ khác nguyên nhân. */
.tts-cap {
  flex: 1 1 auto;
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(5, auto);
  column-gap: 28px;
  min-width: 0;
}
@media (max-width: 760px) {
  .tts-cap { grid-auto-flow: row; grid-template-rows: none; }
}
.tts-mot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 5px 0;
  /* Kẻ CHẤM ngăn dòng - đúng mockup, và nhẹ hơn kẻ liền cho một bảng
     10 dòng. Dòng cuối không kẻ. */
  border-bottom: 1px dotted var(--vien);
}
.tts-mot:last-child { border-bottom: none; }
/* NHÃN THÔNG SỐ - MỘT kiểu cho MỌI bảng thông số của trang khách (bảng một
   sản phẩm `.tts-k` + cột nhãn bảng so sánh `.tam-bang-nhan`). Mockup Bruno
   duyệt 09/10 (45WmWkk2f9y8nxtHCrHeCZ): bỏ chữ ĐỨNG HẸP Barlow Condensed,
   dùng CHÍNH font thân (Inter tự host, cùng họ với cột giá trị) - in hoa,
   đậm vừa, giãn nhẹ, xám phụ. Cỡ `--f1` (.78rem ≈ 12,5px) thay 13px của
   mockup: thang chữ trang khách không có 13px và trần cỡ ngoài thang đã đầy
   (test_chuan_giao_dien_video) - không đẻ cỡ mới. Màu qua token nên Sáng/Tối
   chỉ đổi màu, không đổi dáng. */
.tts-k,
.tam-bang th.tam-bang-nhan {
  font-family: inherit;
  font-weight: 500;
  font-size: var(--f1);
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--chu-mo);
}
.tts-k { white-space: nowrap; }
.tts-v {
  font-size: var(--f1);
  color: var(--chu);
  overflow-wrap: anywhere;
  text-align: right;
  font-weight: 600;
}
.tts-v--dam { font-weight: 700; color: var(--oliu-sang); }
/* ⚠ LUẬT "mobile chỉ 4 cặp" ĐÃ BỎ (04/09): nó sinh ra vì bản cũ bày
   NGANG một hàng - hàng ấy tràn ở màn hẹp nên phải cắt bớt. Bảng DỌC
   không có vấn đề đó, và cắt mất 6/10 thông số trên điện thoại là
   giấu đúng thứ khách đang muốn đọc (phần lớn khách xem bằng điện
   thoại). Nay bày đủ 10 dòng ở mọi cỡ màn. */

/* Nguồn của con số - nhỏ và mờ. FPS và joule đến từ hai nguồn khác
   nhau và KHÔNG quy đổi được cho nhau; không ghi nguồn thì người đọc
   tưởng shop tự đo được cả hai. */
.tam-nguon {
  display: block;
  margin-left: 0;
  font-size: .64rem;
  color: var(--chu-mo);
  text-transform: uppercase;
  letter-spacing: .08em;
}

/* ---- v2: dấu "ĐÃ KIỂM DUYỆT", GÓC PHẢI, NGHIÊNG -3° ------------- */
/* ⚠ DẤU "ĐÃ KIỂM DUYỆT" NẰM Ở MÉP PHẢI HÀNG TÊN (22/09). Trước đó nó
   đứng cùng hàng tiêu đề "Thông số kỹ thuật" - hàng ấy đã BỎ (Bruno:
   "Người xem họ sẽ tự hiểu thông tin bên dưới là gì"). Neo tuyệt đối
   trong `.tts-ten` (đã `position: relative`), tên chừa `padding-right`
   để không chạy xuống dưới dấu. */
.tts-dau {
  position: absolute;
  right: 0;
  top: 0;
  padding: 4px 10px;
  border: 1px solid var(--oliu-dam);
  border-radius: 3px;
  color: var(--oliu-sang);
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 700;
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .1em;
  white-space: nowrap;
  transform: rotate(-3deg);
}
@media (max-width: 599px) {
  /* Dải hẹp: dấu ẩn để dành chỗ cho 4 cặp thông số - "đã kiểm duyệt"
     không phải thông tin khách cần đọc lướt bằng ngón tay trên điện
     thoại, khác 4 cặp khoá-giá trị. */
  .tts-dau { display: none; }
}

.tam-day {
  margin-top: 12px;
  text-align: center;
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .18em;
  color: var(--chu-mo);
}

/* BẢNG SO SÁNH nhiều cột (chốt 27/08) - video gắn >=2 sản phẩm. Cùng
   khung thép/đinh tán/tiêu đề/footer với tấm 1-cột (`.tam-ts`), chỉ
   thân đổi từ flex-dòng sang bảng. `.tam-bang-cuon` cho phép trượt
   ngang khi >=3 sản phẩm không đủ chỗ; cột nhãn GHIM TRÁI (sticky) để
   luôn biết đang đọc trường nào dù đã cuộn qua cột thứ mấy. */
.tam-bang-cuon { overflow-x: auto; }
.tam-bang { width: 100%; border-collapse: collapse; }
.tam-bang th, .tam-bang td {
  padding: 7px 10px 7px 0;
  border-bottom: 1px solid var(--vien);
  font-size: var(--f1);
  text-align: center;
  white-space: nowrap;
}
.tam-bang tr:last-child th, .tam-bang tr:last-child td { border-bottom: none; }
.tam-bang th:first-child, .tam-bang td:first-child {
  position: sticky; left: 0; z-index: 1;
  background: var(--tam);
  text-align: left;
  font-weight: 400;
  color: var(--chu-mo);
  white-space: normal;
  min-width: 76px;
}
.tam-bang-cot { min-width: 108px; }
.tam-bang-ten {
  font-family: 'Inter', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  color: var(--chu);
  font-weight: 600;
  font-size: var(--f3);
  line-height: 1.3;
  overflow-wrap: anywhere;
  white-space: normal;
}
td.tam-bang-trong { color: var(--chu-mo); }
/* Hàng khác giá trị - tô nhấn NHẸ, đủ để liếc thấy, không loè loẹt. */
.tam-bang-khac td, .tam-bang-khac th.tam-bang-nhan { background: var(--oliu-nen); }
.tam-bang-xem {
  color: var(--oliu-sang);
  font-size: .72rem;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ---- tầng 2: chip (màn danh sách) ---- */
/* NỚI TO + TÁCH SỐ ĐẾM + TĂNG TƯƠNG PHẢN (08/09, Phase 2 Việc 1b/c/d).
   Dùng CHUNG cho ba nơi (`.dai-loc`/`.loc-panel`/`.dong-strip` - xem
   `veMotChip()` trong video_public.js), một khuôn không ba bản chép -
   nới ở đây là nới ĐỦ CẢ BA, đúng tinh thần "một lớp, không ba biến
   thể lệch nhau" (bẫy #11 CLAUDE.md).
   Nền cũ `var(--tam)` TRÙNG HỆT nền của cả `.dong-strip`/`.loc-panel`
   chứa nó -> chip chìm vào khối cha. Nay `var(--tam-cao)` (nổi hơn
   một bậc, đã dùng cho `.chip-cd` cùng tệp) + viền `--vien-sang`
   (rgba trắng 42%, đã dùng ở dải điều khiển lightbox) thay vì
   `--vien` xám tối - viền RÕ trên nền tối thay vì gần như vô hình. */
.dai-chip { padding: 12px var(--le) 4px; }
.chip-cum { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  background: var(--tam-cao); border: 1px solid var(--vien-chip); border-radius: 999px;
  padding: 11px 16px; font-size: 14px; font-weight: 500; color: var(--chu);
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px; box-sizing: border-box;
  cursor: pointer; font-family: inherit;
}
/* Số đếm trong Ô NỀN RIÊNG bo tròn - tách khỏi tên mẫu/hãng, đúng bẫy
   "Glock 17 141" đọc như một dãy số (tên mẫu vốn có sẵn chữ số). Cùng
   khuôn `.chip-cd-so` (viên ô-liu đặc) nhưng ĐẢO màu: chip này còn
   phải phân biệt được trạng thái chọn/chưa chọn qua chính ô số. */
.chip .c-dem {
  font-size: var(--f1); font-weight: 600; color: var(--chu-mo);
  background: var(--nen); border-radius: 999px; padding: 2px 8px;
  font-variant-numeric: tabular-nums;
}
.chip.chon { background: var(--oliu); border-color: var(--oliu); color: var(--chu-tren-oliu); font-weight: 600; }
.chip.chon .c-dem { background: var(--bl-chon-dem-nen); color: var(--chu-tren-oliu); }
.chip.xem-them { border-style: dashed; color: var(--oliu-sang); background: none; }
/* bo-loc-web-phase2, Việc 3b - chip vét "Hãng khác" - KHÔNG bấm được
   (`<button disabled>`), viền đứt cùng khuôn `.chip.xem-them` nhưng mờ
   hơn (không phải một lối đi tiếp, chỉ là số gộp).
   ⚠ SỬA (bo-loc-web-phase3, Việc 5a) - `opacity: .6` cũ làm mờ ĐỀU cả
   khối (nền/viền/chữ), chữ vẫn giữ `color: var(--chu)` bên dưới lớp mờ
   nên NHÌN VẪN GIỐNG một chip bấm được, chỉ nhạt hơn - Bruno báo "trông
   như bấm được". Nay khai riêng CHỮ XÁM (`--chu-mo`, token phụ có sẵn,
   dùng khắp trang cho chữ không nhấn) + viền cũng hạ xuống `--vien`
   (không còn `--vien-sang` mặc định của `.chip`) - không còn opacity
   nên không còn gì "gợi ý còn bấm được nếu nhìn kỹ". `:hover` khai
   THẲNG để chốt "không đổi màu khi rê chuột" không phụ thuộc việc
   `.chip:hover` có được thêm ở nơi khác sau này hay không. */
.chip.chip--vet,
.chip.chip--vet:hover {
  border-style: dashed; border-color: var(--vien);
  background: var(--tam); color: var(--chu-mo);
  cursor: pointer;   /* p9: bấm để bung các hãng bị gom */
}
.chip.chip--vet[aria-expanded="true"] { color: var(--chu); }

/* ---- tầng 3: lưới video - mật độ TỰ NHIÊN theo bề ngang, NGANG chiếm trọn hàng ---- */
/* `dense` (24/08): video ngang chiếm trọn hàng (`grid-column: 1/-1`),
   nên khi nó rơi vào ô lẻ thì Grid mặc định để TRỐNG ô bên cạnh rồi
   mới xuống hàng - giữa trang thủng một lỗ. `dense` cho Grid quay lại
   nhét thẻ dọc sau đó vào chỗ trống ấy.
   Đánh đổi có ý thức: thứ tự hiển thị xê dịch cục bộ (một thẻ mới hơn
   có thể tụt lên trước thẻ cũ hơn vài ô). Chấp nhận được vì lưới này
   sắp theo ngày ở mức "mới trước" chứ không phải một dãy số cần đọc
   đúng thứ tự, còn lỗ giữa trang thì ai cũng thấy. */
/* MẬT ĐỘ v2 (04/09, mockup Bruno duyệt 03/09) - THAY ép cứng 2 cột
   MỌI khổ màn (bệnh Bruno chỉ ra: desktop chỉ 2 thẻ/hàng, thẻ phóng to
   vô lý). `auto-fill` + `minmax(168px,1fr)` tự co số cột theo bề ngang
   thật - ra ~6-7 thẻ/hàng ở desktop 1440px, không phải một số cứng.
   ⚠ Mốc 640px KHÔNG thuộc thang 599/600/1439/1440 sẵn có của bốn mốc
   trang này (xem cuối tệp) - Bruno chỉ định con số này RIÊNG cho lưới
   danh sách để ép CỨNG 3 cột thay vì để `auto-fill` tự quyết (tự quyết
   ở khổ hẹp có thể ra 2 hay 4 cột tuỳ vài px lệch, ép cứng giữ ổn
   định). Số 640 đã có sẵn trong `_NGOAI_LE` của bánh cóc breakpoint
   (khai cho `admin_xuong_video.css`, lý do khác) - dùng lại đúng số đó
   cho một lý do MỚI, đã cập nhật chú thích tại đó thay vì thêm ngoại
   lệ trùng. */
/* bo-loc-web-phase2, Việc 6 - `#ds-video` nay có thể bị ẨN (trang MẪU
   dùng `#ds-mau-video` thay), và lớp `display: grid` bên dưới THẮNG
   luật `[hidden]` mặc định của trình duyệt (bẫy đã ghi nhiều lần trong
   CLAUDE.md) - phải tự khai lại. */
.luoi-video[hidden] { display: none; }
.luoi-video {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  grid-auto-flow: dense;
  gap: 16px 14px;
  padding: 12px 16px;
}
@media (max-width: 640px) {
  .luoi-video { grid-template-columns: repeat(3, 1fr); gap: 12px 9px; }
}
.the-video {
  background: var(--tam); box-shadow: var(--bong-the); border: 1px solid var(--vien); border-radius: var(--bk); overflow: hidden;
  display: flex; flex-direction: column;
  /* Mốc cho nút ghim đặt tuyệt đối - nút là ANH EM của `.the-video-hit`
     (không lồng <button> trong <button>) nên phải neo vào thẻ ngoài. */
  position: relative;
}
/* v3 (04/09, LÔ ĐỒNG CAO): `span 2`/`.rong` ĐÃ BỎ HẲN. Thẻ ngang span 2
   cột từng "sửa" lỗi tràn màn (v2) nhưng đẻ ra lỗi MỚI nặng hơn: khung
   16:9 trong ô 2-cột THẤP HƠN NHIỀU khung 9:16 của thẻ dọc 1-cột kế
   bên (2W×9/16 = 1.125W so với W×16/9 = 1.78W - ngang chỉ cao ~63% thẻ
   dọc), nên tiêu đề mỗi thẻ một độ cao và đáy thẻ ngang chừa khoảng
   trống lớn - đúng ảnh Bruno gửi. Nay MỌI thẻ (ngang lẫn dọc) dùng
   CHUNG một khung 9:16, đúng 1 cột - `.the-video .hinh` không còn tách
   `aspect-ratio` theo `.doc`/`.ngang` nữa, cả hai đều 9:16. */
.the-video-hit {
  display: block; width: 100%; text-align: left;
  background: none; border: none; padding: 0; margin: 0; color: inherit; font: inherit; cursor: pointer;
}
.the-video .hinh {
  position: relative; width: 100%; aspect-ratio: 9 / 16;
  background: var(--ta-khung); overflow: hidden;
  /* Viền + transition (06/09, Việc 1 hợp nhất hover) - trước đây
     KHÔNG có, nên "viền chuyển ô-liu lúc hover" không có gì để
     chuyển. Đúng khuôn `.the-nho .hinh` (chuẩn tham chiếu). */
  border: 1px solid var(--vien); transition: border-color .16s;
}
.the-video .hinh img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ===== THẺ NGANG - BẢN V4 (04/09) =================================
   ⚠ HAI LÔ TRƯỚC SAI HƯỚNG, ghi lại để không quay lại: chúng nhét ảnh
   16:9 vào khung DỌC 9/16 rồi lấp chỗ trống bằng chính ảnh đó phóng to
   + làm mờ. Kết quả: ảnh thật co thành một dải nhỏ kẹp giữa hai mảng
   mờ - mà video ngang lại đúng là các bài REVIEW DÀI, thứ khách cần
   nhìn rõ nhất. Bruno duyệt mockup v4: thẻ ngang RỘNG RA thay vì ảnh
   co lại.

   `span 3`: ba cột + hai khe hở = 3W + 2*14px. Muốn ảnh 16:9 CAO BẰNG
   ảnh dọc (W*16/9) thì cần (3W+28)*9/16 = W*16/9 -> W = 175px, tức
   3 cột + 2 khe = 3,16W. Đo thật ở 1440px: cột ra 189,1px nên hai bên
   lệch ~1,3px - trong dung sai 2px của bài canh. Không ép cứng chiều
   cao bằng px vì số cột đổi theo bề ngang màn; để hình học tự khớp.

   Ảnh nguồn VỐN 16:9 nên `cover` ở đây phủ kín mà KHÔNG cắt gì -
   khác hẳn `cover` trong khung 9/16 của bản cũ (cắt mất hai bên). */
.the-video--ngang { grid-column: span 3; }
.the-video--ngang .hinh { aspect-ratio: 16 / 9; }
/* ≤640px lưới ép cứng 3 cột, nên thẻ ngang chiếm TRỌN hàng - một video
   một hàng, đúng đề bài. `1 / -1` chứ không `span 3`: ở 3 cột thì hai
   cách trùng nhau, nhưng `1 / -1` giữ đúng ý "trọn bề ngang" nếu số
   cột mốc này đổi về sau. */
@media (max-width: 640px) {
  .the-video--ngang { grid-column: 1 / -1; }
}

/* ⚠ KHỐI CSS "TRANG DÒNG - LƯỚI XEN KẼ DÀI/SHORT" (11/09, mockup #7)
   ĐÃ GỠ (SỬA bo-loc-web-phase3, "hai lưới ngang/dọc là luật chung") -
   `.xk-khoi`/`.xk-luoi`/`.xk-luoi--dai`/`.xk-luoi--short` không còn
   phần tử nào mang lớp này (JS tương ứng đã gỡ, xem
   `admin_web/static/video_public.js`). Lưới ngang/dọc nay dùng
   `.lq-luoi--ngang`/`.lq-luoi--doc` (mục "5. VIDEO LIÊN QUAN, TÁCH HAI
   NHÓM" phía dưới) - cột CỐ ĐỊNH theo CSS thuần, không còn JS tính số
   cột theo bề ngang màn.
   `.the-video--ngang` (khối ngay TRÊN) GIỮ NGUYÊN - "Loạt nhiều phần"
   (trang Tháo lắp & bảo dưỡng, ngoại lệ Bruno chốt KHÔNG tách ngang/
   dọc) vẫn dùng `veTheVideo()`/`.luoi-video` nguyên vẹn, cần đúng luật
   span-3/16:9 này. */

/* HUY HIỆU "REVIEW CHI TIẾT" - thứ DUY NHẤT thêm lên ảnh thẻ ngang. */
.the-video .huy-hieu,
.the-nho .huy-hieu {
  position: absolute; top: 8px; left: 8px; z-index: 1;
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 700; font-size: 11.5px; letter-spacing: .16em;
  text-transform: uppercase; line-height: 1.3;
  background: var(--ta-oliu); color: var(--ta-nen);
  border-radius: 3px; padding: 2px 8px;
}
/* v2 (04/09): 34px -> 36px, viền trắng mờ -> viền ô-liu - khớp bảng
   màu "Thép & Ô-liu" của trang thay vì một viền trắng lạc tông. */
.hinh button.phat, .hinh .phat {
  position: absolute; inset: 0; margin: auto; width: 38px; height: 38px;
  background: var(--khan-toi); border: 1px solid color-mix(in srgb, var(--ta-oliu) 45%, transparent); border-radius: 999px;
  display: flex; align-items: center; justify-content: center;
  transition: background-color .16s, transform .16s;
}
.hinh .phat svg {
  width: 12px; height: 12px; fill: var(--ta-chu); margin-left: 4px;
  transition: fill .16s;
}
/* Thẻ ngang là bài REVIEW DÀI - nút play to hơn để "xem được ngay" rõ
   hơn hẳn so với clip dọc lướt nhanh. */
.the-video--ngang .hinh .phat,
.the-nho--ngang .hinh .phat { width: 52px; height: 52px; }
.the-video--ngang .hinh .phat svg,
.the-nho--ngang .hinh .phat svg { width: 16px; height: 16px; }
.hinh .dai {
  position: absolute; right: 4px; bottom: 4px;
  max-width: calc(40% - 5px);
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  background: var(--nhan-nen); border-radius: var(--bk);
  font-size: var(--f-nhan-goc); padding: 2px 5px; font-variant-numeric: tabular-nums; color: var(--ta-chu);
}

/* Việc 4 (bo-loc-web-phase3) - nhãn NGÀY ĐĂNG, góc dưới-trái - trang
   THÔNG BÁO, THAY CHỖ `.hinh .xem` (không đứng cùng lúc, xem
   `veTheVideo`/`tuyChon.ngayGoc`). Khung viền + chữ Ô-LIU (khác
   `.hinh .xem`/`.hinh .dai` nền/chữ trung tính) - trang này ưu tiên
   "khi nào" hơn "bao nhiêu lượt xem". */
.hinh .ngay-goc {
  position: absolute; left: 4px; bottom: 4px;
  background: var(--nhan-nen); border: 1px solid var(--vien-oliu);
  border-radius: var(--bk); font-size: var(--f-nhan-goc); padding: 2px 5px;
  color: var(--ta-oliu-ro); font-variant-numeric: tabular-nums;
}
/* Cũ hơn 3 tháng: cả KHUNG chuyển xám, không chỉ chữ - đọc được ngay cả
   lúc lướt nhanh không kịp đọc số.
   ⚠ Từ 16/09 đây là TÍN HIỆU DUY NHẤT cho video cũ - lớp mờ cả thẻ
   (`.the-video--cu`) đã bỏ, xem chú thích ở `veTheLQ`. */
.hinh .ngay-goc--cu { border-color: var(--ta-vien); color: var(--ta-chu-mo); }
/* (d) 16/09, Việc 6 - LƯỚI AN TOÀN chống đè nhãn thời lượng. `.hinh .xem`
   (nhãn mà `.ngay-goc` thay chỗ) vốn đã mang `max-width: calc(60% - 5px)`
   từ lâu, `.ngay-goc` thì QUÊN - nên ở thẻ dọc 119px nó rộng 95px và đè
   lên `.dai` 22px, đo thật trên production. Cơ chế CHÍNH vẫn là rút gọn
   chữ ("21/11/25", xem `dinhDangNgayGon`); dòng này chỉ là cái chặn cho
   dữ liệu bất thường, cùng khuôn `.hinh .xem-so`. */
.hinh .ngay-goc {
  max-width: calc(60% - 5px);
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}

/* Việc 3 - "part N" (khu "Loạt nhiều phần", trang THÁO LẮP & BẢO
   DƯỠNG), góc TRÊN-PHẢI - chỗ duy nhất còn trống trên ảnh thẻ (dưới đã
   kín lượt xem/thời lượng, trên-trái là huy hiệu Review/nút sửa nhãn). */
.hinh .phan-n {
  position: absolute; top: 8px; right: 8px; z-index: 1;
  background: var(--ta-oliu); color: var(--ta-nen); border-radius: 3px;
  font-size: var(--f-nhan-goc); font-weight: 700; padding: 2px 7px;
  font-variant-numeric: tabular-nums;
}

/* Việc 2 - trang SALE OFF/LIKE NEW: video ĐÃ BÁN. Ba mảnh đi CÙNG NHAU
   khi `v.da_ban` (xem `veTheVideo`) - tái dùng NGUYÊN `--c-sao-do` đã
   có sẵn trong :root (không đẻ token đỏ thứ hai):
     - `.the-video--daban`         : CẢ THẺ mờ đi một bậc.
     - `.the-video-daban-phu/-chu` : lớp phủ tối + "ĐÃ BÁN" GIỮA ảnh.
     - `.the-video-daban-nhan`     : nhãn đỏ nhỏ NGAY TRÊN tiêu đề. */
.the-video--daban { opacity: .72; }
.the-video-daban-phu {
  position: absolute; inset: 0; z-index: 2;
  background: var(--khan-toi);
  display: flex; align-items: center; justify-content: center;
}
.the-video-daban-chu {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 700; font-size: 15px; letter-spacing: .18em;
  color: var(--ta-chu); border: 1px solid var(--D-sao-do); border-radius: 3px;
  padding: 4px 12px;
}
.the-video-daban-nhan {
  display: inline-block;
  background: var(--D-sao-do); color: var(--ta-nen);
  font-size: 11px; font-weight: 700; letter-spacing: .04em;
  border-radius: 3px; padding: 1px 6px; margin: 0 0 4px;
}

/* Việc 4 - dòng khoảng cách tương đối ("4 ngày trước") dưới dòng hãng,
   trang THÔNG BÁO. Video cũ hơn 3 tháng: CẢ THẺ mờ đi một bậc - cùng
   mức `.the-video--daban` ngay trên, cho nhất quán "trạng thái phụ,
   không phải nội dung chính". */
/* `.the-video--cu { opacity: .72 }` ĐÃ BỎ 16/09 (Việc 6e) - không nơi
   nào còn gắn lớp này. Lý do đo được ghi ở `veTheLQ` trong JS. */
.the-video-khoang-cach {
  font-size: var(--f1); color: var(--chu-mo); margin-top: 2px;
}

.the-video .duoi { padding: 8px 12px 12px; }
/* v2 (04/09): Barlow Condensed thay Inter (font THÂN của body) - bệnh
   Bruno chỉ ra "tiêu đề dùng font thân nên nhạt và chiếm chỗ". Cỡ chữ
   TĂNG (16.5px desktop so với `--f2` cũ .86rem≈13.8px) nhưng Barlow
   Condensed hẹp bề ngang hơn Inter ở cùng cỡ nên vẫn gọn theo chiều
   ngang; `min-height: 2.44em` (đơn vị EM nên tự co theo cỡ chữ, không
   cần khai riêng cho mốc mobile) giữ đáy thẻ thẳng hàng dù tiêu đề một
   dòng hay hai dòng - trước đây không có, tiêu đề ngắn làm card thấp
   hơn card bên cạnh trong cùng hàng dense. */
.the-video .tv {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 500;
  font-size: 19px; line-height: 1.22; letter-spacing: .015em; color: var(--chu);
  /* HIỆN ĐỦ, KHÔNG CẮT (Bruno 21/09) - cùng luật `.lq-ten`. */
  overflow-wrap: anywhere;
  min-height: 2.44em;
}
@media (max-width: 640px) {
  .the-video .tv { font-size: 16.5px; }
}
/* Dòng HÃNG xanh dưới tiêu đề thẻ ĐÃ BỎ (Bruno 21/09 22:49: "nhìn rất
   rối mắt"). ⚠ Tên lớp `the-hang` VẪN SỐNG ở THẺ HÃNG của lưới chọn dòng
   (TTI/Novritsch, JS + bài canh bám vào nó) - khối luật cũ phải có một
   dòng đè `.the-loai-chu.the-hang` để thẻ ấy khỏi bị đẩy xuống 3px; gỡ
   khối luật thì gỡ luôn dòng đè, thẻ hãng về đúng hình học gốc. */
/* Nhãn sản phẩm gạch chấm dưới tiêu đề ĐÃ BỎ 22/09 (Bruno: "Giữ lại
   phần tiêu đề video thôi") - thẻ video chỉ còn ảnh + tiêu đề. */

/* ---- ĐẦU TRANG danh sách, v2 (04/09) ------------------------------
   H1 lớn tách khỏi header dính - khuôn giống `.chi-tiet-noi h1` (cùng
   ý tưởng "tiêu đề lớn nằm trong luồng trang"), nhưng cỡ chữ RIÊNG
   (34px, mockup chỉ định đích danh cho màn danh sách - lớn hơn tiêu đề
   video 21.6px của màn chi tiết). */
.ds-dau-trang { padding: 16px var(--le) 4px; }
.ds-dau-trang h1 {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 700; font-size: 34px; letter-spacing: .06em;
  text-transform: uppercase; line-height: 1.15; color: var(--chu);
}
@media (max-width: 640px) {
  .ds-dau-trang h1 { font-size: 26px; }
}
.ds-dau-trang p { margin-top: 6px; font-size: var(--f1); color: var(--chu-mo); }

/* ---- trạng thái / rỗng / đang tải ---- */
.trang-thai {
  color: var(--chu-mo); text-align: center; padding: 24px var(--le); font-size: var(--f2);
}
.dang-nap { color: var(--chu-mo); text-align: center; padding: 16px 0 28px; font-size: var(--f1); }

/* ---- ĐANG NẠP: tâm ngắm + băng đạn BB (20/09) ----------------------
   Hai dòng "Đang tải…"/"Đang tải thêm…" trước đây là chữ trơn giữa
   một màn đen - Bruno xin một dáng hợp với da Thép & Ô-liu của trang
   và chốt TÂM NGẮM cho màn chờ chính.

   ⚠ HAI DÁNG, mỗi chỗ một việc: màn chờ CHÍNH (chưa có gì trên màn)
   dùng tâm ngắm 44px - đủ lớn để nói "đang làm việc"; lượt cuộn thêm
   thì lưới video đã đầy màn nên chỉ một băng đạn mảnh ở đáy, một tâm
   ngắm nữa ở đó là ồn.

   ⚠ Băng đạn vẽ VIÊN TRÒN, không phải vạch thẳng: đạn airsoft là bi
   BB, mà vạch chữ nhật đọc ra "thanh tiến độ" chứ không ra băng đạn.
   Một dãy `radial-gradient` lặp ngang cho ra đúng hàng bi, vẫn chỉ
   tốn MỘT phần tử + một pseudo.

   ⚠ THUẦN CSS, KHÔNG ảnh, KHÔNG tệp mới: mọi hình dựng bằng gradient
   trên đúng hai token sẵn có (`--vien` cho viên rỗng, `--oliu` cho
   viên đã nạp). Thêm một tệp ảnh ở màn chờ là thêm một lượt tải nữa
   đúng lúc trang đang chờ tải - tự mâu thuẫn với chính việc tối ưu
   tốc độ vừa làm.

   ⚠ Hai CỠ, một dáng: màn chờ CHÍNH (chưa có gì trên màn) dùng bản to
   + chữ xuống dòng; lượt cuộn thêm thì lưới video đã đầy màn nên chỉ
   một băng mảnh, chữ nằm cạnh. */
.nap {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
}

/* GIỮA MÀN, không dính ngay dưới nội dung (Bruno, 20/09). Màn chờ có
   thể đã bày sẵn tiêu đề và khối chọn dòng, nên tâm ngắm nằm trong
   luồng sẽ tụt lên sát nội dung và bỏ trống cả nửa màn dưới.

   ⚠ `:has()` chứ không phải một lớp do JS gắn: khối `.trang-thai` còn
   dùng cho thông báo RỖNG và LỖI ("Không có video nào") - những câu
   ấy phải nằm ngay dưới nội dung như cũ, chỉ ca ĐANG NẠP mới chiếm
   giữa màn. Gắn lớp bằng JS thì phải nhớ gỡ ở mọi đường thoát, quên
   một đường là câu lỗi nhảy ra giữa màn.

   Trình duyệt không có `:has()` (Safari < 15.4) rơi về đúng dáng cũ -
   tâm ngắm vẫn hiện, chỉ không căn giữa. Suy biến êm, không vỡ gì. */
.trang-thai:has(.nap-ngam) {
  position: fixed; inset: 0;
  display: flex; align-items: center; justify-content: center;
  /* Không chặn cú chạm: phần trên vẫn là header và khối chọn dòng
     THẬT, người dùng phải bấm được chúng trong lúc chờ. */
  pointer-events: none;
}

/* MỘT chỉ báo một lúc (Bruno, 20/09: "cần 1 cái này thôi chứ").

   Lúc đang chờ lần đầu, mốc cuộn-vô-tận nằm ngay trong tầm nhìn (lưới
   còn rỗng) nên nó bật luôn chỉ báo "đang nạp thêm" - màn chờ hoá ra
   bày HAI chỉ báo chồng nhau. Có từ trước lô này, thấy rõ trong chính
   ảnh màn hình Bruno gửi lúc mở lô.

   ⚠ Ẩn bằng CSS chứ không sửa 5 chỗ bật `#ds-dang-nap` trong JS: nó
   được bật từ năm đường nạp khác nhau, vá từng đường là chắc chắn sót
   một, mà sót thì hỏng CÂM (chỉ thừa một dòng chữ, không lỗi nào kêu).
   Luật ở đây là một điều kiện HIỂN THỊ - thuộc về CSS.

   ⚠ Chỉ ẩn khi màn chờ CHÍNH đang hiện. Lượt cuộn thêm THẬT (lưới đã
   đầy, tâm ngắm đã tắt) vẫn phải có báo, không thì khách cuộn tới đáy
   không biết máy còn đang nạp hay đã hết video. */
#ds-trang-thai:has(.nap-ngam) ~ #ds-dang-nap { display: none; }

/* ⚠⚠ ẨN THÌ PHẢI ẨN THẬT (lỗi production 20/09, Bruno báo: "dữ liệu
   đã load lên hết rồi mà nó vẫn chạy").

   `show()` bên JS tắt khối bằng thuộc tính `hidden`, mà `display` đặt
   bởi một LỚP THẮNG luật `[hidden]` mặc định của trình duyệt - nên từ
   lúc khối này có `display: flex` ở trên, `show(bao, false)` không còn
   ẩn được nó: trang chủ tải xong mà tâm ngắm vẫn quay giữa màn.

   Bẫy này đã ghi sẵn SÁU lần trong chính tệp này (`.dong-xemthem`,
   `.dong-strip`, `.dong-strip-tomtat`, `.dong-strip-chiphang`,
   `#ds-dong-strip-than`, `.dong-strip-hangnb`) và một lần nữa trong
   chú thích của `show()` bên `video_public.js` - vẫn dính. Mọi lớp
   MỚI đặt `display` phải kèm dòng `[hidden]` của chính nó, ngay đây,
   không để lần sau ai đó phải tìm lại.

   Đặc hiệu cao hơn hẳn luật `display: flex` ở trên để không phụ thuộc
   thứ tự dòng trong tệp. */
.trang-thai[hidden]:has(.nap-ngam) { display: none; }
.trang-thai[hidden] { display: none; }

/* Tâm ngắm: vòng ngoài xoay, cung ô-liu là phần "quét"; bốn vạch ngắm
   ĐỨNG YÊN (xoay ngược cùng tốc độ) nên mắt đọc được là vòng đang
   quay chứ không phải cả cụm trôi. */
.nap-ngam {
  position: relative; width: 44px; height: 44px;
  border: 2px solid var(--vien);
  border-top-color: var(--oliu);
  border-radius: 50%;
  animation: nap-quay 1.1s linear infinite;
}
.nap-ngam::before {
  content: ""; position: absolute; inset: -7px;
  background:
    linear-gradient(var(--vien-oliu), var(--vien-oliu)) top center/1px 5px no-repeat,
    linear-gradient(var(--vien-oliu), var(--vien-oliu)) bottom center/1px 5px no-repeat,
    linear-gradient(var(--vien-oliu), var(--vien-oliu)) left center/5px 1px no-repeat,
    linear-gradient(var(--vien-oliu), var(--vien-oliu)) right center/5px 1px no-repeat;
  animation: nap-quay 1.1s linear infinite reverse;
}
.nap-ngam::after {
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--oliu);
  animation: nap-tim 1.1s ease-in-out infinite;
}

/* `--o` = bước lặp của một viên; bán kính viên = --o/2 trừ khe hở.
   Đổi cỡ băng chỉ cần đổi `--o` và `width`. */
.nap-bang {
  --o: 14px;
  position: relative;
  width: calc(var(--o) * 8); height: var(--o);
  background:
    radial-gradient(circle at center,
      var(--vien) calc(var(--o) / 2 - 4px),
      transparent calc(var(--o) / 2 - 3.2px)) 0 0 / var(--o) var(--o) repeat-x;
}
/* Lớp viên ĐÃ NẠP: cùng dãy viên, màu ô-liu, lộ dần từ trái sang. */
.nap-bang::after {
  content: ""; position: absolute; inset: 0;
  background:
    radial-gradient(circle at center,
      var(--oliu) calc(var(--o) / 2 - 4px),
      transparent calc(var(--o) / 2 - 3.2px)) 0 0 / var(--o) var(--o) repeat-x;
  clip-path: inset(0 100% 0 0);
  animation: nap-chay 1.6s ease-in-out infinite;
}
/* Băng nhỏ cho lượt cuộn thêm - cùng dáng, chỉ khác bước lặp. */
.dang-nap .nap-bang { --o: 10px; width: calc(var(--o) * 8); }

/* Chữ: cùng lối chữ hoa giãn của tên shop và tiêu đề màn.
   ⚠ Chữ trong DOM viết THƯỜNG - chữ hoa là `text-transform`. Bài canh
   so text phải so bản thường (bài học đã ghi cho nút lọc "Xem N video"). */
.nap-chu {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 600; text-transform: uppercase; letter-spacing: .14em;
  font-size: var(--f1); color: var(--chu-mo);
}
/* Hàng ngang thì `text-align: center` của khối cha KHÔNG căn được nữa
   (flex item không nghe align văn bản) - phải nói thẳng. */
.dang-nap .nap { flex-direction: row; justify-content: center; gap: 8px; }

@keyframes nap-quay { to { transform: rotate(360deg); } }
@keyframes nap-tim { 0%, 100% { opacity: .3; } 50% { opacity: 1; } }
@keyframes nap-chay {
  0%   { clip-path: inset(0 100% 0 0); }
  55%  { clip-path: inset(0 0 0 0); }
  100% { clip-path: inset(0 0 0 100%); }
}
}
.moc-nap { height: 1px; }

/* ---- MÀN 3 - CHI TIẾT ---- */
/* V4 (26/08): KHUNG PLAYER THEO ĐÚNG CHIỀU VIDEO.
   Đo thật trên sổ máy chủ: 2718/2718 dòng đều có cờ hướng, KHÔNG dòng
   nào thiếu - nên nhánh mặc định gần như không bao giờ chạy, nhưng vẫn
   giữ (video mới quét về mang `huong=''` cho tới khi nhịp nền hỏi xong).

   ⚠ Khung DỌC trước đây là `9/14` - KHÔNG phải tỉ lệ thật của Shorts
   (9/16). Lệch tỉ lệ thì trình phát YouTube tự chèn hai vệt đen hai
   BÊN để giữ khung hình, đúng cái đang muốn bỏ. Nay 9/16 khớp nguồn,
   căn giữa, cao tối đa 85vh (62vh cũ phí gần một phần tư màn dọc).

   `--cao-phat-doc` để một chỗ: đổi ý chỉ sửa một dòng. */
.man-phat { background: var(--phat-nen); }
.man-phat .khung {
  aspect-ratio: 9 / 16;
  max-height: var(--cao-phat-doc);
  /* ⚠ KHÔNG khai `width` ở đây - `auto` vốn là giá trị mặc định của
     một khối, và trình duyệt tự co bề ngang theo `aspect-ratio` khi
     `max-height` cắt chiều cao. Đã thử khai hẳn ra kèm một chú thích
     giải thích "phần quan trọng": sabotage bỏ dòng ấy đi thì đo vẫn ra
     đúng 287x510, tức nó chưa từng làm gì. */
  margin: 0 auto;
  position: relative;
  background: var(--phat-nen);
}
/* Video NGANG: 16:9 FULL bề ngang, không bó chiều cao. */
.man-phat .khung.ngang {
  aspect-ratio: 16 / 9;
  width: 100%;
  max-height: none;
}
.khung iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.khung .phat-lon {
  position: absolute; inset: 0; margin: auto; width: 58px; height: 58px;
  background: var(--khan-toi); border: 1px solid var(--ta-vien-sang); border-radius: 999px;
  display: flex; align-items: center; justify-content: center;
}
.khung .phat-lon svg { width: 20px; height: 20px; fill: var(--ta-chu); margin-left: 4px; }

/* ===== MOCKUP V8 (04/09): TRANG CHI TIẾT MỘT CỘT =====================
   THAY HẲN khối "BỐ CỤC 2 CỘT >=861px" + "DANH SÁCH LIÊN QUAN XẾP DỌC"
   dựng sáng cùng ngày (aa863e9 + fd68a03). Không còn `.ct-grid`,
   `.ct-col-trai/phai`, không còn `position: sticky` trên player.

   ⚠ Lý do đổi nằm ở phía Bruno (duyệt mockup V8), không phải vì bố cục
   cũ đo sai - mọi số của nó vẫn xanh lúc gỡ. Ghi ra để phiên sau đừng
   đi tìm "lỗi" của bản 50/50 rồi khôi phục nhầm. */
/* ⚠ `margin-top` TÁCH CLIP KHỎI THANH ĐƯỜNG DẪN (Bruno chốt 19/09:
   "clip chi tiết phải cách 1 khoảng với thanh điều hướng bên trên").
   Trước đó `margin: 0 auto` nên khung phát dính ngay dưới viền dưới
   của `.crumb` - hai khối khác hẳn vai trò mà đọc lên như một mảng
   liền. Đặt ở `.ct-cot` chứ KHÔNG ở `.crumb`: `.crumb` dùng chung với
   màn danh sách (`#ds-crumb`), thêm đệm ở đó là đổi luôn một màn Bruno
   không phàn nàn. */
.ct-cot {
  max-width: 1120px;
  margin: 20px auto 0;
  padding: 0 24px;
}
@media (max-width: 640px) {
  .ct-cot { padding: 0 14px; margin-top: 12px; }
}
/* Con trong cột đã ăn đệm của chính `.ct-cot` - đừng thụt hai lần.
   Các lớp này vốn tự mang `var(--le)` cho bố cục một-cột toàn màn cũ. */
.ct-cot .chi-tiet-noi,
.ct-cot .nut-tv-chinh,
.ct-cot .bt-moi,
.ct-cot .ct-bread { padding-left: 0; padding-right: 0; }
/* ⚠ `.tam-ts` mang `margin: 16px var(--le) 0` từ bố cục một-cột-toàn-màn
   cũ - trong `.ct-cot` nó CỘNG THÊM vào đệm của cột, đẩy biển thông số
   thụt sâu hơn mọi khối khác (đo thật: 26 so với 14). Bài canh bắt được
   vì so mép trái với `h1`, không so các dòng trong biển với nhau. */
.ct-cot .nut-tv-chinh,
.ct-cot .tam-ts,
.ct-cot .the-sp { margin-left: 0; margin-right: 0; }

/* ---- 1. PLAYER ----------------------------------------------------
   Ngang: 16/9 trọn bề ngang cột. Dọc: 9/16, căn giữa, chặn trần chiều
   cao để LUÔN nằm trọn một khung nhìn.
   ⚠ `width: auto` + `max-width`, KHÔNG khai `width` cứng: `aspect-ratio`
   chỉ giữ được hình dạng khi MỘT chiều tự do - khai cứng bề ngang rồi
   để `max-height` cắt chiều cao là làm vỡ tỉ lệ. Đã trả giá đúng lỗi
   này một lần trong ngày (tỉ lệ ra 0,758 thay vì 0,563). */
/* ⚠ NỀN TỐI CHỈ ĐEO QUANH CHÍNH KHUNG PHÁT, không trải hết cột.
   Lỗi TỰ SOI ẢNH bắt được: `.man-phat` mang `background` và trải trọn
   1120px, nên với video DỌC (khung chỉ 399px) nó thành hai mảng tối
   rộng ~360px mỗi bên - đọc như video bị letterbox, trong khi khung
   thật vẫn đúng 9:16. Ở bố cục 50/50 cũ cột chỉ 645px nên hai mảng ấy
   hẹp, không ai để ý; V8 nới cột lên 1120px mới lộ.
   `.khung` vốn đã tự mang `background: var(--phat-nen)` nên vùng chờ
   tải của trình phát KHÔNG mất gì. */
.ct-cot .man-phat { background: none; }
.ct-cot .man-phat .khung { width: 100%; max-height: none; margin: 0 auto; }
.ct-cot .man-phat .khung.doc {
  max-height: calc(100vh - 190px);
  max-width: 100%; width: auto;
}
@media (max-width: 860px) {
  .ct-cot .man-phat .khung.doc {
    max-height: 68vh; max-width: min(100%, 52vh); width: auto;
  }
}

/* ---- 2. TIÊU ĐỀ ---------------------------------------------------- */
.ct-cot .chi-tiet-noi h1 {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 600;
  font-size: 32px; line-height: 1.13; letter-spacing: .02em;
}
@media (max-width: 640px) {
  .ct-cot .chi-tiet-noi h1 { font-size: 24px; }
}

/* ---- 3. HÀNG SẢN PHẨM + NÚT TƯ VẤN --------------------------------
   HAI Ô LUÔN CÙNG MỘT HÀNG (chỉ xếp dọc <=640px). `align-items:
   stretch` (mặc định) để hai ô CAO BẰNG NHAU - `start` là đúng cái làm
   ô thấp hơn tụt lên trên, trông như lệch hàng. */
.ct-hang-sp {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  align-items: stretch;
  margin-top: 16px;
}
.ct-hang-sp[hidden] { display: none; }
/* ⚠ CHƯA GẮN SẢN PHẨM -> MỘT Ô, không phải một ô rỗng bên phải.
   Lỗi TỰ SOI ẢNH production bắt được, số đo không: lưới `1fr 1fr` với
   thẻ SP `display:none` vẫn giữ nguyên hai rãnh, nút tư vấn rơi vào
   rãnh TRÁI và chỉ rộng nửa trang, nửa phải trống hoác - trông như
   thiếu mất một khối. Mọi phép đo cũ vẫn xanh vì chúng chỉ hỏi "nút có
   hiện không" và "hai ô có cùng hàng không" (ca này chỉ còn một ô).
   JS gắn lớp này trong `capNhatHangSp()` - cùng chỗ đã quyết ẩn/hiện
   khối bọc, không đẻ đường thứ hai. */
.ct-hang-sp--mot { grid-template-columns: 1fr; }
@media (max-width: 640px) {
  .ct-hang-sp { grid-template-columns: 1fr; }
}
/* Nút tư vấn trong hàng: trải HẾT ô, căn giữa dọc. Bỏ mọi lề ngoài mà
   bản một-cột cũ mang theo - `gap` của lưới lo khoảng cách rồi. */
/* Thẻ SP trong hàng: bỏ lề ngoài của bản một-cột cũ, cao HẾT ô để
   bằng nút bên phải. `align-items: flex-start` cho phần chữ bám mép
   trên - ảnh 84px thấp hơn ô khi nút bên kia kéo hàng cao lên, để
   `center` thì chữ trôi xuống giữa một khoảng trống. */
.ct-hang-sp .the-sp {
  margin: 0; height: 100%;
  align-items: flex-start;
  padding: 14px;
}
.ct-hang-sp .nut-tv-chinh {
  margin: 0; height: 100%;
  padding: 18px;
  font-size: 19px; font-weight: 700; letter-spacing: .14em;
}

/* ---- 5. VIDEO LIÊN QUAN, TÁCH HAI NHÓM ---------------------------- */
.lq-khoi { margin-top: 30px; }
/* LỀ HAI BÊN cho lưới DANH SÁCH (22/09, Bruno: "Tiêu đề video sát mép màn
   hình quá"). Đo production: `#ds-hl-khoi` nằm thẳng dưới `.trang` (không
   đệm) nên ảnh + tiêu đề chạm 0 và chạm mép phải ở 390px LẪN 834px, trong
   khi tiêu đề trang, thanh đường dẫn, dải chip đều cách mép `--le`. Khối
   video liên quan ở màn chi tiết không dính vì nằm trong `#ct-cot` (đã
   đệm) - nên chỉ khai cho đúng khối danh sách, không đụng `.lq-khoi` chung. */
#ds-hl-khoi { padding-inline: var(--le); }
.lq-khoi[hidden] { display: none; }
.lq-dau {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 600; font-size: 22px; text-transform: uppercase;
  letter-spacing: .06em; color: var(--chu);
  display: flex; align-items: baseline; gap: 10px;
  margin: 0 0 4px;
}
/* `.lq-nhom-dau .dem` (bo-loc-web-phase2, Việc 6) - trang MẪU ghi số
   đếm NGAY TRÊN từng nhóm ("N video ngang"/"N video dọc"), khác trang
   CHI TIẾT chỉ ghi một số duy nhất ở `.lq-dau` (khối cha). Cùng kiểu
   dáng, chỉ mở rộng bộ chọn - không đẻ khối CSS thứ hai. */
.lq-dau .dem, .lq-nhom-dau .dem {
  font-family: inherit; font-size: 12.5px; color: var(--chu-mo);
  letter-spacing: normal; text-transform: none;
}
.lq-nhom { margin-top: 18px; }
.lq-nhom[hidden] { display: none; }
.lq-nhom-dau {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 600; font-size: 17px; text-transform: uppercase;
  letter-spacing: .08em; color: var(--chu);
  margin: 0 0 12px; padding-left: 10px;
  border-left: 3px solid var(--oliu-dam);
}
/* ⚠ SỐ THẺ MỖI HÀNG LÀ HẰNG SỐ, KHÔNG `auto-fill`: nhóm "Video ngắn"
   phải đúng 3 thẻ/hàng ở MỌI cỡ màn KỂ CẢ iPhone - `auto-fill` với
   `minmax` sẽ tự tụt về 2 rồi 1 khi màn hẹp, đúng cái đề bài cấm. */
.lq-luoi { display: grid; }
/* SỐ CỘT TỰ TĂNG THEO BỀ NGANG (16/09, lô "trang-khach-cay" Việc 3) -
   Bruno chốt "2560px: 4 thẻ ngang, 6 thẻ dọc; giảm dần theo bề rộng;
   iPhone giữ như hiện tại". Khai bằng HAI BIẾN ở `.lq-luoi`, mỗi mốc
   chỉ đổi hai con số - `grid-template-columns` viết ĐÚNG MỘT LẦN, nên
   không có đường cho hai lưới lệch nhau khi ai đó thêm mốc thứ năm.

   ⚠ VẪN LÀ HẰNG SỐ THEO MỐC, KHÔNG `auto-fill` - lý do cũ không đổi:
   `auto-fill` + `minmax` tự tụt số cột theo nội dung nên nhóm "Video
   ngắn" mất đúng luật "3 thẻ/hàng ở iPhone" mà đề bài cấm bỏ.

   | bề ngang        | ngang | dọc | vì sao                              |
   | <=640px         |   1   |  3  | iPhone - GIỮ NGUYÊN, không đụng     |
   | 641-1023px      |   2   |  3  | iPad dọc/ngang - như trước lô này   |
   | 1024-1439px     |   2   |  4  | laptop: dọc hẹp nên thêm được cột   |
   | 1440-1919px     |   3   |  5  | khung khoá 1760px bắt đầu từ đây    |
   | >=1920px        |   4   |  6  | màn 27" (2560) - đích Bruno chốt    |

   Đo ở 2560px (khung 1760 - lề 40x2 = 1680px nội dung): thẻ ngang
   (1680-3*20)/4 = 405px, thẻ dọc (1680-5*18)/6 = 265px. */
/* ⚠ KHAI GIÁ TRỊ GỐC Ở `:root` TRẦN, rồi mới để các mốc ghi đè - đúng
   luật "đừng để một giá trị chỉ tồn tại bên trong @media" đã ghi trong
   CLAUDE.md cho bảng màu. Bản đầu chỉ khai trong bốn khối `@media`, nên
   dải 641-1023px (iPad) KHÔNG có khai nào và JS phải rơi về con số dự
   phòng của chính nó - hai bảng mốc nằm ở hai nơi, đúng thứ lô này định
   tránh. Bài canh đọc biến ở 768px ra `NaN` và bắt được. */
:root { --cot-ngang: 2; --cot-doc: 3; }
.lq-luoi--ngang {
  grid-template-columns: repeat(var(--cot-ngang, 2), 1fr);
  gap: 22px 20px;
}
.lq-luoi--doc {
  grid-template-columns: repeat(var(--cot-doc, 3), 1fr);
  gap: 22px 18px;
}
@media (max-width: 640px) {
  :root { --cot-ngang: 1; --cot-doc: 3; }
  .lq-luoi--doc { gap: 14px 9px; }
}
@media (min-width: 1024px) {
  :root { --cot-ngang: 2; --cot-doc: 4; }
}
@media (min-width: 1440px) {
  :root { --cot-ngang: 3; --cot-doc: 5; }
}
@media (min-width: 1920px) {
  :root { --cot-ngang: 4; --cot-doc: 6; }
}

.lq-the {
  display: block; width: 100%; min-width: 0;
  /* Mốc cho `.the-sua`/`.ghim` đặt tuyệt đối (12/09) - xem chú thích
     đầy đủ ở `.the-nho`. */
  position: relative;
}
.lq-the-hit {
  display: block; width: 100%; min-width: 0;
  background: none; border: none; padding: 0; margin: 0;
  color: inherit; font: inherit; text-align: left; cursor: pointer;
}
.lq-hinh {
  position: relative; width: 100%;
  border-radius: var(--bk); overflow: hidden;
  background: var(--ta-khung);
  /* Viền + transition (06/09, Việc 1 hợp nhất hover) - xem chú thích
     đầy đủ ở `.the-video .hinh`. */
  border: 1px solid var(--vien); transition: border-color .16s;
}
/* Ảnh giữ ĐÚNG TỈ LỆ THẬT của từng nhóm - không cắt, không mảng mờ. */
.lq-the--ngang .lq-hinh { aspect-ratio: 16 / 9; }
.lq-the--doc .lq-hinh { aspect-ratio: 9 / 16; }
.lq-hinh img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* (b) 16/09, Việc 6 - ẢNH KHÔNG ĐÚNG TỈ LỆ KHUNG (đo thật: 1/3 số ảnh ở
   lưới dọc trang Thông báo). `cover` cắt mất một mảng lớn, nên khi lệch
   quá 12% thì đổi sang `contain` (thấy TRỌN ảnh) và lấp phần khung còn
   lại bằng CHÍNH ảnh ấy phóng to + làm mờ, thay vì hai mảng đen.
   JS gắn lớp + đặt `--anh-nen` sau khi ảnh tải xong (`canhAnhVoiKhung`)
   - không có JS/ảnh chưa tải thì thẻ giữ nguyên `cover` như cũ. */
.lq-hinh--lech img { object-fit: contain; position: relative; z-index: 1; }
.lq-hinh--lech::before {
  content: ""; position: absolute; inset: 0;
  /* `none` là dự phòng CÓ NGHĨA, không phải chiều lòng bánh cóc:
     `--anh-nen` do JS đặt SAU khi ảnh tải xong, nên giữa lúc lớp
     `--lech` đã gắn mà biến chưa có thì nền phải là KHÔNG VẼ GÌ chứ
     không phải giá trị rác. Bánh cóc `test_khong_co_token_chet` đòi
     đúng điều này: token dùng mà không khai ở đâu thì phải nói rõ nó
     là một cái núm bằng `var(--x, ...)`. */
  background-image: var(--anh-nen, none); background-size: cover;
  background-position: center;
  filter: blur(18px) brightness(.55); transform: scale(1.15);
}
/* (a) 16/09, Việc 6 - thẻ trang Thông báo từng bỏ riêng dòng hãng + nhãn
   sản phẩm; từ 21-22/09 MỌI thẻ đã bỏ cả hai nên luật riêng ấy không còn. */
/* (c) Trang THÔNG BÁO không bày nhãn nhóm - xem chú thích ở JS. */
.lq-khoi--khong-nhan .lq-nhom-dau { display: none; }
/* Nút play nhóm dọc nhỏ hơn - thẻ dọc hẹp hơn hẳn, giữ chung một cỡ
   thì nó chiếm gần trọn bề ngang ảnh. */
.lq-the--doc .lq-hinh .phat { width: 34px; height: 34px; }
.lq-the--doc .lq-hinh .phat svg { width: 13px; height: 13px; }

.lq-ten {
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 500; line-height: 1.2; letter-spacing: .015em;
  color: var(--chu); margin-top: 8px;
  /* HIỆN ĐỦ, KHÔNG CẮT (Bruno 21/09 22:49: "hiện đầy đủ tiêu đề video").
     Bản trước khoá 2 dòng + ba chấm. `min-height` giữ lại làm SÀN: tựa
     ngắn vẫn chiếm 2 dòng; tựa dài thì thẻ cao ra - lưới grid tự kéo các
     ô cùng hàng bằng nhau nên đáy thẻ vẫn thẳng. */
  overflow-wrap: anywhere;
  min-height: 2.4em;
}
.lq-the--ngang .lq-ten { font-size: 19px; }
.lq-the--doc .lq-ten { font-size: 16.5px; }
@media (max-width: 640px) {
  .lq-the--doc .lq-ten { font-size: 13.5px; }
}
/* SỬA bo-loc-web-phase3 ("hai lưới là luật chung") - `.lq-the` nay vẽ
   MỌI lưới danh sách, kể cả sát mép màn hẹp (trang Loại/Dòng ở 390px).
   `.ghim`/`.the-sua` mặc định neo `top:6px;right:6px`/`top:6px;left:6px`
   (bung vùng chạm 44px bằng `::before` quanh ô vẽ 28px - xem chú thích
   gốc ở `.ghim`), nên vùng chạm tràn RA NGOÀI mép thẻ đúng
   `(44-28)/2 - 6 = 2px` mỗi bên - đo thật ở
   `TestManDanhSach::test_o_390px_khong_tran`
   (`documentElement.scrollWidth` > `innerWidth` ở `?loai=pistol`).
   `.the-video` đã né đúng lỗi này từ trước (`top/left/right: 10px`,
   dư đúng `10-8=2px`) - áp lại NGUYÊN offset đó cho `.lq-the`, không
   bịa số mới. */
.lq-the .ghim { top: 10px; right: 10px; }
.lq-the .the-sua { top: 10px; left: 10px; }


/* ===== THANH ĐƯỜNG DẪN (11/09, #10 Việc 1) ==========================
   Thay HẲN `#ct-bread` (breadcrumb cột phải, chỉ ≥861px) + `#ct-quay`/
   `#ds-quay` (nút "Quay lại" kiểu history.back) - một thanh DUY NHẤT,
   dưới topbar, MỌI trang trừ trang chủ. Mockup #10 Bruno duyệt: nền
   riêng, mỗi cấp một nút bo tròn viền, cấp hiện tại đặc nền ô-liu. */
.crumb {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px var(--le); background: var(--tam);
  border-top: 1px solid var(--vien); border-bottom: 1px solid var(--vien);
}
.crumb .seg {
  display: inline-flex; align-items: center; gap: 7px;
  border: 1.5px solid var(--oliu-dam); color: var(--chu);
  border-radius: 20px; padding: 6px 14px;
  font-size: var(--f3); font-weight: 600; text-decoration: none;
  transition: border-color .15s, color .15s, background-color .15s;
}
.crumb .seg svg { width: 15px; height: 15px; flex: none; }
@media (hover: hover) and (pointer: fine) {
  .crumb .seg:hover { border-color: var(--oliu-chu); color: var(--oliu-chu); background: var(--oliu-nen); }
}
.crumb .cur {
  display: inline-flex; align-items: center;
  background: var(--oliu); color: var(--chu-tren-oliu);
  border-radius: 20px; padding: 6px 14px;
  font-size: var(--f3); font-weight: 700;
}
.crumb .sep { color: var(--oliu-chu); font-size: 18px; line-height: 1; }
/* Điện thoại: CHỈ một nút viền ô-liu "‹ <cấp trên liền kề>" (mục 3
   nhiệm vụ) - ẩn chuỗi đầy đủ, hiện đúng một `.seg` đã đánh dấu
   `.crumb-mob`. `display:contents` để `.full` không tự thành một hộp
   flex lồng bên trong `.crumb` (vốn đã là flex row). */
.crumb .full { display: contents; }
.crumb .mob { display: none; }
@media (max-width: 599px) {
  .crumb .full { display: none; }
  .crumb .mob { display: inline-flex; }
  .crumb .mob .seg { border-color: var(--oliu-chu); color: var(--oliu-chu); }
}

/* Nháy viền ô-liu ~1,5s trên thẻ video vừa cuộn tới (mục 4 nhiệm vụ) -
   dùng lại đúng khuôn outline+offset, không đổi cỡ/màu chính thẻ (PHẠM
   VI CẤM). */
@keyframes vk-nhay-vien {
  0%, 100% { outline-color: transparent; }
  15%, 65% { outline-color: var(--oliu); }
}
.the-video.vk-flash, .vc.vk-flash, .lq-the.vk-flash {
  outline: 3px solid transparent; outline-offset: 2px;
  animation: vk-nhay-vien 1.5s ease-in-out;
}

/* ================================================================
   CHẾ ĐỘ QUẢN TRỊ (#8, 11/09) - công tắc riêng thiết bị, không cấp
   quyền gì (quyền do đăng nhập ql đảm nhận). MỘT lớp DUY NHẤT trên
   <body> (`vk-quan-tri`) quyết định hiện/ẩn CẢ dải báo lẫn mọi nút bút
   chì đã có sẵn trong DOM - bấm "Tắt" chỉ gỡ một lớp, ẩn hết NGAY,
   không cần vẽ lại thẻ nào (khuôn y hệt mockup Bruno duyệt:
   `body.adm .ed{display:flex}`). */
.admbar {
  display: none; align-items: center; gap: 10px;
  background: var(--vk-quan-tri-nen); border-bottom: 1px solid var(--vk-quan-tri-vien);
  color: var(--vk-quan-tri); font-size: 13px; font-weight: 600;
  padding: 7px var(--le);
}
.admbar a { color: var(--vk-quan-tri); margin-left: auto; font-weight: 500; text-decoration: underline; }
body.vk-quan-tri .admbar { display: flex; }

/* Bút chì "Sửa nhãn" trên thẻ video - góc TRÊN-TRÁI ảnh bìa, đối xứng
   với `.ghim` (trên-phải). Ẩn mặc định, CHỈ hiện qua `body.vk-quan-tri`
   - xem chú thích khối trên. */
.the-sua {
  display: none; position: absolute; top: 8px; left: 8px; z-index: 2;
  width: var(--o-ghim); height: var(--o-ghim);
  border: none; border-radius: 50%;
  background: var(--D-quan-tri); color: var(--ta-nen);
  align-items: center; justify-content: center; padding: 0; cursor: pointer;
}
.the-sua::before {
  content: ""; position: absolute;
  top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: var(--cham-ghim); height: var(--cham-ghim);
}
.the-sua svg { width: 14px; height: 14px; }
body.vk-quan-tri .the-sua { display: flex; }
.the-video .the-sua { top: 10px; left: 10px; }
/* Bút chì LUÔN được dựng (xem `veNutSuaNhan`) nên huy hiệu "Review chi
   tiết" luôn phải nhường chỗ - đẩy sang phải để hai thứ không đè nhau.
   ⚠ SỬA 12/09: từng viết `.the-sua ~ .huy-hieu` (yêu cầu CÙNG CHA) -
   sau khi gỡ nested-button, `.the-sua` không còn là sibling của
   `.huy-hieu` (nó lên làm con trực tiếp của thẻ ngoài, còn `.huy-hieu`
   vẫn ở trong `.hinh`) nên đổi sang đúng cặp selector base ở trên. */
.the-video .huy-hieu, .the-nho .huy-hieu { left: 42px; }

/* Nút "Sửa nhãn" cạnh tiêu đề trang chi tiết - khuôn viền-rỗng như
   `.edb` mockup, màu cam thay ô-liu. */
.ct-sua-nhan {
  display: none; align-items: center; gap: 6px; flex: none;
  margin-top: 4px;
  border: 1.5px solid var(--vk-quan-tri); color: var(--vk-quan-tri); background: none;
  border-radius: var(--bk); padding: 6px 11px;
  font-size: 13px; font-weight: 600; white-space: nowrap; cursor: pointer;
}
.ct-sua-nhan svg { width: 15px; height: 15px; flex: none; }
body.vk-quan-tri .ct-sua-nhan { display: inline-flex; }

/* Thông báo "Đã lưu"/"Đã cập nhật" sau khi sửa nhãn - dùng lại đúng
   `#bao-thoang` (`baoThoang()`), chỉ đổi màu viền/chữ khi gọi với
   `kieu: "cam"`. */
.bao-thoang--cam { border-color: var(--vk-quan-tri-vien); color: var(--vk-quan-tri); }

/* ===================================================================
   CHẾ ĐỘ SOÁT - mã sản phẩm trên thẻ video (20/09, mockup Bruno duyệt)
   ===================================================================
   ⚠ KHÁC `body.vk-quan-tri` ở trên: lớp `vk-soat` do MÁY CHỦ quyết
   (gói dữ liệu có khối `soat` hay không), `vk-quan-tri` do thiết bị
   quyết. Hai lớp rời nhau có chủ đích - Bruno tắt bút chì vẫn soát
   được mã, và ngược lại một thiết bị bật `?quantri=bat` mà không có
   phiên ql thì KHÔNG có `vk-soat`, không thấy mã nào.
   ⚠ KHÔNG một hex/rgba MỚI nào trong cả khối này: ba trạng thái dùng
   `--oliu-sang` / `--vk-quan-tri` / `--c-sao-do` đã có sẵn trong bảng,
   sắc mờ suy bằng `color-mix()` - trần hex/rgba của tệp này là bánh
   cóc một chiều (xem `tests/test_chuan_giao_dien_shop.py`). */
.soatbar {
  display: none; align-items: center; gap: 8px; flex-wrap: wrap;
  background: var(--vk-quan-tri-nen);
  border-bottom: 1px solid var(--vk-quan-tri-vien);
  color: var(--vk-quan-tri); font-size: 13px;
  padding: 7px var(--le);
}
body.vk-soat .soatbar { display: flex; }
.soatbar-ct {
  margin-left: auto; display: inline-flex; align-items: center; gap: 4px;
  /* 44px vùng chạm: Bruno bật/tắt bằng ngón cái trên điện thoại. */
  min-height: 44px; cursor: pointer;
}
.soatbar-ct input { width: 18px; height: 18px; accent-color: var(--vk-quan-tri); }

/* Chip mã dưới thẻ. ANH EM của nút bấm chính (không lồng <button>
   trong <button>, bài học 2534bb4) nên nó là con trực tiếp của thẻ
   ngoài - xem `veChipMa` bên JS. */
.the-ma {
  display: none; align-items: center; gap: 4px;
  margin: 0 12px 8px; padding-top: 8px;
  border-top: 1px dashed var(--vien);
}
body.vk-soat .the-ma { display: flex; }
/* Công tắc "hiện mã sản phẩm" - giấu chữ đã tải về để xem đúng thứ
   khách thấy. Một lớp trên <body>, không phải vẽ lại thẻ nào. */
body.vk-soat-an .the-ma { display: none; }
.the-ma-chu {
  flex: 1 1 auto; min-width: 0;
  font-size: var(--f1); line-height: 1.35; color: var(--chu-mo);
  /* ⚠⚠ BỐN dòng, và con số ấy ĐO RA chứ không chọn cho đẹp. Lịch sử
     đáng nhớ vì nó lặp lại ba lần:
       · mockup cắt MỘT dòng -> ở 375px ra "SUGL38 · WE ...", Bruno chỉ
         còn thấy MÃ SỐ, mà mã số không nói được gắn ĐÚNG hay SAI;
       · sửa thành HAI dòng, bài canh chỉ đọc lại con số 2 nên XANH -
         ảnh dựng lại mới lòi ra là vẫn cắt, và ca NHIỀU MÃ ra
         "2 mã · không..." mất đúng ba chữ mang cả nghĩa;
       · gốc thật là BỀ NGANG THẺ, không phải số dòng (xem khối lùi
         lưới xuống 2 cột phía dưới).
     Đo lần cuối 20/09 SAU KHI thêm ô tick chọn nhiều (ô ấy ăn ~26px
     bề ngang chữ), tên mã dài nhất đang có trong sổ ("WE Glock 18C
     gen 3 Metal Slide BK,SV,GD"): 320px cần 5 dòng · 360-390px cần 4 ·
     từ 414px cần 3. Clamp 5 là trần của ca xấu nhất, giữ lại để một
     cái tên quái dị không kéo cao cả hàng lưới.
     ⚠ Thêm/bớt BẤT KỲ nút nào trong chip là đổi bề ngang chữ ⇒ phải
     ĐO LẠI con số này, đừng đoán.
     Bài canh đo TRÀN THẬT (`scrollHeight` so `clientHeight`), không
     đọc lại con số clamp - đọc lại con số là canh chính mình. */
  display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical;
  overflow: hidden; overflow-wrap: anywhere;
}
.the-ma-sku { color: var(--oliu-sang); font-weight: 700; }
/* Ô TICK chọn nhiều clip. Vẽ 18px nhưng vùng chạm bung 44px bằng
   `::before` - cùng lý do đã ghi cho `.the-ma-sua`: thẻ ở màn danh
   sách chỉ ~180px, mỗi nút 44px là một mảng bề ngang lấy mất của TÊN
   MÃ, mà tên mã mới là thứ Bruno cần đọc. */
.the-ma-tick {
  flex: none; position: relative; width: 18px; height: 18px;
  margin: 0 4px 0 0; padding: 0;
  display: grid; place-items: center;
  background: none; color: var(--chu-mo);
  border: 1.5px solid var(--vien); border-radius: 6px;
  cursor: pointer; font-size: 12px; line-height: 1;
}
.the-ma-tick::before {
  content: ""; position: absolute;
  top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 44px; height: 44px;
}
.the-ma-tick[aria-checked="true"] {
  background: var(--oliu); border-color: var(--oliu); color: var(--chu-tren-oliu);
}

/* Thanh nổi ở đáy khi đã tick ít nhất một clip. */
.soat-thanh {
  display: none; position: fixed; z-index: 30;
  left: 50%; transform: translateX(-50%);
  /* ⚠⚠ ĐỨNG TRÊN NÚT CHAT, không cạnh nó. `.vc-nut-mo` là một nút
     tròn 56px `position: fixed; right: 18px; bottom: 18px; z-index:40`
     — nó phủ đúng góc phải-dưới, tức ĐÚNG CHỖ nút "Gán mã" của thanh
     này. Đo thật 20/09: `elementFromPoint` ở tâm nút Gán mã trả về
     `BUTTON.vc-nut-mo`, nên một cú bấm của Bruno mở hộp chat khách
     chứ không gán mã.
     18 + 56 + 12 = 86px là mép trên nút chat cộng một khe. Đừng hạ
     con số này xuống mà không đo lại `.vc-nut-mo`. */
  bottom: calc(86px + env(safe-area-inset-bottom));
  width: min(560px, 100% - 24px);
  align-items: center; gap: 8px;
  padding: 8px 12px;
  background: var(--tam); color: var(--chu);
  border: 1px solid var(--vien-oliu); border-radius: 12px;
  box-shadow: 0 8px 28px var(--bong);
  font-size: var(--f2);
}
body.vk-soat:not(.vk-soat-an) .soat-thanh:not([hidden]) { display: flex; }
.soat-thanh > span { flex: 1 1 auto; min-width: 0; }
.soat-thanh .hop-ma-btn { flex: none; min-height: 40px; padding: 0 12px; }
.the-ma-sua {
  /* ⚠ Nút VẼ nhỏ (24px) nhưng VÙNG CHẠM 44px bung bằng `::before`
     trong suốt - KHÔNG phóng to chính nút. Ở thẻ 118px, một nút 44px
     ăn 37% bề ngang và đẩy tên mã vào đúng chỗ bị cắt; cùng cách đã
     dùng cho `.ghim` (`--cham-ghim`). */
  flex: none; position: relative; width: 24px; height: 24px;
  margin: -4px -4px -4px 0;
  display: grid; place-items: center;
  background: none; border: 0; border-radius: var(--bk);
  color: var(--chu-mo); cursor: pointer;
}
.the-ma-sua::before {
  content: ""; position: absolute;
  top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 44px; height: 44px;
}
.the-ma-sua svg { width: 16px; height: 16px; }
.soatbar-sap { font: inherit; color: inherit; background: transparent; border: 1px solid currentColor; border-radius: var(--bk); padding: 4px; }
.the-ma-sua:hover { background: var(--tam-cao); color: var(--oliu-sang); }
/* NÚT "BÁO SAI MÃ" trên chip (23/09) - DÒNG RIÊNG dưới tên mã (`flex-basis:
   100%` + `flex-wrap` của chip), nên KHÔNG lấy một pixel bề ngang nào của
   tên mã (bài canh "tên mã THẬT không bị cắt"). */
body.vk-soat .the-ma { flex-wrap: wrap; }
.the-ma-sai {
  flex: 1 0 100%; min-height: 36px; margin: 4px 0 0; padding: 0 12px;
  background: color-mix(in srgb, var(--c-sao-do) 10%, transparent); color: var(--c-sao-do);
  border: 1px solid color-mix(in srgb, var(--c-sao-do) 55%, transparent);
  border-radius: var(--bk); font-size: var(--f1); font-weight: 600; cursor: pointer;
}
.the-ma-sai[hidden] { display: none; }
/* BA TRẠNG THÁI phân biệt bằng CHỮ trước, màu chỉ là bậc hai (một
   người phân biệt màu kém vẫn phải đọc ra được). */
.the-ma--trong { border-top-color: var(--vk-quan-tri-vien); }
.the-ma--trong .the-ma-chu { color: var(--vk-quan-tri); }
.the-ma--nhieu { border-top-color: color-mix(in srgb, var(--c-sao-do) 55%, transparent); }
.the-ma--nhieu .the-ma-chu { color: var(--c-sao-do); }
/* ⚠⚠ LƯỚI DỌC LÙI TỪ 3 CỘT XUỐNG 2 KHI ĐANG SOÁT, và đây là một
   QUYẾT ĐỊNH chứ không phải một phép chỉnh cho vừa mắt. Đo thật ở
   390px: 3 cột ⇒ thẻ 124px ⇒ ô chữ của chip chỉ 72px, mà một tên mã
   thật ("Umarex Glock 19 Gen 5 MOS Đen/Tan") cần 5 dòng và ở 320px
   cần 8 - tức chip hoặc bị cắt, hoặc kéo thẻ cao gấp đôi. Cả hai đều
   giết đúng thứ Bruno cần: ĐỌC được tên mã để biết gắn đúng hay sai.
   Hai cột ⇒ ô chữ ~158px ⇒ 2-3 dòng, đọc được.
   ⚠ Bù lại, đây là chỗ DUY NHẤT của cả lô làm màn khác đi so với cái
   khách thấy - nên công tắc "hiện mã sản phẩm" phải trả lại NGUYÊN
   bố cục cũ (`:not(.vk-soat-an)`), và nó có bài canh riêng.
   ⚠ Đè thẳng `grid-template-columns`, KHÔNG đổi token `--cot-doc`:
   JS đọc token ấy từ `:root` để tính số video xin mỗi lượt
   (`moiDocHaiLuoi`) - đổi token là lặng lẽ đổi luôn nhịp tải. */
@media (max-width: 640px) {
  body.vk-soat:not(.vk-soat-an) .lq-luoi--doc {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Viền CẢ THẺ cho hai ca cần mắt dừng lại - chỉ trong chế độ soát.
   ⚠ `outline` chứ KHÔNG phải `border-color`, hai lý do:
     · `.lq-the` (thẻ của màn danh sách, chính là màn Bruno soát)
       KHÔNG có `border` nào - đặt `border-color` lên nó là một luật
       CSS không làm gì cả, và nó không làm gì trong IM LẶNG. Bắt được
       bằng ảnh dựng lại 20/09, đọc mã không thấy;
     · `outline` nằm ngoài luồng bố cục nên bật/tắt chế độ soát không
       xê dịch một pixel nào - `border` 1px thì có. */
body.vk-soat:not(.vk-soat-an) .the-clip--ma-trong {
  outline: 2px solid var(--vk-quan-tri-vien); outline-offset: 2px;
}
body.vk-soat:not(.vk-soat-an) .the-clip--ma-nhieu {
  outline: 2px solid color-mix(in srgb, var(--c-sao-do) 55%, transparent);
  outline-offset: 2px;
}

/* ---- HỘP SỬA MÃ (dialog, trượt lên từ đáy) ---------------------- */
.hop-ma {
  /* ⚠ GIỮA MÀN HÌNH — Bruno chốt 20/09 ("để duyệt tin cho dễ"), ĐỔI so
     với mockup. Bản đầu neo ĐÁY theo mockup (ngón cái với tới trên điện
     thoại), nhưng anh soát trên màn lớn: hộp nằm dưới cùng thì mắt phải
     nhảy từ thẻ đang xem xuống tận mép dưới mỗi lần, và cả lô soát là
     vài trăm lượt nhảy như thế.
     `<dialog>` mặc định đã căn giữa nên chỉ cần trả `margin` về `auto`;
     vẫn ở TOP LAYER nên không dính bệnh "tấm trượt biến mất lúc cuộn"
     của tấm lọc cũ (bỏ 25/08).
     `min()` giữ một khe 12px hai bên ở màn hẹp — căn giữa mà dán sát
     hai mép thì nhìn như tràn chứ không như một hộp. */
  margin: auto; width: min(560px, 100% - 24px);
  max-height: 88vh; overflow: auto;
  background: var(--tam); color: var(--chu);
  border: 1px solid var(--vien);
  border-radius: 16px;
  padding: 16px var(--le) calc(20px + env(safe-area-inset-bottom));
  box-shadow: 0 12px 40px var(--bong);
}
.hop-ma::backdrop { background: var(--khan-toi); }
.hop-ma h2 { font-size: var(--f3); margin: 0 0 4px; color: var(--chu); }
.hop-ma-tua {
  margin: 0 0 12px; font-size: var(--f1); color: var(--chu-mo);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Chip GỢI Ý TÌM — mẫu + từng hãng của clip, mỗi cái một cú chạm.
   ⚠ Chúng là NHÃN ĐÃ GÁN của clip, không phải một phép dò mờ tiêu đề:
   máy chỉ thu hẹp danh sách, người vẫn là người CHỌN mã. */
.hop-ma-goi { display: flex; flex-wrap: wrap; gap: 4px; margin: 0 0 8px; }
.hop-ma-goi:empty { display: none; }
.hop-ma-goi-chip {
  min-height: 36px; padding: 0 12px;
  background: var(--tam-cao); color: var(--chu);
  border: 1px solid var(--vien); border-radius: 999px;
  font-size: var(--f1); cursor: pointer;
}
.hop-ma-goi-chip[aria-pressed="true"] {
  background: var(--oliu-nen); border-color: var(--oliu); color: var(--oliu-sang);
}
.hop-ma-dang { margin-bottom: 12px; }
.hop-ma-dang:empty { display: none; }
.hop-ma-dong {
  display: flex; align-items: center; gap: 8px;
  min-height: 48px; padding: 4px 8px; margin-bottom: 4px;
  background: var(--oliu-nen); border: 1px solid var(--vien-oliu);
  border-radius: var(--bk); font-size: var(--f2);
}
.hop-ma-dong-chu { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
/* Nút "Báo sai mã" từng mã trong hộp (23/09 - thay nút "Gỡ"). Chữ nhỏ
   màu mờ, không viền, không nền — Bruno 23/09 (sau khi xem ảnh năm chỗ có
   nút): "Các nút báo cáo sai mã này để nhỏ lại và ở những vị trí không nổi
   bật. Để tránh việc bấm nhầm". Còn hộp xác nhận trước khi gỡ. */
.hop-ma-sai {
  flex: none; min-height: 32px; padding: 0 4px;
  background: none; color: var(--chu-mo); border: 0;
  font-size: var(--f1); cursor: pointer;
}
.hop-ma-tim {
  width: 100%; min-height: 48px; margin-bottom: 8px; padding: 8px 12px;
  background: var(--nen); color: var(--chu);
  border: 1px solid var(--vien); border-radius: var(--bk);
  /* 16px: dưới mức này Safari iOS TỰ PHÓNG TO cả trang lúc chạm vào ô
     nhập, và không có cách nào lùi lại bằng tay. */
  font-size: 16px;
}
.hop-ma-ds { list-style: none; margin: 0 0 12px; padding: 0; max-height: 40vh; overflow: auto; }
.hop-ma-ds li { margin-bottom: 4px; }
.hop-ma-nut {
  width: 100%; display: flex; align-items: center; gap: 8px;
  min-height: 48px; padding: 8px 12px; text-align: left;
  background: var(--tam-cao); color: var(--chu);
  border: 1px solid var(--vien); border-radius: var(--bk);
  font-size: var(--f2); cursor: pointer;
}
.hop-ma-nut[aria-pressed="true"] {
  background: var(--oliu-nen); border-color: var(--oliu);
}
.hop-ma-nut .sku { color: var(--oliu-sang); font-weight: 700; flex: none; }
.hop-ma-nut .ten { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.hop-ma-nut .gia { color: var(--chu-mo); font-size: var(--f1); flex: none; }
.hop-ma-bao { margin: 0 0 12px; font-size: var(--f1); color: var(--vk-quan-tri); }
/* Tạo mã mới ngay trong hộp. Nút MỞ là chữ trần viền đứt - nó không
   phải hành động chính của hộp (hành động chính là CHỌN một mã đã
   có), nhưng phải thấy được ngay khi danh sách không có gì. */
.hop-ma-tao { margin: 0 0 12px; }
.hop-ma-tao-mo {
  width: 100%; min-height: 44px;
  background: none; color: var(--oliu-sang);
  border: 1px dashed var(--vien-oliu); border-radius: var(--bk);
  font-size: var(--f2); cursor: pointer;
}
.hop-ma-tao-form[hidden] { display: none; }
.hop-ma-tao-form .hop-ma-tim { margin-bottom: 8px; }
/* LUẬT NÚT CẶP (16/09) viết tay - xem lý do ở `video.html`. Grid chứ
   không flex: `2fr 3fr` chia đúng tỉ lệ phần CÒN LẠI sau khi trừ khe,
   và grid không có khái niệm "wrap xuống dòng" nên "luôn cùng hàng ở
   mọi bề ngang" là MẶC ĐỊNH của layout, không phải một @media giữ hộ. */
.hop-ma-ghi-chu { color: var(--chu-mo); font-size: var(--f1); padding: 4px; }
.hop-ma-cap { display: grid; grid-template-columns: 2fr 3fr; gap: 16px; }
/* ⚠⚠ HÀNG NÚT CHỐT GHIM XUỐNG ĐÁY HỘP — Bruno 20/09: *"thông tin đã
   đầy đủ sao không gán mã sản phẩm được?"*, và trong ảnh anh gửi mã
   ĐANG được chọn (ô sáng ô-liu) nhưng nút "Lưu mã này" nằm DƯỚI mép
   màn hình. Hộp cao hơn khung thì nó tự cuộn, mà nút chốt trôi theo
   nội dung nên có lúc không với tới — người dùng đọc ra là "bấm mãi
   không gán được", không phải "phải cuộn xuống".
   `sticky` giữ nó dính đáy vùng cuộn CỦA CHÍNH HỘP, nên dài bao nhiêu
   cũng luôn thấy. Nền đặc + đệm để danh sách cuộn bên dưới không lòi
   ra sau nút. */
.hop-ma-cap--chot {
  position: sticky; bottom: 0; z-index: 1;
  background: var(--tam);
  padding: 8px 0 4px;
  margin-top: -4px;
}
.hop-ma-btn {
  min-height: 48px; border-radius: var(--bk); font-size: var(--f3);
  cursor: pointer; padding: 0 8px;
  border: 1px solid var(--vien); background: none; color: var(--chu);
}
.hop-ma-btn--chinh {
  background: var(--oliu-dam); border-color: var(--oliu-dam);
  color: var(--chu-tren-oliu); font-weight: 700;
}
.hop-ma-btn[disabled] { opacity: .5; cursor: default; }

.chi-tiet-noi { padding: 16px var(--le) 8px; }
/* Hàng tiêu đề + nút "Sửa nhãn" (#8, 11/09) - `h1` co giãn, nút giữ
   nguyên bề ngang (`flex: none`), không rơi xuống dòng riêng trừ khi
   thật sự hết chỗ. */
.ct-tieu-hang {
  display: flex; align-items: flex-start; gap: 10px;
  justify-content: space-between;
}
.chi-tiet-noi h1 {
  /* Commit 4: 23px/600 mobile, 30px/1.12/600 desktop (đề bài chỉ định
     đích danh, thay cho --f5/700 cũ). */
  font-size: 23px; line-height: 1.25; letter-spacing: .02em;
  text-transform: none; font-weight: 600; color: var(--chu);
}
@media (min-width: 861px) {
  .chi-tiet-noi h1 { font-size: 30px; line-height: 1.12; }
}
.hang-meta {
  display: flex; gap: 8px; margin-top: 8px; font-size: 12.5px;
  color: var(--chu-mo); flex-wrap: wrap; align-items: center;
}
/* Loại + hãng "sáng hơn" các trường còn lại của dòng meta (thời
   lượng/ngày/mẫu giữ màu dim mặc định). */
.hang-meta .dam { color: var(--chu); }

/* ---- HAI NÚT sản phẩm (25/08, thay khối .khoi-sp cũ) ----
   Kiểu 1 của mockup: icon trái, chữ MỘT DÒNG. Hai nút NGANG ở mọi bề
   ngang - `grid-template-columns: 1fr 1fr` chứ không flex-wrap, vì
   wrap là đúng cái sẽ lặng lẽ xếp dọc khi chữ dài ra. */
.cap-nut-sp {
  display: grid; grid-template-columns: 1fr 1fr; gap: 9px;
  margin: 12px var(--le) 0;
}
.cap-nut-sp[hidden] { display: none; }
/* Một nút bị ẩn (sản phẩm chưa có đường dẫn) thì nút còn lại chiếm
   trọn hàng, không để một nửa trống lơ lửng. */
.cap-nut-sp:has(> .nut-sp[hidden]) { grid-template-columns: 1fr; }
.nut-sp[hidden] { display: none; }

.nut-sp {
  /* min-width: 0 THẬT SỰ cần ở đây (khác `.ten-loai-phu`): các con của
     grid mang `min-width: auto`, mà nút KHÔNG có `overflow: hidden` ở
     tầng ngoài - thiếu nó thì chữ dài đẩy hai cột phình quá khung. */
  min-width: 0;
  height: 48px; border-radius: 6px;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  font-family: 'Barlow Condensed', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  font-weight: 700; font-size: 11px; text-transform: uppercase;
  letter-spacing: .04em; text-decoration: none; cursor: pointer;
  border: 1px solid transparent;
}
/* Chữ MỘT DÒNG, không xuống dòng, chật thì cắt ba chấm. */
.nut-sp > span {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  min-width: 0;
}
.nut-sp svg { width: 14px; height: 14px; flex: none; }
.nut-sp--chinh { background: var(--oliu); color: var(--chu-tren-oliu); }
.nut-sp--phu {
  background: none; color: var(--oliu-chu); border-color: var(--vien-oliu);
}
.nut-sp:active { filter: brightness(1.12); }
/* Bàn phím phải THẤY được đang ở đâu - `:focus-visible` chứ không
   `:focus`, để chạm tay không bật viền. */
.nut-sp:focus-visible { outline: 2px solid var(--oliu-sang); outline-offset: 2px; }
/* Vùng chạm >= 44px: nút cao 48px đã đủ, nhưng khai rõ để lần sau ai
   hạ chiều cao thì thấy dòng này mà dừng lại. */

/* `.nut-hoi` GỠ BỎ 24/08 - lối liên hệ duy nhất của thân trang nay
   là nút header (#ct-hoi-gia, dùng lớp .nut-fb có sẵn). Video gắn
   nhiều sản phẩm trước đây thành nhiều nút Hỏi giá giống hệt nhau. */

/* ⚠ `.bang-tem` / `.dong-tem` ĐÃ GỠ 26/08 - MÃ CHẾT từ V0+V2.
   Cây phụ nay dùng chính component tấm thông số (`.tam-ts`) của cây
   chính, và hàm `veBangThongSo` dựng ra chúng không còn chỗ gọi nào.
   Lộ ra lúc truy một bài đỏ còn ghim tên lớp cũ.

   ⚠ Cùng lượt ấy lộ thêm một lỗi CÂM: lời mời "chưa có thông số"
   (`#ct-tem-moi`, lớp `.bt-moi`) nằm THẲNG trong thân trang chứ không
   nằm trong `.bang-tem` nào, nên luật cũ `.bang-tem .bt-moi` chưa bao
   giờ áp được lên nó - nó hiện bằng cỡ chữ mặc định của trình duyệt
   suốt từ V2. Nay khai lại ở tầng gốc. */
.bt-moi {
  margin: 12px var(--le) 0;
  padding: 12px; font-size: var(--f2); color: var(--chu-mo); line-height: 1.5;
  background: var(--tam); border: 1px solid var(--vien);
  border-radius: var(--bk);
}
.bt-moi strong { color: var(--oliu-sang); font-weight: 600; }
.bt-moi[hidden] { display: none; }

/* ---- khung chat nổi: phần GỐC nằm ở `khung_chat.css` (dùng chung với
   /timkiem từ 28/09, nạp TRƯỚC tệp này). Ở đây chỉ còn luật RIÊNG của
   trang video. ---- */
/* Commit 5 (04/09): bong bóng chat + khung chat ẩn khi màn TÌM đang
   mở - `position:fixed` của cả hai không hề biết tới `#man-tim`, nên
   trước lô này chúng vẫn nổi đè lên UI tìm kiếm (đã đo thật: dòng
   diễn giải MỚI đẩy ô tìm xuống đủ để chạm vùng bong bóng, lộ ra lỗi
   này vốn đã cận kề từ trước). `#vc-nut-mo` đứng TRƯỚC `#man-tim`
   trong DOM (xem video.html) nên không dùng được `~`/`+` - phải bắc
   qua `body:has()`. */
body:has(#man-tim.hien) #vc-nut-mo,
body:has(#man-tim.hien) #vc-khung { display: none; }

/* ==== THANH BA NÚT ĐÁY + ĐẦU TRANG GỌN (27/09, mockup Bruno duyệt) ======
   Cùng dáng web tìm kiếm /timkiem: ba ô vuông 50px bo 12px - Trang chủ ·
   Tìm · Hỗ trợ (chat bot) - cố định cách đáy 16px, căn giữa, mọi màn. Đầu
   trang chỉ còn tên hiệu + icon nhỏ đổi giao diện; kính lúp, ô tìm, nút
   Facebook "Tư vấn" và nút chat tròn nổi rời đi (thanh đáy thay chúng).
   ⚠ CHỈ ĐIỆN THOẠI + IPAD DỌC (≤1023px, mốc 1024 sẵn có của trang) - Bruno:
   "iPad màn hình ngang và PC thì để như hiện tại". Chỉ dùng token: nút
   thường theo `--tam`/`--tam-cao` nên TỰ đổi sáng/tối (bản sáng ô trắng,
   Bruno chọn A); nút Hỗ trợ giữ ô-liu đậm cố định ở cả hai chế độ. */
.vd-day, .vd-mo-day { display: none; }
@media (max-width: 1023px) {
  .vd-mo-day {
    display: block; position: fixed; left: 0; right: 0; bottom: 0;
    height: calc(104px + env(safe-area-inset-bottom));
    background: linear-gradient(180deg, transparent, var(--nen) 60%);
    pointer-events: none; z-index: 39;
  }
  .vd-day {
    display: flex; position: fixed; left: 0; right: 0;
    bottom: calc(16px + env(safe-area-inset-bottom));
    justify-content: center; gap: 12px;
    z-index: 40; pointer-events: none;
  }
  .vd-nut-day {
    pointer-events: auto; flex: none;
    width: 50px; height: 50px; padding: 0; border-radius: 12px;
    border: 1px solid var(--vien);
    background: linear-gradient(180deg, var(--nut-day-tren), var(--tam-cao));
    box-shadow: 0 8px 20px var(--bong-noi);
    color: var(--chu); cursor: pointer;
    display: flex; align-items: center; justify-content: center;
  }
  .vd-nut-day svg { width: 25px; height: 25px; }
  .vd-nut-day:focus-visible { outline: 2px solid var(--oliu-sang); outline-offset: 2px; }
  .vd-nha { fill: currentColor; }
  .vd-nha-cuoi { stroke: var(--tam-cao); }
  .vd-nut-day--chat {
    border-color: transparent;
    background: linear-gradient(180deg,
      color-mix(in srgb, var(--D-oliu) 72%, var(--phat-nen)),
      color-mix(in srgb, var(--D-oliu) 46%, var(--phat-nen)));
  }
  .vd-bong { fill: var(--S-the); }
  .vd-cham { fill: color-mix(in srgb, var(--D-oliu) 46%, var(--phat-nen)); }

  .trang { padding-bottom: calc(96px + env(safe-area-inset-bottom)); }
  /* Dòng báo thoáng qua (đẩy ghim cũ, lưu mã…) vốn nằm cách đáy 16px - đúng
     chỗ ba nút. Nâng lên trên thanh: 16 + 50 + khe 14 = 80px. */
  .bao-thoang { bottom: calc(80px + env(safe-area-inset-bottom)); }

  .dau .o-tim-desktop, .dau .nut-tim, .dau .nut-fb, .vc-nut-mo { display: none; }
  .dau .dau-nut { margin-left: auto; }
  .dau .nut-gd { background: none; border: 0; color: var(--chu-mo); }
  .dau .nut-gd svg { width: 22px; height: 22px; }
  /* Đầu trang nay chỉ còn tên hiệu + icon giao diện - thu chiều cao (Bruno
     27/09: "chiều cao ngắn lại"): bỏ sàn 70px của trang chủ, đệm dọc 4px.
     Cao = ô chạm 44px của icon + 8px + viền 1px ≈ 53px (cũ ~73px). */
  .dau, #man-chu .dau { min-height: 0; padding-top: 4px; padding-bottom: 4px; }
  /* Tên hiệu to hơn (Bruno 27/09: "làm to thêm") - đầu trang nay chỉ còn nó
     và một icon 44px nên dư chỗ: 15px -> 22px. Khoảng cách chữ giữ luật cũ
     (.12em; <380px .04em để hiện trọn ở 320px). */
  .ten-hieu { font-size: 22px; }
}
/* Màn tìm phủ kín (z-index 50). ĐỔI 10/10 (Bruno: "không có nút home,
   search, chat ở dưới"): thanh ba nút NỔI TRÊN màn tìm, chỉ rời đi lúc ô
   tìm đang được gõ (bàn phím ảo cần chỗ). Cuộn kết quả / bấm Enter là thu
   bàn phím (video_public.js) nên thanh trở lại. Khung chat mở từ nút Hỗ
   trợ cũng phải nổi trên màn tìm. Máy tính/iPad ngang không có thanh này. */
@media (max-width: 1023px) {
  body:has(#man-tim.hien) .vd-mo-day { z-index: 51; }
  body:has(#man-tim.hien) .vd-day { z-index: 52; }
  body:has(#man-tim.hien) #vc-khung:not([hidden]) { display: flex; z-index: 53; }
  #man-tim.hien { padding-bottom: calc(96px + env(safe-area-inset-bottom)); }
}
body:has(#tim-nhap:focus) .vd-day,
body:has(#tim-nhap:focus) .vd-mo-day { display: none; }
/* Chấm số tin chưa đọc (`.vc-chua-doc`, ở `khung_chat.css`) neo vào nút Hỗ
   trợ của thanh đáy. */
.vd-nut-day--chat { position: relative; }
@media (max-width: 1023px) {
  /* Thanh ba nút ẩn khi chat mở. Lớp `vc-mo` do video_chat.js bật/tắt (không
     dùng :has theo `hidden`) để lúc THU NHỎ thanh hiện ra TRƯỚC, khung thu
     đúng vào icon chat đang thấy. */
  body.vc-mo .vd-day,
  body.vc-mo .vd-mo-day { display: none; }
}

/* ===================================================================
   BỐN MỐC BỀ NGANG (26/08, `--rong-clip`/`--cao-thumb` GỠ 05/09)

   ⚠ Mục này TỪNG neo bề ngang/cao thẻ cuộn ngang vào hai biến
   `--rong-clip`/`--cao-thumb` (công thức giải ngược từ mục tiêu "ló
   mép N px" - lịch sử đầy đủ xem git log nếu cần tra lại). Từ 05/09,
   `.hang-loai-cuon`/`.cuon-ngang` đổi sang LƯỚI TỰ GIÃN
   (`repeat(auto-fill, minmax(...,1fr))`) nên bề ngang cột do CHÍNH
   LƯỚI quyết theo bề ngang màn, KHÔNG cần một biến "cao thumbnail" gõ
   tay cho từng mốc nữa - `aspect-ratio` trên `.hinh` tự suy chiều cao
   từ bề ngang cột. Hai biến ấy đã GỠ khỏi `:root` và bốn khối dưới
   đây; bốn mốc VẪN GIỮ vì `--le` (đệm lề) còn dùng ở nhiều nơi khác
   (header, khối, v.v). */
.trang { margin: 0 auto; }

/* <600px - ĐIỆN THOẠI (mặc định đã khai ở `:root`, ghi lại cho dễ
   đọc cạnh ba mốc kia) */
@media (max-width: 599px) {
  :root { --le: 12px; }
}

/* 600-1023px - IPAD DỌC. Đây là mốc SINH RA lát này. */
@media (min-width: 600px) and (max-width: 1023px) {
  :root { --le: 20px; }
}

/* 1024-1439px - IPAD NGANG / LAPTOP */
@media (min-width: 1024px) and (max-width: 1439px) {
  :root { --le: 28px; }
}

/* >=1440px - MÁY TÍNH. Nội dung KHOÁ 1760px canh giữa (nới từ 1400px,
   05/09, mockup lưới tự giãn - Bruno duyệt) - lưới auto-fill của loại
   súng/hàng video giờ tận dụng được bề ngang rộng hơn thay vì chừa
   trắng hai bên hoặc phải cuộn. */
@media (min-width: 1440px) {
  :root { --le: 40px; }
  .trang { max-width: 1760px; }
}

/* Transition ảnh DÙNG CHUNG cho cả ba nơi bày thẻ video (06/09, Việc 1
   hợp nhất hover) - trước đây CHỈ `.the-nho .hinh img` khai transition
   này, nên hover ở `.the-video`/`.lq-the` đổi scale/độ sáng TỨC THÌ
   (không mượt) dù đích đến giống hệt - lệch CẢM GIÁC dù giá trị cuối
   khớp nhau. Đặt ở NGOÀI `@media (hover: hover)` vì đây là transition
   CƠ SỞ, áp cho cả chiều vào lẫn chiều ra khỏi hover. */
.the-clip .hinh img { transition: transform .32s, filter .32s; }

/* MÁY CÓ CHUỘT mới có trạng thái rê. `hover: hover` MỘT MÌNH chưa đủ -
   vài trình duyệt di động khai `hover: hover` cho thao tác chạm, và
   lúc ấy trạng thái rê DÍNH LẠI sau khi chạm xong. Cộng thêm
   `pointer: fine` mới lọc đúng máy có con trỏ nhọn. */
@media (hover: hover) and (pointer: fine) {
  /* ---- 6A: THẺ VIDEO, MỘT BỘ DÙNG CHUNG (Việc 1, 06/09) -----------
     Trả giá TRƯỚC lô này: `.the-nho` (hàng cuộn trang chủ) có ĐỦ NĂM
     dấu hiệu, `.the-video` (lưới trang danh sách/tìm kiếm) chỉ có
     viền, `.lq-the` (hai dải "video liên quan" trang chi tiết) KHÔNG
     có gì - ba nơi bày cùng MỘT khái niệm "thẻ video" mà ba luật khác
     nhau, đúng bẫy đã dính nhiều lần (hai đường ghi video, hai đường
     đếm, hai định nghĩa thẻ - xem CLAUDE.md).
     Sửa TẬN GỐC: mọi hàm dựng thẻ (`veTheNho`/`veTheVideo`/`veTheLQ`,
     video_public.js) nay đều gắn thêm lớp DÙNG CHUNG `the-clip` lên
     thẻ ngoài và `the-clip-ten` lên tiêu đề - lớp riêng cũ
     (`the-nho`/`the-video`/`lq-the`...) VẪN GIỮ NGUYÊN cho mọi luật
     KHÔNG phải hover (kích thước, tỉ lệ khung...). `.lq-the` vốn dùng
     `.lq-hinh` cho vùng ảnh (khác tên `.hinh` của hai thẻ kia) nên
     JS gắn THÊM lớp `hinh` cạnh `lq-hinh` - `.the-clip .hinh` nhờ đó
     khớp ở cả ba nơi mà không cần liệt kê ba tên lớp trong CSS.
     Từ nay THÊM một nơi bày thẻ video mới chỉ cần gắn hai lớp này,
     không phải chép lại khối luật hover. */
  /* ⚠ KHÔNG VIỀN Ô-LIU KHI RÊ CHUỘT (Bruno chốt 19/09) - bỏ CẢ HAI
     vế viền cùng lúc, vì chúng vẽ ra cùng một thứ người dùng thấy:
     vòng `0 0 0 1px var(--vien-oliu)` ôm ngoài thẻ, và
     `border-color: var(--oliu-dam)` trên khung ảnh. Bỏ một vế thôi
     thì viền xanh vẫn còn đúng một vòng - trông như chưa sửa gì.
     GIỮ NGUYÊN phần còn lại của hover (nhấc thẻ, bóng đổ, ảnh phóng
     nhẹ + sáng lên, nút phát tô ô-liu, tựa đổi màu): thứ Bruno gạt là
     cái VIỀN, không phải toàn bộ phản hồi rê chuột - bỏ hết thì thẻ
     đứng im và không còn dấu hiệu nào nói "bấm được". */
  /* ⚠ 24/09 ĐẢO LẠI chốt 19/09 ở trên: đề bài theme sáng/tối Bruno duyệt
     ghi rõ "Thẻ video rê chuột: VIỀN Ô-LIU, nhấc 3px, tiêu đề đổi màu
     ô-liu". Vẽ bằng vòng `0 0 0 1px` (không đổi `border`) nên không xê
     dịch một pixel bố cục nào. */
  .the-clip:hover {
    transform: translateY(-3px);
    box-shadow: 0 0 0 1px var(--oliu), 0 8px 26px var(--bong-noi);
  }
  .the-clip:hover .hinh img { transform: scale(1.06); filter: brightness(1.08); }
  .the-clip:hover .hinh .phat { background: var(--ta-oliu); transform: scale(1.12); }
  .the-clip:hover .hinh .phat svg { fill: var(--ta-nen); }
  .the-clip:hover .the-clip-ten { color: var(--oliu-sang); }
  .the-clip:hover .ghim { background: var(--ta-nen); }

  /* ---- 6B: THẺ LOẠI SÚNG (trang chủ tầng 1) ---- */
  .the-loai-chu:hover {
    transform: translateY(-3px);
    box-shadow: inset 0 0 0 1px var(--oliu-dam), 0 8px 26px var(--bong-noi);
  }
  .the-loai-chu:hover .tlc-anh { transform: scale(1.07); }
  .the-loai-chu:hover .tlc-ten-txt { color: var(--oliu-sang); }

  /* ---- 6C: CHIP CHỦ ĐỀ ---- */
  .chip-cd:hover {
    border-color: var(--oliu-dam); border-left-color: var(--oliu);
    background: var(--oliu-nen); transform: translateY(-2px);
  }
}

/* Cây thứ 3 trở đi, thu gọn (24/08). Bày đủ bốn khối CTA + bảng thông
   số thì trang dài lê thê, cuộn mãi không tới "Cùng sản phẩm này". */
.sp-them-hop > summary {
  padding: 12px 16px;
  color: var(--oliu-chu);
  font-weight: 600;
  cursor: pointer;
}

/* ===================================================================
   DẢI LỌC + BOTTOM SHEET + MÀN TÌM (mockup v4, 24/08)
   =================================================================== */

/* Kính lúp - có mặt trên header CẢ BA màn.
   ⚠ SÁT CẠNH NÚT TƯ VẤN, CẢ CỤM DỒN MÉP PHẢI (chốt 26/08). Trước đây
   `margin-left: auto` nằm trên `.nut-fb` — đúng ở `#man-ct` (không có
   `.dau-chu` xen giữa) NHƯNG hỏng ở `#man-chu`/`#man-ds`: `.quay`/
   `.dau-chu` không tự giãn, nên khoảng trống thừa dồn hết vào margin
   TRƯỚC `.nut-fb`, đẩy icon tìm kiếm kẹt lại ngay sau tiêu đề - cách
   xa nút tư vấn, đúng bug đo được (khoảng hở 37-102px giữa hai icon
   tuỳ độ dài tiêu đề). Dời `margin-left: auto` sang ĐÂY - icon tìm
   kiếm là phần tử ĐẦU TIÊN của cụm-dồn-phải trên CẢ BA màn, nên gắn
   nó ở đây thì tự đúng cho cả ba, không cần khai riêng từng màn. */
/* Vùng CHẠM ≥44x44px (Apple HIG / WCAG 2.5.5) - kích thước THẬT của
   chính nút, không phải một lớp phủ ảo đè lên trên.
   ⚠ BẪY ĐÃ TRẢ GIÁ lúc dựng: bản đầu dùng `::before` phủ rộng hơn hộp
   gốc (`width: max(44px, 100%)`, đặt `position:absolute` LỚN HƠN
   `.nut-tim` 38px) - vùng chạm đúng 44px thật, nhưng `::before` tràn
   RA NGOÀI hộp `.nut-tim` (không `overflow:hidden`) làm chính
   `scrollWidth` của `.nut-tim` PHÌNH LÊN 40px trong khi `clientWidth`
   chỉ 36px - đúng bẫy "tràn ngang ở TẦNG CHA" đã ghi trong CLAUDE.md,
   chỉ khác đây là tầng chính NÓ chứ không phải cha nó. Bánh cóc
   `test_KHONG_TRAN_NGANG_o_MOI_TANG_du_12_danh_muc` (viết từ lô khác,
   đo MỌI tầng chứ không riêng nội dung nó test) bắt được ngay.
   Đơn giản hơn NHIỀU: cho chính hộp nút to 44px luôn, không cần lớp
   phủ nào - không có gì để tràn. */
/* ---- CỤM BA NÚT hành động topbar (tìm / giao diện / tư vấn) ----
   24/09, hai lượt cùng ngày: (1) Bruno "các nút đang hơi cách nhau xa,
   cho gần nhau 1 chút xíu" -> vá tạm bằng `margin-left:-4px` trên từng
   nút (gap còn 18px, đo thật production). (2) Bruno gửi ảnh + số cụ
   thể "giảm khoảng cách lại bằng 70% hiện tại" (18px) -> ĐỔI HẲN sang
   một khối bọc `.dau-nut` với `gap` CỐ ĐỊNH thay vì trừ lùi từ gap của
   `.dau` (22px trang chủ / 12px hai màn kia - hai gốc khác nhau nên
   trừ một số trừ chung không ra cùng một tỉ lệ ở cả ba topbar). 12px
   = 66,7% của 18px - số gần 70% nhất mà vẫn là bội của 4 (giữ đúng
   `test_khoang_cach_khong_phinh_them_ngoai_boi_4`, không nâng trần).
   `margin-left: auto` dời từ `.nut-tim` sang chính `.dau-nut` (đẩy cả
   cụm sang phải, y hệt hành vi cũ) - RESET về 0 ở `@media (min-width:
   761px)` bên dưới, đúng chỗ `.nut-tim` từng bị ẩn nên margin của nó
   trước đây KHÔNG hề có tác dụng ở bề ngang đó (nút không render). Có
   quên reset thì `.dau-nut` (luôn render, khác `.nut-tim` cũ) sẽ ăn
   hết khoảng trống thừa sau `.o-tim-desktop` trên máy tính - lệch hành
   vi desktop, ngoài phạm vi việc đang sửa. */
.dau-nut {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-left: auto;
}
.nut-tim {
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: var(--bk);
  background: var(--tam);
  border: 1px solid var(--vien);
  color: var(--chu);
  display: flex;
  align-items: center;
  justify-content: center;
}

.nut-tim svg { width: 16px; height: 16px; }

/* ---- NÚT + MENU GIAO DIỆN Sáng / Tối / Theo máy (24/09) ----
   Cùng khuôn ô vuông 44px với `.nut-tim` đứng ngay trước nó, cả hai nay
   là con của `.dau-nut` (xem giải thích ở đó). Menu dùng chung cho ba
   topbar, `video_theme.js` đặt nó ngay dưới nút vừa bấm. */
.nut-gd {
  flex: none;
  width: 44px; height: 44px;
  border-radius: var(--bk);
  background: var(--tam); border: 1px solid var(--vien);
  color: var(--chu);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; font: inherit;
}
.nut-gd svg { width: 18px; height: 18px; }
.nut-gd[aria-expanded="true"] { border-color: var(--oliu); }
.nut-gd:focus-visible { outline: 2px solid var(--oliu); outline-offset: 2px; }
.gd-menu {
  position: fixed; z-index: 60;
  min-width: 168px; padding: 4px;
  background: var(--tam); border: 1px solid var(--vien); border-radius: var(--bk);
  box-shadow: 0 8px 28px var(--bong);
  display: flex; flex-direction: column;
}
.gd-menu[hidden] { display: none; }
.gd-menu button {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 44px; padding: 0 12px;
  background: transparent; border: 0; border-radius: var(--bk);
  color: var(--chu); font: inherit; font-size: var(--f3); text-align: left; cursor: pointer;
}
.gd-menu button:hover, .gd-menu button:focus-visible { background: var(--oliu-nen); outline: none; }
/* Icon + chữ đi CÙNG một khối bên trái - nút cha vẫn `space-between`
   nên dấu tích luôn dồn phải, tách khỏi khối này. */
.gd-menu .gd-muc { display: flex; align-items: center; gap: 8px; min-width: 0; }
.gd-menu .gd-icon { width: 18px; height: 18px; flex: none; color: var(--chu-mo); }
.gd-menu button[aria-checked="true"] .gd-icon { color: var(--oliu-chu); }
.gd-menu .gd-tich { width: 18px; height: 18px; fill: none; stroke: var(--oliu-chu); stroke-width: 2.4; visibility: hidden; }
.gd-menu button[aria-checked="true"] .gd-tich { visibility: visible; }
.gd-menu button[aria-checked="true"] { color: var(--oliu-chu); font-weight: 600; }

/* ---- Ô TÌM KIẾM TRÊN TOPBAR, DESKTOP (Commit 2B còn nợ, 04/09) ----
   Bo tròn, max-width 460px, chỉ hiện ở desktop (>760px) - dưới mốc đó
   thu về icon `.nut-tim` như cũ. KHÔNG phải ô nhập thật - một NÚT
   trông giống ô tìm, bấm là mở thẳng máy tìm sẵn có (`moManTim()`,
   overlay `#man-tim`) - "không viết máy tìm mới" đúng như đề bài, chỉ
   thêm một cửa vào TRÊN topbar cho màn rộng. */
.o-tim-desktop {
  display: none;
  flex: 1 1 auto; max-width: 460px; margin-left: auto;
  align-items: center; gap: 8px;
  height: 44px; padding: 0 14px;
  background: var(--tam); border: 1px solid var(--vien); border-radius: 999px;
  color: var(--chu-mo); font-size: var(--f2); font-family: inherit;
  cursor: pointer; text-align: left;
}
.o-tim-desktop svg { width: 16px; height: 16px; flex: none; opacity: .7; }
.o-tim-desktop span {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 760 KHÔNG thuộc thang 599/600/1439/1440 sẵn có của trang này - Bruno
   chỉ định con số này riêng cho việc thu gọn ô tìm desktop, độc lập
   với bốn mốc bố cục `--le`. Khai vào `_NGOAI_LE` của bánh cóc
   breakpoint kèm lý do này. */
@media (min-width: 761px) {
  .o-tim-desktop { display: flex; }
  .nut-tim { display: none; }
  /* `.o-tim-desktop` đã tự có `margin-left: auto` riêng (đẩy chính nó
     sang phải, `flex:1 1 auto` chiếm hết chỗ trống tới max-width) -
     RESET auto-margin của `.dau-nut` về 0 ở đây, đúng bề ngang nó từng
     im lặng "không có" vì hồi trước chủ margin (`.nut-tim`) bị ẩn hẳn
     (không render = margin không tính). `.dau-nut` nay LUÔN render nên
     phải reset TAY, không thì nó ăn thêm khoảng trống thừa sau ô tìm
     desktop - lệch hành vi cũ, ngoài phạm vi việc đang sửa. */
  .dau-nut { margin-left: 0; }
}

/* DẢI LỌC `.dai-loc` + nút `.nut-loc` + PANEL `.loc-panel` (25/08)
   ĐÃ XOÁ HẲN 18/09 cùng markup và JS của chúng - trang loại nay dùng
   CHUNG khung `.dong-strip`/`.dong-tang` với trang dòng (Việc 2 lô dọn
   trang khách). Luật `body:has(.loc-panel.mo) .dai-loc{position:static}`
   vá vụ "chip lọc đè ô tìm" (26/08) đi theo: khung chung nằm TRONG
   luồng trang, không `sticky`, nên không còn hai thanh tranh chỗ. */
.dai-dang-ap[hidden] { display: none; }
/* Hàng chip - ĐIỆN THOẠI cuộn ngang một hàng, không đẩy video xuống.
   ⚠ PC XUỐNG DÒNG (12/09, #21 - Bruno chốt: bỏ trần số chip, "không
   cắt, không +N nữa" thì hàng phải tự giãn ra chứa hết, không giấu
   bớt sau một thanh cuộn hẹp) - dùng CHUNG cho cả hàng mẫu-top trang
   loại (`#ds-hang-chip`) lẫn hàng mẫu/hãng trang dòng
   (`.dong-strip-chiphang .hang-chip`), một khuôn cho MỌI hàng chip. */
/* bo-loc-web-phase2, Việc 3c - `veHangChipLoc()` ẩn `.hang-chip` bằng
   `[hidden]` khi ô gõ tìm không khớp gì (thay bằng dòng "Không tìm
   thấy") - lớp `display: flex` bên dưới THẮNG luật `[hidden]` mặc
   định nếu không khai lại (bẫy đã ghi nhiều lần trong CLAUDE.md). */
/* CHẤM MÀU trên chip hàng "Màu" (16/09, lô "trang-khach-cay" Việc 2).
   Giá trị vào qua biến `--cham` do JS đặt từ `ma_mau` server gửi, nên nó
   có thể là hex HOẶC `linear-gradient(...)` ("Camo" là hoạ tiết, không
   phải một màu đơn) - dùng `background` (không phải `background-color`)
   để nhận được cả hai. Viền mảnh sáng giữ cho chấm màu tối vẫn đọc được
   trên nền tối của trang. */
.chip-cham {
  display: inline-block; width: 10px; height: 10px; border-radius: 50%;
  margin-right: 6px; vertical-align: -1px;
  background: var(--cham, var(--chu-mo));
  border: 1px solid var(--vien-chip);
}

.hang-chip[hidden] { display: none; }
.hang-chip {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scrollbar-width: none;
  padding-right: 16px;
  flex: 1;
}

.hang-chip::-webkit-scrollbar { display: none; }
.hang-chip .chip { flex: none; white-space: nowrap; }

@media (min-width: 600px) {
  .hang-chip { flex-wrap: wrap; overflow-x: visible; padding-right: 0; }
  /* Nhãn "Mẫu"/"Hãng" (trang dòng) neo ĐẦU khối khi chip xuống nhiều
     dòng - `center` cũ chỉ đúng cho một hàng duy nhất. */
  .dong-strip-chiphang { align-items: flex-start; }
  .dong-strip-chiphang .dong-strip-nhan { padding-top: 6px; }
}

/* Bộ lọc đang áp - chip ✕ gỡ từng cái. */
.dai-dang-ap {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  padding: 12px 16px 0;
}

.chip-ap {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--oliu-nen);
  border: 1px solid var(--oliu-dam);
  border-radius: 999px;
  color: var(--oliu-sang);
  font-size: var(--f2);
  padding: 4px 8px 4px 12px;
}

.chip-ap b { font-weight: 600; }

/* Vùng chạm 24px - ngón tay, không phải con trỏ chuột. */
.chip-ap .x {
  width: 24px;
  height: 24px;
  border-radius: 999px;
  background: var(--oliu-nen);
  border: none;
  color: var(--oliu-sang);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--f2);
  line-height: 1;
}

@media (prefers-reduced-motion: reduce) {
  /* Chip bốn khối Mẫu/Hãng/Hệ/Màu (18/09) - cùng luật tắt chuyển động
     0,13 giây khi hệ điều hành xin giảm hiệu ứng. */
  .dong-tang .chip { transition: none; }
  .ke-chat { transition: none; }
  /* Tâm ngắm + băng đạn (20/09): TẮT chuyển động nhưng GIỮ hình - máy
     vẫn phải nói được "đang làm việc" cho người đã xin giảm hiệu ứng.
     Cung ô-liu và một băng nạp dở đứng yên vẫn đọc ra điều đó. */
  .nap-ngam, .nap-ngam::before, .nap-ngam::after { animation: none; }
  .nap-bang::after { animation: none; clip-path: inset(0 40% 0 0); }
}

/* ---- màn tìm kiếm toàn màn (SỬA CHỚP 04/09) --------------------------
   Trước lô này `#man-tim` chỉ có `.hien{display:block}` dùng chung với
   ba màn kia (man-chu/man-ds/man-ct) - không hề phủ kín, trang chủ lộ
   ra phía dưới. Nay phủ kín thật: cố định toàn màn, đứng TRÊN cả bong
   bóng chat nổi (z-index 40) lẫn khung chat (41). Nền dùng ĐÚNG token
   nền trang (`--nen`, khớp `body`) - không có token `--vd-bg` nào
   trong tệp này, dùng lại thay vì đẻ mới.
   Khoá cuộn nền bằng CSS thuần (`body:has()`, đã dùng cùng lối cho
   bong bóng chat ở trên) - không đụng JS: đóng màn thì `.hien` mất,
   `overflow:hidden` tự gỡ, `body` chưa từng bị đổi `scrollTop` nên vị
   trí cuộn cũ tự nguyên vẹn. */
#man-tim.hien {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: var(--nen);
  overflow-y: auto;
  /* Cuộn tới đáy/đỉnh lớp phủ không chuyền sang trang bên dưới (10/10). */
  overscroll-behavior: contain;
  padding-top: env(safe-area-inset-top);
}
body:has(#man-tim.hien) { overflow: hidden; }
/* Màn tìm PHỦ KÍN giấu trang bên dưới (10/10, ảnh Bruno: dưới thẻ thứ 24 là
   một khoảng trống dài tới hết trang). Đo: nội dung lớp phủ dừng ở ~2.690px,
   phần dưới là NỀN của lớp phủ `position:fixed; inset:0` trùm lên trang chủ
   cao ~4.800px bên dưới (iOS: `overflow:hidden` trên body không chặn cuộn
   tài liệu, và chụp cả trang thì lớp phủ kéo theo chiều cao tài liệu). Giấu
   `.trang` thì tài liệu không còn cao hơn lớp phủ. Vị trí cuộn cũ JS trả
   lại khi đóng màn tìm (`traCuonTruocTim`). Từ 10/10 (Q1=B) áp cho MỌI trạng
   thái của màn tìm, kể cả ô trống. */
body:has(#man-tim.hien) .trang { display: none; }

.man-tim .t-dau {
  display: flex;
  /* `wrap` (24/09): dòng "Khớp từng từ" + chip tổ hợp là con của `.t-dau`;
     không xuống dòng thì chúng bị ÉP thành một cột chữ dọc bên phải ô tìm
     (Bruno chụp đúng ca "bds9"). Xem luật `flex-basis: 100%` ngay dưới. */
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--vien);
  position: sticky;
  top: 0;
  background: var(--dau-nen);
  backdrop-filter: blur(8px);
  z-index: 20;
}

/* Việc 4 (26/08): "Huỷ" chữ ngoài khung đã bỏ - đây là nút ĐÓNG màn
   thay thế, hộp chạm thật 44x44px (không dùng `::before` phủ rộng: lớp
   ấy làm PHÌNH `scrollWidth` của chính phần tử khi không có
   `overflow:hidden`, đã trả giá đúng bẫy này ở icon tìm kiếm trên
   header cùng ngày - xem `.nut-tim`). */
.t-dong {
  flex: none;
  width: 44px;
  height: 44px;
  margin: -6px -8px -6px 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  color: var(--oliu-sang);
  padding: 0;
  cursor: pointer;
}
.t-dong svg { width: 20px; height: 20px; flex: none; }

.o-tim-lon {
  flex: 1;
  /* Commit 5: căn giữa trang, không vượt quá 860px - `border`/`--oliu-
     dam` đã đúng từ trước, không đổi. */
  max-width: 860px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--tam);
  border: 1px solid var(--oliu-dam);
  border-radius: var(--bk);
  padding: 13px;
}

.o-tim-lon svg { width: 16px; height: 16px; opacity: .7; flex: none; }

.o-tim-lon input {
  flex: 1;
  min-width: 0;
  background: none;
  border: none;
  color: var(--chu);
  font: inherit;
  font-size: 16px;
  outline: none;
}

/* ⚠ ẨN NÚT XOÁ NATIVE của `<input type="search">` - vá 27/08.
   Trình duyệt nhân WebKit/Blink (Safari iPhone, Chrome) TỰ vẽ một dấu
   ✕ trong ô `type="search"` khi ô có chữ. Trước Việc 4 nó nằm cạnh nút
   chữ "Huỷ" nên trông như một phần của bố cục; từ khi "Huỷ" thành icon
   ✕ riêng (`.tim-xoa`) thì thành HAI dấu ✕ sát nhau, người dùng không
   biết bấm cái nào.
   Giữ `type="search"` (không đổi sang `text`): nó là thứ báo cho iOS
   hiện phím Tìm trên bàn phím ảo và mang đúng ngữ nghĩa cho trình đọc
   màn hình - đổi kiểu ô để giấu một cái icon là trả giá đắt hơn nhiều
   so với ẩn đúng cái icon ấy. */
.o-tim-lon input::-webkit-search-cancel-button,
.o-tim-lon input::-webkit-search-decoration {
  -webkit-appearance: none;
  appearance: none;
  display: none;
}

/* Icon X xoá chữ, NẰM TRONG khung (mép phải, vì là item cuối của hàng
   flex `.o-tim-lon`) - chỉ xoá, KHÔNG đóng màn. Hộp chạm thật 44x44px
   dù icon vẽ nhỏ (16px, thừa hưởng luật `.o-tim-lon svg` phía trên);
   bù trừ bằng margin ÂM để không đẩy khung tìm kiếm cao hẳn lên. */
.tim-xoa {
  flex: none;
  width: 44px;
  height: 44px;
  margin: -6px -10px -6px 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  border-radius: 999px;
  color: var(--chu-mo);
  padding: 0;
  cursor: pointer;
}
.tim-xoa svg { opacity: 1; }
.tim-xoa[hidden] { display: none; }
@media (hover: hover) and (pointer: fine) {
  .tim-xoa:hover { color: var(--oliu-sang); }
}

/* Commit 5 (04/09): dòng diễn giải "khớp từng từ" - ngay dưới ô tìm,
   cùng bề rộng 860px căn giữa. */
.tim-dien-giai {
  max-width: 860px; margin: 10px auto 0; padding: 0 var(--le);
  font-size: var(--f1); color: var(--chu-mo);
}
.tim-dien-giai[hidden] { display: none; }
/* Trong `.t-dau` (flex): chiếm TRỌN một hàng dưới ô tìm, bỏ lề riêng - `.t-dau`
   đã có đệm của nó. */
.man-tim .t-dau > .tim-dien-giai,
.man-tim .t-dau > .tim-to-hop { flex-basis: 100%; max-width: none; margin: 0; padding: 0; }
.tim-dien-giai-nhan { color: var(--chu-mo); }
.tim-dien-giai mark { background: none; color: var(--oliu-sang); font-weight: 600; }

.tim-to-hop {
  max-width: 860px; margin: 10px auto 0; padding: 0 var(--le);
  display: flex; flex-wrap: wrap; gap: 8px;
}
.tim-to-hop[hidden] { display: none; }
.tim-to-hop .chip[disabled] { opacity: .5; cursor: default; }

.t-khoi { padding: 16px var(--le) 4px; }
.t-khoi .tem { display: block; margin-bottom: 12px; }
.goi-y { display: flex; flex-wrap: wrap; gap: 8px; }

/* Chế độ "giữ trang" (ô tìm trống thì lớp phủ trong suốt, trang đang xem lộ
   bên dưới - mockup 24/09) ĐÃ BỎ 10/10 (Bruno chốt Q1=B, lô soizz-tim-nen-dac):
   màn tìm phủ nền đặc ở MỌI trạng thái, "Mẫu hot" nằm dưới ô tìm trên nền ấy.
   Dáng "Mẫu hot" giữ nguyên như khách vẫn thấy từ 24/09: MỘT hàng chip trượt
   ngang, nhãn đứng cùng hàng. */
#man-tim #tim-khoi-hot {
  display: flex; align-items: center; gap: 12px;
  padding: 8px var(--le); background: var(--nen);
  border-bottom: 1px solid var(--vien);
}
#man-tim #tim-khoi-hot[hidden] { display: none; }
#man-tim #tim-khoi-hot .tem { margin: 0; flex: none; }
#man-tim #tim-khoi-hot .goi-y {
  flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
}
#man-tim #tim-khoi-hot .goi-y::-webkit-scrollbar { display: none; }
#man-tim #tim-khoi-hot .goi-y > * { flex: none; }

.ket-qua { padding: 4px var(--le); }

/* Commit 5 (04/09): lưới kết quả tìm nay dùng `.luoi-video`/`.the-video`
   (Commit 1) - dáng dòng `.kq-dong`/`.kq-hit`/`.kq-hinh`/`.kq-chu`/
   `.kq-ten`/`.kq-phu` cũ đã hết người gọi (grep JS: 0 chỗ), XOÁ hẳn
   thay vì để lại code chết. Từ khoá tô sáng ô-liu, KHÔNG nền vàng mặc
   định của <mark> - luật dùng chung ở đầu tệp component thẻ. */
.the-video .tv mark { background: none; color: var(--oliu-sang); font-weight: 600; }

/* ==================================================================
   TRANG LOẠI GỘP - HAI TAB (10/10, lô "soizz-sung-ngan-tab", Bruno duyệt
   mockup): Súng ngắn = tab "Bán tự động" + tab "Ổ quay · Revolver", CÙNG
   HÀNG chia đôi bề ngang, cao ≥52px, không xuống dòng ở 390px. Tab đang
   mở tô đặc ô-liu (token `--bl-chon-*` của chip đang chọn - chữ TRẮNG ở
   bảng sáng; bảng tối giữ chữ tối trên ô-liu sáng vì trắng trên #a3b06a
   chỉ ~2,2:1), tab kia nền trong. Bộ lọc dùng LẠI khung `.dong-strip`. */
.gop-loc[hidden], .gop-tab[hidden], .gop-video-dau[hidden] { display: none; }
.gop-tab {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 8px; padding: 4px var(--le) 12px;
}
.gop-tab-nut {
  min-height: 52px; min-width: 0; padding: 6px 8px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  border: 1px solid var(--vien); border-radius: 8px;
  background: transparent; color: var(--chu);
  font: inherit; cursor: pointer; text-align: center;
}
.gop-tab-nut[aria-selected="true"] {
  background: var(--bl-chon-nen); border-color: var(--bl-chon-nen); color: var(--bl-chon-chu);
}
.gop-tab-ten {
  font-size: 13px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.gop-tab-dem { font-size: 12px; font-weight: 500; white-space: nowrap; color: var(--chu-mo); }
.gop-tab-nut[aria-selected="true"] .gop-tab-dem { color: var(--bl-chon-chu); }
.gop-loc {
  margin: 0 var(--le) 4px;
  background: var(--bl-khung-nen); box-shadow: var(--bong-the); border-radius: 12px;
  padding: 8px 24px;
}
.gop-loc:not(:has(.dong-strip-chiphang)) { display: none; }
.gop-video-dau h2 { text-transform: uppercase; }
.gop-video-dau .dem { color: var(--chu-mo); font-size: 13px; margin-left: 8px; white-space: nowrap; }
@media (max-width: 599px) {
  .gop-loc { padding: 4px 16px; }
}

/* NGỪNG BÁN TRÊN ẢNH THẺ (10/10, lô `rulo-ngoai-le-nhan-ngung-ban`, Bruno chốt):
   DÙNG LẠI đúng dấu "Hết hàng" của trang tra hàng (`timkiem.css` .tk-anh-het /
   .tk-dau-het - mockup Bruno duyệt 10/10): chỉ ẢNH mờ + xám + nhạt, dấu đóng
   chéo ở lớp TRÊN, cùng vị trí (giữa ảnh, xoay -12°), cùng viền đỏ, cùng chữ
   đậm in hoa. Màu CỐ ĐỊNH (dấu nằm trên ảnh, ảnh không đổi theo Sáng/Tối) - đỏ
   và nền trắng lấy từ bảng gốc, không mã màu mới. Ở thẻ hẹp (thẻ cuộn ngang
   ~108px) cỡ chữ co theo ô ảnh (`cqi`) để không tràn khung - Safari < 16 giữ
   17px. Thẻ vẫn bấm xem được (`pointer-events: none`). */
.hinh.anh-ngung { container-type: inline-size; }
.hinh.anh-ngung img {
  filter: blur(3px) grayscale(.7) opacity(.7);
  transform: scale(1.08);
}
.ngung-ban {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 3;
  transform: translate(-50%, -50%) rotate(-12deg);
  padding: 4px 8px;
  border: 3px solid var(--S-het);
  border-radius: 8px;
  background: color-mix(in srgb, var(--S-the) 70%, transparent);
  color: var(--S-het);
  opacity: .65;
  font-size: 17px;
  font-size: min(17px, 10cqi);
  font-weight: 800;
  line-height: 1.35;
  letter-spacing: .04em;
  text-transform: uppercase;
  white-space: nowrap;
  pointer-events: none;
}
/* Trang chi tiết: góc trên-trái khung phát, không xoay, không đè giữa video. */
.ngung-ban--goc {
  top: 8px;
  left: 8px;
  transform: none;
  opacity: .85;
  font-size: 17px;
}
