/* EOS Studio — kiểu riêng của từng màn.
   Tách khỏi `vo.css` để lớp thêm cho một màn không phá màn khác. */

/* ── Studio — bàn hậu kỳ một lượt tạo ────────────────────── */

/* ── `.ban-lam-viec` ĐI HẲN — 28/08/2026 ──────────────────────
 *
 * Lớp ấy chia `340px + 1fr`: hẹp trái, rộng phải. Ba tệp dùng nó, và cả ba đều
 * đặt thứ người ta GÕ VÀO ở cột hẹp — đúng cái mà `.hai-cot` (nen.css) ra đời
 * để lật lại. Nay cả ba đã chuyển:
 *
 *   `an-pham.js`        → `.hai-cot`, cột soạn rộng, danh sách 420px
 *   `hau-ky-ban.js`        → `.hai-cot` của `studio.js`, cột trái là `#st-ban`
 *   `doanh-nghiep-logo.js` → `.canh-nhau` (nó vốn chỉ mượn lớp rồi ghi đè
 *                            `1fr 1fr`, chưa từng cần lưới 340px)
 *
 * Hai luật form của nó thì KHÔNG mất theo — chúng vẫn đúng, chỉ là đã đội tên
 * một cái lưới suốt từ v15. Bàn hậu kỳ là chỗ duy nhất còn dùng `<label>` trần
 * cạnh `<input type=text>` trần, nên chúng theo về đó. */
/* Hai chọn tử, không một: đợt 2n chuyển ô «Ghi chú» sang thẻ `#st-lam`, và hai
   luật này ở lại `#st-ban` — nên nhãn của nó thôi xuống dòng và ô nhập co về
   bề rộng mặc định của trình duyệt. Đo trong app: nhãn và ô nằm CÙNG một dòng,
   ô rộng 180px giữa một cột 564px. Một cặp luật viết cho «form của bàn hậu kỳ»
   thì phải theo cả form, kể cả khi form ấy nằm trong hai cái thẻ. */
#st-ban label, #st-lam label { display: block; font-size: var(--cs-phu); color: var(--chu-nhat); margin: var(--k-3) 0 var(--k-1) }
#st-ban input[type=text], #st-lam input[type=text] { width: 100% }
/* Trừ ô mã màu: nó chở đúng bảy ký tự, và một ô 560px cho `#20409a` đọc ra
   «gõ gì vào đây cũng được». Nó đứng cạnh ô chọn màu nên hai thứ phải bằng nhau
   về mặt thị giác, không phải một chấm nhỏ cạnh một dải dài. */
#st-ban .st-mau input[type=text] { width: 112px; flex: 0 0 auto }
#st-ban .st-mau input[type=color] { width: 56px; flex: 0 0 auto }

/* ── Ô CHỌN HỌ CHỮ HIỆN BẰNG CHÍNH HỌ ẤY ─────────────────────
   Mặt chữ đặt bằng JS (`hau-ky-ban-chu.js`), không bằng thuộc tính `style` —
   tên họ đi thẳng vào CSS thì phải bỏ escape, và bỏ escape trong một thuộc
   tính là đúng cánh cửa mà lưới escape của N17 sinh ra để đóng. Ở đây chỉ nới
   chiều cao dòng: một mục chữ script như Allison cao gần gấp đôi Inter, và
   dòng chật thì nó bị cắt cả phần chân chữ. */
#f-font-td select, #f-font-dp select { line-height: var(--dong-chay); padding-block: 5px }
#f-font-td option, #f-font-dp option { font-size: var(--cs-de); line-height: var(--dong-chay) }

/* ── LƯỚI LỒNG ĐI HẲN — 28/08/2026, đợt 2m ───────────────────
 *
 * Đợt 2b lồng một lưới hai cột NỮA (`.st-ban-luoi`) vào trong cột trái của
 * tab, để ba thẻ đọc-thôi đứng cạnh form. Ý đúng — ảnh gốc phải ở cạnh thứ
 * đang sửa — nhưng hai lưới lồng nhau, mỗi lưới một ngưỡng, sinh ra một VÁCH
 * bề rộng đi ngược chiều: cột soạn `= #st-ban − 336` khi lưới trong tách và
 * `= #st-ban` khi nó gập, vách ở 720px. Đo trong trình duyệt 28/08:
 *
 *   1366 → 1023px  ·  1536 → 717  ·  1600 → 445  ·  1920 → 765
 *
 * Rộng thêm 64px thì hẹp đi 272px, và gập thanh bên ở 1536 mất 128px. Nâng
 * ngưỡng chỉ DỜI vách, lại bỏ luôn lý do lưới lồng tồn tại. Nên bỏ hẳn nó: ba
 * thẻ đọc-thôi sang `#st-doc`, đầu cột phải của lưới NGOÀI. Một lưới, không
 * vách nào, và ảnh gốc cạnh form ở mọi khổ.
 *
 * Gác chiều ngược ở `test-web` khối 14r: đừng ai dựng lại `.st-ban-luoi`.
 *
 * `#st-ban` GIỮ khung đo, chỉ đổi tên: nay nó CHÍNH LÀ cột soạn, nên các hàng
 * bên trong form (xem `.cf-hang`) hỏi thẳng nó. Trước đây `ban` đo cả lưới
 * lồng còn `soan` đo cột soạn — hai số lệch nhau 336px; nay chỉ còn một. */
#st-ban { container-type: inline-size; container-name: soan }

/* Ba thẻ đọc-thôi ở đầu cột phải. Khe 14px LẤY LẠI của `.hai-cot > .phai`:
   đây là một cái bọc, không phải một tầng bố cục mới, nên nó phải xếp con y
   như thể chúng là con trực tiếp của cột. Rỗng thì biến mất hẳn — một hộp cao
   0 vẫn ăn một khe 14px, và khe ấy đọc ra một thẻ đang tải dở. */
/* ── HAI CỘT NGANG CƠ — đợt 2n, bản vẽ 28/08/2026 ─────────────
 *
 * `.hai-cot` mặc định là «một cột rộng + một rail»: `minmax(0,1fr)` cạnh một
 * bề rộng CỐ ĐỊNH, chặn dưới nửa khung. Hậu kỳ không phải hình ấy. Nó là
 * «khung tranh + bảng màu»: bên trái là ảnh và bằng chứng, bên phải là mọi cái
 * núm vặn — hai cột cùng hạng, và cả hai đều co giãn theo khung.
 *
 * `0.92fr` chứ không `1fr`: cột trái chở ảnh, và ảnh là thứ duy nhất ở màn này
 * dùng được từng điểm ảnh thừa. Ở 1536 ra 52/48, đúng tỉ lệ của bản vẽ.
 *
 * ── LUẬT GẬP PHẢI KHAI LẠI, KHÔNG «MƯỢN» ĐƯỢC ───────────────
 *
 * Bản đầu của đợt này chỉ khai dòng dưới và tưởng ngưỡng gập của `.hai-cot`
 * còn nguyên hiệu lực. Không: luật gập là `.hai-cot` bên trong `@container`,
 * cùng hạng riêng (0,1,0) với `.st-cot`, mà `man.css` nạp SAU `nen.css` — nên
 * `.st-cot` thắng kể cả lúc điều kiện container đã khớp. Đo ở 375×812: lưới
 * vẫn hai cột, mỗi cột 161px, 24 lỗi bố cục và cả trang tràn ngang.
 *
 * Một lớp biến thể ghi đè `grid-template-columns` thì phải chở theo CẢ ngưỡng
 * gập của nó. `.ap-luoi` không dính vì nó chỉ đặt `--cot-phai`, không đụng vào
 * template. */
.st-cot { grid-template-columns: minmax(0, 1fr) minmax(0, 0.92fr) }
@container khu (max-width: 1040px) { .st-cot { grid-template-columns: minmax(0, 1fr) } }

/* ── CÁI BỌC TÀNG HÌNH PHẢI CHUYỀN NHỊP XUỐNG ────────────────
 *
 * `.hai-cot > .trai/.phai` là flex có `gap`, nên khe chỉ áp cho CON TRỰC TIẾP
 * của cột. Chỗ nào bọc thêm một `<div id="…">` để có chỗ `dat()` đổ vào thì cái
 * bọc ấy nhận trọn khe, còn mấy thẻ bên trong nó dính liền nhau.
 *
 * `#st-doc` vấp lỗi này ở đợt 2b. `#ng-ben` vấp đúng nó, và sống thêm hai đợt
 * nữa — chủ dự án báo 29/08: «cột phải của tab Media nguồn bị dính với nhau».
 * Ba thẻ, khe đo được **0px · 0px**.
 *
 * Vì sao lần trước không bắt được: trang mẫu đổ `veBen()` THẲNG vào `.phai`,
 * bỏ mất cái bọc — nên nó vẽ một bố cục app không dựng, và máy soi soi đúng
 * cái bố cục sai ấy. Đã sửa trang mẫu cùng lượt này.
 *
 * Cả hai đều mượn khe của CỘT, nên `test-kieu` mục 2c gác cặp: dời khe cột thì
 * hai cái bọc phải đi theo, không thì lệch quay lại. */
#st-doc, #ng-ben { display: flex; flex-direction: column; gap: var(--k-4) }
#st-doc:empty, #ng-ben:empty { display: none }

/* ── HÀNG CẶP TRONG FORM ─────────────────────────────────────
 *
 * Bốn trục của cùng một dòng chữ đọc thành hai hàng thay vì bốn. Gập theo
 * khung đo `soan` — tức cột PHẢI của tab, không phải cửa sổ: cùng lý lẽ đã ghi
 * ở `.cf-hang`, và ở đây nó cần thiết hơn vì cột ấy co giãn theo `0.92fr` chứ
 * không đứng ở một con số. Dưới 520px thì một ô chọn họ chữ còn ~240px, không
 * chở nổi «Noto Serif Display Condensed». */
.st-doi { display: grid; grid-template-columns: 1fr 1fr; gap: var(--k-3) var(--k-4); align-items: start }
@container soan (max-width: 520px) { .st-doi { grid-template-columns: 1fr } }
.st-doi select { width: 100% }

/* ── HÀNG ĐẾM CON ────────────────────────────────────────────
 *
 * `auto-fit` chứ không một con số cột: hàng «Màu nhấn · Tỉ lệ xuất ra · Vị trí
 * cắt» có BA nhóm với ảnh và HAI với clip (clip không đổi tỉ lệ được), và hàng
 * ba ô lệch thì luôn ba. Đếm bằng CSS thì cả hai ca dùng chung một lớp, không
 * phải một nhánh `laVideo` thứ hai trong JS chỉ để đổi tên lớp.
 *
 * Sàn 160px: một nhóm chip năm cái («giữa trên dưới trái phải») cần chừng ấy
 * mới không gãy làm ba dòng. */
.st-hang {
  display: grid; gap: var(--k-3) var(--k-4); align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
}
.st-hang > * > label:first-child { margin-top: 0 }
/* Ô đầu của mỗi cột không được đội thêm lề trên của `label` — hai cột phải bắt
   đầu ngang nhau, nếu không cặp đọc ra hai hàng lệch. */
.st-doi > * > label:first-child { margin-top: 0 }

/* Khối Dòng phụ: dòng chữ THỨ HAI, nên nó có khung riêng. Trước đợt 2n ô nhập
   của nó đứng lẫn giữa các trục của tiêu đề và không gì nói ra điều đó. */
.st-phu { margin: var(--k-4) 0 0; background: var(--sau) }
.st-phu > input[type=text] { width: 100% }

/* Nhãn của một tấm ảnh trong thẻ so sánh — không phải `<label>` của ô nhập
   nào, nên nó là `<p>`: dùng `<label>` cho một thứ không nhập được là nói dối
   trình đọc màn hình. */
.st-nhan { margin: 0 0 var(--k-2); font-size: var(--cs-phu); color: var(--chu-nhat) }

/* ── HAI TẤM PHẢI CÙNG MỘT THANG ĐO ──────────────────────────
 *
 * Hai ô của `.canh-nhau` rộng bằng nhau, nhưng hai tấm ảnh bên trong thì
 * không: bản xem thử đội trần `max-height: 60vh` của `.xt-khung`, còn bản gốc
 * không có trần nào. Đo ở 1536×864 với một bản xem thử 9:16 — 60vh là 518px,
 * suy ra bề ngang 291px, trong khi bản gốc ăn trọn ô 389px. Hai tấm lệch nhau
 * gần một phần tư, và mắt đọc chênh lệch ấy thành «bản sửa bị thu nhỏ».
 *
 * Chốt CHIỀU CAO làm thang đo chung, không phải chiều rộng: hai tấm có thể
 * khác tỉ lệ (xem thử 9:16 cạnh bản gốc 1:1), nên bằng nhau về bề ngang là
 * ép sai. Bằng nhau về chiều cao thì cùng một chủ thể hiện ra cùng một cỡ,
 * và đó mới là thứ người ta so.
 *
 * ── CHỌN TỬ PHẢI DÀI HƠN, KHÔNG CHỈ ĐỨNG SAU ────────────────
 * Bản đầu viết `.st-sanh img` — cùng hạng riêng (0,1,1) với `.xt-khung img`,
 * mà luật kia đứng SAU trong cùng tệp, nên nó thắng và trần vẫn là 60vh. Đo
 * lại: `max-height` tính ra 518,4px thay vì 46vh. Nêu tên đúng hai khối bị ghi
 * đè cho chọn tử dài ra một bậc, và nó cũng nói ra nó đang ghi đè cái gì. */
.st-sanh .xt-khung img, .st-sanh .goc img, .st-sanh .goc video {
  max-height: var(--cao-sanh); width: auto; max-width: 100%; margin-inline: auto;
}
.st-sanh {
  /* Khai trên chính khối dùng nó, không ở `:root`: đây là một núm của thẻ so
     sánh, không phải một token của bảng màu. */
  --cao-sanh: 46vh;
}
/* Gập một cột thì hai tấm thôi đứng cạnh nhau — trần thấp không còn nghĩa gì,
   và một tấm 46vh giữa một cột 351px là một tấm bị bóp vô cớ. */
@container khu (max-width: 900px) {
  .st-sanh {
    --cao-sanh: none;
  }
}

/* Ảnh tỉ lệ trong cột đọc-thôi là BẰNG CHỨNG, không phải bản xem. `.luoi` có
   sàn 300px — đúng cho một lưới ảnh chiếm hết bề ngang, sai cho ba ô trong một
   cột 460px: đo 28/08 sau khi chuyển, mỗi ô ra 430px và khối «Bản đang sống»
   cao 1273px, trong đó hơn 1000px là ba tấm thu nhỏ xếp dọc. Sàn 130px cho ba
   tấm một hàng; bấm vào mở bản đầy đủ ngay trong app (`loi/xem-anh.js`). */
#st-doc .luoi { grid-template-columns: repeat(auto-fill, minmax(min(130px, 100%), 1fr)); gap: var(--k-2) }
/* `.hang` DỜI về `nen.css` 01/09/2026 — dùng ở 15 tab, nên nó là từ vựng chung
   chứ không phải kiểu của một màn. Lý do đầy đủ ở đó, cạnh `.doi`. */

/* ── HÀNG NÚT GIỮA THẺ — 23/08/2026 ───────────────────────────
 *
 * `.thanh-hanh-dong` KHÔNG phải "một hàng nút". Nó là **thanh hành động DÍNH ĐÁY
 * của một thẻ**: `position: sticky; bottom: 0`, nền đục, và `margin: 14px -14px
 * -14px` để tràn ra sát mép thẻ. Đúng ở chỗ nó sinh ra (cuối một form dài), và
 * hỏng theo hai kiểu ở mọi chỗ khác:
 *
 *   · Đặt GIỮA thẻ → nó dính đáy màn hình và **đè lên chữ bên dưới** trong lúc
 *     cuộn. Nền đục + `--lop-dinh` nên chữ bị che hẳn, không phải mờ đi.
 *   · Đặt trong một hộp con (`.chan`) → lề âm 14px kéo nó ra NGOÀI hộp, nút nằm
 *     trên nền trang còn hộp thì kết thúc phía trên nó.
 *
 * Cả hai đã xảy ra thật ở tab Chuẩn thương hiệu, và cả hai chỉ lộ ra khi CUỘN —
 * ảnh chụp tĩnh lúc dựng xong trông đúng. Đây là cùng một lỗi với `.bc-pc-hang`
 * mà đợt này vừa gỡ: mượn một class dựng cho chỗ khác vì nó "trông giống".
 *
 * Hàng nút bình thường dùng class này: không dính, không lề âm, không nền. */
.hang-nut {
  display: flex; gap: var(--k-2); align-items: center; flex-wrap: wrap;
  margin: var(--k-3) 0 0;
}

/* `.mieng` và `.mieng.chon` DỜI về `nen.css` 01/09/2026 — hạng nút thứ tư, dùng
   ở 9 tab, nay đứng cùng chỗ với ba hạng kia. Lý do đầy đủ ở đó. */

.goc { border: 1px dashed var(--vien-sang); border-radius: var(--bo-lon); padding: var(--k-2); background: var(--sau) }
.goc img, .goc video { max-width: 100%; display: block; border-radius: var(--bo-nho) }

.phien-ban { display: flex; gap: var(--k-2); overflow-x: auto; padding: var(--k-1) 0 }
.phien-ban a { flex: 0 0 auto; text-align: center; color: var(--chu-nhat); font-size: var(--cs-nho); text-decoration: none }
.phien-ban img {
  width: 76px; height: 76px; object-fit: cover; border-radius: var(--bo-nho);
  background: var(--nen-anh); display: block; border: 2px solid transparent;
}
.phien-ban a.dang img { border-color: var(--vien-chon) }

/* ── Ô MEDIA KHÔNG PHẢI ẢNH — 07/09/2026 ───────────────────────
 *
 * Một lượt giọng đọc hay một clip không có khung poster thì KHÔNG có ảnh nào để
 * bày. Bảy chỗ trong `web/man/` từng đổ thẳng địa chỉ tệp vào `<img src>` và cùng
 * vẽ ra ô ảnh vỡ; nay chúng gọi `web/loi/o-media.js`, và đây là bộ kiểu của nó.
 *
 * Huy hiệu TRƠ (`.dau-media`) đứng đúng chỗ tấm ảnh từng đứng, nên nó phải mang
 * cùng cỡ với ảnh của TỪNG khu — thẻ, ô chọn, dải phiên bản ba cỡ khác nhau. Kế
 * thừa bằng cách bám vào chính bộ chọn của ảnh ở khu ấy, không đặt một con số
 * thứ hai: một cỡ gõ tay ở đây là một cỡ sẽ lệch ngày ảnh đổi cỡ. */
.dau-media {
  display: grid; place-items: center; background: var(--nen-anh);
  border-radius: var(--bo-nho); color: var(--chu-nhat); font-size: var(--cs-de);
}
/* Thẻ của «Media đã tạo» — ảnh ở đó ăn trọn bề ngang, nên huy hiệu cũng vậy. */
.the .dau-media { width: 100%; aspect-ratio: 1; font-size: var(--cs-so) }
/* Nút bọc tấm ảnh của thẻ: bản trước bọc TRỌN thân thẻ, nay chỉ bọc ảnh — khối
 * chữ có nút riêng. Gỡ đệm để tấm ảnh vẫn dính sát mép thẻ như cũ. */
.the > .mang-bam.the-nut-anh { display: block; padding: 0; width: 100% }
/* Máy phát của thẻ đứng ở ĐÚNG chỗ tấm ảnh, nên nó lấy đệm của thẻ chứ không
 * lấy khoảng cách trên như khi nó treo dưới một khối chữ. */
.the > .may-phat { margin: var(--k-3) }
/* Ô chọn của Hậu kỳ và dải phiên bản — bám đúng cỡ ảnh của hai khu ấy. */
.lua-chon .dau-media { width: 52px; height: 52px; flex: 0 0 auto }
.phien-ban .dau-media { width: 76px; height: 76px; border: 2px solid transparent }

/* Tem của ô bảng «Lịch sử tạo media» — cùng cỡ với `img.nho`, và bấm được. */
.tem-media {
  display: grid; place-items: center; width: 54px; height: 54px;
  border-radius: var(--bo-nho); background: var(--nen-anh); color: var(--chu-nhat);
  font-size: var(--cs-de); text-decoration: none;
}
.tem-media:hover { background: var(--nen-luot); color: var(--chu) }

/* Máy phát dùng chung. Cùng lý lẽ với `.ng-tieng` của kho nguồn: dưới ~200px thì
 * Chrome bỏ luôn thanh tua, mà tua chính là việc người ta cần ở một bản thu. */
.may-phat { display: block; width: 100%; margin: var(--k-2) 0 0 }



/* ── Bàn prompt (Studio · N15.6) ────────────────────────── */
/* Ba tầng chữ phải trông CÙNG MỘT HỌ để so sánh được bằng mắt: cùng nền, cùng
   bề rộng, cùng cách xuống dòng. Khác nhau ở chỗ tầng 2 sửa được, hai tầng kia
   thì không — và đó là khác biệt duy nhất được phép nhìn thấy. */
.ba-tang {
  background: var(--sau); border: 1px solid var(--vien); border-radius: var(--bo);
  padding: var(--k-3); margin: 0; font: 12px/1.6 Consolas, monospace; color: var(--chu-code);
  white-space: pre-wrap; word-break: break-word; max-height: 190px; overflow-y: auto;
}
.ba-tang.doc { font-family: inherit; font-size: var(--cs-ban); color: var(--chu) }
#st-prompt label { display: block; margin: var(--k-3) 0 var(--k-1) }
#st-prompt textarea { min-height: 110px; font: 12px/1.6 Consolas, monospace }

/* ── Biến thể theo kênh (Studio · N15.7) ────────────────────── */
/* Ô màu vẽ ra thay vì chỉ in mã hex: "#b2b3b6" không nói được nó là xám nhạt,
   và người bấm nút đang quyết định 30 file trông thế nào. */
.o-mau {
  display: inline-block; width: 12px; height: 12px; border-radius: var(--bo-nho);
  border: 1px solid var(--vien-sang); vertical-align: -1px;
}
#st-bien-the th { position: static }
#st-bien-the input[type=text] { font-size: var(--cs-phu); padding: var(--k-1) var(--k-2) }

/* ── Khung chọn (Studio) ────────────────────────────────── */
/* `.khung-chon` và `.mot-bai` ĐỔI TÊN thành `.lua-chon-luoi` và `.lua-chon`,
   DỜI về `nen.css` 01/09/2026 — chủ dự án chốt. Ba tab dùng cặp này, và
   «một bài» là tên sai: nó chở lượt tạo, lượt thử và việc gần đây, không cái
   nào là một bài. Ghi đè theo tab (`#hom-nay-ra`, `.gb-khu`) ở lại đây. */

/* ── Hôm nay ────────────────────────────────────────────── */
.o-dem { cursor: pointer }
/* Con số đếm mang serif như số trong sổ cái — nó là thứ được TRƯNG BÀY, không
 * phải thân bài. Div nên phải khai font-family, không thừa hưởng từ h1-h3. */
/* ── CỠ SỐ KHÔNG PHỤ THUỘC VÀO Ô CÓ BẤM ĐƯỢC HAY KHÔNG ───────
 *
 * Luật này từng khai `.o-dem .con-so`, mà `.o-dem` chỉ có khi ô mang một đích
 * đến (`oDem(…, diToi)`). Ba ô không có đích — «lượt đã hậu kỳ lại», «clip đang
 * chạy», «đã gỡ tệp» — vì thế in số ở cỡ THÂN BÀI trong khi ba ô bên cạnh in ở
 * `--cs-so`. Cùng một hàng, hai cỡ số. Chủ dự án chấm 29/08.
 *
 * Một con số là một con số; nó to bằng nhau bất kể bấm vào có đi đâu không.
 * Bấm được hay không là việc của `.o-dem` (con trỏ, nền khi rê chuột), không
 * phải việc của cỡ chữ. */
.con-so { font-size: var(--cs-so); font-weight: 600; font-family: var(--tieu-de); font-variant-numeric: tabular-nums }
.cot-chi { display: flex; align-items: flex-end; gap: var(--k-2); height: 80px }
.cot-chi > div { flex: 1; text-align: center }
.cot-chi .cot { background: var(--thuong); border-radius: var(--bo-nho) var(--bo-nho) 0 0 }

/* ── Hôm nay, điện thoại — kiểu SỔ CÁI ──────────────────────
 * Bỏ hết thẻ bo góc của `.tam`, chỉ còn dòng kẻ ngang: đúng dáng một trang sổ
 * sách, không phải một bảng điều khiển. Không dựng markup mới — vẫn NGUYÊN
 * `oDem()`/`.lua-chon` mà desktop dùng, chỉ đổi DÁNG bằng CSS ở đúng bề rộng
 * điện thoại (`order` xếp lại số/nhãn, không đổi thứ tự trong DOM).
 * Scope theo `#hom-nay-ra` — không đụng `.tam`/`.lua-chon` ở bất kỳ màn nào
 * khác. */
@container khu (max-width: 640px) {
  #hom-nay-ra .luoi { display: block }
  #hom-nay-ra .luoi > .tam {
    display: flex; align-items: baseline; justify-content: space-between; gap: var(--k-4);
    background: none; border: 0; border-radius: 0;
    border-bottom: 1px solid var(--vien); padding: var(--k-3) 0;
  }
  #hom-nay-ra .luoi > .tam:first-child { border-top: 1px solid var(--vien) }
  #hom-nay-ra .luoi > .tam .con-so { order: 2; white-space: nowrap }
  #hom-nay-ra .luoi > .tam .nhat { order: 1 }

  /* Đợt 2c: ba thẻ dưới nay nằm trong `.hai-cot` (bản vẽ N10), không còn là con
   * trực tiếp — selector phải với vào. Và thẻ chú `.khoi` ĐỨNG NGOÀI kiểu sổ
   * cái: bỏ nền/viền của nó là bỏ luôn cái vạch nhấn, thứ duy nhất nói «dòng
   * này là một lời chú». */
  #hom-nay-ra > .tam:not(.khoi), #hom-nay-ra .hai-cot .tam {
    background: none; border: 0; border-radius: 0;
    border-top: 1px solid var(--vien); padding-top: var(--k-4);
  }
  #hom-nay-ra > .tam:not(.khoi) h3, #hom-nay-ra .hai-cot .tam h3 {
    margin: 0 0 var(--k-3); font-family: var(--tieu-de); font-size: var(--cs-phu);
    letter-spacing: .12em; text-transform: uppercase;
  }

  #hom-nay-ra .lua-chon-luoi { display: block; margin-top: 0 }
  #hom-nay-ra .lua-chon {
    background: none; border: 0; border-radius: 0;
    border-bottom: 1px solid var(--vien); padding: var(--k-3) 0;
  }
  #hom-nay-ra .lua-chon:first-child { border-top: 1px solid var(--vien) }
}

/* ── Hướng dẫn dạng FAQ ─────────────────────────────────── */
/* `.hd-thanh` ĐỔI TÊN thành `.thanh-cong-cu` và DỜI về `nen.css` 01/09/2026 —
   chủ dự án chốt. Năm màn dùng nó, và chú thích của bốn màn đều phải ghi «theo
   khuôn hd-thanh» để giải thích vì sao mình mượn một lớp mang tên tab khác. */

.faq { border: 1px solid var(--vien); border-radius: var(--bo-lon); background: var(--tam); margin-bottom: var(--k-2) }
.faq > summary {
  /* Câu hỏi mang serif 15px: nó là TIÊU ĐỀ của khối trả lời, cùng họ với
   * h2/h3 — phần trả lời bên trong vẫn sans như thân bài. */
  cursor: pointer; padding: var(--k-3) var(--k-4); font-weight: 600; font-size: var(--cs-de);
  font-family: var(--tieu-de); letter-spacing: .01em;
  display: flex; gap: var(--k-2); align-items: baseline; list-style: none;
}
.faq > summary::-webkit-details-marker { display: none }
/* Mũi tên tự vẽ: dấu tam giác mặc định của trình duyệt khác nhau giữa Chrome và
   Firefox, và ở nền tối nó gần như không thấy. */
