/**
 * Vinpack — CSS CHỈ CỦA trang danh mục sản phẩm (taxonomy-vp_product_cat.php),
 * Phase I Task 1.
 *
 * Nguồn: ~/vp-mockups/danhmuc.html — `.sp-banner`, `.wrap` chứa `.cat-row`,
 * `.shop.wrap` (`.filter` + `.prod-grid` + `.pager`).
 *
 * Dependency bắt buộc 'vinpack-global' + 'vinpack-layout' (khai ở
 * inc/enqueue.php) — file này dùng token màu/khoảng cách của global.css và
 * không định nghĩa lại `.wrap` / `section.wrap` / `.section-head`, đã có sẵn.
 *
 * ---------------------------------------------------------------------------
 * BỐN TRANG DÙNG CHUNG FILE NÀY, KHÔNG PHẢI HAI (Phase M Task 2)
 * ---------------------------------------------------------------------------
 * `.art-wrap`/`.art-layout`/`.art-toc`/`.art-author` (TOC + tác giả tĩnh) và
 * `.faq`/`.faq-box`/`.faq-list` giờ phục vụ CẢ single-vp_project.php lẫn
 * single-vp_product.php/taxonomy-vp_product_cat.php/archive-vp_product.php —
 * inc/enqueue.php thêm is_singular( 'vp_project' ) vào ĐÚNG điều kiện đã có
 * cho is_singular( 'vp_product' ) (Phase J Task 2), không tạo nhánh enqueue
 * riêng. `.art-author` (khối tác giả) dời từ product-single.css sang đây ở
 * Task này vì có người dùng thứ hai — xem docblock ngay tại rule đó.
 *
 * project-single.css KHÔNG khai lại bất kỳ rule `.art-*`/`.pd-author-*` nào ở
 * đây — chỉ chứa `.detail-*` thật sự mới của single-vp_project.php.
 *
 * @package Vinpack
 */

/* ---------- Banner ---------- */
/*
 * `.sp-banner` VẪN dùng nguyên vẹn ở archive-vp_product.php (trang
 * "/san-pham/", chung file CSS này) — KHÔNG xoá/sửa 5 rule dưới đây dù
 * taxonomy-vp_product_cat.php đã đổi sang `.cat-hero`/`.cat-hero-info`
 * (SỬA 27/08/2026, xem docblock ngay trong taxonomy-vp_product_cat.php).
 * Khách xác nhận đổi layout CHỈ áp cho trang danh mục, không đụng "/san-pham/".
 */
.sp-banner{
	background:linear-gradient(160deg,var(--navy) 0%,var(--navy-dark) 100%);
	color:#fff;
	padding:56px 0 64px;
	/*
	 * CANH TRÁI (07/09/2026, đợt đồng bộ banner). Đo trước khi sửa: breadcrumb
	 * ở 562..703 và H1 ở 408..857 — cả khối nằm giữa màn hình, trong khi bảy
	 * banner khác của site đặt breadcrumb/H1 ở mốc trái 75px.
	 */
	text-align:left;
}
/*
 * SỬA (28/08/2026, khách yêu cầu "đồng bộ lại tất cả cùng 1 style" cho
 * breadcrumb): màu đổi từ hex #A9C4FF/#fff CHÉP TAY sang token var(--on-
 * navy-text)/var(--white) + thêm letter-spacing:.3px — khớp đúng
 * `.service-banner .crumb` của page-dichvu.css (banner nền navy còn lại
 * duy nhất khác trên site). #A9C4FF TRÙNG giá trị --on-navy-accent (một
 * token KHÁC, xem global.css) — không phải cùng công thức breadcrumb đã
 * chọn thống nhất ở đây, nên đổi hẳn sang --on-navy-text, không chỉ đổi
 * cách viết.
 */