.faq > summary::before { content: '▸'; color: var(--chu-nhat); flex: 0 0 auto }
.faq[open] > summary::before { content: '▾'; color: var(--chu) }
.faq > summary:hover { background: var(--nen-luot); border-radius: var(--bo-lon) }
.faq[open] > summary { border-bottom: 1px solid var(--vien); border-radius: var(--bo-lon) var(--bo-lon) 0 0 }
.faq .dap { padding: 0px var(--k-4) var(--k-4) var(--k-6) }
.faq .dap p { line-height: var(--dong-chay) }
.faq .dap ol, .faq .dap ul { line-height: var(--dong-chay); padding-left: var(--k-5) }
.faq .dap table { margin: var(--k-3) 0 }
.faq .dap pre {
  background: var(--sau); border: 1px solid var(--vien); border-radius: var(--bo);
  padding: var(--k-3) var(--k-3); overflow-x: auto; font-size: var(--cs-phu);
}

/* Khối kỹ thuật — viền đứt để phân biệt ngay bằng mắt với phần trả lời chính. */
.kt { margin-top: var(--k-3); border: 1px dashed var(--vien-sang); border-radius: var(--bo); background: var(--sau) }
.kt > summary { cursor: pointer; padding: var(--k-2) var(--k-3); font-size: var(--cs-phu); color: var(--chu-nhat) }
.kt > summary:hover { color: var(--chu) }
.kt .noi { padding: 0 var(--k-3) var(--k-3); font-size: var(--cs-phu) }
.kt .noi p { line-height: var(--dong-chay); margin: var(--k-2) 0 }

/* Công tắc tổng ẩn HẲN, không chỉ đóng: người không cần phần kỹ thuật thì cũng
   không nên phải cuộn qua hàng chục khối đang đóng của nó. */
.an-ky-thuat .kt { display: none }

.nhom-faq {
  /* Cùng ngôn ngữ với nhãn nhóm thanh bên: in hoa giãn .12em. Là h2 nên nó
   * mang serif — chữ hoa serif giãn rộng là nhãn mục sách in đúng nghĩa. */
  /* ── BA THUỘC TÍNH ĐÃ XOÁ, VÀ VÌ SAO KHÔNG PHỤC HỒI — 02/09 ──
   * Khối này từng khai thêm `font-size: var(--cs-phu)` (12px), `border: 0` và
   * `padding: 0`. Cả ba CHẾT: `.trang-tai-lieu h2` ở `nen.css` cùng độ đặc
   * hiệu 0,1,1 và khai sau, nên tiêu đề nhóm thật ra vẽ 20px + gạch chân + đệm
   * dưới. Chú thích ngay trên đây tả một hình không tồn tại suốt từ đó.
   *
   * Chủ dự án chốt 02/09: GIỮ hình đang vẽ, xoá ý định. Trang Hướng dẫn có 21
   * nhóm và hơn trăm câu, nên tiêu đề nhóm là MỐC CUỘN — 20px có gạch chân
   * phục vụ việc ấy tốt hơn 12px. Xoá ba dòng chết thay vì phục hồi chúng, để
   * mã thôi hứa một hình mà nó không dựng được.
   *
   * Ba thứ CÒN SỐNG ở đây vì `.trang-tai-lieu h2` không khai lại chúng: chữ
   * hoa, giãn .12em, mực `--chu-nhat`. Đó là phần thật của cái nhãn mục sách. */
  margin: var(--k-6) 0 var(--k-3); font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--chu-nhat);
}
.nhom-faq:first-child { margin-top: var(--k-1) }

/* Nhãn đầu mỗi cột của tab Trần chi tiêu — CÙNG ngôn ngữ nhãn nhóm ở trên
 * (in hoa giãn .12em), vì nó làm đúng việc ấy: chia bảy ô trần thành hai nhóm
 * theo bán kính vụ nổ. Không mượn thẳng `.nhom-faq` vì đó là `h2` trong một
 * trang tài liệu phẳng, còn đây là `h3` đứng đầu một cột lưới — nhịp trên
 * dưới khác hẳn, và mượn tên là để một lần sửa trang Hướng dẫn đổi luôn tab
 * này. */
.tr-nhom {
  margin: 0; font-size: var(--cs-phu); font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--chu-nhat);
}

/* Nhóm vừa được một màn trỏ tới. Vệt tô tắt sau ~2 giây: nó trả lời câu "mình
   vừa được đưa tới đâu", và câu đó chỉ cần trả lời một lần. Dùng outline chứ
   không dùng background — background đổi chiều cao dòng, làm nhảy chỗ cuộn
   ngay khi người ta đang đọc. */
.nhom-faq.vua-toi {
  outline: 2px solid var(--thuong); outline-offset: 6px;
  border-radius: var(--bo-nho); transition: outline-color .5s;
}

/* Link "Hướng dẫn" chèn trong dòng tự-giới-thiệu ở đầu một tab. */
a.di-hd { color: var(--thuong); text-decoration: none; white-space: nowrap }
a.di-hd:hover { text-decoration: underline }

/* ── CỘT CỦA MỘT TAB TÀI LIỆU — khai MỘT lần ──────────────────
 *
 * Chủ dự án chốt 23/08/2026: áp cho mọi tab tài liệu, không riêng tab vừa sửa.
 *
 * `#khu` rộng 1500px, và đó là bề rộng của một BẢNG nhiều cột — Hàng đợi, Sổ
 * truy nguồn, Thư viện. Một tab mà chữ là chính thì ở bề rộng ấy dòng dài quá
 * tầm mắt và nút bị đẩy ra xa chỗ người ta đang đọc.
 *
 * 900px không phải số mới: `.huong-dan` đã mang nó từ lâu, và TÁM màn đang
 * mượn class ấy làm vỏ tài liệu (Ấn phẩm · Ví credit · Doanh nghiệp · Đội nhóm
 * · Tôi · Trí nhớ · Đăng nhập · Hướng dẫn). Tức là app đã có chuẩn này rồi, chỉ
 * là nó mang tên của một tab. Đặt tên đúng cho nó, và để `.huong-dan` giữ đúng
 * phần thuộc về riêng trang Hướng dẫn: kiểu chữ.
 *
 * ── VIỆC ẤY LÀM XONG NGÀY 01/09/2026, MỘT TUẦN SAU ───────────
 * Lượt 23/08 tách được nửa BỐ CỤC ra và đặt tên `.tai-lieu`. Nửa CHỮ thì ở lại,
 * và nó ở lại MANG NGUYÊN CÁI TÊN mà chính đoạn trên vừa nói là sai — bốn màn
 * tiếp tục mượn `.huong-dan` làm vỏ chữ thêm chín ngày.
 *
 * Nay nửa ấy tên `.trang-tai-lieu` và khai ở `nen.css`. Câu «đặt tên đúng cho
 * nó» của đoạn trên coi như đã thi hành trọn.
 *
 * Đáng ghi lại: chỗ hỏng này được CHẨN ĐÚNG từ 23/08, viết thành chữ, và vẫn
 * sống thêm chín ngày — vì chẩn đoán nằm trong một chú thích, không nằm trong
 * một phép thử. Nay nó có: `test-kieu` mục 6d và 6e.
 *
 * Tab Chuẩn thương hiệu là tab tài liệu DUY NHẤT không mượn class này — và đó
 * đúng là lý do nó rộng 1460px trong khi ô chữ bên trong rộng 700px.
 *
 * ── CHỦ DỰ ÁN CHỐT 23/08/2026: KHÔNG SỐ CỐ ĐỊNH NÀO ──────────
 * *"Set chiều rộng của các block là 100% khung chứa, không set theo giá trị cố
 * định nữa."*
 *
 * Bản đầu của đợt này đặt `.tai-lieu { max-width: 900px }` và giữ 78ch cho ô
 * chữ. Hai con số lồng nhau chính là bệnh cũ ở quy mô nhỏ hơn: thẻ một bề
 * rộng, chữ bên trong một bề rộng khác, và không cái nào giải thích được cái
 * kia. Nay **mọi block ăn trọn khung chứa nó**, và chỗ DUY NHẤT còn một con số
 * là vỏ ngoài cùng `#khu` (`vo.css`) — đó là khung của cả app, không phải của
 * một block.
 *
 * `.tai-lieu` ở lại làm móc ngữ nghĩa (tab dạng tài liệu) và làm chỗ treo thang
 * khoảng cách, không làm chỗ treo bề rộng.
 *
 * ── ÁP CHO MỌI MÀN, CÙNG NGÀY ────────────────────────────────
 * *"Đổi luôn các màn khác, không cố định nữa."* Nên `.huong-dan` — vỏ mà TÁM
 * màn đang mượn (Hướng dẫn · Ấn phẩm · Ví credit · Doanh nghiệp · Đội nhóm ·
 * Tôi · Trí nhớ · Đăng nhập) — cũng bỏ 900px, cùng bốn trần `ch` trên các khối
 * giải thích ở Media nguồn và Chi tiết ảnh.
 *
 * Sau lượt này, con số bề rộng DUY NHẤT còn lại trong app là `#khu` ở
 * `vo.css` (1500px) — vỏ của cả khu nội dung, không phải của một block. Muốn
 * bỏ nốt thì sửa đúng một dòng ở đó.
 *
 * KHÔNG đụng những chỗ con số là KÍCH THƯỚC CỦA VẬT: `.ct-anh` (cột ảnh 320px),
 * `.kd-the` (thẻ trong lưới flex), `.ng-tep-o` (chip tên tệp). Ở đó con số tả
 * chính vật thể, không tả bề rộng của một khối chữ — bỏ nó là lưới sập. */
/* `.tai-lieu` DỜI về `nen.css` 01/09/2026 — cả 20 màn đi qua nó, nên nó là lớp
   dùng chung nhất của app chứ không phải kiểu của một màn. Cả `width: 100%` lẫn
   luật nhịp `> * + *` đi cùng nhau; lý do đầy đủ ở đó. Hai luật `.tai-lieu > …`
   còn lại trong tệp này là ghi đè theo TAB, và chúng ở lại đúng chỗ. */


/* `.huong-dan` ĐỔI TÊN thành `.trang-tai-lieu` và DỜI về `nen.css` 01/09/2026 —
   chủ dự án chốt. Bốn màn dùng vỏ chữ này, và chỉ MỘT trong bốn là tab Hướng
   dẫn. Lý do đầy đủ ở `nen.css`, gồm cả cái va tên mà lượt đổi này gỡ được. */

/* ── MỤC LỤC DÍNH — 29/08/2026 ────────────────────────────────
 *
 * Trang Hướng dẫn có 21 nhóm và hơn trăm câu; vào thẳng tab này là rơi xuống
 * đầu một trang dài mà không có bản đồ. Cột phải dùng `.phai.bam` có sẵn nên
 * phần dính, phần tự cuộn và phần thôi-dính-khi-hẹp đã có luật, không dựng lại.
 *
 * Ở đây chỉ còn cái danh sách, và nó cố ý NHẸ: mục lục là chỗ để liếc, không
 * phải chỗ để đọc. Cỡ `--cs-phu`, mực mờ, không viền, không nền — thứ duy nhất
 * đậm lên là mục ĐANG ĐỌC.
 *
 * `scroll-margin-top` trên chính các tiêu đề: bấm một mục thì trình duyệt cuộn
 * tiêu đề lên đúng mép trên cửa sổ, mà mép ấy đang bị dải tiêu đề màn che. Thiếu
 * dòng này thì mọi cú bấm đều đưa người dùng tới một tiêu đề nằm khuất. */
/* Đường SANG TAB, gắn vào chính tiêu đề nhóm. Nhẹ hơn tiêu đề hẳn một bậc và
   đẩy sang phải: nó là lối đi RA, không phải một phần của cái tên. `margin-left:
   auto` trong một tiêu đề flex đẩy nó tới mép — mắt quét tên nhóm ở cột trái,
   gặp đường đi ở cột phải, không thứ nào chen thứ nào. */
.trang-tai-lieu h2.nhom-faq { display: flex; align-items: baseline; gap: var(--k-3); flex-wrap: wrap }
.nhom-di {
  margin-left: auto; font-size: var(--cs-phu); font-weight: 400;
  color: var(--lien-ket); text-decoration: none; white-space: nowrap;
}
.nhom-di:hover { text-decoration: underline }

/* ── DẢI CÔNG CỤ CỦA TRANG HƯỚNG DẪN — bản vẽ N3, 30/08/2026 ──
 *
 * Lớp RIÊNG, không tô nền cho `.hd-thanh`: lớp ấy đang là khuôn đầu tab của
 * tám màn khác, và một dòng nền ở đó đổi cả tám cùng lúc.
 *
 * `position: sticky` vì đây là chỗ người ta quay lại nhiều lần trong một trang
 * dài trăm câu — ô tìm cuộn mất là ô tìm phải cuộn ngược lên mới gõ tiếp được.
 * Bám ngay dưới `#dau-man`, cùng cách `.phai.bam` đã đo. */
/* Chiều cao khai THÀNH TOKEN (`--cao-hd-cong-cu`, ở `nen.css` cùng chỗ mọi
 * token khác) vì hai chỗ phải biết nó: chính dải này, và `--cao-dinh` mà cột
 * mục lục dính đọc để không bám lên nằm khuất sau nó. Hai con số gõ tay ở hai
 * chỗ là hai con số sẽ lệch nhau. */
.hd-cong-cu {
  position: sticky; top: var(--cao-dau-man); z-index: var(--lop-dinh-tren);
  display: flex; align-items: center; gap: var(--k-3); flex-wrap: wrap;
  height: var(--cao-hd-cong-cu); box-sizing: border-box;
  margin-bottom: var(--k-2); padding: var(--k-2) 0;
  background: var(--nen); border-bottom: 1px solid var(--vien);
}
/* Ô tìm ăn hết chỗ thừa, nhưng có SÀN — co xuống dưới 200px thì placeholder
   cụt mất và ô thôi nói được nó dùng để làm gì. */
.hd-tim { flex: 1 1 200px; min-width: 0 }
/* Bộ đếm về mép phải, và KHÔNG bao giờ chen với hai nút: ở khổ hẹp nó xuống
   dòng cùng cả dải nhờ `flex-wrap` ở trên. */
.hd-dem { margin-left: auto; white-space: nowrap }
.hd-chu-kt { margin: 0 0 var(--k-4); font-size: var(--cs-nho) }

/* Cột đọc KHÔNG có trần bề rộng — chủ dự án chốt 30/08 sau khi nhìn màn thật.
 *
 * Bản trước khai `max-width: 900px` theo bản vẽ N3, với lý lẽ «chữ liền chạy
 * 1100px thì mắt lạc dòng». Lý lẽ ấy đúng cho một trang chữ TRẦN, nhưng trang
 * này không phải: mỗi câu là một thẻ `.faq` có viền, và trần bề rộng chỉ đẩy ra
 * một dải trống bên phải mỗi thẻ — bề rộng của thẻ vẫn là bề rộng của cột. Nên
 * nó không mua được gì, chỉ để lại chỗ trống. Quay về luật chung của chốt
 * 23/08: mọi block ăn trọn khung chứa. */

/* ── MỤC LỤC DẠNG SƠ ĐỒ CÂY — 30/08/2026 ─────────────────────
 * Đầu cột: dòng nhãn + hai nút «mở tất cả» / «đóng tất cả». Hai nút ấy vốn ở
 * dải công cụ, mà dải ấy cuộn khỏi tầm từ màn hình thứ hai — ở đây thì chúng
 * dính cùng cột và bấm được bất cứ lúc nào. */
.hd-ml-dau {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--k-2); flex-wrap: wrap; margin-bottom: var(--k-2);
}
.hd-ml-dau > .hd-ml-de { margin: 0 }
/* Dòng TAB — bậc một của cây. Số thứ tự đi theo menu trái, nên đọc mục lục là
   đọc đúng trật tự người dùng đã quen ở thanh bên. */
.hd-ml-tab { margin-top: var(--k-2) }
.hd-ml-tab:first-child { margin-top: 0 }
.hd-ml-tab > a, .hd-ml-tab > .hd-ml-ten { font-weight: 600; color: var(--chu) }
.hd-ml-stt { flex: 0 0 auto; color: var(--chu-mo); font-variant-numeric: tabular-nums }
.hd-ml-ten { flex: 1; min-width: 0 }
/* Nhánh CON — thụt vào một bậc và có vạch dọc, để mắt đọc ra quan hệ cha–con
   mà không cần đọc chữ. Vạch nằm ở `border-left` của chính dòng, không phải
   một ký tự vẽ — ký tự thì trình đọc màn hình đọc lên thành rác. */
.hd-ml-ds a.sau {
  margin-left: var(--k-3); padding-left: var(--k-3);
  border-left: 1px solid var(--vien); border-radius: 0;
}
.hd-ml-ds a.sau.dang { border-left-color: var(--thuong-chu) }
/* Nhánh «Không thuộc tab nào»: một nhãn, không phải một đường đi. */
.hd-ml-tab > .hd-ml-ten { display: block; padding: var(--k-1) var(--k-2); color: var(--chu-nhat) }

.hd-ml-de {
  margin: 0 0 var(--k-2); font-size: var(--cs-nho); font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--chu-mo);
}
/* Số câu của mỗi nhóm — đẩy về mép phải mục lục, nhẹ hơn tên hẳn một bậc: nó
   là chú thích cho cái tên, không phải một phần của tên. Luật `display` nằm
   trong chính khối `.hd-ml-ds a` bên dưới, không khai đè ở đây: hai luật cùng
   hạng thì luật SAU thắng, và một dòng đè ngược lên đúng thứ mình vừa đặt là
   cách chắc chắn nhất để mất nửa giờ tìm. */
.hd-ml-so { margin-left: auto; font-size: var(--cs-nho); color: var(--chu-mo) }
.hd-ml-ds a.dang .hd-ml-so { color: var(--chu-nhat) }
.hd-ml-ds { margin: 0; padding: 0; list-style: none }
.hd-ml-ds a {
  display: flex; align-items: baseline; gap: var(--k-2);
  padding: var(--k-1) var(--k-2);
  border-left: 2px solid transparent; border-radius: 0 var(--bo-nho) var(--bo-nho) 0;
  font-size: var(--cs-phu); line-height: var(--dong-chat); color: var(--chu-nhat);
  text-decoration: none;
}
.hd-ml-ds a:hover { background: var(--nen-luot); color: var(--chu) }
/* Mục đang đọc: vạch trái cộng mực đậm. Hai tín hiệu, vì một vạch 2px mà không
   đổi mực thì ở cột 260px mắt không bắt được. */
.hd-ml-ds a.dang {
  border-left-color: var(--thuong-chu); color: var(--chu); font-weight: 600;
  background: var(--nen-luot);
}
.trang-tai-lieu h2.nhom-faq { scroll-margin-top: calc(var(--cao-dau-man) + var(--k-4)) }
.trang-tai-lieu .faq { scroll-margin-top: calc(var(--cao-dau-man) + var(--k-4)) }

/* ── v9 — Bàn dựng ảnh bốn khối ─────────────────────────────
 * Hai cột, và khối 4 CỐ Ý trông khác ba khối kia: nó ra lệnh ngược lại
 * ("bỏ qua mọi vật trong ảnh này"), nên bố cục tự dạy người dùng cái phân
 * biệt làm nên tính năng. Đó là thông tin, không phải trang trí. */
/* `auto-fit` chứ không phải `1fr 1fr` — 28/08/2026. Sau khi tab tách hai cột,
   lưới này không còn nằm trên cả bề ngang trang mà nằm trong CỘT TRÁI, và bề
   rộng cột trái đổi theo cửa sổ chứ không theo một ngưỡng @media nào. Một luật
   `1fr 1fr` cứng cho hai khối 280px cạnh nhau trong một cột 560px thì vừa,
   trong cột 420px thì cả hai đều vỡ — mà @media thì đo cửa sổ, không đo cột. */
.bd-luoi { display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); gap: var(--k-3) }

/* ── «Ảnh này dùng vào việc gì» SANG CỘT PHẢI — 28/08/2026 ───
   Luật cũ ở đây là `grid-column: 1 / -1` — cho nó chiếm trọn một hàng của
   `.bd-luoi`, vì nó nói về ĐẦU RA giữa năm khối nói về đầu vào, và ở nửa bề
   ngang thì năm nhóm nút của nó mỗi nhóm xuống hai ba dòng.

   Nay nó rời hẳn sang cột phải, đứng trên nút bậc 1 — cùng lý lẽ «đầu ra khác
   loại với đầu vào», chỉ giải bằng CỘT thay vì bằng một hàng chiếm trọn. Luật
   `grid-column` đi theo: nó là một khối của lưới nào nữa đâu mà giữ.

   ĐO TRƯỚC KHI CHUYỂN, vì lo cũ là năm nhóm nút sẽ vỡ dòng ở cột hẹp hơn:

     1160px (chỗ cũ)          năm nhóm mỗi nhóm một dòng · thẻ cao 349px
     620px  (thanh bên gập)   y hệt — 349px, không nhóm nào vỡ
     556px  (thanh bên mở)    một nhóm «Chừa chỗ cho chữ» xuống hai dòng · 392px

   Lo cũ nói «ở nửa bề ngang thì MỖI nhóm xuống hai ba dòng» — con số ấy đúng
   cho nửa của một ô lưới 270px, không đúng cho một cột 556px. Một nhóm xuống
   hai dòng, không nhóm nào tràn. */



/* Ảnh ĐANG CHỌN trong một khối — 23/08/2026 khối thôi bày cả kho, nên không
   còn trạng thái «chưa chọn» ở đây: mọi tấm trong dải này đều đang được dùng. */
.bd-hang-anh { display: flex; flex-wrap: wrap; gap: var(--k-2) }
.bd-anh {
  position: relative; line-height: 0;
  border: 2px solid var(--vien-chon); border-radius: var(--bo-nho);
}
.bd-anh img { width: 64px; height: auto; display: block; border-radius: var(--bo-nho) }

/* Nút bỏ một tấm ra khỏi khối. Nằm ĐÈ lên ảnh vì nó nói về đúng tấm ấy — một
   hàng nút dưới dải thì phải đếm để biết nút nào ứng với ảnh nào.

   ── ĐÂY LÀ PHẦN RIÊNG CỦA CHỦ, HÌNH CHUNG Ở `nen.css` — 01/09/2026 ──
   Việc Ⓕ gộp ba cái tên (`.the-xoa` · `.kpc-go` · `.bd-bo`) về một lớp `.nut-bo`.
   Lúc đề xuất tôi nói ba nút ấy «khác nhau đúng chỗ đứng». Đo lại thì KHÔNG chỉ
   thế: chúng còn khác hình (tròn so với bo góc) và khác màu lúc trỏ vào. Nên
   phần chung về `nen.css`, còn ba khoản chênh thật thì ở lại với chủ của chúng —
   ghi ra chứ không gộp bừa, vì gộp bừa là đổi hình mà không ai chốt.

   Chênh của chủ này: TRÒN, tràn ra ngoài mép ảnh, và lúc trỏ vào thì TÔ ĐẶC màu
   dừng — nó xoá một tấm khỏi khối, không phải mở một bảng.

   Kích thước thì THÔI là chênh, 07/09/2026: chủ này từng gõ 18px và chủ `.kpc-o`
   gõ 20px, hai con số không ai giải thích được, cả hai dưới vùng chạm nhỏ nhất.
   Nay cả hai đọc `--cham`. Hình vẫn khác nhau — tròn hay bo góc, trong hay ngoài
   mép — nhưng CHẠM TRÚNG thì không phải sở thích của một chủ. */
.bd-anh .nut-bo {
  top: -7px; right: -7px; width: var(--cham); height: var(--cham);
  padding: 0; font-size: var(--cs-ban); border-radius: 50%;
  border-color: var(--vien);
}
.bd-anh .nut-bo:hover { background: var(--vien-dung); border-color: var(--vien-dung); color: var(--nen) }

/* Hạn đồng ý — v15 bước 5. Dấu nằm TRÊN ô chọn, không đợi tới lúc bấm Tạo.
   Chỉ hai mức KÊU mới có dấu: `chua-han` để im, vì đặt hạn là tuỳ chọn và một
   dấu luôn hiện là một dấu người ta thôi đọc (`src/dong-y.js`). */
.bd-anh > .nhan {
  position: absolute; left: 0; right: 0; bottom: 0;
  line-height: var(--dong-chat); padding: 1px var(--k-0); text-align: center;
  white-space: normal; border-radius: 0 0 var(--bo-nho) var(--bo-nho);
}
.bd-dy-het-han { border-color: var(--vien-dung) }
.bd-dy-sap-het { border-color: var(--vien-chan) }

/* HÀNG Ô NHẬP đặt tên vai cho từng ảnh. Xếp thành cột hẹp cùng bề rộng, để
   mắt đọc được «mấy tấm này là mấy thứ khác nhau» mà không phải dò từng dòng.
 *
 * Tên cũ là `.bd-vai`, và chính cái tên ấy đã gây ra một lỗi: nó đọc y hệt
 * NHÃN VAI `.khoi-vai` bên `nen.css` — một `<span>` in hoa cỡ nhỏ đẩy về mép
 * phải. 15 chỗ thuộc 13 tệp đã mượn nhầm tên này cho nhãn, và không lỗi nào
 * báo vì lớp có tồn tại: nhãn chỉ lặng lẽ nhận `display: flex` của một hàng ô
 * nhập, mất `margin-left: auto` nên không về mép phải, mất luôn cỡ chữ và in
 * hoa. Chữ `ô` là thứ phân biệt: đây là chỗ NHẬP, không phải chỗ ĐỌC. */
.bd-o-vai { display: flex; flex-wrap: wrap; gap: var(--k-2) }
.bd-o-vai input { flex: 1 1 130px; min-width: 0; font-size: var(--cs-phu); padding: var(--k-1) var(--k-2) }

/* Nhãn của một nhóm nút chọn trong ô «Ảnh này dùng vào việc gì». */
.bd-nhan { display: block; margin: var(--k-1) 0 0 }

/* ── HÀNG CHIP CHỈ CHỞ MỘT CHỮ SỐ — 29/08/2026 ────────────────
 *
 * `.mieng` đệm `--k-1 --k-2` (4/8) vì nó thường chở một cụm chữ, và ở đó đệm
 * ngang rộng hơn là đúng. Một chữ số thì không: ô ra hình chữ nhật nằm, và mắt
 * đọc nó thành một cái nhãn chứ không thành một lựa chọn bấm được.
 *
 * Đệm bốn chiều bằng nhau cộng `min-width` bằng chiều cao cho ra một ô VUÔNG —
 * hình mà mọi bộ chọn số lượng đều dùng, nên không ai phải học lại.
 *
 * Ô đang chọn tô `--thuong` (mảng đặc, chữ trên nền màu) chứ không `--chon`
 * (nền mờ): trong một hàng tám ô giống hệt nhau, một nền mờ không đủ nói ô nào
 * đang được chọn — chủ dự án chấm đúng chỗ ấy. `--thuong` là màu nhấn khi nó
 * làm MẢNG TÔ, và cặp `--chu-tren-mau` đã được `test-mau` đo tương phản. */
/* Ô VUÔNG = `--cao-dk` × `--cao-dk`, không phải «bỏ trần chiều cao».
 *
 * `.mieng` là `<button>`, nên nó nhận trần 40px của quy tắc nền. Đo lần đầu ra
 * 30×40 — đệm đã bằng bốn chiều rồi mà hộp vẫn chữ nhật, vì bề rộng co theo
 * một chữ số còn chiều cao thì bị trần kéo.
 *
 * Cách chữa KHÔNG phải gỡ trần (như đã làm cho nút biểu tượng): những chip này
 * đứng cùng hàng với chip khổ ảnh và chip mức nét, và trần sinh ra đúng để cả
 * hàng ấy cao bằng nhau. Nên kéo BỀ RỘNG lên bằng trần — ô vuông 40×40, cao
 * đúng bằng hàng bên cạnh. */
.chip-so .mieng {
  padding: var(--k-2); min-width: var(--cao-dk);
  justify-content: center; font-variant-numeric: tabular-nums;
}
.chip-so .mieng.chon {
  background: var(--thuong); border-color: var(--thuong); color: var(--chu-tren-mau);
  font-weight: 600;
}

/* ── Hộp chọn ảnh — DÙNG CHUNG (23/08/2026) ─────────────────
   Lưới ô vuông, không phải thẻ ngang như Media nguồn: ở đây người ta CHỌN bằng
   mắt, không đọc hồ sơ. Khung cuộn có trần chiều cao để hàng nút của hộp luôn
   nhìn thấy được — cuộn tới cuối mới thấy nút Xong là một hộp trông như không
   có lối ra.

   Tiền tố đổi `bd-kho-` → `kho-anh-` cùng ngày, khi hộp rời `ghep-anh-that-kho.js`
   sang `web/man/kho-anh-hop.js` để tab Chuẩn thương hiệu dùng chung. `bd-` là
   viết tắt của Bàn dựng, và một class mang tên một tab rồi được ba tab dùng là
   đúng cái nhầm mà `.huong-dan` ở trên vừa phải gỡ. */
.kho-anh-than { max-height: min(56vh, 460px); overflow-y: auto }
.kho-anh-luoi { display: grid; gap: var(--k-2); grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)) }
.kho-anh-the {
  /* Nút kiểu HÀNG: nội dung dồn về trái, không nhận `center` của quy tắc nền
     `button` — nếu không, thẻ nhãn ngắn bị đẩy ảnh vào giữa và cột ảnh so le
     (đo ở lưới chọn ảnh Hậu kỳ: lề trái ba thẻ liền nhau ra 72 · 9 · 68px). */
  justify-content: flex-start;
  display: flex; flex-direction: column; gap: var(--k-1); padding: var(--k-1); text-align: left;
  border: 2px solid var(--vien); border-radius: var(--bo); background: var(--tam);
}
.kho-anh-the:hover { border-color: var(--vien-chon) }
.kho-anh-the.chon { border-color: var(--vien-chon); background: var(--chon) }
.kho-anh-the img {
  width: 100%; aspect-ratio: 1; object-fit: cover;
  border-radius: var(--bo-nho); background: var(--nen-anh); display: block;
}
.kho-anh-ten {
  font-size: var(--cs-nho); line-height: var(--dong-chat); color: var(--chu-nhat);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

.bd-muc {
  display: flex; gap: var(--k-2); align-items: flex-start; cursor: pointer;
  border: 1px solid var(--vien); border-radius: var(--bo);
  padding: var(--k-2) var(--k-3); margin-bottom: var(--k-1);
}
.bd-muc.chon { border-color: var(--canh) }
.bd-muc input { margin: var(--k-1) 0 0; flex: none }

/* ── Ba lựa chọn loại trừ nhau, xếp NGANG — 28/08/2026 ───────
 *
 * `.bd-muc` xếp dọc là đúng khi các mục dài ngắn khác nhau hoặc nhiều hơn ba.
 * Với ĐÚNG BA nhánh của một câu hỏi, mỗi nhánh một câu hệ quả, xếp dọc tốn gần
 * 200px chiều cao và đẩy nút kết thúc chuỗi xuống dưới mép màn ở khổ 1536×864.
 *
 * `auto-fit` + `minmax` chứ không `repeat(3, 1fr)`: dưới 250px một cột thì ba
 * câu hệ quả thành ba cột chữ bẻ vụn, và lúc ấy dọc mới là bố cục đúng. Lưới tự
 * quyết theo chỗ nó ĐANG có, nên nó cũng đúng khi khối này nằm trong một cột
 * hẹp — cùng lý lẽ với `@container` của `.hai-cot`.
 *
 * Lề dưới của `.bd-muc` phải gỡ: `gap` đã lo khoảng cách, để cả hai là hàng
 * cuối cách khối dưới nó gấp đôi mọi khoảng khác. */
.muc-hang {
  display: grid; gap: var(--k-2); align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
.muc-hang .bd-muc { margin-bottom: 0; height: 100% }

/* ── Kho nguồn ──────────────────────────────────────────────
 * Thẻ ngang: ảnh bên trái giữ đúng tỉ lệ thật, chữ bên phải. Bản đầu xếp
 * ảnh trên chữ dưới trong cột hẹp 190px, và với một hai nguồn thì màn hình
 * rộng gần như trống trơn — chủ dự án báo 17/08/2026. */
.ng-nhom { margin: var(--k-5) 0 var(--k-3); font-size: var(--cs-chinh) }
/* ── 340px → 260px, sau khi lưới vào một CỘT — 28/08/2026 ────
 *
 * `minmax(340px)` ra đời lúc lưới còn nằm trên cả bề ngang trang. Đợt 2b đưa
 * nó vào cột trái của `.hai-cot`, và ở đó con số cũ cho đúng HAI ô một hàng:
 * đo trong app ở 1700px, cột trái 881px, thẻ ra 435px — to gấp đôi bản vẽ, và
 * quét 26 tấm bằng mắt mất ba màn hình. Cùng họ với lỗi `@media` của đợt 2a:
 * một con số đo cho khung cũ, im lặng sai sau khi khung đổi.
 *
 * 260px cho ba ô × 286px, cột trái 3182 → 2718px. Bản vẽ D5a vẽ BỐN ô, và đợt
 * này cố ý không theo: bốn ô của bản vẽ đi kèm một cái thẻ chỉ chở tên + một
 * dòng, trên một tấm ảnh CẮT cao 150px. Thẻ ở đây chở thêm huy hiệu đồng ý
 * (v14 bước 5 — thứ duy nhất trong kho có hệ quả ngoài phần mềm) và huy hiệu
 * «đang được đọc / chưa được đọc» của trần 6 tấm. Dựng thử cả hai 28/08: lưới
 * bốn ô đúng bản vẽ cho cột trái 2751px — KHÔNG hơn ba ô ở đây một chút nào,
 * mà phải trả bằng năm tín hiệu và bằng chốt 17/08 «ảnh giữ đúng tỉ lệ thật». */
.ng-luoi { display: grid; gap: var(--k-3); grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)) }
.ng-the { display: flex; gap: var(--k-3); align-items: flex-start; margin: 0 }
.ng-anh { flex: 0 0 120px }
.ng-anh img, .ng-anh video { width: 100%; height: auto; display: block; border-radius: var(--bo) }
.ng-chu { min-width: 0; flex: 1 }

/* Thẻ TIẾNG giữ nguyên hình dáng thẻ, chỉ hẹp ô ảnh lại: không có tấm ảnh nào
   để nhìn, nhưng cái nút mở chi tiết thì vẫn phải ở đó — mọi thẻ trong kho mở ra
   bằng cùng một cú bấm vào ô bên trái.

   Máy phát nằm bên CỘT CHỮ, không nằm trong ô 120px: nút play, thanh chạy và
   đồng hồ của trình duyệt chen nhau ở bề ngang ấy tới mức không bấm trúng. */
.ng-the-tieng { flex-wrap: wrap }
.ng-the-tieng .ng-anh { flex: 0 0 56px }
.ng-tieng-o {
  display: grid; place-items: center; aspect-ratio: 1; border-radius: var(--bo);
  background: var(--nen-anh); border: 1px solid var(--vien); font-size: var(--cs-so); color: var(--chu-nhat);
}
.ng-tieng { display: block; flex: 1 0 100%; width: 100%; margin: var(--k-2) 0 0 }

@container khu (max-width: 640px) { .ng-the-tieng .ng-anh { width: 56px } }

/* Điện thoại: LƯỚI hai cột thay vì một cột thẻ ngang. Lý lẽ ở trên (ảnh trái,
 * chữ phải để không bỏ trống bề ngang) đúng cho máy tính, nơi 340px vẫn còn
 * dư chỗ — nhưng dưới 640px, `auto-fill, minmax(340px,1fr)` ép về đúng MỘT
 * cột, và bây giờ bề ngang lại là thứ khan hiếm. Hai cột thẻ đứng (ảnh trên,
 * chữ dưới) quét bằng mắt nhanh hơn một cột thẻ ngang cao gấp đôi. */
@container khu (max-width: 640px) {
  .ng-luoi { grid-template-columns: 1fr 1fr; gap: var(--k-3) }
  .ng-the { flex-direction: column }
  .ng-anh { flex: none; width: 100% }
}
.ng-chu p { word-break: break-word }

/* Vùng kéo–thả trong TỪNG khối của bàn dựng. Bản HTML chủ dự án duyệt có nó ở
   mỗi khối; tách sang màn khác là bắt đi hai màn cho một việc. */
.bd-tha {
  border: 1.5px dashed var(--vien-sang); border-radius: var(--bo);
  background: var(--sau); padding: var(--k-3) var(--k-4); cursor: pointer;
}
.bd-tha:hover, .bd-tha.roi { border-color: var(--vien-chon); background: var(--chon) }
.bd-tha:focus-visible { outline: 2px solid var(--canh); outline-offset: 2px }

/* ── Bảng sửa ảnh nguồn (v11) ───────────────────────────────
 * Điều khiển bên trái, xem trước bên phải. Xem trước LUÔN là hai ảnh cạnh
 * nhau: mọi phép ở đây là chỉnh nhẹ, và một mình bản đã sửa thì không nói
 * được nó có tốt hơn không — mắt người thích nghi trong hai giây. */
.ns-luoi { display: grid; grid-template-columns: 300px minmax(0, 1fr); gap: var(--k-4); align-items: start }
@container khu (max-width: 900px) { .ns-luoi { grid-template-columns: 1fr } }

.ns-dieu-khien { display: flex; flex-direction: column; gap: var(--k-3) }
.ns-dong { display: flex; flex-direction: column; gap: var(--k-1); font-size: var(--cs-ban) }
.ns-dong input[type=range] { width: 100% }
.ns-dong input[type=checkbox] { margin-right: var(--k-2) }
label.ns-dong { flex-direction: row; align-items: flex-start; cursor: pointer }

.ns-so { display: grid; grid-template-columns: 1fr 1fr; gap: var(--k-2) }
.ns-so img { width: 100%; height: auto; display: block; border-radius: var(--bo); margin-top: var(--k-1) }

/* Ảnh NGANG: hai HÀNG thay vì hai cột — xem chú thích `anhNgang` trong
 * `web/man/media-nguon-sua.js`. Chia đôi bề rộng cho một tấm ngang làm nó cao còn
 * ~230px, và ở cỡ đó thì mịn da, giảm nhiễu và làm nét trông y hệt nhau. */
.ns-so-hang { grid-template-columns: 1fr }

/* ── Kịch bản · form sửa một cảnh ────────────────────────────
 *
 * Bố cục theo BA CÂU HỎI người dùng đang trả lời, không theo thứ tự cột của
 * bảng phân cảnh — xem chú thích đầu `web/man/kich-ban-ngan-form.js`. Mỗi bước có
 * một dải tiêu đề, và MỌI ô đều có nhãn nhìn thấy được: bản trước dùng
 * placeholder, mà ô có nội dung thì placeholder biến mất và ô thành vô nghĩa. */
/* ── TIÊU ĐỀ THẬT, KHÔNG PHẢI MỘT DẢI GHI CHÚ — 23/08/2026 ────
 *
 * Chủ dự án chấm đúng bằng chữ *"dễ bị nhầm lẫn là ghi chú"*, và số đo xác
 * nhận: bản trước là 12px — NHỎ HƠN thân bài 14px nó đang dẫn đầu — bọc trong
 * một nền `--sau` + vạch trái, tức là CÙNG ngôn ngữ hình khối với `.chan` và
 * `.o-may` (nền chìm + vạch màu = "đây là một ghi chú, đọc kỹ hoặc bỏ qua").
 * Một tiêu đề mang đúng hình dạng của một ghi chú thì đọc ra là ghi chú, bất
 * kể đứng ở đâu.
 *
 * Sửa bằng chữ, không bằng hộp — nền `--sau` đã cạn tác dụng (đo 1,1–1,2:1 với
 * nền thẻ, dưới ngưỡng mắt tách được hai mảng phẳng). `h1,h2,h3` toàn app đã
 * dùng `--tieu-de` (`nen.css`) làm tiêu đề thật; `.kf-buoc` là `<p>` nên không
 * thừa hưởng — cho nó mượn cùng họ chữ, cùng cỡ lớn hơn thân bài, cùng gạch
 * chân mảnh mà `.huong-dan h2` đã dùng, để nó đọc đúng vai: tiêu đề của một
 * KHỐI, không phải một dòng phụ chú.
 *
 * `display: flex` để nhận thêm một `.nhat` cuối dòng (nhãn nguồn, link Hướng
 * dẫn) mà không phá gạch chân — nó đẩy sang phải bằng `margin-left: auto`
 * ngay ở chính `.nhat` khi đứng trong `.kf-buoc`, không cần class riêng.
 *
 * ── ĐÃ GỘP VÀO `.tam h3` — ĐỢT 7, 31/08/2026 ─────────────────
 * Lớp này đi hẳn. 47 chỗ dùng nó đổi sang `<h3>`, và hình gộp về `.tam h3`
 * (`nen.css`) theo chốt của chủ dự án: mực mờ, không gạch chân, tách hai khối
 * bằng lề trên `--k-4`.
 *
 * Hai thứ của nó được GIỮ vì chúng là khả năng thật, không phải trang trí:
 * `display: flex` để nhận một `.nhat` cuối dòng, và lề trên để tách hai khối.
 * Hai thứ bị BỎ: gạch chân, và `letter-spacing: .01em` — quy tắc nền
 * `h1,h2,h3` đã khai `-.015em`, đúng luật mục 04 cho cỡ từ `--cs-de` trở lên.
 *
 * Thứ đáng ghi lại nhất: nó là một `<p>`. Đó là lý do nó thua cái THẺ dù thắng
 * cái HÌNH ở mọi điểm khác — 47 mục dựng bằng `<p>` thì không lên cây tiêu đề,
 * nên trình đọc màn hình không liệt kê được chúng. Một lối tiêu đề vẽ đúng mà
 * khai sai loại thẻ thì nó chỉ đúng với người đang NHÌN. */

/* ── PHÂN CẤP: NHÃN → GIẢI THÍCH → Ô NHẬP ───────────────────
 *
 * Chủ dự án chấm 7/10 (17/08/2026): *"chưa thật sự sắc nét, rõ ràng giữa tiêu
 * đề và trường nhập liệu"*. Bản trước nhãn 13px đậm nằm ngay trên một dòng giải
 * thích cũng cỡ đó — ba mức thông tin (nhãn · giải thích · ô) trông gần bằng
 * nhau, nên mắt phải đọc mới biết cái nào là cái nào.
 *
 * Sửa bằng KHOẢNG CÁCH và ĐỘ TƯƠNG PHẢN chứ không thêm đường kẻ:
 *   · trong một nhóm thì SÁT nhau (nhãn 3px, giải thích 6px)
 *   · giữa hai nhóm thì XA hẳn (20px)
 *   · nhãn to hơn, đậm hơn, sáng hơn; giải thích nhỏ hơn và mờ đi
 * Đó là quy tắc gần-xa: thứ gì thuộc về nhau thì đứng gần nhau. */
/* `.kf-o-chu` và `.kf-nhan` ĐỔI TÊN thành `.truong` và `.truong-nhan`, DỜI về
   `nen.css` 01/09/2026 — chủ dự án chốt. Bốn tab dùng cặp này, và tên cũ hứa
   một cái ô mà khối này không hứa (một chỗ dùng thật không chở ô nào). Cả khối
   chú thích quy tắc gần-xa ở trên đi theo chúng; lý do đầy đủ ở đó. */

/* `input[type=text]` có mặt ở đây vì một ô chữ một dòng trong khối này phải
 * trông y hệt ô nhiều dòng — bản trước chỉ nuôi `textarea`, nên ô «Tên phim»
 * của tab Kịch bản phim thiếu cả bề rộng lẫn nền. Xem thêm chú thích `type` ở
 * `nen.css`: thẻ thiếu thuộc tính `type` thì không bộ chọn nào khớp nó.
 *
 * ── KHỐI NÀY TỪNG LẤY ĐI HAI THỨ CỦA TẦNG NỀN — gỡ 01/09/2026 ──
 * Việc ① của `../../docs/kien-truc/chuan-cau-truc-giao-dien.md` (luật K1 · B3).
 * Bản trước còn khai `background` · `border` · `border-radius`, cộng một luật
 * `:focus` riêng. Đo từng dòng thì ba dòng đầu hoặc THỪA hoặc SAI, và luật
 * `:focus` thì chỉ còn một tác dụng thật: trừ đi.
 *
 *   `background: var(--sau)`     → `nen.css` đã cho mọi ô chữ đúng màu ấy. Thừa.
 *   `border-radius: var(--bo)`   → cũng thế. Thừa.
 *   `border: 1px solid var(--vien)` → **SAI TOKEN.** Mục 3.2 sổ tay nhận diện
 *       tách hai loại viền: `--vien` là TRANG TRÍ (chỉ cần thấy được), `--vien-nut`
 *       là ĐIỀU KHIỂN và WCAG 1.4.11 đòi ≥3:1. Đo trong trình duyệt 01/09:
 *
 *         --vien-nut trên --sau  3,37   trên --tam  3,96   ✔ đạt
 *         --vien     trên --sau  1,16   trên --tam  1,37   ✘
 *
 *       Ba họ ô của form sửa cảnh mang viền 1,16 ở chỗ chuẩn đòi 3,0. `test-mau`
 *       không thấy: nó đo TOKEN có đạt ngưỡng không, không đo token ấy được
 *       dùng ở đâu. Lưới gác hai đầu, hở đúng khúc giữa.
 *
 *   `:focus { border-color: …; outline: none }` → nửa đầu THỪA, nửa sau HẠI.
 *       `nen.css:645` đã khai `input/textarea/select:focus-visible` với ĐÚNG
 *       `border-color: var(--vien-chon)` cộng một vòng ngoài 2px. Và
 *       `:focus-visible` khớp cả khi bấm CHUỘT vào ô chữ — đo bằng chuột thật
 *       trên `textarea`, `input[type=text]` và `input[type=number]`, cả ba đều
 *       `:focus-visible = true`. Nên nửa `border-color` không mua thêm gì.
 *
 *       Nửa `outline: none` thì lấy đi vòng ngoài ấy, và nó THẮNG vì hạng riêng
 *       (0,2,1) cao hơn (0,1,1) của quy tắc nền. Đo bằng một cú Tab thật:
 *       ô trong khối này ra `outline: 2.4px none`, ô thường ra `2.4px solid`.
 *       Người dùng bàn phím mất dấu ở ba họ ô — và đó là tín hiệu DUY NHẤT họ có.
 *
 * Bài học ở lại: **tầng màn không được lấy đi thứ tầng nền đã hứa.** Muốn hình
 * khác thì khai một biến thể (`.tam.khoi` là tiền lệ đúng), đừng đè lên gốc.
 *
 * ── LUẬT NÀY TÁCH LÀM ĐÔI Ở ĐỢT ④ (01/09/2026) ──────────────
 * Hai nhánh `.kf-o-chu` đi theo cái tên mới `.truong` sang `nen.css` — chúng là
 * số đo của một thành phần DÙNG CHUNG. Nhánh của ô SỐ theo cái tên mới
 * `.truong-ngang` sang cùng chỗ ở đợt ⑤ — biến thể ngang cũng dùng ở 3 tab, nên
 * nó thuộc về tầng nền y như biến thể dọc. */

/* ── HAI Ô CHIA ĐỀU — chủ dự án chốt 04/09/2026 ─────────────
 * Bản trước `2fr 1fr`: ô lời thoại rộng gấp đôi ô chữ trên video, và hai ô
 * trông không ngang hàng. Cùng cỡ chữ, cùng hai dòng, cùng một câu hỏi «người
 * xem nghe và đọc gì» — không ô nào cần hơn ô nào. Phần lệch DỌC thì chữa ở
 * markup (mỗi ô bọc một `<div>`, xem `kich-ban-ngan-form-ve.js`), không đè
 * `.truong:first-of-type` của tầng nền. */
.kf-doi { display: grid; grid-template-columns: 1fr 1fr; gap: var(--k-3) }
@container khu (max-width: 760px) { .kf-doi { grid-template-columns: 1fr } }

/* Hàng nút «Viết lại bằng tiếng Anh» đứng ngay dưới ô tiếng Việt của nó. */
.kf-viet { margin-top: var(--k-2) }

/* ── THANH LƯU ĐỨNG NGOÀI BA THẺ — 04/09/2026 ────────────────
 * `.thanh-hanh-dong` (nen.css) khai lề âm `-k-4` để ăn hết bề ngang một `.tam`,
 * và chỉ có viền trên vì ba cạnh kia là của thẻ chở nó. Từ 04/09 form sửa
 * cảnh là BA thẻ rời và thanh Lưu là mắt cuối của chuỗi, không nằm trong thẻ
 * nào: `position: sticky` chỉ dính trong khối chứa, đặt nó vào thẻ cuối là mất
 * nó đúng lúc đang gõ bước 1. Đứng một mình thì lề âm thò ra ngoài cột và ba
 * cạnh trống viền — hai số đo bố cục của riêng chỗ này, có lý do ngay đây (K1
 * loại ②), không phải lấy đi thứ tầng nền hứa. Biến thể là lớp ghép (Đ3). */
.thanh-hanh-dong.roi { margin: 0; border: 1px solid var(--vien); border-radius: var(--bo-lon) }

/* Media nguồn: nhóm theo loại, có tên dưới ảnh, và số @image1 in trên ảnh đã
 * chọn. Bản trước đổ một hàng ảnh 46px không nhãn — bảy tấm cùng một khuôn mặt
 * ở cỡ đó là bảy ô vuông giống hệt nhau. */
.kf-nhom { margin: var(--k-3) 0 var(--k-1); font-weight: 600 }
/* `.kf-anh-hang` · `.kf-o` · `.kf-so` ĐỔI TÊN và DỜI về `nen.css` ngày
   01/09/2026 (đợt ⑫, luật Đ4) — nay là `.luoi-chon-media` · `.media-o` ·
   `.media-so`. Chúng dùng ở 5 tab, tức là từ vựng dùng chung đang đeo tên
   viết tắt của một tab. Hai luật HẸP dưới đây mượn chúng và ở lại đây, vì
   chúng là bố cục của riêng hai khối ấy. */
/* ── Ô MEDIA CHỞ CẢ VIDEO, KHÔNG CHỈ ẢNH — 29/08/2026 ────────
 *
 * Chủ dự án: *"màn hình sửa phân cảnh trong tab Kịch bản ngắn, kích cỡ hiển
 * thị của video đang bị vượt khung chứa."*
 *
 * Luật này từng chỉ gọi tên `img`. `veMedia()` ở `kich-ban-ngan-form.js` thì vẽ
 * `<video>` cho mọi media `video/*` trong Media nguồn — và một `<video>` không
 * ai đặt bề rộng thì nó lấy bề rộng THẬT của tệp. Cái nút bọc nó là ô flex, mà
 * ô flex mặc định `min-width: auto` nên nó KHÔNG co xuống dưới nội dung: một
 * clip 1920px kéo cái nút 84px thành 1920px, và cả hàng tràn ngang qua bảng
 * cảnh bên cạnh.
 *
 * Lỗi này KHÔNG kêu ở đâu cả — không lỗi console, không phép thử đỏ, và ô ảnh
 * ngay cạnh thì vẫn đúng. Nó chỉ lộ ra khi Media nguồn của khách có một clip.
 *
 * Ba luật dưới đây phải gọi tên CẢ HAI thẻ, và cả ba đều thế: hai luật hẹp
 * (`.bc-pc-hang` · `.ng-soat`) MƯỢN luật này, nên sửa một chỗ mà bỏ hai chỗ
 * kia là để lại đúng cái khe vừa vá. Kho này đã có tên cho khuôn ấy —
 * `.goc img, .goc video` · `.ng-anh img, .ng-anh video` · `.ct-anh img,
 * .ct-anh video` — chỉ ô media bị bỏ quên. */
/* Ba luật trên cũng đi cùng — xem chú thích ngay trên. */

.kf-khuyen { margin: var(--k-2) 0 0 }

/* Con số tiền đứng ngay dưới chỗ bấm gây ra nó — xem `veGiaAnh`. */
.kf-gia, .kf-tong {
  margin: var(--k-2) 0 0; padding: var(--k-2) var(--k-3);
  background: var(--sau); border-radius: 0 var(--bo) var(--bo) 0; border-left: 3px solid var(--vien-sang);
}
.kf-tong { margin-top: var(--k-4); border-left-color: var(--thuong) }

/* ── ĐÃ TIÊU THẬT ───────────────────────────────────────────
 *
 * Bản trước dùng xanh thương hiệu `--thuong` — đúng màu của nút bấm chính và
 * của mọi thứ đang MỜI người ta hành động. Một con số tiền đã tiêu thì không
 * mời gì cả, nó là sự thật đã rồi; mặc màu hành động vào nó là làm loãng chính
 * cái màu ấy. Chủ dự án báo 17/08/2026.
 *
 * Đổi sang `--canh` (hổ phách): trong bảng màu của app đây là màu của "để mắt
 * tới" — đúng nghĩa với con số duy nhất trên màn hình chỉ có thể tăng. Nó cũng
 * tách bạch ngay với bảng ƯỚC TÍNH bên dưới, thứ không bao giờ nhúc nhích.
 *
 * Con số to hơn phần chữ vì đó mới là thứ người ta liếc vào. */
/* ── Thẻ gập của Kịch bản ngắn — đợt 2d, 28/08/2026 ──────────
 *
 * Bối cảnh · bản thảo đã cắt · Chuẩn thương hiệu · ảnh phong cách bài này: bốn
 * khối còn việc để làm, nhưng không phải việc của mỗi lần mở kịch bản. Bản vẽ
 * d4a không vẽ khối nào trong số đó, và chốt của chủ dự án là thu chúng lại chứ
 * không bỏ.
 *
 * Chính cái `<summary>` là thẻ ở trạng thái gập — nó mượn đúng ba thuộc tính
 * của `.tam` (viền, bo, nền) thay vì bọc `.tam` quanh bốn `.tam` bên trong, thứ
 * mà bản audit 23/08 cấm ở mọi tab.
 *
 * Bỏ dấu tam giác mặc định vì nó nằm SÁT chữ và ở mỗi trình duyệt một kiểu;
 * mũi tên tự vẽ đứng ở mép phải, nơi mắt tìm một cái nút gập. */
/* Ô «Model tạo clip» — khối dùng chung của màn Kịch bản ngắn và màn Phim
 * (`web/man/kich-ban-model-video.js`, #231 khoá trộn).
 *
 * Hai lớp này trước 18/09/2026 chỉ là neo, không luật nào tả, và khoảng cách
 * viết thẳng vào `style=` của thẻ. Dồn về đây vì cùng một lý do: khoảng cách
 * giữa hai khối là việc của bảng kiểu, còn thẻ thì nói nó LÀ CÁI GÌ. Và một
 * lớp không luật nào tả thì không ai biết nó là móc hay là rác. */
.kb-model-video { margin: 0 0 var(--k-2) }
.kb-model-cach { margin: var(--k-2) 0 0 }

.kb-gap { margin-bottom: var(--k-4) }
.kb-gap > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: baseline; gap: var(--k-3); flex-wrap: wrap;
  padding: var(--k-4); background: var(--tam);
  border: 1px solid var(--vien); border-radius: var(--bo-lon);
}
.kb-gap > summary::-webkit-details-marker { display: none }
.kb-gap > summary:hover { border-color: var(--vien-sang) }
.kb-gap > summary::after { content: "\25BE"; margin-left: auto; color: var(--chu-nhat) }
.kb-gap[open] > summary::after { content: "\25B4" }
.kb-gap[open] > summary { margin-bottom: var(--k-4) }

.kb-da-tieu {
  margin: 0 0 var(--k-3); padding: var(--k-2) var(--k-3);
  background: var(--nen-chan); border: 1px solid var(--vien-chan);
  border-radius: 0 var(--bo) var(--bo) 0; border-left: 3px solid var(--canh);
  display: flex; gap: var(--k-3); align-items: baseline; flex-wrap: wrap;
}
.kb-da-tieu b { font-size: var(--cs-de); color: var(--canh) }


/* Dòng của cảnh đang mở form — nối bằng mắt giữa form ở trên và dòng ở dưới. */
.kb-dang-sua > td { background: var(--sau) }

/* Thanh hành động DÍNH ĐÁY khung nhìn khi bảng sửa cao hơn màn hình.
 *
 * Bảng sửa cao ~840px (11 thanh trượt bên trái, hai ảnh chân dung bên phải) trên
 * một khung nhìn 720px. Đặt nút Lưu ở cuối luồng văn bản nghĩa là nó nằm ngoài
 * tầm mắt đúng lúc người ta vừa chỉnh xong và muốn lưu. Dính đáy thì nó luôn ở
 * đó, và không cần đoán người dùng sẽ cuộn tới đâu. */
/* Luật ĐỔI TÊN thành `.thanh-hanh-dong` và DỜI về `nen.css` ngày 01/09/2026
   (đợt ⑫, luật Đ4) — nó cặp với `.thanh-cong-cu`: thanh trên chở công cụ,
   thanh dưới chở hành động. */