.sp-banner .crumb{ font-size:13px; color:var(--on-navy-text); margin-bottom:var(--sp-4); letter-spacing:.3px; }
.sp-banner .crumb a{ color:var(--on-navy-text); }
.sp-banner .crumb a:hover{ color:var(--white); }
.sp-banner h1{ color:#fff; font-size:38px; margin-bottom:var(--sp-4); }
.sp-banner p{ color:var(--on-navy-text); font-size:16px; max-width:640px; margin:0; line-height:1.7; }

/*
 * `.cat-hero`/`.cat-hero-info` — CHỈ taxonomy-vp_product_cat.php (SỬA
 * 27/08/2026, khách gửi ảnh chụp /tui-nilon/, khoanh đỏ khối breadcrumb/H1/
 * dòng dẫn: "chuyển info khoanh đỏ xuống vùng trắng còn vùng xanh là banner
 * có thể bỏ ảnh vào được kích thước tỷ lệ phổ biến tương đương ~16:5").
 *
 * SỬA LẦN 2 (27/08/2026, cùng ngày): khách gửi ảnh banner mẫu thật
 * (okachi.vn, tên file mã hoá kích thước "2640x500") để chốt đúng tỉ lệ —
 * đo được 2640:500 = 5.28:1 (rút gọn 132:25), KHÁC "~16:5" (3.2:1) đã ước
 * lượng lúc đầu. Đổi `aspect-ratio` theo đúng tỉ lệ mẫu thật, không dùng số
 * ước lượng ban đầu nữa.
 *
 * `aspect-ratio:2640/500` giữ đúng tỉ lệ mẫu khách gửi bất kể ảnh gốc kích
 * thước gì — `object-fit:cover` cắt ảnh cho vừa khung thay vì méo hình. Nền gradient
 * navy (giống hệt màu `.sp-banner` cũ) hiện SẴN phía sau — chưa danh mục
 * nào có `tc_banner_image` nên đây là trạng thái graceful "chưa có ảnh",
 * không phải ô trống lỗi; khi có ảnh thật, ảnh phủ kín khung, không thấy
 * gradient nữa.
 *
 * SỬA (27/08/2026, khách gửi ảnh chụp /tui-nilon/ khoanh đỏ 2 khoảng trắng
 * thừa — trên khung ảnh VÀ dưới khối info): `.cat-hero` là thẻ <section>
 * TRẦN, dính rule chung `:where(section){padding-block:var(--sp-8)}`
 * (global.css) — KHÔNG chủ ý, bỏ sót khi dựng lần đầu. `.cat-hero-img` (tỉ
 * lệ 16:5 tự thân) và `.cat-hero-info` (đã có padding riêng) không cần —
 * hơn nữa KHÔNG được cần — khoảng đệm ngoài của chính `.cat-hero`. Đặt
 * `padding:0` xoá khoảng thừa cả trên khung ảnh lẫn dưới khối info, không
 * đụng `:where(section)` gốc (rule dùng chung toàn site, nhiều nơi khác vẫn
 * cần).
 */
.cat-hero{ padding:0; }
/*
 * SỬA 05/09/2026 (khách chốt kích thước ảnh banner): desktop 1920x425
 * (aspect-ratio 1920/425 ~ 4.52:1, cao hơn mốc 2640/500 = 5.28:1 chốt
 * 27/08/2026), điện thoại 430x150 (~2.87:1) để ảnh không mỏng như một vệt khi
 * bề ngang chỉ còn ~430px. Mốc 600px là breakpoint điện thoại các file này đang
 * dùng. Ảnh vẫn `object-fit:cover` nên ảnh gốc cỡ nào cũng lấp đúng khung.
 */
.cat-hero-img{
	width:100%;
	aspect-ratio:1920/425;
	overflow:hidden;
	background:linear-gradient(160deg,var(--navy) 0%,var(--navy-dark) 100%);
}
.cat-hero-img-el{
	width:100%;
	height:100%;
	object-fit:cover;
	display:block;
}
/*
 * Khối info chuyển sang NỀN TRẮNG (thừa hưởng nền trang, không tự đặt
 * background) — chữ đổi từ trắng-trên-navy (`.sp-banner` cũ) sang
 * navy/xám-trên-trắng. `text-align:center` + `max-width` của `p` giữ
 * nguyên bố cục cũ, chỉ đổi bảng màu.
 *
 * SỬA (27/08/2026, cùng phản hồi "giảm spacing luôn" ở dưới): `padding-
 * bottom` giảm từ `--sp-7` (48px) xuống `--sp-5` (24px) — khoảng trắng
 * khách khoanh đỏ giữa đoạn mô tả và hàng danh mục con là TỔNG của đệm
 * dưới `.cat-hero-info` CỘNG đệm trên của `.cat-sec.wrap` ngay sau (xem
 * rule đó bên dưới, cũng giảm cùng lúc) — giảm CẢ HAI phía mới hết khoảng
 * trắng thừa, giảm một phía thôi vẫn còn thấy to.
 */
.cat-hero-info{
	padding:var(--sp-6) var(--wrap-x) var(--sp-5);
	text-align:center;
}
/*
 * SỬA (27/08/2026, khách gửi ảnh chụp /tui-nilon/ khoanh gạch chéo đè lên
 * dòng dẫn + mũi tên chỉ breadcrumb): "bỏ cái mô tả nhỏ trên tất cả product
 * cat và chuyển cái breadcrumb canh lề trái". `text-align:left` CHỈ áp cho
 * `.crumb` — `.cat-hero-info` (khối cha) vẫn giữ `text-align:center` để H1
 * không đổi (khách không khoanh vào H1).
 */
.cat-hero-info .crumb{ font-size:13px; color:var(--text-muted); margin-bottom:var(--sp-4); text-align:left; }
.cat-hero-info .crumb a{ color:var(--text-muted); }
.cat-hero-info .crumb a:hover{ color:var(--navy); }
.cat-hero-info h1{ color:var(--navy); font-size:38px; margin-bottom:var(--sp-4); }
/*
 * `.cat-hero-info p` (dòng dẫn tc_banner_lead, từng có text-align:justify +
 * padding riêng, xem commit 3407458) đã XOÁ khỏi CSS — template
 * (taxonomy-vp_product_cat.php) không còn render thẻ <p> này nữa (SỬA
 * 27/08/2026, khách yêu cầu bỏ hẳn mô tả nhỏ khỏi mọi trang danh mục). Field
 * ACF tc_banner_lead vẫn còn, chỉ ngừng hiển thị — xem lịch sử git nếu cần
 * khôi phục lại rule CSS này.
 */

/* ---------- Heading danh mục cha ---------- */
/*
 * ---------------------------------------------------------------------------
 * TRI SO LAY DUNG TU MOCKUP, KHONG LAM TRON VE TOKEN
 * ---------------------------------------------------------------------------
 * Thang token cua theme la 4/8/12/16/24/32/48/96. Mockup trang danh muc
 * (~/vp-mockups (3.1)/(3.2)) dung mot so tri so KHONG nam trong thang do:
 * 14 / 18 / 20 / 22 / 36 / 44 / 72 / 88. Ban dung dau da "lam tron" chung ve
 * token gan nhat, gay lech 13 cho so voi thiet ke — do that bang computed
 * style, mockup mo cung mot trinh duyet voi trang that.
 *
 * Khach yeu cau dong bo 100% voi mockup, nen nhung cho nay ghi THANG px dung
 * bang mockup. Doi lai la mat tinh nhat quan cua thang token o dung may cho
 * nay; day la danh doi CO Y, khong phai quen dung token.
 */
/*
 * ---------------------------------------------------------------------------
 * KHOANG CACH DOC — CO Y KHAC MOCKUP (khach yeu cau thu gon)
 * ---------------------------------------------------------------------------
 * `section.wrap` dung chung cho ca `.cat-sec` lan `.shop` va cho ca hai
 * padding 96px tren duoi (dung y mockup). Hai khoi nay DINH NHAU nen khoang
 * ho giua dai danh muc va cot loc bi CONG DON: do that 96 + 96 = 192px, gan
 * bang mot man hinh dien thoai chi de trong.
 *
 * Khach xem trang that va yeu cau thu gon. Day la cho DUY NHAT trong trang
 * danh muc co y khac mockup — ghi ro de sau nay khong ai "sua lai cho dung
 * thiet ke" ma khong biet vi sao.
 *
 * Dang chu y: chinh mockup cung khai `.shop{padding-bottom:80px}` nhung rule
 * do THUA do dac hieu (`.shop` la (0,1,0), `section.wrap` la (0,1,1)) nen
 * chua bao gio co tac dung. Tuc y do goc cua designer cho khoi nay von cung
 * nho hon 96px — thu gon o day di dung huong do, khong phai bia ra.
 *
 * Sau khi sua (do that): banner -> tieu de 56px (cu 96), dai danh muc -> cot
 * loc 48px (cu 192).
 *
 * SUA LAN 2 (27/08/2026, khach gui anh chup /bao-bi-duoc-pham-y-te/ khoanh
 * do + mui ten chi khoang trang giua doan mo ta va dai danh muc con, cung
 * yeu cau voi doi text-align:justify o .cat-hero-info p): 56px top nay tinh
 * tu thoi con `.sp-banner` (padding-bottom rieng 64px) - gio doi sang
 * `.cat-hero-info` (padding-bottom da giam con 24px, xem rule do trong file
 * nay), tong khoang trang do that 24+56=80px van con to hon can thiet. Giam
 * tiep top xuong 24px (tong con 24+24=48px) - giam CA HAI phia (chinh no va
 * `.cat-hero-info` cung luc) moi het khoang trang thua, giam mot phia thoi
 * van con thay to.
 */
.cat-sec.wrap{ padding-top:24px; padding-bottom:48px; }
/* Noi tiep ngay duoi dai danh muc — khong can dem tren nua; day giu 80px dung
   bang con so mockup da khai cho chinh `.shop`. */
/*
 * `padding-top:0` GIỚI HẠN LẠI CHỈ khi `.shop.wrap` đứng NGAY SAU `.cat-sec.wrap`
 * — khách (25/08/2026, ảnh /tui-sinh-hoc/): "ko có cat con thì bị sát quá".
 *
 * "Túi sinh học" là danh mục cấp một DUY NHẤT không có danh mục con (đo bằng
 * `wp term list` — không có term nào parent=id của nó), nên từ SỬA LẦN 2
 * (.cat-row đổi sang hiện danh mục CON), khối `.cat-sec.wrap` KHÔNG render gì
 * cho trang này (guard `if ($vp_dm_siblings)` trong taxonomy-vp_product_cat.php)
 * — `.shop.wrap` nhảy lên đứng NGAY SAU `.sp-banner`. `padding-top:0` viết
 * cho trường hợp CÓ `.cat-sec` (tránh cộng dồn hai nguồn khoảng cách — chính
 * `.cat-sec.wrap` đã có `padding-bottom:48px` riêng) giờ áp NHẦM cho cả
 * trường hợp KHÔNG có `.cat-sec`, khiến banner navy dính sát chữ "Hiển thị
 * 9 trên tổng 10 sản phẩm..." — 0px, không phải lỗi hiển thị ngẫu nhiên.
 *
 * Selector kết hợp `.cat-sec.wrap + .shop.wrap` (0,4,0) CHỈ áp `padding-top:0`
 * khi thật sự có `.cat-sec.wrap` đứng liền trước — trường hợp không có (như
 * "Túi sinh học"), `.shop.wrap` rơi về `padding-top:var(--sp-8)` tự nhiên của
 * `section.wrap` (global.css, 96px) thay vì bị ép 0. Không cần bịa một giá trị
 * mới: đây CHÍNH LÀ khoảng cách mặc định mọi `<section class="wrap">` khác
 * trên site đã dùng, chỉ là `.shop.wrap` từng luôn có `.cat-sec` đứng trước
 * (mọi danh mục cấp một trước SỬA LẦN 2 đều có ít nhất một con) nên chưa ai
 * thấy nhánh "không có" tới tận bây giờ.
 */
.shop.wrap{ padding-bottom:80px; }
.cat-sec.wrap + .shop.wrap{ padding-top:0; }

.cat-head{ text-align:center; max-width:640px; margin:0 auto 44px; } /* mockup 44px, token --sp-7 la 48px */

/* .cat-row/.cat-col/.cat-ic: chuyen sang assets/css/cat-slider.css (slider
   Swiper) — xem docblock file do. Chi 2 trang dung (taxonomy-vp_product_cat.php,
   archive-vp_product.php), tach rieng de khong bat cac trang khac dung
   taxonomy-danhmuc.css tai them CSS Swiper khong can den. */

/* ---------- Layout: bộ lọc trái + lưới phải ---------- */
.shop{ background:var(--white); padding-bottom:80px; }
/*
 * SỬA LẦN 3 — khách (25/08/2026): "xoá cái sidebar và cả cho sản phẩm 1 dòng
 * 4 item", áp dụng ĐỒNG BỘ cho cả taxonomy-vp_product_cat.php lẫn
 * archive-vp_product.php (hai template dùng CHUNG các class dưới đây, xác
 * nhận phạm vi qua AskUserQuestion — không phải suy đoán).
 *
 * `.shop-layout` từ lưới HAI CỘT (236px sidebar + 1fr lưới sản phẩm) rút về
 * MỘT khối chứa `.prod-main` duy nhất — không xoá hẳn div này (vẫn giữ
 * `max-width:1180px; margin:0 auto` để canh giữa, cùng bề rộng hộp chứa cũ,
 * tránh lưới sản phẩm đột ngột đổi độ rộng khung so với `.cat-row`/`.sp-banner`
 * phía trên).
 *
 * RULE `.filter`/`.filter-list`/`.filter-item*` ĐÃ XOÁ — không còn markup nào
 * sinh ra chúng ở CẢ HAI template (`<aside class="filter">` đã gỡ). Giữ lại
 * là để CSS chết trong repo, đúng loại lỗi mà `.footer-more`/`.cat-head` (khi
 * dùng ở trang đã gỡ) đã dọn ở các đợt trước.
 */
.shop-layout{
	max-width:1180px;
	margin:0 auto;
}

/* Lưới sản phẩm */
.prod-top{ display:flex; align-items:center; justify-content:space-between; margin-bottom:20px; } /* mockup 20px, token --sp-5 la 24px */
.prod-top .count{ font-size:14px; color:var(--text-muted); }
.prod-top .count b{ color:var(--navy); font-weight:700; }
/*
 * 4 CỘT — khách (25/08/2026): "cho sản phẩm 1 dòng 4 item". Bề rộng khả dụng
 * tăng đúng bằng phần sidebar 236px+36px vừa gỡ (`.shop-layout` ở trên), nên
 * mỗi thẻ sản phẩm rộng xấp xỉ NHƯ CŨ dù thêm một cột — không phải bốn thẻ bị
 * bóp nhỏ trong cùng bề ngang trước đây (đo: 3 cột/908px ≈ 288px một thẻ TRƯỚC
 * so với 4 cột/1180px ≈ 278px một thẻ SAU, chênh 10px, không đáng kể).
 */
.prod-grid{
	display:grid;
	grid-template-columns:repeat(4,1fr);
	gap:22px;
}
/*
 * "STRETCHED LINK" — cả thẻ bấm được, không chỉ riêng "Xem chi tiết".
 *
 * Khách (25/08/2026, ảnh khoanh đỏ mũi tên chỉ vào phần ảnh sản phẩm):
 * "cập nhật tất cả nhấn vào box thì nhảy qua link luôn ko nhất thiết chỉ
 * nhấn vào nút 'xem chi tiết'".
 *
 * KHÔNG bọc cả `.prod-card` trong một `<a>` — `.prod-photo`/`.prod-name`
 * không có link riêng nào khác bên trong nên về mặt HTML điều đó hợp lệ,
 * nhưng vẫn không chọn cách này vì phải sửa markup ở CẢ BA nơi dùng
 * `.prod-card` (taxonomy-vp_product_cat.php, archive-vp_product.php, khối
 * "Sản phẩm liên quan" của single-vp_product.php) — đúng ba chỗ đã tránh
 * chép lại CSS cho nhau ở bản vá 4/3 phía trên, không lý gì giờ lại tách ra.
 *
 * THAY VÀO ĐÓ: `.prod-cta` (liên kết `<a>` DUY NHẤT, THẬT, đã có sẵn trong
 * PHP ở cả ba nơi) nhận thêm một lớp phủ `::after` tuyệt đối phủ kín TOÀN BỘ
 * `.prod-card` (`inset:0` trên `.prod-card{ position:relative }`). Vùng bấm
 * được nới rộng ra cả thẻ, nhưng DOM/accessibility tree KHÔNG đổi — vẫn đúng
 * một link, một href, một accessible name "Xem chi tiết" — không phải kỹ
 * thuật JS `onclick` trên toàn thẻ (mất focus bàn phím, mất "mở tab mới"
 * bằng chuột giữa/Ctrl+click, mất `<a>` xuất hiện đúng chỗ cho trình đọc
 * màn hình). Đây là mẫu chuẩn "link card" không cần JS, không đổi markup,
 * không lặp CSS ba lần.
 *
 * `.prod-photo`/`.prod-info` KHÔNG cần `z-index` riêng: chúng không phải
 * link/nút nào cả (chỉ ảnh + chữ tĩnh), nên phủ `::after` đè lên chúng không
 * che mất một hành vi bấm nào khác để mà phải nhường chỗ.
 */
.prod-card{
	background:#fff;
	border-radius:14px;
	overflow:hidden;
	border:1px solid var(--border);
	box-shadow:0 4px 16px rgba(0,27,183,.05);
	transition:transform .25s ease, box-shadow .25s ease, border-color .25s ease;
	display:flex;
	flex-direction:column;
	position:relative;
	cursor:pointer; /* toan the la vung bam duoc, con tro phai bao dung tu diem cham dau tien, khong doi mau o rieng .prod-cta */
}
.prod-card:hover{ transform:translateY(-6px); box-shadow:0 18px 40px rgba(0,27,183,.13); border-color:transparent; }
.prod-cta::after{ content:""; position:absolute; inset:0; }
/*
 * KHUNG 4/3 + object-fit:contain — KHÔNG PHẢI vuông + cover như mockup.
 *
 * Khách (24/08/2026): "ảnh nó đang chữ nhật, cái này hình vuông thì có cách xử
 * lý nào cho nó không cắt cái logo được không — tất cả product in grid".
 *
 * VÌ SAO MOCKUP SAI Ở ĐÂY, chứ không phải "chiều theo khách": mockup
 * (3.1)/(3.2) đặt `aspect-ratio:1` + `object-fit:cover`, nhưng MỌI thẻ
 * `.prod-card` trong hai file mockup đó chỉ vẽ SVG giữ chỗ — không có lấy một
 * tấm ảnh thật nào. Tức lựa chọn "vuông + cover" chưa từng được thử với ảnh
 * thật; nó là mặc định của một bản vẽ chỉ có ô xám.
 *
 * ĐO TRÊN 284 SẢN PHẨM THẬT (wp eval, không ước lượng) — KHÔNG có ảnh dọc nào:
 *
 *     4:3   (1.333)  249 ảnh  87.7%   ← 300x225, 600x450, 1200x900, 800x600
 *     1.846            28 ảnh   9.9%   ← 1200x650
 *     3:2   (1.500)     6 ảnh   2.1%   ← 1872x1248
 *     vuông (1.000)     1 ảnh   0.4%   ← 1536x1536
 *
 * Với khung VUÔNG + cover, ảnh ngang bị cắt hai bên: 4:3 mất 25% bề rộng
 * (đo trình duyệt thật ở 1280px: khung 277x277, ảnh 300x225 → cắt đúng 25.0%),
 * còn ảnh 1.846 mất 45.8% — gần một nửa. LOGO VINPACK NẰM Ở GÓC TRÊN-TRÁI của
 * chính nhóm 1.846 đó (đã mở ảnh gốc ra xem: logo quả địa cầu + "vinpack.vn" +
 * slogan), nên nhóm bị cắt nặng nhất đúng là nhóm mang logo — hỏng đúng thứ
 * khách hỏi.
 *
 * `contain` một mình KHÔNG đủ: giữ khung vuông thì 87.7% ảnh chừa 25% khoảng
 * trống dọc, thẻ trông rỗng ruột. Đổi khung sang 4/3 là khớp ĐÚNG tỉ lệ của
 * 87.7% ảnh — nhóm này lấp kín khung, không cắt mà cũng không chừa viền. Trung
 * bình có trọng số toàn kho chỉ còn ~3.1% khoảng trống, so với ~26.4% nếu giữ
 * khung vuông.
 *
 * NỀN TRẮNG ĐẶT TRÊN <img>, KHÔNG PHẢI TRÊN .prod-photo: với `contain`, thẻ
 * <img> vẫn phủ kín 100% khung, phần "viền" chỉ là chỗ trống bên trong thẻ đó
 * — nên `background` của chính <img> lấp đúng phần viền ấy. Mọi ảnh sản phẩm
 * đều chụp nền trắng, nên viền trắng hoà vào ảnh, không lộ ra như một dải xám.
 * Giữ `--img-bg` trên `.prod-photo` để SVG GIỮ CHỖ (sản phẩm chưa có ảnh) vẫn
 * đứng trên nền xám như thiết kế — đặt trắng lên khung sẽ làm hỏng ca đó.
 *
 * Dùng CHUNG cho cả ba nơi có lưới sản phẩm (taxonomy-vp_product_cat.php,
 * archive-vp_product.php, khối "Sản phẩm liên quan" của single-vp_product.php)
 * — inc/enqueue.php nạp file này cho cả ba, nên sửa một chỗ là đủ, đúng như
 * khách yêu cầu "tất cả product in grid".
 */
.prod-photo{
	aspect-ratio:4 / 3;
	background:var(--img-bg);
	border-bottom:1px solid var(--border);
	display:flex;
	align-items:center;
	justify-content:center;
	overflow:hidden;
	position:relative;
}
.prod-photo svg{ width:52px; height:52px; color:var(--icon-muted); }
.prod-photo img{ width:100%; height:100%; object-fit:contain; background:var(--white); display:block; }
.prod-info{ padding:16px 18px 18px; display:flex; flex-direction:column; flex:1; } /* mockup 16/18/18 */
.prod-name{ font-size:15px; color:var(--navy); font-weight:700; font-family:var(--font-head); line-height:1.4; margin-bottom:var(--sp-3); flex:1; }
.prod-cta{
	display:inline-flex;
	align-items:center;
	gap:7px;
	font-size:13.5px;
	font-weight:700;
	color:var(--cobalt);
	text-decoration:none;
	transition:gap .2s ease;
}
.prod-card:hover .prod-cta{ gap:11px; }
.prod-cta svg{ width:15px; height:15px; }

/* Phân trang */
.pager{ text-align:right; margin-top:44px; } /* mockup 44px, token --sp-7 la 48px */
.pager-inner{ display:inline-flex; align-items:center; gap:var(--sp-2); flex-wrap:wrap; }
.pager-inner .page-numbers{
	min-width:40px;
	height:40px;
	border-radius:10px;
	display:flex;
	align-items:center;
	justify-content:center;
	font-size:14px;
	font-weight:600;
	text-decoration:none;
	color:var(--text);
	background:#fff;
	border:1px solid var(--border);
	transition:all .2s ease;
	padding:0 var(--sp-2);
}
.pager-inner a.page-numbers:hover{ border-color:var(--cobalt); color:var(--cobalt); }
.pager-inner .page-numbers.current{ background:var(--navy); color:#fff; border-color:var(--navy); }
.pager-inner .page-numbers.next,
.pager-inner .page-numbers.prev{ padding:0 var(--sp-4); gap:6px; margin-left:var(--sp-2); }

/* ===== Responsive ===== */
@media(max-width:960px){
	/*
	 * SỬA LẦN 3 — khối `.filter{...}` (chuyển sidebar từ sticky-dọc sang tĩnh-
	 * ngang khi màn hẹp) ĐÃ XOÁ, không còn `<aside class="filter">` nào ở
	 * bất kỳ bề rộng nào để mà chuyển. `.shop-layout{ grid-template-columns:
	 * 1fr }` cũng bỏ theo — rule gốc ở ngoài @media giờ không còn khai
	 * grid-template-columns nào để ghi đè (đã rút về một khối không phải
	 * lưới hai cột, xem rule `.shop-layout` phía trên).
	 *
	 * `.prod-grid` GIẢM CÒN 3 CỘT ở khổ này (mới thêm — trước đây không có
	 * breakpoint riêng vì 3 cột gốc đã đủ hẹp để không cần giảm tới tận
	 * 680px). 4 cột gốc dùng bề rộng ĐẦY ĐỦ 1180px của `.shop-layout`; ở
	 * 960px, khung đó bị bóp lại theo viewport nên mỗi thẻ 4-cột chỉ còn
	 * ~215px — chật hơn đáng kể so với ~278px lúc 1180px. Xuống 3 cột ở đây
	 * giữ mỗi thẻ khoảng ~290px, gần bằng cỡ thẻ gốc, đọc được ảnh + tên +
	 * nút mà không phải ép chữ quá nhỏ.
	 */
	.prod-grid{ grid-template-columns:repeat(3,1fr); }
}
@media(max-width:680px){
	.prod-grid{ grid-template-columns:repeat(2,1fr); gap:var(--sp-4); }
	/*
	 * Thu gọn khoảng trắng dọc dưới H1/breadcrumb ở mobi (khách 03/09/2026,
	 * ảnh chụp /tui-sinh-hoc/ khoanh đỏ khoảng trắng giữa "Túi sinh học" và
	 * "Hiển thị X trên tổng Y sản phẩm") — áp cho TẤT CẢ trang danh mục, chỉ
	 * ở mobi (desktop giữ nguyên, không đụng).
	 *
	 * `.cat-hero-info{padding-bottom:24px}` luôn cộng dồn với đệm trên của
	 * section liền sau. Danh mục CÓ con: section liền sau là `.cat-sec.wrap`
	 * (24px, không đổi ở đây). Danh mục KHÔNG con (vd "Túi sinh học" — không
	 * render `.cat-sec.wrap`, xem guard `$vp_dm_siblings` trong taxonomy-
	 * vp_product_cat.php): section liền sau là `.shop.wrap`, đệm trên rơi về
	 * mặc định `section.wrap` (--sp-8, global.css đã giảm còn 64px ở mốc
	 * 900px) — đo thật trên /tui-sinh-hoc/ ở 375px: 16 (margin dưới H1) + 24
	 * (đệm dưới info) + 64 (đệm trên shop) = 104px trắng trơn trước dòng
	 * "Hiển thị...". Giảm CẢ HAI phía (đúng nguyên tắc đã ghi ở rule
	 * `.cat-sec.wrap` phía trên — giảm một phía thôi vẫn còn thấy to): còn
	 * 16+16+40 = 72px.
	 *
	 * `.cat-hero + .shop.wrap` (combinator kề sát) CHỈ khớp khi không có
	 * `.cat-sec.wrap` chen giữa — danh mục có con vẫn ăn nguyên rule
	 * `.cat-sec.wrap + .shop.wrap{padding-top:0}` gốc, không bị đụng.
	 */
	.cat-hero-info{ padding-bottom:var(--sp-4); }
	.cat-hero + .shop.wrap{ padding-top:40px; }
}
@media(max-width:480px){
	/*
	 * GIỮ 2 CỘT xuống tận khổ hẹp nhất (03/09/2026, khách: "xuống mobi 1 hàng
	 * 2 item sản phẩm") — trước đây rớt về 1 cột ở đây.
	 *
	 * Ở 375px, hai cột + gap 12px + lề trang cho mỗi thẻ ~165px. Chật hơn
	 * mockup nhưng vẫn đủ cho ảnh vuông + hai dòng tên; nên GIẢM gap từ
	 * var(--sp-4) (16px) xuống var(--sp-3) (12px) để trả thêm bề ngang cho
	 * thẻ thay vì cho khe.
	 */
	.prod-grid{ grid-template-columns:repeat(2,1fr); gap:var(--sp-3); }
}
@media(prefers-reduced-motion:reduce){
	.prod-card,.prod-cta,.filter-item{ transition:none; }
}

/*
 * ---------- Nội dung SEO: sidebar TOC + .art-content (Phase I Task 2) ----------
 *
 * SỬA — khách (25/08/2026, ảnh khoanh đỏ khoảng trắng lớn giữa phân trang và
 * khối "NỘI DUNG BÀI VIẾT"): "spacing to quá". ĐO ĐƯỢC LỖI THẬT, không phải
 * tinh chỉnh thẩm mỹ: `.cat-seo{ padding-top:var(--sp-4) }` (0,1,0) đứng SAU
 * `section.wrap{ padding:var(--sp-8) var(--wrap-x) }` (global.css, 0,1,1)
 * trong thứ tự nạp CSS, nhưng có ĐỘ ƯU TIÊN THẤP HƠN — 1 class trần thua 1
 * class + 1 tag. `<section class="cat-seo wrap">` mang cả hai class, nên
 * rule global THẮNG bất kể viết sau: computed padding-top đo được là 96px
 * (đúng --sp-8), không phải 16px (--sp-4) như code đọc vào tưởng.
 *
 * Cộng với `.shop.wrap{ padding-bottom:80px }` ngay phía trên .cat-seo trong
 * DOM, tổng khoảng trắng giữa phân trang và "NỘI DUNG BÀI VIẾT" là 80+96=176px
 * — đúng dải trống khách khoanh đỏ.
 *
 * SỬA đúng chỗ hỏng: thêm class `.wrap` vào chính selector này
 * (`.cat-seo.wrap`, 0,2,0) để nó THẬT SỰ thắng `section.wrap` (0,1,1) —
 * cùng cách `.shop.wrap` đã làm đúng ngay từ đầu cho khối phía trên. Giá trị
 * vẫn --sp-4 (16px, không đổi ý định gốc), chỉ là lần đầu nó thật sự có hiệu
 * lực. Kết quả: 80 (shop) + 16 (cat-seo, ĐÚNG) = 96px — một dải ngăn cách vừa
 * phải, không phải khoảng trống 176px trông như lỗi.
 */
.cat-seo.wrap{ background:var(--white); padding-top:var(--sp-4); }

.art-wrap{ max-width:1080px; margin:0 auto; }

/*
 * SỬA 07/09/2026 (cùng đợt rà mép trái/phải các trang chi tiết): khối nội dung
 * SEO của trang danh mục hụt vào so với phần trên của chính nó. ĐO tại 1280px:
 * breadcrumb và lưới sản phẩm ở 75/1116, còn `.art-wrap` ở 93/1080 — lệch 18px
 * mỗi bên, do rule `.art-wrap{max-width:1080px}` ngay trên (dùng chung sáu
 * template) hẹp hơn bề ngang nội dung của `section.wrap` (1180 - 2×32 = 1116).
 *
 * Trang danh mục KHÔNG lấy mốc 1180 như trang sản phẩm chi tiết: banner đầu
 * trang ở đây là ảnh full-bleed (đo 0/1265, chạy hết bề ngang màn hình) nên
 * không có "mép ảnh" nào để căn — khối chuẩn của trang là lưới sản phẩm ở
 * 1116. Bỏ max-width để `.art-wrap` lấp đúng bề ngang đó; padding-inline của
 * `section.wrap` vẫn lo phần lề nên mọi bề ngang nhỏ hơn tự khớp theo lưới,
 * không cần media query riêng. Chỉ ăn `.art-wrap` con TRỰC TIẾP của
 * `.cat-seo.wrap` — năm template còn lại giữ nguyên 1080px.
 */
.cat-seo.wrap > .art-wrap{ max-width:none; }
.art-layout{
	display:grid;
	/*
	 * minmax(0,1fr) chứ không phải 1fr trần: track 1fr mặc định là
	 * minmax(auto,1fr) — KHÔNG co nhỏ hơn min-content của nội dung bên
	 * trong. Ảnh <img width="1200"> hoặc <table> trong .art-content đẩy
	 * cột này rộng ra tới min-content của chúng, vỡ khung .art-wrap
	 * (max-width:1080px) và tràn hẳn ra ngoài body. Đã đo trên trình
	 * duyệt thật: scrollWidth 1621px trong khi clientWidth 1265px.
	 * Đặt sàn 0 thì track co vừa .art-wrap, còn rule ".art-content img" với
	 * width:100% (đã có sẵn trong global.css) lo phần ảnh co vừa track đó.
	 */
	grid-template-columns:280px minmax(0,1fr);
	gap:var(--sp-7);
	align-items:start;
}
.art-toc{
	position:sticky;
	top:100px;
	/*
	 * position:sticky chỉ dính khi chiều cao phần tử <= khoảng trống viewport
	 * còn lại (viewport - top). Đo thật: .art-toc cao 1045px trong khi
	 * viewport desktop chỉ ~900px -> không bao giờ dính, trôi khỏi màn hình.
	 * Chặn chiều cao theo viewport (trừ top và một khoảng đệm dưới bằng
	 * var(--sp-5)) rồi cho tự cuộn bên trong.
	 */
	max-height:calc(100vh - 100px - var(--sp-5));
	overflow-y:auto;
	/*
	 * KHONG dat overscroll-behavior:contain o day. Khi muc luc NGAN hon
	 * max-height (truong hop thuong gap sau khi bo H3 — do that: 601px trong
	 * khung 776px, tuc khong co gi de cuon ben trong), `contain` van co the
	 * nuot su kien cuon khi con tro dang nam tren cot muc luc, khien nguoi doc
	 * tuong trang bi dung. Cot nay chiem gan het chieu cao man ben trai nen
	 * xac suat con tro nam tren no rat cao. Doi lai: khi muc luc DAI that va
	 * da cuon het, cuon se noi tiep sang trang — hanh vi mac dinh, chap nhan
	 * duoc, va it hai hon nhieu so voi cam giac "trang bi khoa".
	 */
	/*
	 * ẨN thanh cuộn — khách (21/08/2026, ảnh khoanh đỏ thanh cuộn xám lộ ra
	 * bên trong khối sticky "Nội dung bài viết"): "check viewport từ 1024px
	 * trở lên sao để không có thanh scroll trên cái sticky này".
	 *
	 * ĐO THẬT trước khi sửa: ở 1024×768 (khổ laptop rất phổ biến), mục lục
	 * 10 mục cao 803px trong khung chỉ còn 644px (viewport trừ top 100px và
	 * đệm) — THỪA 159px, tức tràn THẬT, không phải lỗi tính toán. overflow-y
	 * auto + max-height ở trên vẫn PHẢI giữ nguyên — bỏ đi thì đúng lỗi mà
	 * docblock ngay phía trên đã cảnh báo: sticky sẽ không bao giờ dính vì
	 * .art-toc cao hơn khoảng trống viewport còn lại, trôi tuột khỏi màn
	 * hình. Khách muốn bỏ đúng CÁI THANH nhìn thấy, không phải bỏ khả năng
	 * cuộn — nên ẩn thanh cuộn TRÊN MỌI TRÌNH DUYỆT nhưng vẫn cuộn được bằng
	 * lăn chuột/trackpad/chạm/phím mũi tên (khi có focus, xem tabindex="0"
	 * ở nơi in <aside class="art-toc">) — cùng kỹ thuật đã dùng cho
	 * `.press-viewport` (home.css) và `.proj-filters` (page-duan.css).
	 */
	scrollbar-width:none;
	-ms-overflow-style:none;
	background:var(--bg-alt);
	border-radius:var(--r-lg);
	padding:22px 18px; /* mockup 22/18, token cho 24/16 */
}
.art-toc::-webkit-scrollbar{ display:none; }
.art-toc h4{
	font-size:12px;
	text-transform:uppercase;
	letter-spacing:.9px;
	color:var(--text-muted);
	margin-bottom:var(--sp-4);
	font-weight:700;
	padding-left:var(--sp-3);
}
.art-toc ol{ list-style:none; display:flex; flex-direction:column; gap:var(--sp-1); }
.art-toc a{
	display:flex;
	align-items:center;
	gap:13px;
	padding:var(--sp-3) var(--sp-4);
	border-radius:var(--r-sm);
	color:var(--text);
	font-size:14.5px;
	text-decoration:none;
	line-height:1.35;
	transition:all var(--dur-micro) var(--ease);
}
.art-toc .num{
	flex-shrink:0;
	width:26px; height:26px;
	border-radius:var(--r-full);
	background:var(--bg-alt);
	color:var(--text-muted);
	display:flex; align-items:center; justify-content:center;
	font-family:var(--font-head);
	font-weight:700;
	font-size:13px;
	transition:all var(--dur-micro) var(--ease);
}
.art-toc a:hover{ color:var(--navy); }
.art-toc a:hover .num{ background:var(--white); color:var(--navy); }
.art-toc a.active{
	background:var(--white);
	color:var(--navy);
	/*
	 * KHONG dung `font-weight:700` o day, du muc dang doc VAN phai noi bat.
	 *
	 * Chu 700 rong hon chu thuong khoang 2.8% — do that voi chinh font Inter
	 * cua site tren mot nhan muc luc: 353.5px -> 363.5px. Cot muc luc rong
	 * co dinh 280px, nen nhan nao dang dung sat mep dong se bi day them MOT
	 * DONG ngay khi doi sang dam: muc dang doc bong nhien cao them ~20px va
	 * ca danh sach ben duoi nhay xuong. Doi voi thanh phan doi trang thai
	 * lien tuc theo cuon (scrollspy) thi kieu nhay do rat kho chiu.
	 *
	 * `text-shadow` lam DAY NET chu ma KHONG dong toi metric chu (rong/cao
	 * cua chu khong doi mot pixel nao), nen so dong luon giu nguyen dung bang
	 * luc chua active. Muc dang doc van du noi bat: da co nen trang, chu navy
	 * va do do rieng so voi cac muc con lai.
	 */
	text-shadow:0 0 .3px currentColor, 0 0 .3px currentColor;
	box-shadow:var(--sh-2);
}
.art-toc a.active .num{ background:var(--navy); color:var(--white); }

@media(max-width:900px){
	/* Cùng lỗi và cùng cách sửa với rule .art-layout ở màn rộng: 1fr trần
	   không co dưới min-content của nội dung (ảnh/bảng), tràn ngang cả
	   trang trên mobile. minmax(0,1fr) buộc track co vừa .art-wrap. */
	.art-layout{ grid-template-columns:minmax(0,1fr); gap:0; }
	/* max-height/overflow-y ở màn rộng không áp dụng trên mobile — position:static
	   không sticky nên không cần giới hạn chiều cao, tránh biến TOC thành ô cuộn tí hon. */
	.art-toc{ position:static; margin-bottom:var(--sp-6); max-height:none; overflow:visible; }
}

/* ============================================================
   Mục lục trên mobile — nút ghim mép trái, mở ra ngăn kéo
   ============================================================
   Khách (03/09/2026): "tối ưu mobi cái mục lục tất cả để nó dạng side bar
   icon sticky bên trái center".

   VẤN ĐỀ. Rule ngay trên biến mục lục thành khối tĩnh full-width nằm TRƯỚC
   nội dung. Bài 8 mục chiếm trọn màn hình đầu, phải cuộn hết mới tới chữ.

   CHỈ ÁP KHI JS ĐÃ CHẠY. Mọi rule dưới đây đều nằm sau `body.has-toc-fab` —
   cờ do assets/js/art-toc-mobile.js tự gắn sau khi dựng xong nút. Không có
   JS thì mục lục giữ nguyên khối tĩnh ở trên: chiếm chỗ nhưng đọc và bấm
   được. Không bao giờ có cảnh mục lục bị ẩn mà không có gì mở nó ra.

   THANG Z-INDEX (xem mục 6 global.css) — SỬA 03/09/2026, xem lý do đầy đủ
   ngay tại rule .toc-fab bên dưới:
     --z-fab       nền mờ .toc-scrim, ngang hàng FAB liên hệ (khác phía)
     --z-fab + 1   ngăn kéo .art-toc VÀ nút .toc-fab (NGANG NHAU — không
                   chồng lấn không gian: nút trượt sang bên phải ngăn kéo
                   lúc mở, xem `body.toc-locked .toc-fab` bên dưới)
   Bậc +1 THẤP HƠN — không còn "ngang hàng" — .vp-drawer-backdrop (+2 trong
   layout.css) và .nav-search-backdrop/.nav-search-pop (+2/+3): mở menu điều
   hướng hoặc popup tìm kiếm thì chúng phải che mục lục, không ngược lại. Bậc
   +2 (bản trước) NGANG HÀNG hai lớp phủ đó nên ai render sau trong DOM thắng
   — nút mục lục (JS thêm vào cuối <body>) từng đè lên nền mờ của popup tìm
   kiếm, lộ giữa màn hình.
   ============================================================ */

/* Ngoài mobile: không tồn tại. */
.toc-fab,
.toc-scrim{ display:none; }

@media(max-width:900px){
	body.has-toc-fab .art-toc{
		position:fixed;
		left:0;
		top:0;
		z-index:calc(var(--z-fab) + 1);
		width:min(84vw, 300px);
		height:100%;
		max-height:none;
		margin:0;
		border-radius:0 var(--r-lg) var(--r-lg) 0;
		overflow-y:auto;
		/*
		 * `contain` ĐÚNG ở đây, khác hẳn cột sticky trên desktop (xem docblock
		 * .art-toc ở màn rộng, nơi cố ý KHÔNG dùng). Trên desktop mục lục chỉ
		 * là một cột cạnh nội dung, nuốt sự kiện cuộn khiến người đọc tưởng
		 * trang bị khoá. Ở đây nó là ngăn kéo phủ lên trang, có nền mờ chặn
		 * phía sau — cuộn hết ngăn kéo mà trang phía dưới trôi theo mới là lỗi.
		 */
		overscroll-behavior:contain;
		/*
		 * translateX(0) chu KHONG phai `none` o trang thai mo: do that tren
		 * may, chuyen tu translateX(-100%) sang `none` thi Chrome giu nguyen
		 * gia tri dau, ngan keo khong truot vao (tat transition di thi rule
		 * ap dung dung — nen loi nam o buoc noi suy, khong phai o cascade).
		 * Hai gia tri cung dang translateX thi noi suy khong con mo ho.
		 */
		transform:translateX(-100%);
		/*
		 * visibility:hidden khi dong — KHONG chi de cho dep. Ngan keo van nam
		 * trong DOM, chi bi day ra ngoai man hinh; thieu dong nay thi 7-8 link
		 * ben trong VAN tab toi duoc, nguoi dung ban phim se lac vao mot khoi
		 * khong nhin thay. Hoan lai 0s SAU khi truot xong (.24s) de van thay
		 * ngan keo trong luc no dang truot ra.
		 */
		visibility:hidden;
		transition:transform .24s ease, visibility 0s linear .24s;
		box-shadow:var(--sh-2);
	}

	body.has-toc-fab .art-toc.is-open{
		transform:translateX(0);
		visibility:visible;
		/* Mo thi hien NGAY, khong cho .24s — nguoc lai voi luc dong. */
		transition:transform .24s ease, visibility 0s;
	}

	/* Khoá cuộn trang khi ngăn kéo mở. */
	body.toc-locked{ overflow:hidden; }

	.toc-scrim{
		display:block;
		position:fixed;
		inset:0;
		z-index:var(--z-fab);
		background:rgba(0, 27, 183, .28);
	}

	/* [hidden] của trình duyệt phải thắng display:block ngay trên. */
	.toc-scrim[hidden]{ display:none; }

	.toc-fab{
		display:flex;
		align-items:center;
		justify-content:center;
		position:fixed;
		left:0;
		/* "sticky bên trái center" — giữa chiều cao màn hình. */
		top:50%;
		transform:translateY(-50%);
		/*
		 * SỬA 03/09/2026 (khách gửi ảnh chụp /tui-nilon/ khi popup tìm kiếm
		 * đang mở: icon mục lục nổi đè lên nền mờ của popup, giữa màn hình,
		 * trông như một icon lạc chỗ) — từ +2 xuống +1.
		 *
		 * Bậc +2 SAI so với chính ý đồ đã ghi ở docblock mục "Mục lục trên
		 * mobile" phía trên file này: "TẤT CẢ DƯỚI .vp-drawer-backdrop (+2
		 * trong layout.css) và .nav-search-pop (+3)" — nhưng +2 lại NGANG
		 * HÀNG với .vp-drawer-backdrop/.nav-search-backdrop (cũng +2), không
		 * phải THẤP HƠN. Hai lớp phủ đó phủ TRỌN viewport
		 * (100vw×100vh, xem layout.css), nên khi ngang hàng, phần tử nào
		 * render SAU trong DOM (nút mục lục, do JS thêm vào cuối <body>) vẽ
		 * ĐÈ LÊN TRÊN — icon mục lục lộ ra giữa lớp nền mờ, đúng như ảnh chụp.
		 *
		 * +1 vẫn cao hơn .toc-scrim của CHÍNH mục lục (mục 6, bậc +0) nên
		 * bấm nút vẫn đóng được ngăn kéo mục lục của chính nó; và giờ THẬT
		 * SỰ thấp hơn hai lớp phủ kia nên bị che khuất — không chỉ nói suông
		 * trong comment.
		 */
		z-index:calc(var(--z-fab) + 1);
		/*
		 * SỬA 07/09/2026 (khách: "thu nút mục lục lại cho hết đè chữ").
		 *
		 * ĐO TRƯỚC KHI SỬA (375px, trang chính sách/dịch vụ/dự án chi tiết —
		 * mọi trang có mục lục): nút ghim ở dải 0–40px trong khi cột chữ bắt
		 * đầu ở 24px (--wrap-x), tức nút phủ 16px đầu MỖI DÒNG chữ, che vài ký
		 * tự đầu dòng suốt cả bài.
		 *
		 * Bề ngang lấy ĐÚNG var(--wrap-x) — cùng token quyết định lề trái của
		 * chữ — nên mép phải của nút luôn CHẠM mép trái cột chữ, không đè một
		 * pixel nào, và tự đúng ở cả 24px (≤900px) lẫn 32px. Số cứng sẽ lệch
		 * lại ngay khi lề trang đổi.
		 *
		 * Bù vùng chạm bằng CHIỀU CAO: 48px -> 56px. Nút hẹp lại 40->24px nên
		 * riêng bề ngang không còn đạt mốc chạm 44px; kéo cao lên giữ diện tích
		 * chạm xấp xỉ cũ (24×56 = 1344 so với 40×48 = 1920) và vẫn đạt 44px ở
		 * chiều dọc. KHÔNG nới vùng chạm vô hình bằng ::after: vùng đó sẽ nằm
		 * ĐÈ lên chữ, nuốt cú chạm vào chính phần bài viết mà thao tác này đang
		 * gỡ ra.
		 */
		width:var(--wrap-x);
		height:56px;
		padding:0;
		border:0;
		border-radius:0 var(--r-lg) var(--r-lg) 0;
		background:var(--navy);
		box-shadow:var(--sh-2);
		cursor:pointer;
		transition:transform .24s ease;
	}

	/*
	 * Khi mở: trượt nút ra sát mép phải ngăn kéo thay vì để nó nằm đè lên.
	 * Cùng quãng đường với chiều rộng ngăn kéo ở trên — sửa một chỗ phải sửa
	 * cả hai.
	 */
	body.toc-locked .toc-fab{ transform:translateY(-50%) translateX(min(84vw, 300px)); }

	/* Ba gạch thu theo nút (18->14px, gap 4->3px) để còn đệm hai bên. */
	.toc-fab-ico{
		display:flex;
		flex-direction:column;
		justify-content:center;
		gap:3px;
		width:14px;
		height:11px;
	}

	.toc-fab-ico > span{
		display:block;
		height:2px;
		border-radius:2px;
		background:var(--white);
		transition:transform .2s ease, opacity .2s ease;
	}

	/* Gạch giữa ngắn hơn — gợi hình danh sách chứ không phải nút menu. */
	.toc-fab-ico > span:nth-child(2){ width:70%; }

	/*
	 * Mở rồi thì ba gạch thành dấu X — cùng cách và cùng con số với
	 * .vp-drawer-toggle trong layout.css, để hai nút trên cùng một trang
	 * không hành xử khác nhau.
	 */
	.toc-fab[aria-expanded="true"] .toc-fab-ico > span:nth-child(1){ transform:translateY(5px) rotate(45deg); }
	.toc-fab[aria-expanded="true"] .toc-fab-ico > span:nth-child(2){ opacity:0; }
	.toc-fab[aria-expanded="true"] .toc-fab-ico > span:nth-child(3){ transform:translateY(-5px) rotate(-45deg); width:100%; }
}

/*
 * ẨN HẲN khi modal khác (popup tìm kiếm/ngăn kéo điều hướng) đang mở — xem
 * giải thích đầy đủ trong assets/js/art-toc-mobile.js, đoạn gắn class này.
 * z-index không giải quyết được vì .nav-search-backdrop nằm TRONG ngữ cảnh
 * xếp chồng riêng của header.site-header (position:sticky + z-index khác
 * auto), không so sánh trực tiếp được với .toc-fab nằm ngoài header.
 */
@media(max-width:900px){
	body.toc-fab-an .toc-fab{ display:none; }
}

@media(prefers-reduced-motion: reduce){
	body.has-toc-fab .art-toc,
	.toc-fab,
	.toc-fab-ico > span{ transition:none; }
}

/*
 * ---------- Tác giả (`.art-author`) — Phase M Task 2, dời từ product-single.css ----------
 * Trước Phase M, khối này chỉ có MỘT nơi dùng (single-vp_product.php) nên đúng
 * chỗ của nó là product-single.css. single-vp_project.php (Phase M Task 2) cần
 * NGUYÊN khối tác giả tĩnh này — hai người dùng thật cho cùng một khối, nên dời
 * vào ĐÂY (file mà CẢ HAI trang đều đã nạp qua is_tax()/is_singular()) thay vì
 * chép sang project-single.css. Cùng lý lẽ đã áp dụng cho vinpack_primary_term()
 * ở Phase M Task 1: một khối dùng chung có ĐÚNG MỘT nơi chứa khi có từ hai
 * người dùng trở lên. single-vp_product.php KHÔNG cần sửa gì để đọc lại đúng
 * rule này — 'vinpack-danhmuc' đã là dependency của 'vinpack-product' từ trước.
 *
 * 328px = 280px (cột .art-toc) + var(--sp-7) (gap của .art-layout ngay trên) —
 * canh mép trái theo đúng cột nội dung phía trên, đúng cho CẢ HAI trang vì cả
 * hai dùng chung một `.art-layout` 280px+gap.
 */
.art-author{
	display:flex;
	gap:20px;
	align-items:center;
	margin:44px 0 0 328px;
	padding:28px 0 0;
	border-top:1px solid var(--border);
	max-width:752px;
}
.pd-author-ava{
	width:72px;
	height:72px;
	border-radius:var(--r-full);
	flex-shrink:0;
	overflow:hidden;
	background:linear-gradient(140deg, var(--navy), var(--cobalt));
	display:flex;
	align-items:flex-end;
	justify-content:center;
}
.pd-author-ava svg{ width:44px; height:44px; color:rgba(255,255,255,.85); }
.pd-author-ava img{ width:100%; height:100%; object-fit:cover; }
.pd-author-info .role{ font-size:12px; text-transform:uppercase; letter-spacing:.6px; color:var(--cobalt); font-weight:700; margin-bottom:4px; }
.pd-author-info h4{ font-size:17px; color:var(--navy); margin-bottom:6px; font-family:var(--font-head); }
/*
 * Tên tác giả nay có thể là một <a> (trang "Tác giả" — xem
 * template-parts/global/author-box.php). Kế thừa màu .pd-author-info h4
 * thay vì màu link mặc định, gạch chân chỉ khi hover/focus — một cái tên
 * không cần trông như link cho tới khi người dùng thật sự tương tác.
 */
.pd-author-info h4 a{ color:inherit; text-decoration:none; }
.pd-author-info h4 a:hover,
.pd-author-info h4 a:focus-visible{ text-decoration:underline; }
.pd-author-info p{ font-size:13.5px; color:var(--text-muted); line-height:1.6; }

@media(max-width:900px){
	.art-author{ margin-left:0; max-width:none; }
}
@media(max-width:600px){
	/* Banner điện thoại 430x150 — xem ghi chú .cat-hero-img. */
	.cat-hero-img{ aspect-ratio:430/150; }

	.art-author{ flex-direction:column; text-align:center; }
}

/* ---------- FAQ (Phase I Task 2) ---------- */
.faq{
	background:var(--bg-alt);
	width:100vw;
	margin-left:calc(50% - 50vw);
	padding:72px 0 88px; /* mockup 72/88, token --sp-8 la 96px */
	overflow:hidden;
}
.faq-box{ max-width:820px; margin:0 auto; padding:0 var(--wrap-x); }
.faq-box .section-head{ text-align:center; margin:0 auto var(--sp-6); max-width:1240px; }
.faq-list{ display:flex; flex-direction:column; gap:var(--sp-3); }
.faq-item{
	background:var(--white);
	border-radius:var(--r-card);
	overflow:hidden;
	box-shadow:var(--sh-1);
}
.faq-q{
	display:flex;
	align-items:center;
	justify-content:space-between;
	gap:var(--sp-4);
	padding:var(--sp-5) var(--sp-5);
	cursor:pointer;
	font-family:var(--font-head);
	font-weight:700;
	font-size:16px;
	color:var(--navy);
	list-style:none;
}
.faq-q::-webkit-details-marker{ display:none; }
.faq-q .ic{
	flex-shrink:0;
	width:24px; height:24px;
	border-radius:var(--r-full);
	background:var(--bg-alt);
	display:flex; align-items:center; justify-content:center;
	transition:transform var(--dur-state) var(--ease), background var(--dur-state) var(--ease);
}
.faq-q .ic svg{ width:14px; height:14px; color:var(--navy); }
.faq-item[open] .faq-q .ic{ transform:rotate(45deg); background:var(--navy); }
.faq-item[open] .faq-q .ic svg{ color:var(--white); }
.faq-a{ padding:0 var(--sp-5) var(--sp-5); color:var(--text-muted); font-size:14.5px; line-height:1.8; }

@media(prefers-reduced-motion:reduce){
	.art-toc a,.art-toc .num,.faq-q .ic{ transition:none; }
}
/*
 * THANG CỠ TIÊU ĐỀ BANNER CHUẨN (07/09/2026): 38px desktop, 30px từ 900px,
 * 28px từ 600px. Trước đợt này mỗi banner tự chọn mốc và cỡ riêng nên ở 800px
 * màn hình có ba cỡ tiêu đề khác nhau cùng lúc — xem docblock đầy đủ trong
 * scratchpad/banner-dong-bo.py và các khối tương ứng ở tám file banner khác.
 */
@media (max-width:900px){
  .sp-banner h1,
  .cat-hero-info h1{ font-size:30px; }
}

@media (max-width:600px){
  .sp-banner h1,
  .cat-hero-info h1{ font-size:28px; }
}