/* ── v12 — khối BỐI CẢNH của một kịch bản ────────────────────
 *
 * Mỗi dòng nói NGUỒN của nó ngay cạnh nhãn. Đây là nguyên tắc quan trọng nhất
 * của khối: hiện chữ ra mà không nói chữ ấy từ đâu thì người dùng vẫn không biết
 * sửa ở đâu mới có tác dụng — sửa trong app, sửa trên Notion, hay sửa mã.
 *
 * Nhãn dùng hai cột: nhãn hẹp cố định bên trái, giá trị chiếm phần còn lại. Bố
 * cục bảng làm mắt quét dọc theo cột nhãn được, thay vì đọc từng đoạn. */
/* Bề rộng cột nhãn là một con số THẬT của bố cục, không phải một bậc khoảng
   cách — nên nó có tên riêng thay vì bị ép về thang. Có tên rồi thì chỗ nào cần
   thẳng hàng với cột giá trị sẽ TÍNH ra nó, thay vì chép lại tổng. */
/* ── CỘT CHỮ: GỠ HẲN — chủ dự án chốt 07/09/2026 ─────────────
 *
 * Khối này từng đặt `--bc-cot-chu: 78ch` (31/08) và năm luật đọc nó, với lý lẽ:
 * cột giá trị rộng 964–1215px cho ra 135–170 ký tự một dòng, mà đọc hết một
 * dòng dài như thế rồi quay về lề trái thì dễ mất dòng.
 *
 * Lý lẽ ấy KHÔNG SAI, nhưng nó không đủ để lật một chốt. Chủ dự án chốt
 * 23/08/2026: *"Set chiều rộng của các block là 100% khung chứa, không set theo
 * giá trị cố định nữa."* Đợt 31/08 lách bằng cách phân biệt «bề rộng của một
 * BLOCK» với «bề rộng một CỘT CHỮ bên trong block» — một phân biệt có thật, và
 * chủ dự án nghe xong vẫn nói không: *«trong một khuôn hiển thị thì đã được bao
 * bằng padding bốn cạnh rồi, vì sao lại bó cột chữ lại làm gì.»*
 *
 * ── VÀ SỐ ĐO ĐỨNG VỀ PHÍA CHỐT ẤY ────────────────────────────
 * Đo lại toàn trang mẫu 07/09: **121 khối chữ** dài trên 140 ký tự, mà chỉ
 * **12 khối** vượt 90 ký tự một dòng. Phần lớn chữ trong app là nhãn, dòng phụ,
 * ô bảng — ngắn, không đọc theo dòng dài. Bó cả app để chữa 12 chỗ là dùng một
 * cái luật quá to cho một cái lỗi quá nhỏ.
 *
 * Cái giá thì đo được ngay: 1 tab bó, 19 tab không, và không ai giải thích được
 * vì sao khác nhau. Trạng thái ấy tệ hơn CẢ HAI đầu — tệ hơn bó hết, tệ hơn
 * không bó gì. Nên nay không bó gì, và `test-web-bo-cuc` gác chiều ấy.
 *
 * Nếu ngày nào một khối THẬT SỰ đọc không nổi thì lời chữa là chia đoạn ngắn
 * hơn hoặc đưa nó vào bố cục hai cột — không phải trả lại một con số `ch`. */
:root {
  --bc-nhan: 190px;
}
.bc-dong {
  display: grid; grid-template-columns: var(--bc-nhan) minmax(0, 1fr); gap: var(--k-3);
  padding: var(--k-2) 0; border-top: 1px solid var(--vien);
}
/* Vạch nằm TRÊN mỗi dòng, trừ khi thứ đứng ngay trên đã có mép của nó rồi:
   tiêu đề khối, một hộp cảnh báo, hay một thẻ nền tảng. Bản trước viết
   `.bc-dong:first-of-type` — nó CHẠY ĐÚNG, nhưng chạy đúng vì tình cờ: `div`
   đầu tiên trong khối hiện là một `.bc-dong`. Ngày hộp cảnh báo đổi từ `<p>`
   sang `<div>`, hay ngày thẻ dàn lên trước dòng đầu, vạch mọc lại ngay dưới
   tiêu đề mà không lưới nào kêu. Ba luật dưới đây nói ĐIỀU KIỆN thật, nên
   chúng không phụ thuộc vào ai đứng thứ mấy — và chúng gỡ luôn cái vạch đôi:
   trước hôm nay, dòng đứng sau thẻ dàn vẽ vạch của mình sát ngay dưới viền
   dưới của thẻ ấy. */
.khoi-dau + .bc-dong, .chan + .bc-dong, .bc-the + .bc-dong { border-top: 0 }
@container khu (max-width: 760px) { .bc-dong { grid-template-columns: 1fr; gap: var(--k-1) } }

.bc-nhan { font-size: var(--cs-ban); font-weight: 600 }
.bc-gt {
  font-size: var(--cs-ban); line-height: var(--dong-chay); word-break: break-word;
}

/* Nguồn đứng DƯỚI nhãn, chữ nhỏ — nó là chú thích của nhãn, không phải một nhãn
 * thứ hai ngang hàng. */

/* Cùng cột chữ với `.bc-gt` ngay trên nó: dòng chú thích rộng hơn chính giá trị
   nó chú thích thì mắt đọc nó ra một khối khác, không ra phần đuôi của khối
   trên. */
/* ── THỤT CHỈ KHI CÓ CỘT ĐỂ THẲNG HÀNG — sửa 01/09/2026 ──────
 *
 * Lề trái 202px sinh ra để dòng chú thích thẳng hàng với CỘT GIÁ TRỊ của lưới
 * `.bc-dong` (nhãn 190px + khe) ở chế độ ĐỌC. Chỗ nào không có lưới ấy thì
 * không có cột nào để thẳng hàng, và 202px thành một dòng chữ lơ lửng giữa
 * khung.
 *
 * Bản trước gác bằng một ngoại lệ theo CÁI BỌC — `.kb-bc-tao .bc-canh-bao` —
 * nên form tạo mới thì đúng, còn form SỬA ở màn một kịch bản (cũng xếp dọc
 * bằng `.truong`, cũng không có cột nhãn) thì lơ lửng. Chủ dự án chỉ ra
 * 21/08/2026 ở chỗ thứ nhất và 01/09/2026 ở chỗ thứ hai — cùng một lỗi, hai
 * lần báo, vì lời chữa lần đầu gác sai thứ.
 *
 * Nay gác theo HÌNH nó căn vào: thụt CHỈ KHI có một `.bc-dong` đứng trước
 * trong cùng cha. Chỗ mới nào cũng tự đúng, không phải khai thêm dòng nào. */
.bc-canh-bao {
  margin: var(--k-2) 0 0;
  font-size: var(--cs-phu);
}
.bc-dong ~ .bc-canh-bao { margin-left: calc(var(--bc-nhan) + var(--k-3)) }
@container khu (max-width: 760px) { .bc-dong ~ .bc-canh-bao { margin-left: 0 } }

/* ── Thẻ nhấn của ba khối nền tảng — 28/08/2026 ──────────────
 *
 * Dàn nhân vật · Chuẩn thương hiệu · Ảnh phong cách dùng CÙNG hình dạng ở cả
 * màn tạo mới lẫn màn một kịch bản; lý lẽ đầy đủ ở `kich-ban-the.js`. Ở đây chỉ
 * còn nhịp dọc — và nó phải khai, vì `.tam` cố ý không mang lề (nhịp thuộc về
 * container, xem khối `--khe-*` ở trên).
 *
 * Trên màn tạo mới, thẻ nằm trong `.kb-bc-tao` vốn tô `--sau`; một `.tam` trên
 * nền ấy nổi lên đúng một bậc — đó chính là cái tầng mà màn ấy đang thiếu. */
.bc-the { margin-top: var(--k-4) }
.bc-the .khoi-dau { margin-bottom: var(--k-2) }
/* Thẻ giữ nguyên bề rộng của khung chứa — nó là một VẬT, và một hàng ảnh thật
   bên trong nó cần cả bề ngang ấy. Chỉ CHỮ trong thẻ về cột chữ. Không có luật
   này thì đúng cái thẻ nằm giữa hai dòng đã bó chữ lại là thẻ đọc dài nhất
   khối — đo được 150 ký tự một dòng trong khi hai dòng kề nó đã về 95.
   `.khoi-dau` đứng ngoài: câu vai của nó phải nằm CẠNH tên, và một trần bề
   rộng ở đó là câu vai xuống dòng. */
.bc-the > span { display: block }
/* Hộp cảnh báo của riêng khối bối cảnh — cùng cột chữ, vì nó là chữ để ĐỌC chứ
   không phải một dải trạng thái để nhìn thấy. Ở bề rộng cũ, hai câu của nó dài
   130 và 150 ký tự, tức còn dài hơn cả đoạn Insight sau khi bó. */
/* Câu vai đứng CẠNH tên, không đẩy sang mép phải: nó là vế thứ hai của một câu
   ("Chuẩn thương hiệu · phong cách chung"), không phải một nhãn phân loại. */
.bc-the .khoi-dau .nhat { margin-left: 0 }

/* Kho insight: năm nhóm cạnh nhau, và NHÓM RỖNG VẪN HIỆN — nhóm "Rào cản" rỗng
 * là câu "chưa ai nghiên cứu vì sao người xem chần chừ", đáng giá hơn một danh
 * sách ngắn. Nhóm rỗng mờ đi nhưng không biến mất. */
.bc-nhom-luoi { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--k-3) }
.bc-nhom {
  background: var(--sau); border: 1px solid var(--vien);
  border-radius: var(--bo); padding: var(--k-2) var(--k-3);
}
.bc-nhom.rong { color: var(--chu-nhat); border-style: dashed }
.bc-nhom-ten { margin: 0 0 var(--k-2); font-size: var(--cs-phu); font-weight: 600 }
.bc-nhom-ten .nhat { font-weight: 400 }

.bc-insight { font-size: var(--cs-phu); line-height: var(--dong-chay); padding: var(--k-1) 0; border-top: 1px solid var(--vien) }
.bc-insight.mo { color: var(--chu-nhat) }

/* Insight bấm chọn được — v12 bước 5. Ô chọn phải trông KHÁC ô chỉ đọc ngay từ
 * xa: bài học lỗi #39 là một ô trông bấm được mà không bấm được thì nuốt thao
 * tác im lặng, và ngược lại cũng đúng. */
button.bc-insight {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: none; border: 0; border-top: 1px solid var(--vien);
  color: inherit; font: inherit; padding: var(--k-2) var(--k-1); border-radius: var(--bo);
}
button.bc-insight:hover { background: var(--nen-luot) }
button.bc-insight.chon { background: var(--chon); box-shadow: inset 2px 0 0 var(--vien-chon) }

/* ── v13 bước 2 — kho insight cuộn, tìm, và nhớ mình đã chọn gì ─
 *
 * Chủ dự án 18/08/2026: kho insight sẽ rất dài khi Notion nhiều bản ghi lên.
 *
 * VÙNG CUỘN NẰM TRONG CỘT, KHÔNG PHẢI CẢ CỘT. Đầu cột đứng ngoài `bc-nhom-ds`
 * vì con số đếm ở đó là thứ DUY NHẤT nói cho người ta biết dưới đáy còn bao
 * nhiêu — cho nó trôi theo là biến hộp cuộn thành hộp trông như chỉ có 5 dòng.
 *
 * Chiều cao là một BIẾN vì khối insight cao không đều: có khối hai dòng, có
 * khối bốn dòng vì kèm cảnh báo "chưa dùng được". 320px ≈ 5 khối. */
.bc-nhom { display: flex; flex-direction: column }
.bc-nhom-ds {
  max-height: var(--kho-cao, 320px); overflow-y: auto;
  scrollbar-width: thin; scrollbar-color: var(--vien) transparent;
  /* Dải mờ ở đáy: một hộp cuộn không có dấu hiệu gì thì không ai biết là cuộn
   * được. Chỉ hiện khi nội dung thật sự tràn — `mask` bám theo vùng cuộn.
   *
   * `#000` ở đây KHÔNG phải màu, nó là độ đục của mặt nạ: đen = giữ nguyên,
   * trong suốt = mờ đi. Thay bằng token màu là hỏng dải mờ ở một trong hai nền.
   * `test-mau` miễn trừ đúng dòng này, và chỉ dòng này. */
  mask-image: linear-gradient(to bottom, #000 calc(100% - 18px), transparent);
}
.bc-nhom-ds:hover { scrollbar-color: var(--vien-sang) transparent }

/* Cột không còn dòng nào khớp bộ lọc: mờ như nhóm rỗng, vì lúc đó nó ĐANG rỗng
 * trước mắt người dùng — nhưng không biến mất, để con số "0/20" còn đọc được. */
.bc-nhom.khong-khop { color: var(--chu-nhat); border-style: dashed }

.bc-tim-hang { display: flex; align-items: center; gap: var(--k-2); margin: 0 0 var(--k-2) }
.bc-tim {
  flex: 1; min-width: 0; padding: var(--k-1) var(--k-2); font-size: var(--cs-phu);
  background: var(--sau); color: inherit;
  border: 1px solid var(--vien); border-radius: var(--bo);
}

/* Dải "Đang chọn" — insight đã tick không được biến mất khỏi màn hình khi nó
 * trôi khỏi vùng cuộn hoặc bị bộ lọc ẩn đi. Nó là thứ sắp đi vào prompt. */
.bc-dang-chon {
  display: flex; align-items: center; gap: var(--k-2); flex-wrap: wrap;
  margin: 0 0 var(--k-2); padding: var(--k-2) var(--k-2);
  background: var(--chon); border-radius: var(--bo);
  box-shadow: inset 2px 0 0 var(--vien-chon);
}
.bc-dang-chon .mieng { padding: var(--k-0) var(--k-2) }

/* v13 bước 4 — hàng ảnh phong cách của riêng kịch bản. Thụt vào bằng nhãn của
 * `bc-dong` để nó ĐỌC như phần thân của dòng ngay trên, chứ không như một mục
 * ngang hàng: nó là tầng hai xếp chồng lên khoá thương hiệu, không thay thế. */
.bc-pc-hang {
  display: flex; align-items: flex-start; gap: var(--k-2); flex-wrap: wrap;
  margin: var(--k-2) 0 0 calc(var(--bc-nhan) + var(--k-3));
}
.bc-pc-hang .media-o img, .bc-pc-hang .media-o video { width: 54px; height: 54px; object-fit: cover }
@container khu (max-width: 760px) { .bc-pc-hang { margin-left: 0 } }

/* ══ Tab Chuẩn thương hiệu ═══════════════════════════════════
 *
 * Cả tab nằm trong `.tai-lieu` (width: 100%, xem khối đầu tệp — chủ dự án chốt
 * 23/08/2026 bỏ mọi bề rộng cố định trên block). Mọi lề và bề rộng ở đây,
 * không một thuộc tính `style=` nào trong BỐN tệp màn của họ `khoa-phong-cach*`
 * — lưới ở `test-web-kich-ban.mjs` (grep `"họ khoa-phong-cach* không còn thuộc tính
 * style="`) gác đúng câu này. Audit UX/UI 23/08 bắt được bản trước của chú
 * thích này viện dẫn một lưới "19a" chưa từng tồn tại. */

/* Đoạn descriptor đi NGUYÊN VĂN vào mọi prompt, nên nó phải đọc được như một
 * đoạn văn: giãn dòng thoáng, không thu nhỏ. Bày nó bằng cỡ chữ phụ như mọi
 * thứ khác là mời người ta không đọc.
 *
 * `max-width: 78ch` bỏ 23/08/2026: nó đúng khi thẻ rộng 1460px, và thành thừa
 * khi cột đã là 900px — hai bề rộng lồng nhau là hòn đảo, xem `.tai-lieu`. */
/* ── VIỀN TRÁI LÀ NGÔN NGỮ CHUNG CỦA MỌI Ô LÕM ─────────────────
 *
 * Đo trực tiếp 23/08/2026: `.kf-buoc` (khi còn là một dải nền) và `.kpc-chu`
 * (ô prompt) từng cùng nền `--sau` và đứng sát nhau trong cùng thẻ — mắt đọc
 * chúng như MỘT loại vật, không phải tiêu đề rồi tới nội dung. Đây đúng là
 * cách mọi ô lõm khác trong app giải quyết: `--sau` là nền DÙNG CHUNG cho
 * input/khối trích dẫn/dải cảnh báo, và viền trái màu mới là thứ nói RA loại
 * nào — xem `.kb-bc-tao` (`--thuong`), `.kf-gia` (`--vien-sang`),
 * `.kb-dan-the.hong` (`--xau`).
 *
 * `.kf-buoc` sau đó thôi là một ô lõm — nó thành TIÊU ĐỀ thật (kiểu chữ, gạch
 * chân, không nền), nên hai class không còn tranh nhau chỗ đứng nữa. `.kpc-chu`
 * vẫn giữ vạch trái `--thuong` của riêng nó: nó bọc thứ quan trọng nhất trong
 * cả tab (đoạn đi thẳng vào mọi ảnh), và màu đỏ rượu vang là màu NHẬN DIỆN của
 * app — dùng cho đúng nội dung xứng đáng nhất, không phải trang trí. */
.kpc-chu {
  margin: var(--k-2) 0 0; line-height: var(--dong-chay);
  padding: var(--k-3) var(--k-3); background: var(--sau);
  border: 1px solid var(--vien); border-left: 3px solid var(--thuong);
  border-radius: 0 var(--bo) var(--bo) 0;
}

/* Dòng đầu khối — nhãn nguồn, số ảnh, và chip ảnh, cùng một hàng đọc. */
.kpc-dau { display: flex; align-items: center; gap: var(--k-2); flex-wrap: wrap; margin: 0 0 var(--k-2) }

/* Chip ảnh trong khối «Đang áp» — 28px, là BẰNG CHỨNG chứ không phải chỗ làm
 * việc. Con số «2 ảnh nhận diện» mà không có ảnh nào cạnh nó thì người đọc phải
 * cuộn xuống khối khác để biết là hai tấm nào. */
.kpc-chip { display: inline-flex; gap: var(--k-1); vertical-align: middle }
.kpc-chip img {
  width: 28px; height: 28px; object-fit: cover; display: block;
  border-radius: var(--bo-nho); border: 1px solid var(--vien); background: var(--nen-anh);
}
a.kpc-toi-anh { color: var(--thuong); text-decoration: none; white-space: nowrap }
a.kpc-toi-anh:hover { text-decoration: underline }

/* ── «ĐANG CÓ HIỆU LỰC» — cột phải, đợt 2r 28/08/2026 ─────────
 *
 * Một `<dl>` chứ không một bảng: đây là cặp nhãn–giá trị, không phải dữ liệu có
 * hàng có cột. Nhãn xám nhỏ trên, giá trị dưới — cùng nhịp với ô của dải điểm
 * nhấn, vì hai chỗ ấy nói cùng một loại câu và đứng cách nhau nửa màn hình. */
/* ── Ô CHỌN BỘ NHẬN DIỆN — bậc B mục 4, 08/09/2026 ────────────
 *
 * Khối này đứng TRÊN mọi thẻ, nên nó phải đọc như một dòng ngữ cảnh chứ không
 * như một thẻ thứ ba.
 *
 * BIẾN THỂ CỦA `.hang`, KHÔNG PHẢI MỘT HÀNG THỨ HAI. Bản đầu khai lại trọn bốn
 * dòng của `.hang` — `display: flex` · `align-items: center` · `flex-wrap` ·
 * `gap` — để đổi đúng một giá trị. `.hang` dùng ở 93 tệp; dựng lại nó ở đây là
 * lối thứ hai làm cùng một việc, và người sửa sau phải đoán chọn cái nào.
 *
 * Markup nay viết `class="hang kpc-th-hang"`, đúng khuôn `.hang-mau` và
 * `.hang-logo` đã đặt 01/09. Chỉ hai khoản CHÊNH ở lại đây: khe rộng hơn một
 * bậc (dòng ngữ cảnh thưa hơn một hàng ô nhập), và một khoảng cách với đoạn
 * chữ trên nó. Cả hai lớp cùng hạng (0,1,0) nên chỉ thứ tự nguồn quyết — và
 * `man.css` luôn nạp sau `nen.css`. */
.kpc-th-hang { gap: var(--k-3); margin-top: var(--k-3) }
/* ── Ô CHỌN: MỘT DẢI, KHÔNG PHẢI MỘT CÁI SÀN ─────────────────
 *
 * Bản đầu khai `min-width: 14rem`. Hai thứ sai trong một dòng.
 *
 * ① `rem` là đơn vị DUY NHẤT của nó trong cả 5.700 dòng CSS — một đơn vị chỉ
 *    xuất hiện một lần là một đơn vị người sửa sau phải dừng lại để hỏi.
 *
 * ② `min-width` trên một ô flex LẤY ĐI thứ `.hang` đã hứa. `nen.css` khai
 *    `.hang > select { min-width: 0 }` để ô chọn CO ĐƯỢC khi hàng chật; một
 *    `min-width` khác đè lên đó là bỏ luôn khả năng co.
 *
 *    Trang mẫu bày ra ngay: một `<select>` tự phình theo mục dài nhất, và với
 *    tên «Enterprise One Management System» nó ra **342px**. Trong cột 530px,
 *    342 + khe + nút «Thêm thương hiệu» 152px không đủ chỗ, nên nút RƠI XUỐNG
 *    DÒNG HAI và hàng cao 92px thay vì 40. Đo được 08/09/2026.
 *
 * Nên nó nhận một BỀ RỘNG chứ không một cái sàn: 220px, co được khi chật,
 * không bao giờ đẩy thứ đứng cạnh xuống dòng.
 *
 * `width` chứ không `flex: 1 1 220px`. Bản giữa dùng flex-grow và đo ra ca thứ
 * hai: một khách chỉ có «Vier» và «Citares» thì ô chọn phình ra **451px** —
 * chiếm trọn chỗ trống cho hai cái tên bốn chữ. Một ô chọn dài gần nửa mét cho
 * một chữ là nói dối về lượng thứ nằm trong nó.
 *
 * Tên dài hơn 220px thì trình duyệt tự cắt — cùng cư xử với thẻ khách ở dải
 * đầu (`max-width: 260px`), và mở ra là thấy đủ. Một ô chọn rộng theo mục dài
 * nhất là để bố cục chạy theo dữ liệu. */
/* `max-width: 100%` KHÔNG khai lại ở đây — `nen.css:822` đã cho mọi `select`,
   và `test-kieu` mục 2n đếm mỗi lần tầng màn chép lại y nguyên một giá trị
   tầng nền đã nói. Nó bắt được dòng ấy ngay lượt đầu. */
.kpc-th-hang select { flex: 0 1 auto; width: 220px; min-width: 0 }

.kpc-so { margin: 0; display: grid; gap: var(--k-3) }
.kpc-so dt {
  font-size: var(--cs-nho); letter-spacing: .14em; text-transform: uppercase;
  color: var(--chu-mo); margin-bottom: var(--k-1);
}
.kpc-so dd { margin: 0; display: flex; align-items: center; gap: var(--k-2); flex-wrap: wrap }

/* Rail 520px của thẻ «Chuẩn hình ảnh» — đúng con số bản vẽ D2a chia
   (`1fr 520px`). Khai bằng CLASS chứ không `style=` trong JS: chốt 23/08 cấm
   con số bố cục trong tệp màn, và `test-web` gác đúng câu ấy cho cả họ
   `khoa-phong-cach*`. Cùng khuôn `.ap-luoi` của tab Ấn phẩm. */
.kpc-luoi { --cot-phai: 520px }

/* ── DUYỆT HỌ CHỮ — vùng Ⓒ, 29/08/2026 ───────────────────────
   Danh sách CÓ THỨ TỰ, nên `<ol>`: số thứ tự là dữ liệu ở đây (họ đứng đầu là
   mặt chữ của bộ đầu ấn phẩm), không phải trang trí. Mặt chữ của từng dòng đặt
   bằng JS — xem `chuan-thuong-hieu-font.js`. */
.kn-f-ds { margin: var(--k-3) 0; padding-left: var(--k-5); display: grid; gap: var(--k-2) }
.kn-f-dong {
  display: flex; align-items: baseline; gap: var(--k-3); flex-wrap: wrap;
  padding: var(--k-1) 0; border-bottom: 1px solid var(--vien);
}
.kn-f-dong:last-child { border-bottom: 0 }
.kn-f-ten { font-size: var(--cs-de); line-height: var(--dong-chat) }
.kn-f-nut { margin-left: auto; display: flex; gap: var(--k-1); flex: 0 0 auto }

/* Bảng chọn của nhóm đang mở. Cuộn dọc trong chính nó: nhóm `sans` có hơn tám
   mươi họ, và một danh sách dài bằng ba màn hình đẩy hai khối tiêu tiền của
   vùng Ⓒ ra khỏi tầm mắt. */
.kn-f-chon {
  display: flex; flex-wrap: wrap; gap: var(--k-2); margin-top: var(--k-3);
  max-height: 240px; overflow-y: auto; scrollbar-width: thin;
  padding: var(--k-2); border: 1px solid var(--vien); border-radius: var(--bo);
  background: var(--sau);
}
.kn-f-chon .mieng { font-size: var(--cs-de); line-height: var(--dong-chay) }

/* ── THẺ CẨM NANG NÉN LẠI — 29/08/2026 ───────────────────────
   Đo 29/08 ở đúng trạng thái bản vẽ chụp (đã chọn hướng · 8/8 viết · 3/8 chốt):
   app cao **5.445px**, bản vẽ **1.811px**. Phần chênh nằm trọn ở RUỘT các khối,
   và cả bốn chỗ phình cùng một bệnh — app bày trạng thái LÀM VIỆC mở sẵn, bản
   vẽ bày trạng thái ĐÃ QUYẾT gập lại. Bốn lớp dưới đây là thuốc. */

/* ── HÀNG CHỌN THẺ — ba tab, MỘT luật ────────────────────────
   Hàng nút chọn thẻ: không `<fieldset>` không `<legend>`, vì tên các thẻ đã
   tự nói mình là gì.

   MỘT luật cho cả ba, và đó là điều lượt 31/08 ĐÃ DẶN mà chưa làm: chú thích
   của `.kbn-the` viết «dùng chung một luật thay vì gọi tên hai lớp… một ngày
   ai đó chỉnh nhịp cho cái này mà quên cái kia là hai tab nói bằng hai hình
   dạng cho cùng một cử chỉ» — trong khi mã bên dưới nó là hai luật trùng thân.
   Tab thứ ba (Quản trị, 02/09) làm cái giá ấy lộ ra: chép thêm lần nữa là ba
   bản sao của một câu.

   Mỗi tab vẫn giữ TÊN LỚP RIÊNG chứ không dùng chung một tên. Đó không phải
   thừa: `test-kieu` gác việc tab này dùng lớp mang tiền tố của tab kia, và một
   tên dùng chung thì phải dời hẳn lên `nen.css` — đổi tên một lớp đang sống ở
   ba tab là quyết định của chủ dự án, không phải một lượt `mv`. Xem mục 07 bộ
   chuẩn, và bảng `MUON_LOP` của `test-kieu`. */
/* ── VÀ NÓ KHÔNG ĐƯỢC LẤY ĐI NHỊP DỌC — 08/09/2026 ───────────
 *
 * Bản trước viết `margin: 0 0 var(--k-4)`. Số `0` đầu tiên ấy là một
 * `margin-top: 0` VIẾT RA, và nó đè lên `.tai-lieu > * + * { margin-top:
 * var(--k-5) }` — nhịp dọc mà mọi màn đứng lên (luật K3, `test-kieu` mục 2k).
 * Hai luật cùng hạng (0,1,0), `man.css` nạp sau, nên bản gỡ được dùng.
 *
 * Nó sai từ ngày viết mà không ai thấy, vì hàng thẻ luôn là khối ĐẦU TIÊN của
 * trang — `* + *` không chạm tới con đầu, nên `margin-top: 0` không lấy đi gì.
 * Ngày 08/09 ô chọn bộ nhận diện chèn vào TRƯỚC nó, hàng thẻ thành khối thứ
 * hai, và chủ dự án thấy ngay: hai cái nút dính vào đáy khung thẻ, khe 0px.
 *
 * Chỉ khai lề DƯỚI. Lề trên là việc của nhịp chung — khối đầu trang không cần,
 * khối thứ hai trở đi nhận 24px, và không luật nào phải biết mình đứng thứ mấy.
 * Ba tab cùng đọc luật này, nên cả ba cùng được chữa. */
.kpc-the, .kbn-the, .qt-the { align-items: center; margin-bottom: var(--k-4) }


/* Khối gập chung của thẻ Cẩm nang — ba hướng đã chọn, ba phần lấy từ nơi khác,
   bàn dựng logo/mockup, danh sách họ chữ. Cùng một mũi gập để bốn thứ ấy đọc ra
   MỘT hạng: «đã quyết rồi, mở khi cần». */
.kn-guong > summary,
.kn-ban-dung > summary {
  cursor: pointer; display: flex; align-items: baseline; gap: var(--k-2); flex-wrap: wrap;
}
.kn-guong[open] > summary,
.kn-ban-dung[open] > summary { margin-bottom: var(--k-3) }

/* Bàn dựng nằm TRONG một thẻ đã có viền, nên nó tự tách bằng một vạch trên chứ
   không bằng viền thứ hai — hai khung lồng nhau đọc ra hai thẻ. */
.kn-ban-dung { margin-top: var(--k-4); padding-top: var(--k-4); border-top: 1px dashed var(--vien) }
details.tam.kn-ban-dung { margin-top: 0; padding-top: var(--k-4); border-top: 1px solid var(--vien) }

}

/* Hai khối gập ở rail phải. Cùng khuôn `<details class="tam">` với «Chi tiết
   kỹ thuật» ngay dưới chúng — ba dòng gập liền nhau phải đọc ra MỘT nhóm, chứ
   không phải ba thứ tình cờ cùng gập được. */
.kpc-gap > summary { cursor: pointer; display: flex; align-items: baseline; gap: var(--k-2); flex-wrap: wrap }
.kpc-gap[open] > summary { margin-bottom: var(--k-3) }

/* Đoạn chỉ dẫn TRÊN DẢI: cắt ở hai dòng. Dải là chỗ đọc trong một nhịp mắt, và
   một đoạn prompt bốn dòng đẩy cả dải cao gấp đôi mọi tab khác. Bản đầy đủ vẫn
   đọc được — nó nằm trong ô ② ở cột trái, và bản dịch tiếng Việt ở cột phải. */
#dai-nhan .kpc-dai-chu {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden; color: var(--chu);
}

/* ── ĐOẠN CHỈ DẪN PHONG CÁCH — khuôn dùng chung, 05/09/2026 ───
 *
 * `web/loi/doan-chuan.js` vẽ đoạn này ở sáu chỗ. Trước nó, mỗi chỗ tự cắt bằng
 * `text.slice(0, 100|110|120)` rồi nối `…` — cắt giữa chữ, ba chấm hiện cả khi
 * không cắt gì, và phần bị cắt KHÔNG có trong DOM nên không copy được.
 *
 * Nay đoạn nằm trọn trong DOM, gập bằng `-webkit-line-clamp` như `.kpc-dai-chu`
 * của dải đỉnh. Trình duyệt cắt theo DÒNG THẬT và tự đặt dấu ba chấm — nên dấu
 * ấy chỉ xuất hiện khi thật sự còn chữ phía sau.
 *
 * Ô chữ mượn nguyên `.kpc-chu` (nền lõm, viền trái màu nhận diện) chứ không khai
 * một khuôn thứ hai: cùng một nội dung — đoạn đi thẳng vào mọi ảnh — thì phải
 * trông y hệt nhau ở tab Kịch bản và tab Chuẩn thương hiệu. Người dùng nhận ra
 * nó bằng HÌNH DẠNG trước khi kịp đọc nhãn. */
.doan-chuan { margin: var(--k-2) 0 0 }
.doan-chuan-nguon { margin: 0 0 var(--k-1) }
.doan-chuan-chu { margin-top: 0 }
/* CLAMP ĐẶT LÊN SPAN BÊN TRONG, KHÔNG LÊN Ô — đo thật 05/09/2026.
 *
 * Bản đầu clamp thẳng `.doan-chuan-chu`, mà ô ấy mượn `.kpc-chu` nên có
 * `padding: var(--k-3)`. `overflow: hidden` cắt ở MÉP NGOÀI padding, không ở mép
 * nội dung — nên dòng thứ BA rơi vào vùng padding-bottom và hiện ra MỘT NỬA
 * THÂN CHỮ. Chụp màn thấy ngay; bộ thử đọc chuỗi HTML thì không thấy gì, vì
 * class `gap` vẫn đúng chỗ và `…` vẫn đúng cuối dòng hai.
 *
 * Span không padding, nên clamp cắt sạch ở đúng ranh giới dòng. */
.doan-chuan-thu { display: block }
.doan-chuan-thu.gap {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
/* Nút và số ký tự đứng CÙNG HÀNG, sát dưới ô chữ: nó nói về đúng ô ngay trên
 * nó, và tách ra một dòng riêng là bắt mắt nối hai thứ cách nhau một khoảng. */
.doan-chuan-nut { display: flex; align-items: baseline; gap: var(--k-2); flex-wrap: wrap; margin: var(--k-1) 0 0 }
/* Câu «đang đọc…» và «chưa có» KHÔNG mượn ô lõm: ô lõm nghĩa là «đây là đoạn sẽ
 * đi vào ảnh», mà hai ca này chưa có đoạn nào cả. */
.doan-chuan-cho { margin: var(--k-2) 0 0 }

/* ── NGHĨA TIẾNG VIỆT ─────────────────────────────────────────
 * Phải đọc ra ngay là KHÔNG PHẢI prompt. Nền nhạt hơn, viền trái, chữ nghiêng
 * nhẹ ở nhãn: người dùng không bao giờ được nhầm bản dịch với đoạn sẽ gửi đi —
 * sửa vào đây thì không có gì đổi trong ảnh cả. */
.kpc-nghia { margin: var(--k-2) 0 0 }
.kpc-nghia > p { margin: 0 }
.kpc-nghia-chu {
  margin: var(--k-2) 0 0; padding: var(--k-2) var(--k-3); line-height: var(--dong-chay);
  border-left: 3px solid var(--vien-sang); background: var(--tam);
  border-radius: 0 var(--bo) var(--bo) 0;
}
.kpc-nghia-chu .nhat { display: block; margin: var(--k-2) 0 0; font-size: var(--cs-nho) }
/* Nút đưa bản dịch sang ô viết tay — 05/09/2026. Nằm TRONG khung dịch, dưới câu
 * «bản dịch để ĐỌC»: nó là lối thoát của chính câu ấy, nên đứng ngay sau nó chứ
 * không đứng ngoài khung. Xuống dòng riêng vì nó là một HÀNH ĐỘNG, không phải một
 * chữ trong câu — cùng lý lẽ đã chốt cho `.hang-nut`. */
.kpc-sua-viet { display: inline-block; margin: var(--k-2) 0 0 }

/* Dải ảnh ĐANG trong bộ — chỗ làm việc, có nút gỡ. Cùng lưới với hộp chọn để
 * hai chỗ bày ảnh giống nhau; ô nhỏ hơn vì đây chỉ là 6 tấm, không phải cả kho. */
.kpc-bo { display: flex; flex-wrap: wrap; gap: var(--k-2); margin: var(--k-2) 0 0 }
.kpc-o { position: relative; width: 96px }
.kpc-o img {
  width: 96px; height: 96px; object-fit: cover; display: block;
  border-radius: var(--bo); border: 2px solid var(--vien-chon); background: var(--nen-anh);
}
.kpc-o-ten {
  display: block; font-size: var(--cs-nho); line-height: var(--dong-chat); margin-top: var(--k-0);
  color: var(--chu-nhat); word-break: break-word;
}
/* Tấm nằm NGOÀI trần 6 ảnh: vẫn trong bộ, nhưng không tham gia lượt đọc. Mờ đi
 * kèm nhãn, thay vì một câu văn ở khối khác nói "máy chỉ đọc 6 tấm mới nhất". */
.kpc-o.ngoai img { border-color: var(--vien); opacity: .45 }
.kpc-o-nhan {
  position: absolute; top: 3px; left: 3px; z-index: var(--lop-trong-the);
  background: var(--canh); color: var(--chu-tren-mau);
  font-size: var(--cs-nho); font-weight: 600; padding: 1px var(--k-1); border-radius: var(--bo);
}
/* Chênh của chủ này so với `.nut-bo` ở `nen.css` (việc Ⓕ, 01/09/2026): tròn,
   nằm TRONG mép ô, và mực đầy thay vì mực nhạt — nút này luôn hiện, nên nó phải
   đọc ra một nút chứ không ra một dấu mờ. Kích thước đọc `--cham` từ 07/09/2026,
   như mọi nút gỡ; xem chú thích ở `.bd-anh .nut-bo`. */
.kpc-o .nut-bo {
  top: 2px; right: 2px; width: var(--cham); height: var(--cham);
  padding: 0; border-radius: 50%; border-color: var(--vien); color: var(--chu);
}

/* Vạch ngăn trong khối gộp ① — «chọn ảnh» và «cho máy đọc» là hai nhịp của MỘT
 * vòng làm việc, nên chúng ở chung thẻ; nhưng chúng vẫn là hai nhịp. */
.kpc-vach { border: 0; border-top: 1px solid var(--vien); margin: var(--k-4) 0 var(--k-3) }

/* Dòng nói ô này đang có tác động hay không. Một ô chữ sửa được mà không nói
 * mình đang ngủ là một ô sẽ bị sửa rồi ngồi đợi kết quả không bao giờ tới. */
.kpc-trang-thai {
  margin: var(--k-2) 0 0; padding: var(--k-2) var(--k-3); font-size: var(--cs-phu); line-height: var(--dong-chay);
  border-left: 3px solid var(--vien-sang); background: var(--sau); border-radius: 0 var(--bo) var(--bo) 0;
}
.kpc-trang-thai.ngu { border-left-color: var(--chu-mo); color: var(--chu-nhat) }

/* Dòng báo trong màn — thay `alert()`. Trống thì không chiếm chỗ. */
.kpc-bao:empty { display: none }
.kpc-bao { margin: 0 0 var(--k-3) }

/* Hộp chọn ảnh (kho-anh-hop.js) — hai hàng công cụ + chân hộp. Tách khỏi
 * `.hang`/`.ht-nut` trần vì hộp này cần khoảng cách riêng ở dưới, còn hai class
 * gốc cố ý không có lề để chỗ khác tự quyết. */
.kho-anh-cong { display: flex; gap: var(--k-2); align-items: center; flex-wrap: wrap; margin-bottom: var(--k-2) }
.kho-anh-tim { flex: 1; min-width: 0 }
.kho-anh-ghi-chu { margin-top: var(--k-2) }
.kho-anh-chan { margin-top: var(--k-4) }

/* Bảng ba tầng trong «Chi tiết kỹ thuật». `table { width: 100% }` chia cột theo
 * nội dung, nên cột nhãn bị bẻ giữa cụm — *«1 · Bản viết / tay»*. Nhãn là một
 * đơn vị đọc, không phải một đoạn văn: khoá nó lại và để cột giải thích ăn phần
 * còn lại. `width: 1%` + `nowrap` là cách chuẩn bảo bảng co cột về đúng nội dung. */
.kv-goc td:first-child { width: 1%; white-space: nowrap; font-weight: 400 }

/* ── v12 bước 7c — bối cảnh trên form TẠO MỚI ────────────────
 *
 * Thu gọn mặc định nhưng KHÔNG ẩn: dòng tóm tắt luôn hiện, vì người dùng phải
 * biết là có một bối cảnh đang tác động dù họ không muốn đọc chi tiết. Ẩn hẳn
 * là quay lại đúng cái "bối cảnh ngầm" mà cả v12 sinh ra để xoá bỏ. */
/* ── THÔI LÀ MỘT HỘP — đợt ⑬, 01/09/2026 ────────────────────
   Khối này từng vẽ một hộp riêng (`--sau`, viền, vạch trái) NẰM TRONG thẻ
   của khối tạo mới, và bên trong nó lại có một `.tam` nữa. Ba tầng, sáng →
   tối → sáng; chủ dự án gọi đúng tên: «quá nhiều div lồng nhau, nhìn rất
   rối».

   Nay nó là một `.tam.khoi-tao` ngang hàng, nên mọi khai vẽ hộp ở đây đi
   hẳn. Lớp giữ lại đúng một việc: móc cho luật hẹp ngay dưới. */
/* `.kb-bc-dau` đi hẳn: dòng đầu của khối nay là một `<h3>`, và `.tam h3`
   đã khai đúng bộ ấy — flex, căn baseline, khe, tự xuống dòng. Giữ lại là dựng
   hai chỗ cho một hình. */

/* ── v13.1 — dải ảnh nhỏ, dùng chung ở ba màn ─────────────────
 *
 * Chủ dự án 18/08/2026: khối khoá phong cách khai "6 ảnh thật" mà không cho xem
 * tấm nào. Ảnh phải đủ to để NHẬN RA đúng xưởng của khách — 40px thì mọi ảnh
 * công nghiệp trông giống nhau — nhưng không được chiếm chỗ của đoạn chữ, vì
 * đoạn chữ mới là thứ đi vào prompt. */
.da-hang { display: flex; gap: var(--k-2); flex-wrap: wrap; margin: var(--k-2) 0 0 }
.da-o {
  display: block; width: 84px; text-decoration: none; color: inherit;
  border: 1px solid var(--vien); border-radius: var(--bo); overflow: hidden;
  background: var(--sau);
}
.da-o:hover { border-color: var(--vien-sang) }
.da-o img { display: block; width: 100%; height: 62px; object-fit: cover }
.da-ten {
  display: block; padding: var(--k-1) var(--k-1); font-size: var(--cs-nho); line-height: var(--dong-chat);
  color: var(--chu-nhat); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.da-hong { display: block; font-size: var(--cs-nho); padding: var(--k-1) var(--k-2) }

/* ── v14 bước 1 — HAI HỌ ẢNH trong Kho nguồn ──────────────────
 *
 * v13 thêm loại `nhan-dien` và cờ `laThamChieu`, nhưng màn Kho nguồn xếp bảy
 * loại cạnh nhau như nhau — trong khi chúng đi vào prompt theo hai đường ngược
 * hẳn. Bố cục phải tự dạy cái phân biệt ấy, vì nó là thứ quyết định hậu quả của
 * một cú bấm: gỡ một ảnh nhận diện đổi phong cách của CẢ chiến dịch. */
.ng-ho {
  margin: var(--k-5) 0 var(--k-0); font-size: var(--cs-de); font-weight: 600;
  padding-bottom: var(--k-2); border-bottom: 1px solid var(--vien);
}
.ng-ho:first-child { margin-top: var(--k-1) }
.ng-ho-mo { margin: 0 0 var(--k-3); line-height: var(--dong-chay) }

/* Câu cảnh báo của riêng một loại — đứng giữa tiêu đề nhóm và lưới ảnh, đúng
 * chỗ mắt đi qua trước khi chạm tới nút gỡ. */
.ng-canh-bao {
  margin: 0 0 var(--k-3); padding: var(--k-2) var(--k-3); line-height: var(--dong-chay);
  background: var(--sau); border-left: 3px solid var(--canh);
  border-radius: 0 var(--bo) var(--bo) 0;
}

/* Thẻ của ảnh KHÔNG đi vào prompt: viền đứt, cùng ngôn ngữ với khối 4 của bàn
 * dựng (`.khoi.nhe`) — chỗ duy nhất khác trong app cũng nói "ảnh này chỉ để đọc,
 * không để gửi đi". Hai chỗ nói cùng một điều thì phải trông giống nhau. */
.ng-the.ng-chu-nghia { border-style: dashed; border-color: var(--vien-sang) }

/* ── v14 bước 4 — "ảnh này đã dùng ở đâu" ─────────────────────
 *
 * Bản đầu vẽ bảng này VÀO TRONG thẻ ảnh, để câu trả lời nằm cạnh tấm ảnh đang
 * xét. Ý đúng, chỗ đặt sai: `.ng-the` là một flex hai cột (ảnh 120px + chữ), nên
 * bảng thành CON THỨ BA và tranh chiều rộng với phần chữ — chủ dự án chụp lại
 * 18/08/2026, mô tả ảnh bị bóp còn một ký tự mỗi dòng.
 *
 * Nay nó có ô riêng ngang hàng với bảng sửa ảnh (`#ng-sua`), ngay trên lưới thẻ:
 * vẫn trong tầm mắt, nhưng có cả chiều rộng màn hình và không bóp gì cả. */
.nd-khung {
  margin: 0 0 var(--k-4); padding: var(--k-3); font-size: var(--cs-phu);
  background: var(--sau); border: 1px solid var(--vien-sang);
  border-radius: var(--bo); max-height: 380px; overflow-y: auto;
  scrollbar-width: thin;
}
.nd-nhom { margin: var(--k-3) 0 var(--k-2); font-weight: 600 }
.nd-nhom:first-of-type { margin-top: 0 }

.nd-dong {
  display: flex; gap: var(--k-2); align-items: center;
  padding: var(--k-1) 0; border-top: 1px solid var(--vien);
}
.nd-dong img { width: 44px; height: 44px; object-fit: cover; border-radius: var(--bo-nho); background: var(--nen-anh) }
.nd-khong-anh {
  width: 44px; height: 44px; flex: 0 0 auto; display: grid; place-items: center;
  border: 1px dashed var(--vien-sang); border-radius: var(--bo-nho); color: var(--chu-nhat);
}
.nd-chu { min-width: 0; line-height: var(--dong-chay) }
.nd-chu b, .nd-chu span { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }

/* Lượt đã thu hồi vẫn HIỆN, chỉ mờ đi: nó là bằng chứng đã tiêu tiền và là một
 * mắt xích của chuỗi truy nguồn — giấu đi là làm câu trả lời pháp lý thiếu. */
.nd-dong.nd-thu-hoi { color: var(--chu-nhat) }
.nd-dong.nd-thu-hoi img { opacity: .55 }

/* ── v14 bước 5 — trạng thái ĐỒNG Ý dùng ảnh ──────────────────
 *
 * Ràng buộc CHECK ép phải có ghi chú LÚC NẠP, rồi thôi. Hạn đồng ý thì trôi qua
 * trong im lặng — đúng kiểu hỏng mà cả v13 lẫn v14 cứ gặp lại: không làm gãy gì,
 * chỉ sai dần. Bốn mức, và hai mức nặng phải đọc khác hẳn từ xa. */
.ng-dy-thieu   { background: var(--vien-dung); color: var(--chu-tren-mau) }
.ng-dy-het-han { background: var(--vien-dung); color: var(--chu-tren-mau) }
.ng-dy-sap-het { background: var(--vien-chan); color: var(--chu-tren-mau) }
.ng-dy-chua-han,
.ng-dy-con-han { color: var(--chu-nhat) }

/* Điều kiện ĐĂNG của ảnh khuôn mặt (bàn giao chéo 05.2, 17/09/2026) — cấm đọc nặng
 * như thiếu đồng ý; hỏi trước và chưa khai cùng mức cảnh; tự do nhạt. */
.ng-dang-cam       { background: var(--vien-dung); color: var(--chu-tren-mau) }
.ng-dang-hoi-truoc,
.ng-dang-chua-khai { background: var(--vien-chan); color: var(--chu-tren-mau) }
.ng-dang-tu-do     { color: var(--chu-nhat) }

/* Dải soát ở đầu màn. Không có gì cần soát thì nó BIẾN MẤT HẲN — một dải cảnh
 * báo luôn hiện là một dải người ta thôi đọc. */
.ng-soat { margin: 0 0 var(--k-4) }
.ng-soat .media-o img, .ng-soat .media-o video { width: 54px; height: 54px; object-fit: cover }

/* Nút GỠ mang màu cảnh báo: nó là lệnh duy nhất trong hàng có hệ quả, và nó
 * không được trông giống ba lệnh kia.
 *
 * Lớp `.ng-lenh` của hàng lệnh trên THẺ đã bỏ 23/08/2026 — thẻ không còn mang
 * lệnh nào, chúng chuyển hết vào khung chi tiết (`.ct-lenh`). */
.ng-nut-go { border-color: var(--vien-dung) }
.ng-nut-go:hover { background: var(--vien-dung); color: var(--chu-tren-mau) }
/* ── v16 — KHỐI VIẾT LẠI BẢN THẢO ──────────────────────────────
   Bản trước bày HAI CỘT so sánh (`.kv-so`) — và cột phải lặp lại y nguyên nội
   dung của ô bản thảo ngay phía trên nó. Chủ dự án chỉ ra 21/08/2026: cùng một
   đoạn chữ hiện hai chỗ, một chỗ sửa được một chỗ không, ba vùng cuộn chồng
   nhau, và nút Cắt bị đẩy xuống dưới cả khối. Nay ô bản thảo LÀ bản máy; khối
   này chỉ giữ bản gốc của người dùng, thu gọn. */
/* 8px là nhịp của chỗ nó sinh ra (dưới một dòng chữ trong form). Trong một cột
 * tài liệu nó là một THẺ, và thẻ đi theo nhịp của cột — nếu không thì khối cuối
 * dính vào khối trên trong khi năm khối kia cách nhau 24px. */
.kv-goc { margin-top: var(--k-2) }
.tai-lieu > .kv-goc { margin-top: var(--k-5) }
.kv-goc summary { cursor: pointer; font-size: var(--cs-ban); color: var(--chu-nhat) }
.kv-goc[open] summary { margin-bottom: var(--k-2) }

.kv-chu {
  margin: 0; padding: var(--k-2) var(--k-3); max-height: 220px; overflow: auto;
  border: 1px solid var(--vien); border-radius: var(--bo);
  background: var(--sau); font: inherit; font-size: var(--cs-ban); line-height: var(--dong-chay);
  white-space: pre-wrap; word-break: break-word;
}

/* ── 21/08/2026 — KHUNG TẠO MỚI NỔI KHỎI BẢNG LIỆT KÊ ─────────
   Trước đây fieldset tạo mới mang đúng viền 1px của mọi fieldset, còn bảng
   liệt kê bên dưới không có khung nào — hai khối không phân biệt được bằng
   mắt. Vạch trái màu thương hiệu cùng ngôn ngữ với nút chính: chỗ nào có nó
   là chỗ bắt đầu một việc.

   ── NỬA SAU CỦA CÂU TRÊN ĐÃ ĐƯỢC CHỮA Ở ĐÚNG CHỖ — 31/08/2026 ──
   «Bảng liệt kê không có khung nào» là thiếu sót của BẢNG, và đợt ấy chữa nó
   bằng cách cắm thêm một dấu vào khối KIA. Nay bảng có thẻ `.tam` và tiêu đề
   mục của riêng nó (bản vẽ d13a), nên hai khối tự phân biệt được.

   Vạch trái vẫn ở lại, và nay nó chỉ còn nói MỘT câu — «chỗ bắt đầu một việc»
   — thay vì kiêm luôn việc bù cho một cái khung thiếu. Một dấu hiệu nói một
   câu thì đọc được; nói hai câu thì không câu nào chắc.

   `background` GIỮ LẠI dù khối ở tab này nay là `.tam` và đã có đúng màu ấy:
   lớp này còn một người mượn nữa — `<fieldset class="khoi-tao">` của tab Kịch
   bản phim (`kich-ban-phim-tao.js`) — và `fieldset` không tự có nền. Gỡ ở đây
   là khối kia trong suốt ngay, ở một tab đợt này không mở ra soi. Dời một giá
   trị dùng chung thì phải dời cả chỗ mượn nó, hoặc đừng dời. */
/* Luật ĐỔI TÊN thành `.khoi-tao` và DỜI về `nen.css` ngày 01/09/2026 (đợt ⑫,
   luật Đ4). Hai tab Kịch bản dùng nó, nên nó thôi đeo tên viết tắt của một
   tab — và câu «dời một giá trị dùng chung thì phải dời cả chỗ mượn nó» ở đoạn
   trên nay được trả lời bằng cách bỏ hẳn quan hệ mượn. */

/* Ô bản thảo cao lên theo chữ — một khe 5 dòng cố định không dùng được cho
   bản thảo 5 phút. `field-sizing` chưa có ở mọi trình duyệt; nơi chưa có thì
   nó là textarea thường với min-height, không hỏng gì. */
#kb-caption { field-sizing: content; min-height: 88px; max-height: 45vh }

/* ── D1 22/08/2026 — THẺ THỰC THỂ TRONG DÀN NHÂN VẬT ───────────
   Mỗi thực thể một thẻ: ảnh nhỏ, tên sửa được, vai, mô tả một dòng. Thẻ nằm
   trong `.luoi-chon-media` nên xếp ngang và tự xuống dòng. */
.kd-the { padding: var(--k-2) var(--k-3); min-width: 250px; max-width: 320px; flex: 1 1 250px }
.kd-the textarea { font-size: var(--cs-ban) }
.kd-anh { width: 56px; height: 56px; object-fit: cover; border-radius: var(--bo-nho); flex: none }

/* ── C1 22/08/2026 — CHUỖI LIÊN TỤC TRONG BẢNG CẢNH ────────────
   Cảnh nối tiếp không có đường kẻ trên: hai dòng liền nhau ĐỌC RA một khối, và
   đó đúng là thứ chuỗi là. Vạch trái màu tiền vì chuỗi ép cảnh thành clip. */
.kb-noi-tiep > td { border-top: 0 }
.kb-noi-tiep > td:first-child { box-shadow: inset 3px 0 0 var(--canh) }
.kb-moc { color: var(--canh); font-weight: 600; margin-right: var(--k-0) }

/* ── Đợt Studio 1 — KHUNG XEM VỊ TRÍ CẮT ───────────────────────
   Mỗi tỉ lệ đang chọn một khung nhỏ, ảnh gốc đặt object-fit: cover với
   object-position theo chip vị trí cắt — cùng ngữ nghĩa với sharp nên khung
   xem LÀ khung sẽ ra. Cao cố định, rộng tự tính từ aspect-ratio. */
#f-cat-xem { display: flex; flex-wrap: wrap; gap: var(--k-2); margin-top: var(--k-2) }
.cx-khung {
  margin: 0; height: 92px; flex: 0 0 auto; position: relative;
  border: 1px solid var(--vien); border-radius: var(--bo); overflow: hidden;
}
.cx-khung img { width: 100%; height: 100%; object-fit: cover; display: block }
.cx-khung figcaption {
  position: absolute; left: 0; bottom: 0; padding: 1px var(--k-2);
  font-size: var(--cs-nho); color: var(--chu-tren-anh); background: rgba(0, 0, 0, 0.55);
  border-radius: 0 var(--bo) 0 0;
}

/* ── Đợt Studio 2 — KHỐI CHỮ VÀ Ô XEM THỬ ──────────────────────
   `.cf-hang` xếp hai ô cạnh nhau (tiêu đề / dòng phụ, hoặc hai mốc giây);
   dưới 700px thì xếp dọc — ô chọn font có tên họ dài, chật là cắt chữ.

   Ngưỡng ấy đo CỘT SOẠN (`#st-ban`), không đo cửa sổ — sửa 28/08/2026. Bản
   `@media (max-width: 700px)` chưa từng khớp ở máy bàn: đo được ở khổ
   1600×864 với bố cục lưới lồng của đợt 2b, cột soạn còn 445px, hai ô chọn
   font mỗi ô 200px và tên họ dài bị cắt — đúng ca mà dòng chú trên đây nói là
   phải xếp dọc, còn cửa sổ thì đang 1600px nên luật không chạy. Đợt 2m bỏ lưới
   lồng nên cột soạn không còn tụt xuống 445px ở máy bàn, nhưng ngưỡng vẫn phải
   hỏi cột: ở bề rộng điện thoại và ở tab gập một cột nó vẫn là thứ quyết định.
   Cùng họ với lỗi `@media` của đợt 2a. */
.cf-hang { display: grid; grid-template-columns: 1fr 1fr; gap: var(--k-2) }
@container soan (max-width: 700px) { .cf-hang { grid-template-columns: 1fr } }
.cf-hang select { width: 100% }

/* Dòng xem mặt chữ: nền sẫm để chữ trắng đọc được giống trên ảnh thật.
   Không cắt xuống dòng — tên họ script chữ rất rộng, xuống dòng làm mất
   cảm giác về độ dài thật của tít. */
.cf-xem {
  margin-top: var(--k-2); padding: var(--k-3) var(--k-3); border-radius: var(--bo);
  background: var(--nen-gia-anh); color: var(--chu-tren-anh); overflow-x: auto; white-space: nowrap;
}
.cf-xem span { display: block; font-size: var(--cs-tab); line-height: var(--dong-chat) }
.cf-xem small { display: block; margin-top: var(--k-1); font-size: var(--cs-ban); opacity: 0.86 }
.cf-canh { margin-top: var(--k-2); font-size: var(--cs-ban); line-height: var(--dong-chay) }

.ban-nut { display: flex; gap: var(--k-2); align-items: center; margin-top: var(--k-4) }

/* Ô xem thử. Cao tối đa 60vh — ảnh 9:16 xem thử mà tràn hết màn hình thì
   nút Xuất lại bị đẩy khỏi tầm mắt, và đó là nút người ta cần bấm tiếp theo. */
#f-xem-thu:not(:empty) { margin-top: var(--k-3) }
.xt-khung { margin: 0 }
.xt-khung img {
  display: block; max-width: 100%; max-height: 60vh;
  border: 1px solid var(--vien); border-radius: var(--bo);
}
.xt-khung figcaption { margin-top: var(--k-2); font-size: var(--cs-phu) }
.xt-canh { margin-top: var(--k-2); font-size: var(--cs-ban); line-height: var(--dong-chay) }

/* ── Đợt Studio 3 — VỊ TRÍ KHỐI CHỮ VÀ HUY HIỆU ────────────────
   Ba ô số chia đều một hàng (`.st-hang` ở trên), thay cho một hàng flex xếp
   dồn về trái — sửa 28/08/2026 theo bản vẽ. Bản flex cũ để ba nhãn dài
   («Khổ chữ % (chỗ xuống dòng — cỡ chữ là ô khác)») gãy làm ba dòng cao 120px
   trong một cột 445px, còn ba ô số 84px thì lọt thỏm giữa đám chữ ấy.
   Nút «về mặc định» chuyển lên cuối hàng chip neo — xem `hau-ky-ban-vi-tri.js`. */
.vt-hang { margin-top: var(--k-2) }
.vt-hang label { margin: 0 }
.vt-hang input[type="number"] { width: 100%; display: block; margin-top: var(--k-1) }

.hh-hang {
  border: 1px solid var(--vien); border-radius: var(--bo);
  padding: var(--k-2) var(--k-3); margin-top: var(--k-2);
}
.hh-hang input[type="text"] { flex: 1 }
.hh-chon { margin-top: var(--k-2); display: flex; flex-wrap: wrap; gap: 0; align-items: center }
.hh-chon .mieng { margin: 0 var(--k-1) var(--k-1) 0 }
.hh-chon .nhat { margin: 0 var(--k-2) var(--k-1) var(--k-0) }

/* ── Đợt Studio 4 — KHỐI MÔ TẢ LẠI ─────────────────────────────
   Sáu ô mô tả co theo nội dung nhưng có trần — mô tả chi tiết là tốt, một ô
   chiếm nửa màn hình thì năm ô kia rơi khỏi tầm mắt. */
#st-mo-ta:not(:empty) { margin-top: var(--k-4) }
#st-mo-ta textarea[data-muc] {
  width: 100%; min-height: 44px; max-height: 160px; resize: vertical;
  font: inherit; font-size: var(--cs-ban); line-height: var(--dong-chay);
}
/* Chỉ khác `.hang` ở một chỗ: KHÔNG khe. Ba dòng kia (`display` · `flex-wrap`
   · `align-items`) từng khai lại y nguyên tầng nền — gỡ ở đợt K1. */
#st-mo-ta .hang { gap: 0 }

/* ── Đợt Studio 5 — GẮN VÀO BÀI NOTION ─────────────────────────
   Khối chỉ hiện khi ảnh CHƯA gắn bài nào, nên nó phải mời gọi mà không tranh
   chỗ với thông tin bài ở ngay trên. Vạch trên tách nó khỏi khối lai lịch. */
.gb-khu {
  margin-top: var(--k-3); padding-top: var(--k-3);
  border-top: 1px dashed var(--vien);
  font-size: var(--cs-ban);
}
.gb-khu .lua-chon-luoi { margin: var(--k-2) 0 }

/* ── L4 22/08/2026 — THANH BỐN BƯỚC của tab Kịch bản ─────────
 *
 * Mượn `.thanh`/`.thanh i` của `web/kieu/vo.css` thay vì dựng một thanh thứ
 * hai: hai thanh tiến độ trông khác nhau trên cùng một app đọc ra hai thứ khác
 * nhau. Chỉ nới chiều rộng trong phạm vi `.kb-buoc`, không sửa lớp gốc — nó
 * đang thuộc về dải ngân sách ở vỏ.
 *
 * Số ①②③④ theo đúng mẫu «bước» duy nhất đang chạy (tab Chuẩn thương hiệu,
 * `.kf-buoc`) — kho không được có hai ngôn ngữ «bước» ở hai tab. */
.kb-buoc { list-style: none; margin: 0; padding: 0 }
.kb-buoc li {
  display: flex; align-items: baseline; gap: var(--k-2); flex-wrap: wrap;
  padding: var(--k-1) 0; border-bottom: 1px solid var(--vien);
}
.kb-buoc li:last-child { border-bottom: 0 }
.kb-buoc li b:first-child { min-width: 130px; flex: none }
.kb-buoc li span { flex: 1; min-width: 180px }
.kb-buoc .thanh { width: 120px }
.kb-buoc li.xong  { color: var(--tot) }
.kb-buoc li.dang  { color: var(--chu) }
.kb-buoc li.chua  { color: var(--chu-nhat) }
.kb-buoc li.dang b:first-child { color: var(--canh) }

/* ── 22/08/2026 — DÀN NHÂN VẬT ở màn sửa kịch bản (chỉ đọc) ──
 *
 * Thẻ chứ không phải một dòng tên: dòng tên không nói được thực thể nào đã hết
 * hạn đồng ý, mà đó là thứ duy nhất khiến một cảnh bị từ chối khi tạo. */
.kb-dan-luoi { display: flex; flex-wrap: wrap; gap: var(--k-2) }
.kb-dan-the {
  flex: 1 1 220px; min-width: 220px; padding: var(--k-2) var(--k-2);
  background: var(--sau); border: 1px solid var(--vien); border-radius: var(--bo);
  font-size: var(--cs-phu); line-height: var(--dong-chay);
  /* Đợt 2 (04/09/2026): ảnh của thực thể đứng bên trái chữ — thẻ dàn ở màn
     chi tiết từng không có ảnh, chủ dự án chỉ ra. Cùng cỡ ô ảnh với `.kd-anh`
     của thẻ ở form tạo mới. */
  display: flex; gap: var(--k-2); align-items: flex-start;
}
.kb-dan-the.hong { border-color: var(--xau) }
.kb-dan-anh { flex: 0 0 auto; width: 44px; height: 44px; object-fit: cover; border-radius: var(--bo-nho) }
.kb-dan-chu { flex: 1 1 auto; min-width: 0 }

/* ── DẢI VÙNG ĐI HẲN — 07/09/2026 ────────────────────────────
 *
 * Họ `.vung` / `.vung-ten` / `.vung-cau` / `.vung-a…d` ra đời 22/08 ở tab Kịch
 * bản (tên cũ `.kb-vung`), dùng chung từ 25/08 cho bốn vùng Ⓐ–Ⓓ của thẻ Cẩm
 * nang. Đo 07/09: **chỉ thẻ Cẩm nang gọi nó**, và tệp `kich-ban-vung.js` mà
 * chú thích cũ dẫn ra làm lý lẽ cho «hai bảng KHÔNG gộp» chưa từng tồn tại.
 *
 * Chủ dự án chốt bỏ tầng vùng: sáu mốc của `TIEN_DO` làm luôn việc phân nhóm,
 * mỗi mốc một thẻ `.tam` mang `<h3 data-so>`. Nên cả họ này mất chỗ dùng —
 * 37 dòng, cùng `web/loi/vung.js`.
 *
 * Hai điều đáng giữ lại từ nó, đã dời sang chỗ khác:
 *   · «màu là lớp thứ hai, chữ phải nói đủ» — nay ở `.kn-td-o`, nơi ba trạng
 *     thái của dải tiến độ có DẤU trước khi có màu.
 *   · «`:first-of-type` so theo TÊN THẺ nên khớp cả `<div>` không phải dải» —
 *     luật ấy đứng ở `.kn-muc`.
 *
 * Bốn màu vạch Ⓐ–Ⓓ không dời đi đâu: chúng mã hoá «vùng này tiêu tiền / vùng
 * này $0», và điều ấy nay do chính câu chữ dưới tiêu đề mốc 5 nói ra. */

/* ── HAI KHỐI CẠNH NHAU — bố cục Nocturne đợt 2b, 28/08/2026 ──
 *
 * ── NÓ LẬT MỘT CHỐT CŨ, VÀ ĐÂY LÀ PHẦN CÒN GIỮ ───────────────
 * Chốt 23/08 ghi ở đầu `chuan-thuong-hieu.js`: *«mọi block ăn 100% khung chứa
 * nó»*. Chốt ấy ra đời sau khi gỡ 25 thuộc tính `style=` rải trong hai tệp JS,
 * và phần lõi của nó là **bố cục đến từ CSS, không từ tệp JS nào** — không phải
 * bề rộng 100%. Chủ dự án chốt lại 28/08: ghép được, miễn ghép bằng một class ở
 * đây. Con số cố định vẫn không có cái nào trong JS.
 *
 * ── VÌ SAO CHIA ĐỀU, KHÔNG PHẢI 400px + 1fr NHƯ BẢN VẼ ───────
 * Bản vẽ cho vùng Ⓒ một cột hẹp (vẽ logo) cạnh một cột rộng (mockup). Ở đây hai
 * khối ấy chia đều, vì thứ tự của chúng là thứ tự NHÂN QUẢ — vẽ logo trước, đặt
 * logo lên vật thật sau — và cách duy nhất để cho mockup cột rộng mà vẫn dùng
 * `.hai-cot` (vốn là `1fr` + cột phải hẹp) là đảo chỗ hai khối, tức là bày kết
 * quả trước nguyên nhân. Chia đều giữ đúng thứ tự và vẫn hết bề ngang.
 *
 * Gập theo `@container`, cùng lý lẽ đã ghi ở `.hai-cot`: thứ chứa nó là `#khu`,
 * đã mất 272px cho thanh bên, nên đo cửa sổ là đo nhầm thứ. Ngưỡng rộng hơn
 * ngưỡng của `.hai-cot` một chút — hai khối này không cõng prompt hay bảng, nên
 * chúng chịu được cột hẹp hơn trước khi phải xếp chồng. */
/* ── CHUỖI KHỐI ĐÁNH SỐ — đợt 2e, 28/08/2026 ─────────────────
 *
 * `.khoi` khai `margin: 0` để chỗ dùng quyết khoảng cách, nên một chuỗi bước
 * phải tự khai nhịp của nó. `--khe-4` là khe GIỮA HAI THẺ, và mỗi bước đúng là
 * một thẻ — bóp hẹp lại để chúng «dính vào nhau cho ra một chuỗi» là phá đúng
 * cái nhịp bốn nấc mà cả app đang đứng trên. Thứ nối các bước thành một chuỗi
 * là vạch trái của `.khoi` và dãy số ①→⑥, không phải khoảng trắng. */
.khoi-chuoi { display: flex; flex-direction: column; gap: var(--k-5) }

/* ── HÀNG KHỐI: nguyên liệu song song, lượt lắp song song ────
 *
 * Ba bước ②③④ không phụ thuộc nhau, hai bước ⑤⑥ thì nối tiếp — nhưng cả hai
 * cụm đều xếp NGANG, vì thứ chúng nói là «đây là một cụm», còn thứ tự thì đã
 * nằm ở dãy số và ở thanh bước phía trên.
 *
 * `auto-fit` + `minmax` thay cho số cột cứng: ở `#khu` 1208px (thanh bên mở,
 * màn 1536 của chủ dự án) hàng ba ra đúng ba cột ~390px; gập thanh bên thì nó
 * rộng ra chứ không đổi số cột; ở cột hẹp nó tự về hai rồi một. Một `repeat(3,
 * 1fr)` cứng thì ở bề rộng điện thoại là ba dải chữ không đọc được.
 *
 * Ngưỡng của hàng HAI rộng hơn (420px): hai khối ấy chở video xem thử và bảng
 * trạng thái từng cảnh, không phải một nút với một đoạn dặn. */
.khoi-hang { display: grid; gap: var(--k-5); align-items: start }
.khoi-hang.ba  { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)) }
.khoi-hang.hai { grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)) }

/* ── KHỐI ⑤ «DỰNG VIDEO» — BA CỘT, 06/09/2026 ────────────────
 * Đặc tả: `docs/dac-ta-tab/thiet-ke-gop-buoc-dung-video-dot-1.md`.
 *
 * Ba cột KHÔNG bằng nhau, và đó là chủ ý: cột GIỮA tiêu tiền và chở nhiều nội
 * dung nhất (dòng giá, danh sách cảnh, nút, cảnh báo), nên nó rộng gấp rưỡi hai
 * cột kia. Ba ô bằng nhau đọc như «chọn một trong ba», trong khi quan hệ thật là
 * «1 rồi 2 rồi 3».
 *
 * `auto-fit` như hai hàng trên: ở màn hẹp nó tự xuống một cột, và lúc ấy thứ tự
 * trên-dưới VẪN đúng chuỗi khoá. */
.kb-dung-cot { display: grid; gap: var(--k-5); align-items: start; margin-top: var(--k-3) }
.kb-dung-cot { grid-template-columns: 1fr 1.5fr 1fr }
/* Cot hep thi ve mot cot, va thu tu tren-duoi VAN dung chuoi khoa. `@container`
   chu khong `@media`: khoi song theo CHIEU RONG CUA COT, khong theo cua so —
   gap thanh ben la doi 336px ma cua so khong nhuc nhich. */
@container khu (max-width: 1040px) { .kb-dung-cot { grid-template-columns: minmax(0, 1fr) } }
.kb-dung-cot > .cot > b { display: block; margin-bottom: var(--k-2) }

/* ── CỘT TIỀN NỔI BẰNG MÀU, KHÔNG BẰNG HỘP — sửa 06/09/2026 ──
 *
 * Bản đầu bọc cột 2 trong một hộp có viền, đệm và nền. Đúng ý (cột tiêu tiền
 * phải trông khác) nhưng sai cách: đệm của hộp đẩy tiêu đề cột giữa xuống, nên
 * ba tiêu đề thôi thẳng hàng — chủ dự án chỉ ra bằng ảnh chụp. Và khi clip đã
 * gửi hết thì cột 2 rỗng, còn cái hộp thì vẫn khoanh lấy một khoảng trống.
 *
 * Nay nổi bằng MÀU của tiêu đề và nút. Nhẹ hơn, và đúng hơn: thứ tiêu tiền là
 * cái NÚT, không phải cả cột. Ba cột giữ nguyên một dòng cơ sở. */
.kb-dung-cot > .cot.tien > b { color: var(--canh) }
/* Không đặt lớp mới cho cái nút: trong cột 2, mọi hành động CHÍNH đều tiêu
   tiền theo định nghĩa — đó là toàn bộ việc của cột. `:not(:disabled)` để nút bị
   khoá giữ nền xám của nó: luật này nằm ở `man.css` nên nặng hơn `button.chinh:disabled`
   ở `nen.css`, và một nút khoá mà vẫn tô đặc là một lời mời bấm vào chỗ không bấm được. */
.kb-dung-cot > .cot.tien button.chinh:not(:disabled) { background: var(--tien) }

/* Thumbnail nằm TRONG cột 2 — chúng là kết quả của chính cột ấy, và cột ấy là
   cột rộng nhất mà lại rỗng nhất sau khi gửi xong. Bản đầu để chúng trải hết
   đáy khối, tức tách rời khỏi thứ sinh ra chúng. */
.kb-dung-thumb { margin-top: var(--k-3); border-top: 1px solid var(--vien); padding-top: var(--k-3) }
.the-clip {
  display: block; padding: 0; border: 1px solid var(--vien); border-radius: var(--bo);
  background: none; cursor: pointer; overflow: hidden; width: 132px;
}
.the-clip video { display: block; width: 100%; height: 74px; object-fit: cover }
.the-clip span { display: block; padding: var(--k-1) var(--k-2); font-size: .85em }

/* `.canh-nhau` DỜI về `nen.css` 01/09/2026 — lưới bố cục dùng ở 5 tab, nay đứng
   cạnh `.hai-cot`. Hai biến thể của nó (`.kn-hinh` · `.kn-giao`) ở LẠI đây và
   vẫn đứng sau lớp gốc; xem chú thích của chúng phía dưới. */

/* ── TAB DOANH NGHIỆP — bản vẽ N15, 30/08/2026 ───────────────
 *
 * Ô LOGO ĐANG THIẾU: bản kem báo «thiếu» bằng NỀN ĐEN; ở nền tối cách ấy hỏng
 * vì nền màn đã tối và ô hoà vào nền. `nx-note` của bản vẽ chốt: đổi dấu hiệu
 * sang VIỀN ĐỨT màu nhấn. Chỉ ô THIẾU đổi — ô đã có logo vẫn tô giấy đúng nền
 * của nó, vì đó là cả lý do có hai bản. */
.dn-o-logo .dn-xem {
  min-height: 76px; display: flex; align-items: center; justify-content: center;
  padding: var(--k-3); border: 1px solid var(--vien); border-radius: var(--bo);
}
.dn-o-logo.thieu .dn-xem {
  border-style: dashed; border-color: var(--vien-chon); background: var(--sau);
}
.dn-thieu { font-size: var(--cs-phu); color: var(--thuong-chu) }
.dn-hau-qua { margin: var(--k-2) 0 0; color: var(--canh) }

/* Ô chọn tệp bọc trong một NHÃN trông như nút: `<input type=file>` lộ thiên là
 * ô xấu nhất màn và mỗi trình duyệt vẽ một kiểu. Ô thật vẫn ở đó — chỉ bị đưa
 * ra ngoài khung nhìn, KHÔNG `display:none`: ô ẩn hẳn thì bàn phím không tới
 * được, và cả nút thành vô dụng với người không dùng chuột. */
.nut-tep { display: block; margin-top: var(--k-2) }
.nut-tep > input[type="file"] {
  position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none;
}
.nut-tep > span {
  display: block; text-align: center; cursor: pointer;
  padding: var(--k-2) var(--k-3); border: 1px solid var(--vien);
  border-radius: var(--bo); font-size: var(--cs-phu); color: var(--chu-nhat);
}
.nut-tep:hover > span { background: var(--nen-luot); color: var(--chu) }
/* Bàn phím tới ô thật thì vành sáng phải hiện trên cái NHÃN — nếu không, người
   dùng bàn phím không thấy mình đang đứng ở đâu. */
.nut-tep > input[type="file"]:focus-visible + span {
  outline: 2px solid var(--vien-chon); outline-offset: 2px;
}

/* ── TAB TÀI KHOẢN — bản vẽ N15, 30/08/2026 ──────────────────
 *
 * Bản vẽ bỏ `<table>` ở CẢ HAI chỗ, và nó đúng: hai dòng «Doanh nghiệp / Vai»
 * không phải một BẢNG, chúng là hai cặp nhãn–giá trị. Bọc chúng trong `<table>`
 * bắt trình đọc màn hình đọc ra một cấu trúc hàng–cột không có thật, và ở cột
 * hẹp thì trình duyệt tự chia đôi bề rộng theo luật bảng chứ không theo ý mình.
 *
 * Nhãn có bề rộng CỐ ĐỊNH để mọi giá trị thẳng hàng — nhưng `flex-shrink` vẫn
 * cho nó co khi cột hẹp lại, thay vì đẩy giá trị ra ngoài. */
.toi-dong, .toi-quyen {
  display: flex; gap: var(--k-3); align-items: baseline;
  padding: var(--k-3) 0; border-bottom: 1px solid var(--vien);
}
/* Dòng CUỐI bỏ vạch: một vạch dưới dòng cuối là vạch không ngăn cách gì. */
.toi-dong.cuoi, .toi-quyen.cuoi { border-bottom: 0 }
.toi-nhan { flex: 0 1 120px; min-width: 0; color: var(--chu-nhat); font-size: var(--cs-phu) }
.toi-gia { min-width: 0; font-size: var(--cs-phu) }
/* Bảng quyền: tên việc ăn hết chỗ, dấu ✓/— dạt về mép phải. */
.toi-quyen > :first-child { flex: 1; min-width: 0; font-size: var(--cs-phu) }
/* Tiêu đề của một PHẦN trong thẻ — nhỏ hơn tiêu đề thẻ, vì nó là nhịp thứ hai
   của cùng một mạch đọc, không phải một thẻ mới. */
/* Mục CON trong thẻ «Đang làm việc cho» của tab Tài khoản — nhịp thứ hai, nhỏ
   hơn tiêu đề thẻ. Phải là `h3.toi-muc` chứ không `.toi-muc`: hai mục ấy nằm
   TRONG một `.tam`, và `.tam h3` (0,1,1) đè một lớp trần (0,1,0). Đo 02/09
   trước khi sửa: cả cha lẫn con cùng 16px — không phân biệt được bậc nào với
   bậc nào, và ý định 12px viết ở đây chưa bao giờ vẽ ra. */
h3.toi-muc { margin: var(--k-5) 0 var(--k-2); font-size: var(--cs-phu) }
.toi-muc.vach { padding-top: var(--k-4); border-top: 1px solid var(--vien) }

/* ── TAB ĐỘI NHÓM — bản vẽ N7, 30/08/2026 ────────────────────
 *
 * Bảng thành viên và ma trận vai là LƯỚI, không `<table>`. Với bảng người thì
 * lý do là bề rộng: `<table>` tự chia cột theo nội dung, nên một email dài bóp
 * cột «Vai» hẹp lại cho tới lúc ô chọn không đọc được. Lưới khai bề rộng từng
 * cột, và cột người là cột DUY NHẤT co giãn.
 *
 * `align-items: start` chứ không `center`: ô người cao ba dòng (tên · email ·
 * đăng nhập cuối), và căn giữa thì ô chọn vai trôi xuống giữa khối chữ ấy. */
.dnh-hang {
  display: grid; grid-template-columns: minmax(0, 1fr) 150px 70px;
  gap: var(--k-3); align-items: start;
  padding: var(--k-3) 0; border-bottom: 1px solid var(--vien);
}
.dnh-luoi > .dnh-hang:last-child, .dnh-mt > .dnh-hang:last-child { border-bottom: 0 }
/* Hàng đầu là NHÃN CỘT, không phải một hàng dữ liệu — in hoa cỡ nhỏ, cùng
   ngôn ngữ với mọi nhãn nhóm khác trong app. */
.dnh-hang.dau {
  padding-top: 0; font-size: var(--cs-nho); font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--chu-mo);
}
.dnh-hang > select { width: 100% }
/* Ma trận khai cột riêng qua `style` (số vai đến từ máy chủ, không đóng đinh
   được ở đây). Dấu ✓/— căn giữa dưới đúng tên vai của nó. */
.dnh-mt > .dnh-hang > :not(:first-child) { text-align: center }

/* Hộp trạng thái đồng bộ: vạch TRÁI, không viền trọn — theo bản vẽ bản tối. */
.dn-trang-thai {
  margin: 0 0 var(--k-4); padding: var(--k-3);
  background: var(--sau); border-left: 2px solid var(--thuong-chu);
  border-radius: var(--bo); font-size: var(--cs-phu); line-height: var(--dong-chay);
}
.dn-trang-thai > .nhat { font-size: var(--cs-nho) }

/* ── HAI BIẾN THỂ CỦA `.canh-nhau`, PHẢI ĐỨNG SAU NÓ ─────────
 *
 * Thứ tự này là BẮT BUỘC, không phải cách xếp cho gọn. Cả hai lớp dưới đây ghi
 * đè `grid-template-columns` của `.canh-nhau` và có CÙNG hạng riêng (0,1,0) với
 * nó — nên chỉ thứ tự nguồn quyết cái nào được dùng. Đo 29/08: đặt chúng ở khu
 * `kpc-*` phía trên thì `.canh-nhau` đứng sau và được dùng, và vùng Ⓓ vẫn ra
 * `568px 568px` dù đã khai ba cột. Lần thứ ba của cùng một cái bẫy — xem
 * `.st-cot` (đợt 2n) và `.kpc-gap`.
 *
 * ── VÀ TỪ 01/09 QUAN HỆ ẤY ĐI QUA HAI TỆP ───────────────────
 * Việc ② dời `.canh-nhau` sang `nen.css`. Chú thích cũ viết «đặt NGAY SAU nó»,
 * mà «ngay sau» thôi đúng khi hai thứ ở cùng một tệp. Nay quan hệ do
 * `index.html` khoá — nen → vo → man — nên hai lớp này đứng sau lớp gốc dù
 * chúng nằm ở dòng nào của tệp này. Chắc hơn chứ không lỏng đi; nhưng nếu ngày
 * nào ai đó dời NGƯỢC lớp gốc xuống `man.css` thì phải đọc lại đúng đoạn này.
 */

/* Ⓒ — Logo hẹp, Mockup rộng. Hai khối không ngang cỡ: ô Logo chở hai bản, ô
   Mockup chở sáu tấm ảnh. Chia đều là ép sáu tấm vào nửa màn còn nửa kia trống. */
.kn-hinh { grid-template-columns: 400px minmax(0, 1fr) }

/* Ⓓ — BA đường lấy hàng ra, không hai. Bản trước gộp PDF với EOS vào một thẻ vì
   «hai đường dùng chung một lời dẫn»; lời dẫn chung thật, nhưng nó dài hai dòng
   còn mỗi đường thì có ba câu dặn riêng. */
.kn-giao { grid-template-columns: repeat(3, minmax(0, 1fr)) }

/* Trạng thái «chưa viết hạng mục nào» chỉ có HAI thẻ, và thẻ đầu đứng thay chỗ
   cả PDF lẫn EOS — nên nó ăn hai cột. Để nó ăn một cột thì cột thứ ba trống, mà
   một ô trống giữa lưới đọc ra như một thẻ vỡ không vẽ được. */
.kn-giao > .kn-giao-trong { grid-column: span 2 }

/* Gập thì cả hai về một cột, cùng ngưỡng và cùng khung đo với lớp gốc — nhưng
   vẫn phải KHAI LẠI, cùng lý lẽ vừa ghi ở trên.

   `span 2` phải gỡ theo: trong lưới một cột nó KHÔNG bị kẹp về 1 mà đẻ ra một
   cột ngầm thứ hai, tức đúng cái tràn ngang mà cú gập sinh ra để tránh. */
@container khu (max-width: 900px) {
  .kn-hinh, .kn-giao { grid-template-columns: minmax(0, 1fr) }
  .kn-giao > .kn-giao-trong { grid-column: auto }
}

/* ══ Media nguồn — đợt tối ưu 1, 23/08/2026 ═══════════════════ */

/* ── Khu đưa tệp vào (nguon-nhap.js) ──────────────────────────
 *
 * Chủ dự án 23/08: khu nhập chưa nổi hơn phần còn lại. Nó không nổi được vì
 * mọi thứ trong nó cùng một trọng lượng — bốn ô, một ô ghi chú, rồi mới tới ô
 * thả. Nay ô thả là thứ DUY NHẤT của nhịp ①, nên nó lấy hết chỗ. */
.ng-nhap { background: var(--tam); border-color: var(--vien-sang) }
.ng-tha {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--k-1); min-height: 132px; padding: var(--k-5); text-align: center; cursor: pointer;
  border: 2px dashed var(--vien-nut); border-radius: var(--bo-lon);
  background: var(--sau);
}
.ng-tha:hover { border-color: var(--vien-chon) }
/* Đang rê tệp lên trên. Bản trước đổi `opacity` — làm CẢ ô mờ đi, tức là tín
 * hiệu "thả được ở đây" trông y hệt tín hiệu "ô này đang bị khoá". */
.ng-tha-vao { border-color: var(--vien-chon); background: var(--chon) }
.ng-tha b { font-size: var(--cs-de) }
.ng-tha .nhat { line-height: var(--dong-chay) }
.ng-nhap-url { margin-top: var(--k-3) }

/* Nhịp ② — chỉ có mặt khi đã chọn tệp. Lùi vào một bậc và kẻ vạch bên trái để
 * đọc ra là "phần tiếp theo của việc vừa làm", không phải một khối mới. */
.ng-cho {
  margin-top: var(--k-4); padding: var(--k-3) var(--k-4);
  border-left: 3px solid var(--vien-chon); background: var(--sau);
  border-radius: 0 var(--bo) var(--bo) 0;
}
.ng-cho-dau { margin: 0 0 var(--k-2); display: flex; gap: var(--k-2); align-items: baseline }
.ng-cho-tep { display: flex; flex-wrap: wrap; gap: var(--k-2); margin-bottom: var(--k-3) }
.ng-tep-o {
  display: inline-flex; align-items: center; gap: var(--k-1); max-width: 240px;
  border: 1px solid var(--vien); border-radius: var(--bo);
  background: var(--tam); padding: var(--k-1) var(--k-1) var(--k-1) var(--k-2); font-size: var(--cs-phu);
}
.ng-tep-ten { overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.ng-nhan { display: block; font-size: var(--cs-phu); color: var(--chu-nhat); margin: 0 0 var(--k-1) }
.ng-cho select, .ng-cho textarea { width: 100% }
.ng-han { display: flex; align-items: center; gap: var(--k-2) }

/* Dòng hệ quả của loại đang chọn. Nó là chỗ trần 6 ảnh nhận diện hiện ra ĐÚNG
 * LÚC còn quyết được — xem `MAX_REFS` trong `src/style-lock.js`. */
.ng-he-qua {
  margin: var(--k-2) 0 0; padding: var(--k-2) var(--k-2); line-height: var(--dong-chay);
  border-left: 2px solid var(--vien-sang); background: var(--tam); border-radius: var(--bo);
}
.ng-he-qua-canh { border-left-color: var(--canh) }

/* ── Thanh lọc (nguon-loc.js) ─────────────────────────────────
 *
 * Bản trước là một hàng ô trần, cách danh sách 4px. Chủ dự án báo hai khu dính
 * nhau; khoảng cách chỉ là triệu chứng, bệnh là thanh lọc không đọc ra một
 * thanh công cụ. Nay có nền, có viền, và DÍNH ĐỈNH khi cuộn — kho lớn thì một
 * thanh lọc ở đầu trang là thanh lọc phải cuộn ngược lên mới đụng tới.
 *
 * ── DÍNH DƯỚI DẢI TIÊU ĐỀ, KHÔNG DÍNH Ở 0 — 28/08/2026 ──────
 * `top: 0` cho thanh này dính đúng chỗ `#dau-man` đang đứng, mà dải ấy cao
 * 68px với z-index 8, còn thanh này cao 62px với z-index 3. Kết quả: cuộn
 * xuống là thanh lọc chui HẲN xuống dưới dải tiêu đề, không còn một điểm ảnh
 * nào — cả lý lẽ ghi ngay phía trên bị vô hiệu trong im lặng. `test-web` và
 * `npm run mau` đều không bắt được vì cả hai dựng KHÔNG CÓ VỎ; nó chỉ lộ ra
 * khi mở app thật. Con số nay đến từ chính chỗ dải ấy được định nghĩa
 * (`--cao-dau-man`, `vo.css`), không gõ lại ở đây. */
/* Chiều cao của thanh này là TẦNG DÍNH THỨ HAI mà cột phải phải trừ đi. Khai
   `min-height`, KHÔNG `height`: hai lý lẽ, và cái thứ hai đo được.
   ① Ở bề rộng còn lưới hai cột, hàng này không bao giờ cuốn (đo tới tận khung
     636px, còn ngưỡng gập lưới là 1041px) và cao tự nhiên 59px — nên
     `min-height` cho nó ĐÚNG 61px, tức token đúng do cấu tạo chứ không do ai
     đo lại, giống hệt `--cao-dau-man`.
   ② `height` thì cắt. Đo 28/08: dưới khung 630px hàng cuốn làm hai và cần
     105px; ép 61px là ô «Chỉ dùng tạm» biến mất, mà ở bề rộng ấy lưới đã gập
     nên không ai còn đọc token — một dải hỏng đổi lấy không gì cả. */
:root {
  --cao-thanh-loc: 61px;
}
.ng-thanh {
  display: flex; gap: var(--k-2); align-items: center; flex-wrap: wrap;
  margin: var(--k-5) 0 0; padding: var(--k-3);
  background: var(--sau); border: 1px solid var(--vien);
  border-radius: var(--bo-lon);
  position: sticky; top: var(--cao-dau-man); z-index: var(--lop-dinh-tren);
  min-height: var(--cao-thanh-loc);
}
.ng-thanh > input, .ng-thanh > select { min-width: 0 }
/* Cột phải của tab này bám dưới HAI tầng dính, không một tầng: dải tiêu đề rồi
   tới thanh lọc. Khai bằng bộ chọn anh em — «một lưới đứng sau một thanh lọc
   dính» — chứ không gõ 61px lần thứ hai vào `nguon.js`: hai chỗ giữ cùng một
   con số là hai chỗ sẽ lệch, đúng cái vừa gỡ ở `th { top: 34px }`. */
.ng-thanh ~ .hai-cot {
  --cao-dinh: var(--cao-thanh-loc);
}
.ng-ket-qua { margin: var(--k-3) 0 var(--k-5); font-size: var(--cs-phu); color: var(--chu-nhat) }

/* ── Thẻ gọn (nguon-the.js) ───────────────────────────────────
 *
 * Thẻ cũ cõng năm nút và cả khối mô tả sáu mục. Nay nó chỉ giữ những gì cần để
 * quyết định CÓ MỞ TẤM NÀY RA KHÔNG, và cả tấm ảnh lẫn cái tên đều bấm được. */
/* Phần reset — `padding` · `border` · `background` · `display` · `cursor` — đã
   về `.mang-bam` ở `nen.css` đợt 7, cùng với hai thứ khối này QUÊN: trần
   `min-height` 40px và `text-align: center`. Ở đây chỉ còn thứ RIÊNG của nút
   ảnh: bo góc theo ảnh, và vòng nét khi rê chuột. */
.ng-anh { border-radius: var(--bo) }
.ng-anh:hover { outline: 2px solid var(--vien-chon); outline-offset: 2px }
.ng-the-ten { margin: 0 0 var(--k-1) }
.ng-the-ten .lienket { text-align: left; font-size: var(--cs-chinh) }
.ng-chu p { margin: 0 0 var(--k-1) }

.ng-trong-tran { border-color: var(--vien-re); color: var(--tot) }
.ng-ngoai-tran { border-color: var(--vien-chan); color: var(--canh) }

/* «Còn N tấm nữa» — nói ra chỗ danh sách bị cắt. Một danh sách cắt trong im
 * lặng đọc như một danh sách đầy đủ. */
.ng-con-nua { margin: var(--k-3) 0 0; display: flex; gap: var(--k-2); align-items: baseline; flex-wrap: wrap }

/* ── Khung chi tiết (nguon-chi-tiet.js) ───────────────────────
 *
 * Ngăn kéo bên phải trên màn rộng, phủ kín màn trên điện thoại. Nó KHÔNG đi qua
 * `showModal()` (lý do ở đầu tệp JS), nên nền mờ và lớp chồng là của ta. */
.ct-nen { position: fixed; inset: 0; background: var(--nen-phu); z-index: var(--lop-hop-phu) }
/* ── KHUNG ĐO RIÊNG CHO NGĂN KÉO — K3, 01/09/2026 ─────────────
 * Ngăn kéo này rộng `min(1040px, 100vw)`, tức bề rộng của nó KHÔNG phải bề rộng
 * cửa sổ và cũng không phải `#khu`. Ba khối bên trong nó từng hỏi `@media`, và
 * ở khổ 1366 thì cửa sổ 1366 trong khi ngăn kéo chỉ 1040 — chênh 326px.
 *
 * Nó là hậu duệ DOM của `#khu` (đổ vào `#ng-ct`), nên `@container khu` sẽ KHỚP
 * mà đo nhầm hộp. Phải có tên riêng. */
.ct {
  container-type: inline-size; container-name: chi-tiet;
  position: fixed; top: 0; right: 0; bottom: 0; z-index: var(--lop-hop);
  width: min(1040px, 100vw); overflow-y: auto; scrollbar-width: thin;
  margin: 0; padding: var(--k-4); border: 0; border-left: 1px solid var(--vien);
  background: var(--tam); color: var(--chu);
}
.ct-tren { display: flex; gap: var(--k-4); align-items: flex-start; margin-bottom: var(--k-4) }

/* Ảnh ở đầu khung là thứ người ta tới đây để NHÌN, không phải một cái tem cạnh
 * tên tệp. 320px và cao tới 46% khung nhìn: đủ để thấy nét mặt, nhãn chai, hạt
 * nhiễu — tức là đủ để quyết định có cần chỉnh gì không.
 *
 * `contain` chứ không `cover`: cắt cho đều thì ảnh dọc mất trên dưới, ảnh ngang
 * mất hai bên — đúng lúc cần nhìn TOÀN tấm. Cùng lý lẽ với thẻ trong lưới. */
.ct-anh { flex: 0 0 320px; max-width: 320px }
.ct-anh img, .ct-anh video {
  width: 100%; height: auto; max-height: 46vh; object-fit: contain;
  display: block; border-radius: var(--bo); background: var(--nen-anh);
}
/* Bảng sửa đang mở thì nó dựng sẵn cặp Gốc / Sau khi sửa to hơn hẳn — tấm này
 * lùi về cỡ tem để khỏi thành bản thứ ba của cùng một bức ảnh. */
.ct-anh-gon { flex-basis: 110px; max-width: 110px }
.ct-anh-gon img, .ct-anh-gon video { max-height: 150px }
.ct-tieu { min-width: 0; flex: 1 }
.ct-tieu h3 { margin: 0 0 var(--k-2); font-size: var(--cs-de); word-break: break-word }
.ct-tieu p { margin: 0 0 var(--k-1) }
.ct-dong { flex: 0 0 auto }

.ct-muc { border-top: 1px solid var(--vien) }
.ct-dau {
  /* Nút kiểu HÀNG — xem `.lua-chon`. */
  justify-content: flex-start;
  display: flex; gap: var(--k-2); align-items: baseline; width: 100%; text-align: left;
  border: 0; background: none; color: var(--chu); cursor: pointer;
  font: inherit; padding: var(--k-3) var(--k-0);
}
.ct-dau:hover { color: var(--lien-ket) }
.ct-mui { color: var(--chu-nhat); width: 12px; flex: 0 0 12px }
.ct-than { padding: 0 var(--k-0) var(--k-4) var(--k-5) }

.ct-bang td { padding: var(--k-1) var(--k-3) var(--k-1) 0; border: 0; vertical-align: top }
.ct-bang td:first-child { width: 34%; white-space: nowrap }

/* Mô tả máy đọc — trọn bề ngang khung, không còn bị ép vào cột phải 200px của
 * thẻ. Ba mục ĐI VÀO KỊCH BẢN mang một dấu tròn thật, không chỉ đậm hơn: khác
 * biệt bằng độ đậm là khác biệt không ai nhận ra. */
.ct-doc { background: var(--sau); border-radius: var(--bo); padding: var(--k-3) var(--k-3) }
.ct-doc-dong { margin: 0 0 var(--k-2); line-height: var(--dong-chay) }
.ct-doc-dong:last-child { margin-bottom: 0 }
.ct-vao-dan::before { content: "● "; color: var(--tot) }
.ct-doc-giai { margin: var(--k-3) 0 0; line-height: var(--dong-chay) }

.ct-lenh { display: flex; flex-wrap: wrap; gap: 0; margin: var(--k-4) 0 0; padding-top: var(--k-4);
           border-top: 1px solid var(--vien) }
.ct-chan { margin: var(--k-2) 0 0; line-height: var(--dong-chay) }

/* Bảng sửa ảnh nằm TRONG khung, và GIỮ bố cục hai cột của nó: thanh trượt bên
 * trái, ảnh xem trước bên phải. Tay kéo và mắt nhìn phải ở cùng một chỗ — chủ dự
 * án nói thẳng điều đó 23/08: *"phải nhìn ảnh mới biết nên sửa gì"*.
 *
 * Nhưng hai bản xem trước thì xếp CHỒNG, không cạnh nhau. `media-nguon-sua.js` đo
 * 17/08: chia đôi bề rộng làm mỗi bản còn ~230px, và ở cỡ đó thì mịn da / giảm
 * nhiễu / làm nét trông y hệt nhau — cả bảng ấy chỉ có một việc là cho người ta
 * NHÌN RA khác biệt. Trong khung 1040px, cột ảnh rộng ~670px, nên chồng lên nhau
 * cho mỗi bản gần gấp đôi bố cục hai cột cũ ngoài trang. */
.ct .ns-so, .ct .ns-so-hang { grid-template-columns: 1fr }
/* Thanh hành động dính đáy KHUNG, không đáy trang: khung mới là thứ đang cuộn. */
.ct .thanh-hanh-dong { margin-left: -var(--k-3); margin-right: -var(--k-3) }

/* `.ct` tự nó ĐÚNG khi hỏi cửa sổ: nó `position: fixed` và đang khai `100vw`.
   Một phần tử phủ theo viewport thì viewport là thứ nó phải hỏi. */
@media (max-width: 1100px) {
  .ct { width: 100vw; border-left: 0 }
}
/* Còn lưới BÊN TRONG ngăn kéo thì hỏi ngăn kéo. */
@container chi-tiet (max-width: 1040px) {
  .ct .ns-luoi { grid-template-columns: 1fr }
}
@container chi-tiet (max-width: 720px) {
  .ct-tren { flex-wrap: wrap }
  .ct-anh { flex-basis: 100%; max-width: 100% }
}

/* `.kf-ngoai-tran` ĐI HẲN 29/08/2026 (đợt 6). Nó tả trần bộ ảnh nhận diện, và
   mã đã đổi sang `.ng-ngoai-tran` mà không ai gỡ luật cũ — một lớp mồ côi sau
   một lượt đổi tên. Không gãy gì, nhưng nó dạy sai: người sửa tiếp theo đọc nó
   rồi tưởng đang có hai kiểu trần khác nhau. `test-kieu` mục 6b nay gác. */
.ng-hang-o { margin-top: var(--k-3); align-items: flex-end }
.ng-nhan input, .ng-nhan select, .ng-nhan textarea { width: 100%; margin-top: var(--k-1) }

/* Đoạn CÁCH NHÌN máy đọc từ một ảnh mẫu (A3). Cùng lối bày với đoạn chuẩn
 * thương hiệu ở tab Chuẩn thương hiệu: chữ tiếng Anh, đọc chậm, nên nó cần nền
 * riêng và dòng thoáng chứ không nằm lẫn trong thân bài. */
.ct-cach-nhin {
  margin: 0; padding: var(--k-3) var(--k-3); line-height: var(--dong-chay); font-size: var(--cs-ban);
  background: var(--sau); border-left: 3px solid var(--vien-chon);
  border-radius: 0 var(--bo) var(--bo) 0;
}

/* Hai lối ra của khung chi tiết (C4 · C7). Tách khỏi hàng lệnh phía dưới bằng
 * nền riêng: «đưa tấm này đi tiếp» và «đổi danh mục · gỡ» là hai loại việc — một
 * bên mở ra một tab khác, một bên sửa chính bản ghi này. */
.ct-di-tiep {
  margin: var(--k-4) 0 0; padding: var(--k-3) var(--k-4);
  background: var(--sau); border-radius: var(--bo);
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--k-2) var(--k-3); align-items: center;
}
.ct-di-tiep-dau { grid-column: 1 / -1; margin: 0; font-style: italic }
.ct-di-tiep .phu { white-space: nowrap }
@container chi-tiet (max-width: 720px) { .ct-di-tiep { grid-template-columns: 1fr } }

/* ── Bản khai thương hiệu (thẻ Cẩm nang, 24/08/2026) ───────────
 * Tám ô chữ dài xếp dọc. Nhịp lấy từ thang `--khe-*` đã có, không đặt số mới:
 * khoảng cách TRONG một ô (nhãn → gợi ý → khung nhập) luôn nhỏ hơn khoảng cách
 * TỚI ô bên cạnh, đúng luật 2 của bản audit 23/08.
 *
 * Họ `khoa-phong-cach*` không được có thuộc tính `style=` nào — lưới ở khối 20
 * của `test-web` đếm, và mọi lề phải đến từ đây. */
.kn-o { margin-top: var(--k-4) }
.kn-o > .nhat { margin: var(--k-1) 0 var(--k-2) }
.kn-o textarea { min-height: 62px }
.kn-nhan { margin: var(--k-4) 0 var(--k-1) }
.kn-o > .kn-nhan { margin-top: 0 }

/* ── Ba hướng định vị (thẻ Cẩm nang, 24/08/2026) ───────────────
 * So sánh là việc của MẮT: ba cột cùng lúc, không ba khối xếp dọc — đọc khối
 * thứ ba xong đã quên khối thứ nhất. Cùng lý lẽ `src/thu-viec.js` ghi cho
 * Phòng thử. Dưới 900px thì tự xếp dọc, vì ba cột 200px thì không đọc được. */
.kn-huong {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--k-4); margin-top: var(--k-4);
}
@container khu (max-width: 900px) { .kn-huong { grid-template-columns: 1fr } }

/* Ô hướng là thứ BẤM ĐƯỢC, nên nó có viền — khác `.tam` ở chỗ nó nằm TRONG một
 * thẻ. Hướng đang dùng đổi viền, không đổi nền: nền đổi thì hai ô còn lại đọc
 * ra như bị vô hiệu, mà chúng vẫn chọn lại được. */
.kn-huong-o {
  border: 1px solid var(--vien); border-radius: var(--bo);
  padding: var(--k-4); display: flex; flex-direction: column;
}
.kn-huong-o.chon { border-color: var(--vien-chon) }
.kn-huong-ten { margin: 0 0 var(--k-2) }
.kn-huong-o .kn-nhan { margin: var(--k-2) 0 0 }
.kn-huong-o > .nhat { margin: 0 }

/* Đánh đổi đẩy xuống đáy ô bằng `margin-top:auto` — ba ô dài khác nhau, mà ba
 * dòng đánh đổi phải thẳng hàng để mắt so được chúng với nhau. */
.kn-huong-doi {
  margin: auto 0 0; padding-top: var(--k-2);
  border-top: 1px solid var(--vien);
}

/* ── Hạng mục của bộ cẩm nang (thẻ Cẩm nang, 24/08/2026) ───────
 *
 * Tiêu đề khối này từng ghi «Mười một hạng mục». Con số ấy bỏ đi 25/08/2026 —
 * khối trên màn đã tách làm hai (hạng mục máy viết · phần lấy từ nơi khác), và
 * một con số chép vào chú thích CSS là một con số không ai nhớ sửa.
 * Một hạng mục là một NHÓM trong thẻ, không phải một thẻ con: tách bằng khoảng
 * trắng và một vạch mảnh, không bằng viền quanh. Đúng luật 1 của bản audit
 * 23/08 — chỉ `.tam` có viền quanh. */
/* VẠCH NGĂN THUỘC VỀ CẶP, KHÔNG THUỘC VỀ MỘT MÌNH KHỐI — 25/08/2026.
 *
 * Bản trước viết `.kn-muc:first-of-type` để bỏ vạch ở khối đầu. Nó đúng chừng
 * nào mọi hạng mục còn là `<div>`. Từ 25/08 hạng mục ĐÃ CHỐT là `<details>`, và
 * `:first-of-type` so theo TÊN THẺ — nên nó khớp cả `<div>` đầu tiên LẪN
 * `<details>` đầu tiên, tức hai khối giữa danh sách bỗng mất vạch ngăn.
 *
 * `.kn-muc + .kn-muc` không quan tâm tên thẻ: vạch mọc ở chỗ có hai khối cạnh
 * nhau, đúng nghĩa của một vạch ngăn. */
.kn-muc { margin-top: var(--k-4) }
.kn-muc + .kn-muc {
  margin-top: var(--k-5); padding-top: var(--k-4); border-top: 1px solid var(--vien);
}
.kn-muc-dau { margin: 0 0 var(--k-2) }

/* Hạng mục ĐÃ CHỐT — gấp lại, vì nó không còn một cái nút nào (xem
 * `chuan-thuong-hieu-muc.js`). Dòng `summary` phải nói ra bên trong có gì, nên nó
 * mang tên + nhãn trạng thái + mấy chữ đầu của đoạn văn. Mẩu chữ ấy cắt bằng
 * `ellipsis`: ở màn hẹp nó xuống dòng thì dòng gấp cao bằng khối mở, và lúc ấy
 * gấp không còn tiết kiệm gì. */
.kn-muc-gap > summary {
  cursor: pointer; list-style: none;
  display: flex; gap: var(--k-2); align-items: baseline;
}
.kn-muc-gap > summary::-webkit-details-marker { display: none }
/* Mũi tên tự vẽ, cùng lý lẽ `.faq`: tam giác mặc định khác nhau giữa Chrome và
 * Firefox, và ở nền tối gần như không thấy. */
.kn-muc-gap > summary::before { content: '▸'; color: var(--chu-nhat); flex: 0 0 auto }
.kn-muc-gap[open] > summary::before { content: '▾'; color: var(--chu) }
.kn-muc-gap > summary:hover { color: var(--chu) }
.kn-muc-gap > summary > .nhat {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kn-muc-gap[open] > summary { margin-bottom: var(--k-2) }
/* Mở ra rồi thì mẩu chữ ở dòng gấp thành bản sao của đoạn ngay bên dưới. */
.kn-muc-gap[open] > summary > .nhat { display: none }

/* Chữ máy viết: nền chìm + vạch trái mang màu trạng thái, KHÔNG viền quanh —
 * cùng khuôn `.kpc-chu` của thẻ Chuẩn hình ảnh, nên hai thẻ bày chữ máy giống
 * nhau. `pre-wrap` vì hạng mục có gạch đầu dòng thật. */
.kn-muc-chu {
  margin: 0; padding: var(--k-2) var(--k-4);
  background: var(--sau); border-left: 2px solid var(--thuong);
  border-radius: 0 var(--bo) var(--bo) 0;
}

/* Ô màu: mẩu màu để XEM, không phải ô để sửa — nên nó `disabled`. */

/* ── Đơn dịch vụ (thẻ Cẩm nang, 24/08/2026) ────────────────────
 * Số CÒN LẠI đứng trước và to hơn, vì đó là con số người ta cần; tổng đứng sau
 * ở cỡ phụ. Đảo lại thì mắt đọc tổng trước rồi phải trừ nhẩm. */
.kn-han-muc { display: flex; flex-wrap: wrap; gap: var(--k-5); margin: var(--k-4) 0 }
.kn-tui b { font-size: var(--cs-tab); font-family: var(--tieu-de) }
.kn-gia { margin: 0 0 var(--k-2); display: flex; align-items: baseline; gap: var(--k-4) }
.kn-gia b { font-size: var(--cs-so); font-family: var(--tieu-de) }

/* «Gồm gì · không gồm gì» — danh sách phẳng, thụt vừa đủ để đọc ra là một liệt
 * kê chứ không phải một đoạn văn. */
.kn-gom { margin: var(--k-1) 0 var(--k-4); padding-left: var(--k-5) }
.kn-gom li { margin: var(--k-1) 0; font-size: var(--cs-phu); color: var(--chu-nhat) }

/* ── Gương ba hạng mục con trỏ (thẻ Cẩm nang, 24/08/2026) ──────
 * Chủ dự án: thông tin đã có ở tab khác vẫn phải bày lại ở đây. Nên logo hiện
 * thành ẢNH THẬT, không thành một dấu tích «đã có». */

/* ── Vẽ logo (thẻ Cẩm nang, D1 — 25/08/2026) ───────────────────
 * Mỗi kiểu là một NHÓM có vạch trái, không phải một thẻ con: ô tick cộng câu hệ
 * quả cộng ô chọn model là ba dòng thuộc về nhau, và viền quanh chỉ dành cho
 * `.tam` (luật 1 của bản audit 23/08). */
.kn-lg-kieu {
  margin: var(--k-4) 0; padding: var(--k-2) var(--k-4);
  background: var(--sau); border-left: 2px solid var(--thuong);
  border-radius: 0 var(--bo) var(--bo) 0;
}
/* `<select>` KHÔNG tự co theo khung chứa như input thường — trình duyệt giãn
 * nó theo option DÀI NHẤT ("Tên model — $0,0x · nền trong suốt"), tràn ngang
 * trên điện thoại dù mọi khối cha đều đã đúng 100%. Khai `width` là bắt buộc,
 * không phải tuỳ chọn, cho MỌI select không nằm trong một `.hang` (nơi
 * `min-width:0` của flex item đã lo việc này) — phát hiện 26/08/2026. */
.kn-lg-kieu select { margin-top: var(--k-1); width: 100% }

.kn-lg-luoi {
  display: grid; gap: var(--k-5);
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  margin-top: var(--k-4);
}
.kn-lg-ban { font-size: var(--cs-phu) }

/* Ô ĐẶT ẢNH LOGO PHẢI CÓ LƯỚI Ô VUÔNG.
 * Bản vẽ nền trong suốt trên nền giấy trắng đọc ra y như bản nền trắng đặc — và
 * đó đúng là điều người dùng cần phân biệt trước khi mang đi in. Lưới ô vuông là
 * cách mọi công cụ thiết kế nói «chỗ này trong suốt». */
.kn-lg-anh {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 1; padding: var(--k-2);
  border: 1px solid var(--vien); border-radius: var(--bo);
  background-color: var(--tam);
  background-image:
    linear-gradient(45deg, var(--sau) 25%, transparent 25%, transparent 75%, var(--sau) 75%),
    linear-gradient(45deg, var(--sau) 25%, transparent 25%, transparent 75%, var(--sau) 75%);
  background-size: 16px 16px;
  background-position: 0 0, 8px 8px;
}
.kn-lg-anh img { max-width: 100%; max-height: 100%; object-fit: contain }

/* D2 — ô tick cảnh mockup xếp thành cột hẹp, không tràn ngang cả thẻ: sáu nhãn
 * ngắn dàn một hàng đọc ra như một câu, không như sáu lựa chọn. */
.kn-mk-canh { display: grid; gap: var(--k-1); margin: var(--k-2) 0 }

/* ══ TAB ẤN PHẨM — dọn 25/08/2026 ═══════════════════════════════
 *
 * ── VÌ SAO CẢ MỘT KHỐI CHO MỘT TAB ĐÃ CHẠY MỘT TUẦN ──────────
 * Đo trước khi sửa: họ `ap-*.js` có **60** thuộc tính `style=` viết tay, 7 thẻ
 * `<h3>`/`<h4>` tự do, và 10 chỗ dùng `.chan` làm khung cho một form. Họ
 * `khoa-phong-cach*` có 0, 0, 0 — và một lưới ở khối 20 giữ cho nó ở 0.
 *
 * Ba cái sai, không phải một:
 *
 *   1. `.chan` sinh ra để in NGUYÊN VĂN câu từ chối, nên nó mang
 *      `white-space: pre-wrap` (xem `nen.css`). Dùng nó làm khung cho một form
 *      là để mọi ô nhập bên trong thừa hưởng một quy tắc xuống dòng không thuộc
 *      về chúng. Khung của một khối là `.tam`.
 *   2. `an-pham.js` gắn `.ban-lam-viec` rồi ghi đè ngay dòng sau bằng
 *      `grid-template-columns:280px…`, trong khi chính class ấy khai `340px`.
 *      Khai một chuẩn rồi tự phá là tệ hơn không khai.
 *   3. Bề rộng ô nhập rải khắp bốn form: `48%` · `70%` · `22%` · `80%` · `44%`.
 *      Chủ dự án chốt 23/08: *«block ăn 100% khung chứa, không set theo giá trị
 *      cố định»*. Sáu con số ấy là cùng một bệnh ở quy mô nhỏ hơn.
 *
 * Nên bố cục ở đây đến từ LƯỚI, không từ phần trăm: một ô chiếm trọn hàng, hai
 * ô cạnh nhau chia đều, và chúng tự xếp dọc ở màn hẹp mà không cần ai khai. */

/* Lưới hai cột của tab — bề rộng cột phải ở ĐÂY, không ở một `style=` trong
 * `an-pham.js`. Bốn tab của đợt 2a khai con số ấy ngay tại chỗ dùng, và đó
 * vẫn là cách đúng cho chúng; họ `ap-*` thì mang luật chặt hơn vì nó từng có 60
 * thuộc tính `style=` viết tay, và lưới `test-web` khối 20 giữ nó ở 0.
 *
 * 420px: danh sách ở cột này là bốn thẻ tạo mới cộng một danh sách tên ấn phẩm
 * — không thẻ nào cần hơn thế, còn form bên trái thì cần từng điểm ảnh còn lại. */
.ap-luoi { --cot-phai: 420px }

/* Một ô nhập: nhãn trên, ô dưới, ô ăn trọn khung chứa. */
.ap-o { margin-top: var(--k-4) }
.ap-o > .ap-nhan { margin-top: 0 }
.ap-nhan { display: block; margin: var(--k-4) 0 var(--k-1); font-size: var(--cs-phu); color: var(--chu-nhat) }
.ap-o input[type=text], .ap-o textarea, .ap-o select { width: 100% }
.ap-o textarea { min-height: 62px }

/* Hai ô cạnh nhau — mã và giá, tên món và giá. `auto-fit` chứ không `1fr 1fr`:
 * ở cột hẹp chúng tự xuống dòng, và không con số điểm gãy nào phải khai. */
.ap-doi { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--k-4) }
.ap-doi > .ap-o { margin-top: 0 }

/* Một dòng trong danh sách (sản phẩm · món · dự án): nhóm có nút bỏ riêng.
 * Vạch trái thay cho viền quanh — luật 1 của bản audit 23/08: chỉ `.tam` có
 * viền quanh, khối con tách bằng nền chìm và một vạch. */
.ap-dong {
  margin-top: var(--k-4); padding: var(--k-2) var(--k-4);
  background: var(--sau); border-left: 2px solid var(--vien); border-radius: 0 var(--bo) var(--bo) 0;
}
.ap-dong-dau { display: flex; align-items: baseline; gap: var(--k-2); margin: 0 }
.ap-dong-dau > .lienket { margin-left: auto }
/* Món nằm TRONG một nhóm món — thụt vào để đọc ra là quan hệ chứa, không phải
 * hai khối ngang hàng. */
.ap-mon { margin-left: var(--k-4) }

/* Danh sách ấn phẩm ở cột trái. */
.ap-ds-o {
  display: block; padding: var(--k-2) var(--k-4); border-radius: var(--bo);
  text-decoration: none; color: inherit;
}
.ap-ds-o:hover { background: var(--nen-luot) }
.ap-ds-o.chon { background: var(--tam) }

/* ── Đợt D (30/08/2026) — HUY HIỆU TRẠNG THÁI VÒNG ĐỜI ────────
 *
 * Bốn trạng thái, ba mức nổi. `nhap` cố ý KHÔNG có màu riêng — nó là ca
 * thường, và tô màu cho ca thường là làm loãng ba ca còn lại. `cho-duyet`
 * dùng màu thương hiệu vì nó là thứ đang ĐỢI người bấm, tức việc cần nhìn;
 * `da-duyet` màu «tốt»; `da-xuat` lùi về chữ nhạt vì việc đã xong rồi.
 *
 * Dùng token có sẵn, không chế mã màu mới: mọi mã màu ngoài khối token đều bị
 * `test-mau` bắt, và đó là lưới đúng. */
.ap-tt {
  display: inline-block; padding: 0 var(--k-1); border-radius: var(--bo-nho);
  border: 1px solid var(--vien); font-size: .85em;
}
.ap-tt-cho-duyet { border-color: var(--thuong); color: var(--thuong) }
.ap-tt-da-duyet { border-color: var(--tot); color: var(--tot) }
.ap-tt-da-xuat { color: var(--chu-nhat) }

/* ── Ấn phẩm, điện thoại — hàng nút dính đáy màn hình ─────────
 * Bản in đem ra nhà in, in sai là bỏ cả lô — Lưu/Dựng bản in phải luôn trong
 * tầm tay, không phải cuộn xuống mới thấy (khớp mockup 5d). Khác
 * `.thanh-hanh-dong` (dính đáy một khung `.tam` bằng lề âm): hàng nút này đứng
 * NGOÀI `.tam` của form, là con trực tiếp của `#ap-soan`, nên dính thẳng vào
 * đáy MÀN HÌNH — cùng khuôn với `#dai-chi-tiet` đã dựng ở vo.css.
 * `:has()` chừa đúng khoảng trống bên trên cho hàng nút, chỉ khi nó có mặt —
 * màn "chưa chọn ấn phẩm" không có `.hang-nut` thì không cần khoảng trống. */
@container khu (max-width: 640px) {
  #ap-soan:has(> .hang-nut) { padding-bottom: var(--k-6) }
  #ap-soan > .hang-nut {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--lop-day);
    margin: 0; background: var(--tam); border-top: 1px solid var(--vien);
    padding: var(--k-3) var(--k-4) calc(var(--k-3) + env(safe-area-inset-bottom, 0px));
  }
}
/* ── Đợt 2 (29/08/2026) — hàng của bảng-trong-form, và bản đã lưu ────
 *
 * `.ap-hang-bang`: một dòng dữ liệu của form sinh-từ-spec (bảng giá, điểm nổi
 * bật). Flex chứ không grid — số ô đổi theo bản mẫu (bảng giá 4, điểm nổi bật
 * 1), và `repeat(auto-fit, …)` KHÔNG đứng chung được với một track `auto` cho
 * nút «gỡ»: khai báo trộn hai thứ ấy bị trình duyệt vứt nguyên dòng, đo được
 * 29/08 — lưới về một cột mà không một lỗi nào báo. */
.ap-hang-bang {
  display: flex; gap: var(--k-1); margin-bottom: var(--k-1); align-items: center;
  flex-wrap: wrap;
}
.ap-hang-bang > input { flex: 1 1 90px; min-width: 0 }
.ap-hang-bang > button { flex: 0 0 auto }

/* ── Đợt B (29/08/2026) — thẻ KHỐI của dải «Thêm khối» ──────────────
 *
 * Mỗi khối thể hiện một thẻ viền mảnh: đầu thẻ là nhãn kiểu + cụm nút xếp/gỡ
 * đẩy phải, thân là form nhỏ của chính khối. Chip thêm khối bọc dòng — bảy
 * kiểu không nằm vừa một hàng ở cột 420px khi lưới sập. */
.ap-khoi-o {
  border: 1px solid var(--vien); border-radius: var(--bo-nho);
  padding: var(--k-1) var(--k-2); margin-bottom: var(--k-1);
}
.ap-khoi-dau { display: flex; align-items: baseline; gap: var(--k-2); margin-bottom: var(--k-1) }
.ap-khoi-nut { margin-left: auto; display: flex; gap: var(--k-2); flex: 0 0 auto }
.ap-khoi-chip { display: flex; flex-wrap: wrap; gap: var(--k-1) }

/* ── Đợt C (29/08/2026) — NHẬP MẪU NGOÀI ────────────────────────────
 *
 * Một nháp là ảnh gốc bên trái, spec máy đọc bên phải. Ảnh cố định 96px: nó ở
 * đây để NHẬN RA tấm nào, không để ngắm — cột phải rộng 420px, cho ảnh nhiều
 * hơn là đẩy phần đọc được xuống dưới màn hình. `min-width:0` trên thân để chữ
 * dài không bơm ô ra ngoài cột (bẫy flex kinh điển, đã đo ở đợt 2b). */
.ap-nhap-tha { display: flex; flex-direction: column; gap: var(--k-1); margin: var(--k-1) 0 }
.ap-nhap-o {
  display: flex; gap: var(--k-2); align-items: flex-start;
  border: 1px solid var(--vien); border-radius: var(--bo-nho);
  padding: var(--k-2); margin-bottom: var(--k-1);
}
.ap-nhap-anh {
  flex: 0 0 96px; width: 96px; border-radius: var(--bo-nho); display: block;
}
.ap-nhap-trong {
  height: 96px; display: grid; place-items: center; text-align: center;
  border: 1px dashed var(--vien-sang); background: var(--sau);
}
.ap-nhap-than { flex: 1 1 auto; min-width: 0 }
.ap-nhap-than > input { width: 100% }
/* Dòng nguồn chở câu ghi công CC, và câu ấy kết bằng một URL dài không có chỗ
 * ngắt. `anywhere` chứ không `break-word`: break-word chỉ cắt khi từ ĐỨNG MỘT
 * MÌNH đã quá rộng, còn ở đây URL đứng cuối một câu dài nên nó không cắt và ô
 * cứ tràn. Đo được ở 375px, đợt C3. */
.ap-nhap-nguon { overflow-wrap: anywhere }

/* ── Đợt C2 (29/08/2026) — LƯỚI CHỌN TỪ MỘT KHO NGOÀI, và hàng một kho ──
 *
 * Lưới ba cột ở cột phải 420px: mỗi ô ~120px, đủ NHẬN RA một bố cục mà không
 * đủ để ngắm — đúng vai của nó, vì thứ người ta chọn là cấu trúc chứ không
 * phải bức ảnh. `auto-fill` chứ không `auto-fit`: một design lẻ loi phải giữ
 * khổ ô của nó, không phình ra hết hàng. Không có track `auto` nào đứng chung
 * — xem bẫy đã đo ở khối `.ap-hang-bang` phía trên.
 *
 * Tên lớp đổi `ap-canva-*` → `ap-kho-*` ở đợt C3: cửa Openverse dùng ĐÚNG lưới
 * này, và một lớp tên Canva bày ảnh Openverse là một câu sai nằm trong markup
 * mà người sau phải đọc mã mới biết. Cửa thứ tư (Pinterest) vào thẳng đây. */
.ap-kho-luoi {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: var(--k-2); margin: var(--k-1) 0;
}
.ap-kho-o {
  display: grid; gap: var(--k-1); padding: var(--k-1); text-align: left;
  border: 1px solid var(--vien); border-radius: var(--bo-nho); background: var(--tam);
}
.ap-kho-o img { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; border-radius: var(--bo-nho) }
.ap-kho-o .nhat { overflow: hidden; text-overflow: ellipsis; white-space: nowrap }

/* Một kho ngoài ở tab Doanh nghiệp: tên + tình trạng bên trái, nút bên phải. */
.dn-kho {
  display: flex; gap: var(--k-2); align-items: center;
  padding: var(--k-2) 0; border-bottom: 1px solid var(--vien);
}
.dn-kho:last-of-type { border-bottom: 0 }
.dn-kho-than { flex: 1 1 auto; min-width: 0 }
.dn-kho-than p { margin: var(--k-1) 0 0 }
.dn-kho > button { flex: 0 0 auto }

/* Một bản đã lưu — dòng gọn: số bản đậm, người + lúc nhạt, hành động cuối. */
.ap-ban-dong {
  display: flex; align-items: baseline; gap: var(--k-2); flex-wrap: wrap;
  padding: var(--k-1) 0; border-bottom: 1px solid var(--vien);
}
.ap-ban-dong:last-of-type { border-bottom: 0 }
.ap-ban-dong > :last-child { margin-left: auto }

.ap-tao { display: grid; gap: var(--k-1); margin: var(--k-2) 0 }
/* Nút tạo mới là một THẺ, không một nút: nó mang tên, khổ giấy và một câu nói
 * dùng khi nào — ba dòng ấy không nằm vừa một nút. */
.ap-tao > button { text-align: left; padding: var(--k-2) var(--k-4); line-height: var(--dong-chay) }
.ap-tao b { display: block }
.ap-tao .nhat { display: block; font-size: var(--cs-nho) }

/* Ảnh xem trước bản in — soi DẤU tiếng Việt trước khi mang đi in. */
.ap-xem { max-width: 100%; border: 1px solid var(--vien); border-radius: var(--bo); margin-top: var(--k-2) }

/* Đơn dịch vụ ĐÃ MỞ — dải trạng thái, không phải khối làm việc (25/08/2026).
 * Xem `chuan-thuong-hieu-don.js` cho lý lẽ: sau cú bấm mở đơn nó thôi là chỗ làm
 * việc, nên nó không được chiếm nửa màn hình đầu tiên mãi mãi. */
.kn-don-them > summary { cursor: pointer; font-size: var(--cs-ban); color: var(--chu-nhat) }
.kn-don-them > summary:hover { color: var(--chu) }
.kn-don-them[open] > summary { margin-bottom: var(--k-2) }
.kn-don .kn-han-muc { margin-bottom: var(--k-4) }

/* ── DẢI TIẾN TRÌNH của thẻ Cẩm nang — 25/08/2026 ─────────────
 *
 * Sáu mốc, mỗi mốc là một nút nhảy tới khối của nó. `auto-fit` chứ không sáu
 * cột cứng: ở cột hẹp chúng tự xuống hàng, và không con số điểm gãy nào phải
 * khai — cùng luật «block ăn 100% khung chứa» chốt 23/08.
 *
 * Là `<button>` chứ không `<a href="#…">`: router của app đọc `location.hash`,
 * nên một neo trần bị nó bắt và hiểu thành một đường lạ. Nút thì không đụng vào
 * hash. Nhưng nó phải ĐỌC RA là chỗ bấm được, nên có viền và đổi nền khi trỏ vào.
 *
 * Ba trạng thái, ba mức đậm — và DẤU trong nút đã nói đủ, nên người không phân
 * biệt được màu vẫn đọc được. Màu là lớp thứ hai — luật này thừa hưởng từ họ
 * `.vung` đã gỡ 07/09, và dải tiến độ nay là chỗ duy nhất giữ nó. */
.kn-td {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--k-1); margin: var(--k-4) 0 0;
}
.kn-td-o {
  display: grid; gap: 1px; text-align: left; cursor: pointer;
  padding: var(--k-2) var(--k-4); line-height: var(--dong-chay);
  background: var(--sau); border: 1px solid var(--vien); border-radius: 0 var(--bo) var(--bo) 0;
  grid-template-columns: auto 1fr; grid-template-areas: 'dau ten' 'dau ghi';
}
.kn-td-o:hover { border-color: var(--vien-sang); background: var(--nen-luot) }
.kn-td-dau { grid-area: dau; align-self: center; margin-right: var(--k-2); font-size: var(--cs-de) }
.kn-td-ten { grid-area: ten; font-size: var(--cs-ban); font-weight: 600 }
.kn-td-o > .nhat { grid-area: ghi; font-size: var(--cs-nho) }
.kn-td-o.xong { border-left: 3px solid var(--tot) }
.kn-td-o.xong .kn-td-dau { color: var(--tot) }
.kn-td-o.chua { border-left: 3px solid var(--canh) }
.kn-td-o.chua .kn-td-dau { color: var(--canh) }
/* «Chưa tới lượt» phải MỜ HẲN: nó không phải việc đang chờ ai, nó là thứ tự. */
.kn-td-o.cho { color: var(--chu-nhat) }

/* ── Media đã tạo — lưới hai cột trên điện thoại (thu-vien.js) ──
 * `.luoi`/`.the` là class DÙNG CHUNG (arena-xem.js, studio-ban.js, hom-nay.js
 * cũng dùng) — đổi thẳng ở đó là đổi cả những màn ấy, nơi lưới đôi khi phục vụ
 * việc SO SÁNH ảnh cạnh nhau và ảnh nhỏ lại có thể là mất, không phải được.
 * Scope theo `#tv-luoi` (khung riêng của thu-vien.js) để chỉ đúng MỘT màn này
 * đổi, còn nơi khác giữ nguyên cách lưới tự co về một cột trên máy hẹp. */
@container khu (max-width: 640px) {
  #tv-luoi .luoi { grid-template-columns: 1fr 1fr; gap: var(--k-3) }
}
.kn-td-o.cho .kn-td-dau { color: var(--chu-mo) }

/* ── DẢI «ĐANG ẨN» — bố cục Nocturne đợt 2b, 28/08/2026 ───────
 *
 * Ba nhãn ấy trước 28/08 là ba `<p class="nhat">` xếp dưới thanh lọc — đúng nội
 * dung, sai HẠNG. Chúng không phải chú thích; chúng là câu trả lời cho «ảnh của
 * tôi đâu», thứ duy nhất chặn giữa người dùng và kết luận app nuốt mất tệp.
 *
 * Nền `--sau` chứ không `--tam`: nó là một dải, không phải một thẻ nữa. Cùng
 * dáng với họ `.vung` đã gỡ 07/09 — dải trong app này thì lùi xuống, không
 * nổi lên. */
.tv-dai {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--k-3);
  margin: 0 0 var(--k-4); padding: var(--k-3) var(--k-4);
  background: var(--sau); border: 1px solid var(--vien);
  border-radius: var(--bo-lon);
}
/* `#tv-loc { margin-bottom }` ĐI HẲN cùng ngày nó ra đời — 29/08 (đợt 6e).
   Nó sinh ra vì màn này đổ thẳng vào `#khu`, không qua `.tai-lieu`, nên không
   có container nào mang nhịp. Nay cả 20 màn đều qua `.tai-lieu`, và
   `> * + *` cho nó khe 24px — một lề đặt tay 16px nằm dưới khe ấy chỉ là một
   dòng CSS không đổi được gì, tức đúng loại lề mà container này sinh ra để
   thay. Chữa tận gốc thì phải dọn cả cái nạng dựng lúc chưa có gốc. */
.tv-dai-nhan {
  font-size: var(--cs-nho); letter-spacing: .14em; text-transform: uppercase;
  color: var(--chu-mo); flex: 0 0 auto;
}
/* Vạch ngăn giữa ba nhãn và câu chú. Biến mất khi dải đã xuống dòng — một vạch
   dọc 22px đứng đầu một dòng mới không ngăn cách gì cả. */
.tv-dai-vach { flex: 0 0 1px; align-self: stretch; min-height: 22px; background: var(--vien) }

/* Nhãn của một nhóm đang bị ẩn. Nó là NÚT, không phải chip lọc: bấm vào là đổi
   thứ đang bày ra, nên nó mang màu CẢNH — có thứ đang bị giấu. */
/* `min-height: auto` KHÔNG thừa — nó gỡ `--cao-dk` mà quy tắc `button` nền áp
 * cho mọi nút. Nhóm này vẽ ra bằng HAI thẻ: `<button>` khi bấm được, `<span>`
 * khi nhóm rỗng (bấm chẳng đổi gì thì nó không phải nút). Trần 40px chỉ với
 * tới nửa `<button>`, nên hai nhãn đứng cạnh nhau đo ra **40px và 28px** —
 * chủ dự án báo 29/08: «thống kê lượt thử và hỏng không đều trên dưới».
 *
 * Đây là chip, không phải điều khiển: cỡ chữ `--cs-phu`, bo `--bo-nho`, đệm
 * `--k-1`. Trần chiều cao sinh ra để mọi ĐIỀU KHIỂN đứng cùng hàng bằng nhau,
 * và một dải thống kê không có ô nhập nào để đứng cùng.
 *
 * Cùng họ với lỗi đợt 3b: quy tắc nền khai thêm một thứ không đúng cho mọi thứ
 * nó phủ. Ở đó là `justify-content`, ở đây là `min-height`. */
.tv-nhan {
  flex: 0 0 auto; display: inline-flex; align-items: baseline; gap: var(--k-2);
  padding: var(--k-1) var(--k-3); font: inherit; font-size: var(--cs-phu); cursor: pointer;
  color: var(--chu); background: var(--nen-chan);
  border: 1px solid var(--vien-chan); border-radius: var(--bo-nho);
  min-height: auto;
}
.tv-nhan:hover { border-color: var(--canh) }
.tv-nhan-di { color: var(--canh); font-size: var(--cs-nho) }
/* Nhóm ĐANG được bày ra: đảo vai, vì lúc ấy nó không còn bị ẩn nữa. */
.tv-nhan.mo { border-color: var(--vien-chon); background: var(--chon) }
.tv-nhan.mo .tv-nhan-di { color: var(--lien-ket) }
/* Nhóm rỗng vẫn HIỆN, chỉ mờ đi. Bỏ hẳn nó là lặp lại đúng lỗi mà cả dải này
   sinh ra để chữa: người dùng không đọc được sự vắng mặt.

   Nó là `<span>` chứ không `<button>` — xem `veDangAn`. Nên không có trạng thái
   rê chuột, và con trỏ giữ nguyên hình chữ. */
.tv-nhan.khong { background: none; border-color: var(--vien); color: var(--chu-nhat) }

/* Bảng so hai tầng xoá — hai cột chữ ngắn, không phải một `<table>`: ở đây
   không có ô nào giao nhau giữa hàng và cột, chỉ có hai danh sách đọc song
   song. Gập về một cột khi cột phải hẹp lại. */
.tv-so { display: grid; grid-template-columns: 1fr 1fr; gap: var(--k-4) }
@container khu (max-width: 1040px) { .tv-so { grid-template-columns: 1fr } }
.tv-so-dau {
  font-weight: 600; font-size: var(--cs-ban);
  padding-bottom: var(--k-2); border-bottom: 1px solid var(--vien-nut);
}
.tv-so-dau.xau { color: var(--xau); border-bottom-color: var(--xau) }
/* Dòng ở đây chỉ có MỘT vế, nên nó không phải «giá trị để tra» — trả nó về màu
   chữ thường. (Việc cho nó CO ĐƯỢC thì `.doi > :last-child:not(:only-child)`
   ở `nen.css` đã lo; xem chú thích tại đó.) */

.tv-so .doi { font-size: var(--cs-phu) }

/* ── TAB QUẢN TRỊ — 01/09/2026 ────────────────────────────────
 *
 * BẢNG SỐ CỦA KHỐI «CÒN CHẠY ĐƯỢC BAO LÂU» THÔI GIÃN HẾT CỘT.
 *
 * `nen.css` cho mọi `<table>` một `width: 100%`, và đó đúng cho bảng nhiều cột
 * — bảng khách hàng chín cột lấp kín 772px và cần mọi milimet nó có. Bảng này
 * thì ba cột: nhãn · một con số · một câu chú. Ở cột nội dung 1.600px của chủ dự
 * án, đo được **~675px trống** giữa «Số dư fal» và «$1,31» — hai vế của cùng một
 * dòng xa nhau tới mức mắt không dóng nổi, và đó là chỗ chủ dự án nêu ra khi soi
 * màn thật.
 *
 * `width: auto` chứ KHÔNG một con số px: bảng co đúng bằng nội dung nó chở, nên
 * không có ngưỡng nào phải đoán và không có con số nào lạc hậu khi thêm một
 * dòng. Đây cũng là lý do luật này KHÔNG dính vào chốt «trần bề rộng cột chữ»
 * đang chờ — nó không đặt một trần, nó thôi ép một chiều rộng.
 *
 * Các đoạn VĂN của tab vẫn chạy hết cột; đó là chuyện của chốt kia. */
.qt-so { width: auto }

/* ── KHU «KÊNH ĐĂNG BÀI» — MỖI KÊNH MỘT THẺ, 03/09/2026 ──────
 *
 * Tới 02/09 cả khu là MỘT thẻ: danh sách kênh là những dòng ngăn nhau bằng nét
 * kẻ, rồi ô khai tay, rồi một hàng nút, rồi một dãy đoạn giải thích. Đo ở
 * `web/_do-doanh-nghiep.html` sau khi có bốn nền tảng: thẻ ấy cao 1.394px, nằm
 * trong rail 460px, cạnh một cột trái cao 512px.
 *
 * Cái sai không phải chiều cao — nó là HÌNH DẠNG. Một bộ sưu tập cần lưới, và
 * lưới cần bề ngang; đặt nó trong rail là ép một thứ vốn xếp ngang phải xếp
 * dọc. Nên khu này ra khỏi hai cột và trải trọn bề.
 *
 * `auto-fill` + `minmax` chứ không số cột cứng: `#khu` 1208px (thanh bên mở,
 * màn 1536 của chủ dự án) ra bốn cột ~290px; gập thanh bên thì rộng ra chứ
 * không đổi số cột; ở bề ngang điện thoại nó tự về một. Ngưỡng 280px là bề hẹp
 * nhất mà một địa chỉ dài còn xuống dòng đọc được.
 *
 * `align-items: start` — thẻ cao thấp khác nhau (kênh thiếu quyền chở thêm hai
 * câu; ô khai tay chở ba ô nhập), và kéo tất cả bằng nhau chỉ tạo khoảng trắng
 * ở đáy những thẻ ngắn.
 *
 * KHÔNG lề trên: `.tai-lieu > * + *` đã lo nhịp dọc giữa các khối cấp cao, và
 * gắn thêm ở đây là cộng hai lần.
 */
.dn-kenh-luoi {
  display: grid; gap: var(--k-3); align-items: start;
  /* TRẦN BỐN CỘT, sàn 264px — chủ dự án chốt 03/09/2026: năm cột thì mỗi ô hẹp
     quá. `max()` làm cả hai vế trong một dòng: ô không bao giờ hẹp hơn 264px, VÀ
     không bao giờ hẹp hơn một phần tư hàng — nên `auto-fill` không xếp nổi cột
     thứ năm dù khu có rộng đến đâu. Không @media nào phải đoán một ngưỡng.
     264 chứ không 280: đo ở `_do-doanh-nghiep.html`, lưới rộng THẬT 1143px khi
     `#khu` 1208px (màn 1536, thanh bên mở), và 4×280+3×14 = 1162 > 1143 — sàn
     280 khoá bố cục lại ở ba cột đúng ở bề rộng chủ dự án đang dùng. */
  grid-template-columns: repeat(auto-fill, minmax(max(264px, calc((100% - 3 * var(--k-3)) / 4)), 1fr));
}

/* Thẻ trong lưới xếp DỌC và đẩy hành động xuống đáy, để hàng nút của các thẻ
 * cạnh nhau không so le theo độ dài câu chữ ở giữa.
 *
 * `> :last-child` chứ không một lớp riêng cho hàng nút: cùng lối `.ap-ban-dong`
 * đã dùng, và nó không bắt chỗ gọi phải nhớ gắn thêm lớp — quên gắn thì thẻ ấy
 * lệch mà không ai kêu. */
.dn-kenh-the { display: flex; flex-direction: column; gap: var(--k-2) }
.dn-kenh-the > p { margin: 0 }
.dn-kenh-the > :last-child { margin-top: auto; padding-top: var(--k-2) }

/* Thẻ rộng HAI cột trong lưới kênh — «Kết nối kho mẫu», chốt 03/09/2026.
 *
 * Chỉ nhả `span 2` khi lưới THẬT SỰ có từ hai cột: dưới ngưỡng ấy lưới còn một
 * cột, và `span 2` ở đó đẻ ra một cột ẩn thứ hai — thẻ tràn ngang ra khỏi khu.
 * 640px là bề hẹp nhất chứa nổi hai ô 280px cộng một khe. */
@container khu (min-width: 640px) {
  .dn-kenh-luoi > .dn-rong-2 { grid-column: span 2 }
}

/* ── Cụm model theo cách nhận thời lượng (Phòng thử, 06/09/2026) ─
 * Tên lớp KHÔNG có gạch nối, cố ý: lưới tiền tố của test-kieu tự sinh một «họ
 * tab» khi ba lớp cùng tiền tố xuất hiện, và bản đầu đặt tên `.nhom-model` đã
 * đẩy họ `nhom-` qua ngưỡng — kéo theo `.nhom-muc` của thanh bên bị báo là lớp
 * tab khai nhầm ở vo.css. Một lớp không gạch nối không thuộc họ nào.
 * Ba nhóm — «Chọn độ dài tự do» · «Chọn theo mức có sẵn» · «Một phân cảnh dài»
 * — không phải cách phân loại cho gọn mắt: chúng là ba câu hỏi khác nhau đặt ra
 * cho khách, nên chúng phải TÁCH RA THẤY ĐƯỢC, không chỉ là ba dòng đậm giữa
 * một danh sách chảy liền.
 *
 * Vạch ngăn ở TRÊN chứ không viền quanh: nhóm cuối cùng không có vạch dưới thừa,
 * và ô model bên trong đã có viền riêng rồi — viền lồng viền thì mắt đọc thành
 * hai tầng lồng nhau trong khi chúng chỉ là một danh sách có chia mục. */
.cum + .cum {
  margin-top: var(--k-4);
  padding-top: var(--k-4);
  border-top: 1px solid var(--vien);
}
.cum > h4 { margin: 0 0 var(--k-1) }
/* Dòng giải thích bó hẹp hơn ô model: nó là câu ĐỌC MỘT LẦN rồi thôi, còn ô
 * model là thứ mắt quét đi quét lại. Để chúng cùng bề ngang thì câu giải thích
 * cạnh tranh chú ý với đúng thứ nó đang giải thích. */
.cum > .nhat { margin: 0 0 var(--k-3); max-width: 62ch }
