/**
 * C-20 · CSS COMPONENT  (T-219)
 *
 * Nguồn: `docs/wp/design-system.md` §5. Target Q-02, Q-05.
 *
 * ⚠️ `_tokens.css` PHẢI nạp TRƯỚC file này. Thiếu nó thì mọi `var(--c-*)`
 *    trả rỗng và trình duyệt rơi về màu mặc định — trang không lỗi, chỉ xấu,
 *    nên rất dễ tưởng là do thiếu CSS chứ không phải sai thứ tự nạp. Thứ tự
 *    khai trong `inc/enqueue.php` qua mảng `$deps`.
 *
 * ⚠️ TƯƠNG PHẢN WCAG AA — design-system §1.4 đã đo và chốt:
 *    chữ trắng trên cam gốc `#FC6C06` chỉ đạt **2,88:1**, TRƯỢT chuẩn AA.
 *    ⇒ Cam gốc `--c-accent` CHỈ dùng cho badge, icon, đường kẻ — thứ không
 *      có chữ trắng đè lên.
 *    ⇒ Nút có chữ dùng `--c-accent-strong` `#BF4E05` (4,87:1) hoặc
 *      `--c-accent-hover` `#A34204` (6,29:1).
 *    Đây là lỗi của layout gốc, không phải lựa chọn thẩm mỹ — đừng "sửa lại
 *    cho giống thiết kế".
 *
 * ⚠️ KHÔNG BAO GIỜ `outline: none` mà không thay bằng vòng focus khác. Người
 *    dùng bàn phím mất dấu con trỏ là mất khả năng dùng trang.
 */

/* =========================================================================
   0. VÒNG FOCUS DÙNG CHUNG  (bổ sung 2026-09-02 — R-06-home F-02)

   Bản đầu chỉ liệt kê 5 class: `.btn`, `.card`, `.form-field`,
   `.pagination__item`, `.filter-chips__item`. Danh sách kiểu đó không bao giờ
   đủ — đo bằng phím Tab thật trên trang chủ: logo, **9 link menu chính**,
   hotline header, 3 link "Tìm hiểu thêm", 7 ô lĩnh vực và nút play video đều
   rơi về vòng focus mặc định của trình duyệt (`dotted 1px`), tức người dùng
   bàn phím gần như không thấy mình đang ở đâu.

   ⚠️ `:where()` ép độ đặc hiệu về 0 nên component nào cần vòng focus riêng
      vẫn ghi đè được, mà không phải `!important` và không phụ thuộc thứ tự
      nạp file. Đây là lý do dùng nó thay vì liệt kê selector.

   ⚠️ `:focus-visible` chứ không `:focus`: bấm chuột vào nút không nên hiện
      vòng focus, chỉ điều hướng bàn phím mới cần. Trình duyệt tự phân biệt.
   ====================================================================== */

:where(a, button, summary, [tabindex]):focus-visible,
:where(input, select, textarea):focus-visible {
	outline: 2px solid var(--c-accent);
	outline-offset: 2px;
}

/* =========================================================================
   1. BUTTON  (T-219.1) — design-system §5.1
   ====================================================================== */

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	min-height: 44px;          /* 44px = ngưỡng vùng chạm tối thiểu */
	padding: 12px 24px;
	font-family: var(--font-body);
	font-size: 15px;
	font-weight: var(--fw-semi);
	line-height: 1.2;
	text-align: center;
	text-decoration: none;
	white-space: nowrap;
	border: var(--border-w) solid transparent;
	border-radius: var(--radius-md);
	cursor: pointer;
	transition: var(--transition);
}

/* Vòng focus dùng chung cho MỌI thứ bấm được. Cam gốc ở đây là hợp lệ: nó
   là viền, không có chữ trắng đè lên. */
.btn:focus-visible,
.form-field:focus-visible,
.pagination__item:focus-visible,
.filter-chips__item:focus-visible,
.card:focus-visible {
	outline: 2px solid var(--c-accent);
	outline-offset: 2px;
}

/*
 * ⚠️ Chỉ NHẤC khi có chuột thật — R-06-layout F-03.
 *
 * `:hover` trên màn cảm ứng không tự hết: chạm xong, nút ở lại trạng thái nhấc
 * lên cho tới khi người dùng chạm chỗ khác. Đo trên iPhone 13: còn nguyên sau
 * 3 giây và sau khi cuộn 500px. Đổi MÀU thì dính cũng không ai đọc nhầm; đổi
 * HÌNH DẠNG thì người dùng đọc thành "cái này đang được chọn".
 *
 * Nền/màu chữ của từng biến thể `.btn--*` cố ý để NGOÀI media query này.
 */
@media (hover: hover) and (pointer: fine) {

	.btn:hover {
		transform: translateY(-1px);
	}
}

.btn:active {
	transform: none;
}

.btn:disabled,
.btn.is-disabled {
	opacity: 0.5;
	cursor: not-allowed;
	transform: none;
}

.btn--primary {
	color: var(--c-text-invert);
	background: var(--c-primary);
}

.btn--primary:hover {
	background: var(--c-primary-800);
}

/* CTA mạnh nhất. `--c-accent-strong`, KHÔNG phải `--c-accent` — xem ghi chú
   tương phản ở đầu file. */
.btn--accent {
	color: var(--c-text-invert);
	background: var(--c-accent-strong);
}

.btn--accent:hover {
	background: var(--c-accent-hover);
}

.btn--secondary {
	color: var(--c-primary);
	background: transparent;
	border-color: var(--c-primary);
}

.btn--secondary:hover {
	color: var(--c-text-invert);
	background: var(--c-primary);
}

.btn--ghost {
	color: var(--c-primary);
	background: transparent;
}

.btn--ghost:hover {
	background: var(--c-primary-50);
}

/* Đặt trên nền navy — đảo màu để vẫn đủ tương phản. */
.btn--on-dark {
	color: var(--c-primary);
	background: var(--c-bg);
}

.btn--on-dark:hover {
	background: var(--c-primary-50);
}

/*
 * Nút phụ trên nền tối — NỀN TRONG SUỐT, viền trắng.
 *
 * Wireframe `home` §3 dòng 130 ghi nút thứ hai của banner là "(secondary viền
 * trắng)". Bản cũ dùng `.btn--on-dark` (nền trắng đặc) nên hai nút nặng ngang
 * nhau, mất phân cấp CTA chính/phụ.
 *
 * ⚠️ Đây là class MỚI chứ không sửa `.btn--on-dark`: biến thể nền trắng đặc
 *    vẫn cần cho khối khác (nút trên dải CTA). Sửa tại chỗ là đổi luôn mọi nơi
 *    đang dùng mà không ai rà lại.
 */
.btn--outline-light {
	color: var(--c-text-invert);
	background: transparent;
	border-color: var(--c-text-invert);
	border-width: 2px;
}

.btn--outline-light:hover,
.btn--outline-light:focus-visible {
	color: var(--c-primary);
	background: var(--c-bg);
}

.btn--lg {
	min-height: 52px;
	padding: 16px 32px;
	font-size: 16px;
}

.btn--sm {
	min-height: 36px;
	padding: 8px 16px;
	font-size: 14px;
}

.btn__icon {
	transition: var(--transition);
}

/* Cùng lý do F-03 với `.btn:hover` — mũi tên trượt rồi đứng luôn ở vị trí mới
   sau khi chạm, trông như nút bị hỏng. */
@media (hover: hover) and (pointer: fine) {

	.btn:hover .btn__icon {
		transform: translateX(2px);
	}
}

/* =========================================================================
   2. FORM  (T-219.1) — design-system §5.3
   ====================================================================== */

.form-row {
	margin-bottom: var(--sp-5);
}

.form-label {
	display: block;
	margin-bottom: 6px;
	font-size: var(--fs-sm);
	font-weight: var(--fw-medium);
	color: var(--c-text);
}

.form-label__required {
	color: var(--c-error);
}

.form-field {
	display: block;
	width: 100%;
	min-height: 44px;
	padding: 10px 14px;
	font-family: var(--font-body);
	font-size: var(--fs-body);
	color: var(--c-text);
	background: var(--c-bg);
	border: var(--border-w) solid var(--c-border);
	border-radius: var(--radius-md);
}

.form-field::placeholder {
	color: var(--c-text-muted);
}

/* `:focus` chứ không chỉ `:focus-visible`: ô nhập cần thấy rõ vùng đang gõ
   kể cả khi bấm chuột. */
.form-field:focus {
	border-color: var(--c-primary);
	box-shadow: 0 0 0 3px var(--c-primary-50);
	outline: none;
}

.form-field[aria-invalid="true"],
.form-field.is-error {
	border-color: var(--c-error);
}

.form-field:disabled {
	color: var(--c-text-muted);
	background: var(--c-bg-alt);
	cursor: not-allowed;
}

textarea.form-field {
	min-height: 120px;
	resize: vertical;
}

.form-error {
	display: block;
	margin-top: 4px;
	font-size: 13px;
	color: var(--c-error);
}

/* =========================================================================
   3. ALERT  (T-219.1) — design-system §5.4
   Nền NHẠT + chữ đậm màu trạng thái, không nền đặc + chữ trắng — tránh lặp
   lại đúng lỗi tương phản của màu cam.
   ====================================================================== */

.alert {
	display: flex;
	gap: 12px;
	padding: 12px 16px;
	font-size: var(--fs-sm);
	line-height: var(--lh-body);
	border-left: 4px solid var(--c-info);
	border-radius: var(--radius-sm);
	background: var(--c-primary-50);
	color: var(--c-heading);
}

.alert--success {
	border-left-color: var(--c-success);
}

.alert--warning {
	border-left-color: var(--c-warning);
}

.alert--error {
	border-left-color: var(--c-error);
}

.alert__icon {
	flex: 0 0 auto;
}

/* =========================================================================
   4. BADGE & TAG  (T-219.1)
   ====================================================================== */

/* Badge số thứ tự card dịch vụ — cam GỐC, và ở đây chữ là màu đậm chứ
   không phải trắng (chữ đen trên cam gốc đạt 7,28:1). */
.badge-num {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 36px;
	height: 36px;
	padding: 0 8px;
	font-family: var(--font-heading);
	font-size: var(--fs-sm);
	font-weight: var(--fw-bold);
	color: var(--c-heading);
	background: var(--c-accent);
	border-radius: var(--radius-sm);
}

.tag {
	display: inline-flex;
	align-items: center;
	padding: 4px 10px;
	font-size: var(--fs-xs);
	color: var(--c-primary);
	background: var(--c-primary-50);
	border-radius: var(--radius-full);
}

/*
 * Biến thể nhỏ — tag đứng LẪN trong một dòng chữ khác (dòng meta của trang chi
 * tiết sản phẩm) chứ không đứng riêng một dòng. Pill giữ nguyên để người dùng
 * còn nhận ra đây là link tới danh mục, chỉ hạ cỡ xuống cho khỏi lấn át chữ
 * quanh nó.
 *
 * ⚠️ Vùng chạm 44px KHÔNG lấy bằng cách phóng to nền pill — làm vậy là tái
 *    phạm F-13 theo hướng ngược lại. Nó do `page/product.css` nới bằng padding
 *    dọc trong suốt ở đúng ngữ cảnh dòng meta.
 */
.tag--sm {
	padding: 2px 8px;
	font-size: 11px;
	line-height: 18px;
}

/* =========================================================================
   5. CARD  (T-219.2) — design-system §5.2
   Dùng cho mọi card ở template-parts/card/ (C-15 · T-214).
   ====================================================================== */

/*
 * D-009 · card phải cao BẰNG NHAU trong cùng một hàng lưới.
 *
 * `height: 100%` là vế còn thiếu của DoD T-214 *(“card thiếu ảnh cao bằng card
 * có ảnh — lưới không vỡ”)*. Thiếu nó thì mỗi card chỉ cao bằng nội dung của
 * chính nó, và hàng lưới so le ngay khi tiêu đề dài ngắn khác nhau.
 *
 * Vì sao tới giờ mới lộ: bộ seed cũ đặt tên "Dịch vụ mẫu 1…6" — dài đúng bằng
 * nhau nên mọi tiêu đề xuống dòng giống hệt nhau và lưới luôn phẳng. Đổi sang
 * tên thật của ngành M&E ("Cấp thoát nước" cạnh "Hệ thống điện nhẹ - Camera,
 * Internet") là lỗi hiện ra ngay ở tablet và mobile — đúng chỗ tiêu đề bắt đầu
 * ngắt dòng khác nhau. Case kiểm đã có sẵn từ T-214 và vẫn xanh suốt, chỉ vì
 * dữ liệu mẫu quá đều để chạm tới nó.
 */
.card {
	display: flex;
	flex-direction: column;
	height: 100%;
	overflow: hidden;
	color: inherit;
	text-decoration: none;
	background: var(--c-bg);
	border: var(--border-w) solid var(--c-border);
	border-radius: var(--radius-md);
	transition: var(--transition);
}

/*
 * NGÔN NGỮ HOVER DÙNG CHUNG cho mọi "thẻ bấm được" — R-06-layout F-07.
 *
 * Trước đây có BA định nghĩa khác nhau cho cùng một loại phần tử (thẻ `<a>` bọc
 * cả khối, dẫn tới một trang chi tiết, nằm trong lưới):
 *
 *   `.card`               nhấc 2px + bóng + viền đậm
 *   `.fields__item`       đổi màu viền + bóng, KHÔNG nhấc
 *   `.about-fields__card` bóng + viền, KHÔNG nhấc
 *
 * Bố cục khác nhau là đúng spec; *phản hồi tương tác* khác nhau thì không có
 * lý do gì. Người cuộn hết trang gặp lưới thẻ nhấc lên rồi tới lưới thẻ không
 * nhấc, không có quy luật để đoán.
 *
 * Nay MỘT quy tắc. Phần tử không phải `.card` chỉ cần thêm class `card-hover`
 * bên cạnh class bố cục riêng của nó — không phải kế thừa cả bộ `.card`.
 *
 * ⚠️ `@media (hover: hover) and (pointer: fine)` là bắt buộc, không phải tô
 *    điểm — R-06-layout F-03. Không có nó thì trên điện thoại, thẻ vừa CHẠM ở
 *    lại trạng thái nhấc-lên + đổ-bóng suốt phần còn lại của phiên cuộn (đo
 *    được: còn nguyên sau 3s và sau khi cuộn 500px), và người dùng đọc đó là
 *    "thẻ này đang được chọn" — một trạng thái không có thật.
 *
 * ⚠️ Thẻ nằm trong Swiper phải có chỗ thở dọc, nếu không `overflow: hidden`
 *    xén mất phần nhấc lên và bóng — xem `.fields__list--slider` ở
 *    `page/home.css` và `.partners__track` cùng file.
 */
@media (hover: hover) and (pointer: fine) {

	.card:hover,
	.card-hover:hover {
		border-color: var(--c-border-strong);
		box-shadow: var(--shadow-md);
		transform: translateY(-2px);
	}
}

/*
 * Bàn phím thì KHÔNG bọc trong media query trên: `:focus-visible` không bao giờ
 * "dính" như hover sau khi chạm, và người dùng bàn phím trên máy cảm ứng vẫn
 * cần thấy thẻ nào đang được chọn. Vòng focus dùng chung ở §0 vẫn chạy song song.
 */
.card:focus-visible,
.card-hover:focus-visible {
	border-color: var(--c-border-strong);
	box-shadow: var(--shadow-md);
}

.card__media {
	position: relative;
	overflow: hidden;
	background: var(--c-bg-alt);
}

/* ⚠️ `aspect-ratio` + `object-fit` là thứ giữ lưới không xô khi ảnh có tỉ lệ
   khác nhau. Ảnh mặc định (T-202) cũng đi qua đây nên card thiếu ảnh cao
   BẰNG card có ảnh — đó là vế thị giác của DoD "không vỡ lưới" ở T-214. */
.card__thumb {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: var(--ar-card);
	object-fit: cover;
}

.card--product .card__media--square .card__thumb {
	aspect-ratio: 1 / 1;
	object-fit: contain;   /* thiết bị chụp nền trắng — cắt sẽ mất phần đầu */
	background: var(--c-bg);
}

.card--post-featured .card__thumb {
	aspect-ratio: var(--ar-hero);
}

.card__num {
	position: absolute;
	top: 12px;
	left: 12px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 36px;
	height: 36px;
	font-family: var(--font-heading);
	font-weight: var(--fw-bold);
	color: var(--c-heading);
	background: var(--c-accent);
	border-radius: var(--radius-sm);
}

.card__badge {
	position: absolute;
	top: 12px;
	left: 12px;
	padding: 4px 10px;
	font-size: var(--fs-xs);
	color: var(--c-text-invert);
	background: var(--c-primary);
	border-radius: var(--radius-full);
}

.card__body {
	display: flex;
	flex-direction: column;
	gap: 8px;
	flex: 1 1 auto;   /* đẩy link xuống đáy để mọi card cao bằng nhau */
	padding: var(--card-padding);
}

/* Tiêu đề và mô tả cắt đúng 2 dòng — không cắt thì tiêu đề dài đẩy card cao
   hơn hẳn và lưới trông gãy. */
.card__title {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	margin: 0;
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: var(--fw-semi);
	line-height: var(--lh-heading);
	color: var(--c-heading);
}

.card__desc,
.card__spec {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	margin: 0;
	font-size: var(--fs-sm);
	line-height: var(--lh-body);
	color: var(--c-text-muted);
}

.card__tags {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
}

.card__tag {
	display: inline-flex;
	/* ⚠️ `.card__body` là flex-column, mà mặc định `align-items: stretch` —
	   pill sẽ bị kéo giãn hết chiều ngang card và trông như một thanh nền,
	   không như nhãn. Chỉ soi ảnh chụp mới thấy. Trong `.card__tags` thì cha
	   là flex-row nên không bị, đây là ca tag đứng một mình (card tuyển
	   dụng). */
	align-self: flex-start;
	padding: 4px 10px;
	font-size: var(--fs-xs);
	color: var(--c-primary);
	background: var(--c-primary-50);
	border-radius: var(--radius-full);
}

.card__meta {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	margin: 0;
	font-size: var(--fs-sm);
	color: var(--c-text-muted);
}

/*
 * Biến thể meta của card DỰ ÁN (layout 2026-09-15): icon ghim/lịch navy 16px,
 * hai mục cách nhau gap cố định (không space-between), địa điểm cắt 1 dòng.
 * Ở ĐÂY chứ không ở `page/project.css` vì `card/project.php` còn chạy ở slider
 * trang chủ — để ở file trang thì trang chủ không nhận, địa điểm dài gãy dòng.
 */
.card__meta--project {
	flex-wrap: nowrap;
	gap: var(--sp-8);
	margin-top: auto;   /* đẩy meta xuống đáy card */
	font-size: var(--fs-sm);
}

.card__meta--project .card__meta-item {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	flex: 1 1 auto;   /* địa điểm (mục đầu) là mục được co và cắt "…" */
	min-width: 0;
}

/* Năm không bao giờ co — đo trang chủ 2026-09-15: "2025" thành "2." khi địa điểm dài. */
.card__meta--project .card__meta-item:last-child {
	flex: 0 0 auto;
}

.card__meta--project .card__meta-icon {
	flex: 0 0 auto;
	color: var(--c-primary);
}

/* Địa điểm dài (3 tỉnh) cắt 1 dòng có "…" — PW-P45. */
.card__meta--project .card__meta-text {
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
}

.card__facts {
	display: flex;
	flex-direction: column;
	gap: 4px;
	/* Giữ chiều cao tối thiểu để vị trí thiếu lương không tụt so với vị trí
	   có đủ — PW-J25 của spec archive-job. */
	min-height: 4.5em;
	margin: 0;
	padding: 0;
	font-size: var(--fs-sm);
	color: var(--c-text-muted);
	list-style: none;
}

.card__deadline {
	align-self: flex-start;
	padding: 4px 10px;
	font-size: var(--fs-xs);
	font-weight: var(--fw-medium);
	border-radius: var(--radius-full);
	background: var(--c-primary-50);
	color: var(--c-primary);
}

.card__deadline--warning {
	background: #FFF4E5;
	color: #8A4B00;   /* chữ đậm trên nền nhạt — nền cam đặc sẽ trượt AA */
}

.card__deadline--urgent,
.card__deadline--expired {
	background: #FDECEC;
	color: #A11212;
}

.card__link {
	margin-top: auto;
	font-size: var(--fs-sm);
	font-weight: var(--fw-semi);
	color: var(--c-primary);
}

.card:hover .card__link {
	text-decoration: underline;
}

/* Lưới card dùng chung — auto-fill để hàng cuối không kéo giãn. */
.card-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
	gap: var(--block-gap);
}

/* =========================================================================
   6. BẢNG THÔNG TIN  (T-219.2) — cho potaco_info_table() (C-10)
   ====================================================================== */

.info-table {
	margin: 0;
}

.info-table__row {
	display: grid;
	grid-template-columns: 1fr;
	gap: 2px;
	padding: 10px 0;
	border-bottom: var(--border-w) solid var(--c-border);
}

@media (min-width: 768px) {
	.info-table__row {
		grid-template-columns: 180px 1fr;
		gap: var(--sp-5);
	}
}

.info-table__label {
	font-weight: var(--fw-medium);
	color: var(--c-text-muted);
}

.info-table__value {
	margin: 0;
	color: var(--c-text);
}

/*
 * ---- Biến thể `striped`  (2026-09-09) ----
 *
 * Bảng thông số kỹ thuật sản phẩm: sọc xen kẽ, dòng sát nhau, cột giá trị đậm
 * hơn cột nhãn. Mặc định GIỮ NGUYÊN cho bảng thông tin dự án (5 dòng cố định,
 * sọc ở đó chỉ làm rối).
 *
 * ⚠️ Sọc phải bám `:nth-child(odd)` của `.info-table__row`, KHÔNG phải của
 *    `<dt>`/`<dd>` — một "dòng" ở đây là `<div>` bọc cả cặp. Đánh dấu nhầm cấp
 *    sẽ ra sọc dọc theo cột thay vì sọc ngang theo dòng.
 */

.info-table--striped .info-table__row {
	padding: 8px 12px;
	/* Đường kẻ dưới thay bằng sọc — giữ cả hai thì bảng 25 dòng rối mắt. */
	border-bottom: 0;
}

.info-table--striped .info-table__row:nth-child(odd) {
	background: var(--c-bg-alt);
}

.info-table--striped .info-table__label {
	font-weight: var(--fw-regular);
}

/* Giá trị đậm hơn nhãn — mắt bắt được cột cần đọc trước. */
.info-table--striped .info-table__value {
	color: var(--c-heading);
	font-weight: var(--fw-semi);
}

@media (min-width: 768px) {
	/*
	 * Nhãn hẹp hơn mặc định (180px → 220px là hướng ngược lại): giá trị bắt
	 * đầu sớm hơn, đúng ảnh layout. 160px vẫn đủ cho nhãn dài nhất của bản
	 * seed ("Tiêu chuẩn áp dụng").
	 */
	.info-table--striped .info-table__row {
		grid-template-columns: 160px 1fr;
		gap: var(--sp-4);
	}
}

/* =========================================================================
   7. PAGINATION  (T-219.2) — design-system §5.4
   ====================================================================== */

.pagination {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	justify-content: center;
	margin: var(--section-gap) 0 0;
}

.pagination__item {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	font-size: var(--fs-sm);
	color: var(--c-text);
	text-decoration: none;
	background: var(--c-bg);
	border: var(--border-w) solid var(--c-border);
	border-radius: var(--radius-md);
}

.pagination__item:hover {
	border-color: var(--c-primary);
}

.pagination__item.is-current,
.pagination .current {
	color: var(--c-text-invert);
	background: var(--c-primary);
	border-color: var(--c-primary);
}

.pagination__item.is-disabled {
	color: var(--c-text-muted);
	pointer-events: none;
}

/*
 * Markup của `paginate_links()` — `a.page-numbers` / `span.current` / `.dots`.
 *
 * Chuyển từ `page/product.css` về đây 2026-09-11 (T-303): trang Dịch vụ dùng
 * cùng hàm WordPress mà ra số trang trần vì luật chỉ nạp ở trang Sản phẩm —
 * dạng lỗi 2 của R-06-product ("CSS nạp sai chỗ"). Mọi archive về sau
 * (Dự án, Tin tức, Tuyển dụng) tự hưởng. `.pagination__item` bên trên là
 * biến thể dựng tay, giữ nguyên.
 */
.pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 40px;
	height: 40px;
	padding: 0 10px;
	border: var(--border-w) solid var(--c-border);
	border-radius: var(--radius-md);
	background: var(--c-bg);
	color: var(--c-text);
	font-size: var(--fs-sm);
	font-weight: var(--fw-semi);
	text-decoration: none;
	transition: var(--transition);
}

.pagination .page-numbers.current {
	border-color: var(--c-primary);
	background: var(--c-primary);
	color: var(--c-text-invert);
}

.pagination .page-numbers.dots {
	border-color: transparent;
	background: none;
}

@media (hover: hover) {
	/* Hover chỉ trong `@media (hover: hover)`: trên thiết bị chạm, trạng thái
	   hover DÍNH LẠI sau khi bấm — đúng lỗi F-03 của trang chủ. */
	.pagination a.page-numbers:hover {
		border-color: var(--c-border-strong);
		background: var(--c-primary-50);
	}
}

.pagination .page-numbers:focus-visible {
	outline: 2px solid var(--c-accent);
	outline-offset: 2px;
}

/* =========================================================================
   8. BREADCRUMB  (T-219.2) — design-system §5.4
   ====================================================================== */

/*
 * ⚠️ `.breadcrumb` là thẻ `<nav>`, danh sách thật là `<ol class="breadcrumb__list">`
 *    bên trong (xem `potaco_breadcrumb()`).
 *
 *    Bản đầu đổ toàn bộ `display: flex` + `list-style: none` lên `<nav>`, nên
 *    `<ol>` giữ nguyên mặc định: khối dọc, có số thứ tự. Breadcrumb hiện ra
 *    thành "1. Trang chủ" / "2. Giới thiệu" xếp hai dòng.
 *
 *    Không ai thấy suốt bước 06 vì trang chủ KHÔNG có breadcrumb — trang Giới
 *    thiệu là màn đầu tiên gọi hàm này. Phát hiện lúc soi ảnh T-302.1.
 */
.breadcrumb {
	padding: var(--sp-5) 0;
	font-size: var(--fs-sm);
	color: var(--c-text-muted);
}

.breadcrumb__list {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 6px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.breadcrumb__item {
	display: flex;
	align-items: center;
	gap: 6px;
}

.breadcrumb a {
	color: inherit;
	text-decoration: none;
}

.breadcrumb a:hover {
	text-decoration: underline;
}

.breadcrumb__sep {
	color: var(--c-border-strong);
}

/* Mục cuối KHÔNG phải link và đậm màu hơn — design-system §5.4. */
.breadcrumb__current {
	color: var(--c-text);
}

/* --- Biến thể NỀN TỐI: breadcrumb nằm trong banner đầu trang ---------------
 *
 * ⚠️ Không phải "tô lại cho đẹp": màu mặc định là `--c-text-muted` (xám nhạt,
 *    dựng cho nền trắng). Đặt nguyên trên nền navy `--c-primary-800` thì tương
 *    phản rơi xuống dưới ngưỡng WCAG AA — chữ vẫn hiện, nhưng đọc không ra.
 *
 * Cấp hiện tại để TRẮNG ĐẶC, các cấp link mờ hơn — giữ đúng thứ bậc thị giác
 * của bản nền sáng (design-system §5.4), chỉ đảo nền.
 */
.breadcrumb--on-dark {
	padding: 0;
	color: rgb(255 255 255 / 76%);
}

.breadcrumb--on-dark a:hover,
.breadcrumb--on-dark .breadcrumb__current {
	color: var(--c-text-invert);
}

.breadcrumb--on-dark .breadcrumb__sep {
	color: rgb(255 255 255 / 50%);
}

/* =========================================================================
   8b. BANNER ĐẦU TRANG DÙNG CHUNG  (page hero · phản hồi khách 2026-09-08)
   ====================================================================== */

/*
 * Markup ở `template-parts/layout/page-hero.php`, gọi qua `potaco_page_hero()`.
 *
 * ⚠️ CSS nằm ở `components.css` chứ KHÔNG ở `page/about.css`, vì file kia chỉ
 *    nạp trên đúng một trang (`potaco_enqueue_about()`). Khối này dùng chung
 *    cho mọi trang nên phải ở file nạp vô điều kiện — để nhầm chỗ thì trang thứ
 *    hai gọi hàm sẽ ra một dải không style, và không lỗi nào hiện ra.
 *
 * Thay cho `.about-hero` cũ (T-302.3.4); khối đó đã gỡ khỏi `about.css`.
 */
.page-hero {
	position: relative;
	display: flex;
	align-items: flex-end;   /* nội dung dồn xuống ĐÁY: breadcrumb sát mép dưới */
	min-height: 260px;
	padding: var(--sp-12) 0 var(--sp-5);
	overflow: hidden;
	background-color: var(--c-primary-800);
	color: var(--c-text-invert);
}

/*
 * Không có ảnh nền ⇒ dải navy đặc, CÙNG chiều cao với bản có ảnh.
 *
 * Bản cũ cho `--solid` `min-height: 0` "vì không giữ chỗ cho tấm ảnh không tồn
 * tại" — hệ quả đo 2026-09-18: Liên hệ 186 · FAQ 130 · Tuyển dụng 258 trong khi
 * trang có ảnh 260, banner nhấp nhô theo số dòng mô tả. CR C-02b v2 chốt MỘT
 * chiều cao mọi biến thể; `--solid` giờ chỉ khác ở chỗ không có `<img>`, và
 * chỉ còn xảy ra khi khách cố ý để trống cả "Ảnh banner mặc định" (option
 * `page_hero_image` — nơi mọi trang không có ảnh riêng ngã về).
 */
.page-hero--solid {
	background-image: linear-gradient(90deg, var(--c-primary-800) 0%, var(--c-primary) 100%);
}

.page-hero__bg {
	position: absolute;
	inset: 0;
	z-index: var(--z-base);
}

.page-hero__img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * Lớp phủ tối — cùng lý do với hero trang chủ: ảnh do khách chọn nên không thể
 * trông cậy vào việc nó đủ tối cho chữ trắng. Hai lớp tách vai: đen lo độ tối
 * (giữ chi tiết ảnh), navy mỏng lo tông thương hiệu.
 *
 * Thêm một nấc tối ở ĐÁY so với bản `.about-hero` cũ: breadcrumb giờ nằm dưới
 * cùng, chữ nhỏ hơn tiêu đề nhiều nên cần nền chắc hơn ở đúng dải đó.
 */
.page-hero__bg::after {
	content: "";
	position: absolute;
	inset: 0;
	background:
		linear-gradient(0deg, rgb(0 0 0 / 45%) 0%, rgb(0 0 0 / 0%) 45%),
		linear-gradient(90deg, rgb(0 0 0 / 58%) 0%, rgb(0 0 0 / 34%) 60%, rgb(0 0 0 / 16%) 100%),
		linear-gradient(90deg, rgb(0 30 90 / 42%) 0%, rgb(0 30 90 / 20%) 65%, rgb(0 30 90 / 8%) 100%);
	pointer-events: none;
}

/* `width: 100%` bắt buộc: `.page-hero` là flex container nên `__inner` là flex
   ITEM và mặc định co lại vừa nội dung — thiếu dòng này thì `margin-inline: auto`
   của `.container` đẩy tiêu đề ra GIỮA màn hình. Đúng lỗi đã gặp ở hero trang chủ. */
.page-hero__inner {
	position: relative;
	z-index: var(--z-dropdown);
	width: 100%;
}

.page-hero__title {
	margin: 0;
	font-size: var(--fs-h2);
	line-height: var(--lh-tight);
	color: var(--c-text-invert);
}

.page-hero__desc {
	margin: var(--sp-2) 0 0;
	max-width: 60ch;
	font-size: var(--fs-body);
	color: var(--c-text-invert);
	opacity: 0.92;
}

.page-hero__crumb {
	margin-top: var(--sp-6);
}

/*
 * ---- Hai khối mở rộng của banner (2026-09-15, nhánh Dự án) ----
 *
 * `eyebrow` (tag loại công trình) · `meta` (ghim địa điểm · lịch năm). Ảnh
 * layout Dự án vẽ chúng BÊN TRONG nền navy của banner, nên CSS ở đây — cùng lý
 * do với phần còn lại của §8b: banner là khối dùng chung, để trong
 * `page/project.css` là trang khác gọi tham số sẽ ra dải không style. Trang
 * không truyền tham số thì markup không in, không có gì để đo.
 *
 * ⚠️ `.page-hero__stats*` (3 số liệu Dự án) · `.page-hero__usps*` (3 lý do
 *    Tuyển dụng) · `.page-hero--light` (Tin tức: nền xám, chữ giữa) đã GỠ
 *    2026-09-18 (CR C-02b v2 — bỏ strength item trong banner, một chiều cao,
 *    canh trái toàn site). Đừng thêm lại vào đây; số liệu có `block/stats-band`.
 */
.page-hero__eyebrow {
	display: inline-flex;
	align-items: center;
	align-self: flex-start;
	margin-bottom: var(--sp-3);
	padding: 5px 12px;
	font-size: var(--fs-xs);
	font-weight: var(--fw-medium);
	letter-spacing: var(--ls-caps);
	text-transform: uppercase;
	color: var(--c-text-invert);
	background: rgb(255 255 255 / 16%);
	border: var(--border-w) solid rgb(255 255 255 / 30%);
	border-radius: var(--radius-full);
}

.page-hero__meta {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-2) var(--sp-4);
	margin: var(--sp-3) 0 0;
	padding: 0;
	list-style: none;
	font-size: var(--fs-sm);
	color: var(--c-text-invert);
}

.page-hero__meta-item {
	display: inline-flex;
	align-items: center;
	gap: var(--sp-2);
}

.page-hero__meta-icon {
	flex: 0 0 auto;
	color: var(--c-text-invert);
}

@media (max-width: 767px) {

	.page-hero__meta {
		flex-direction: column;
	}
}

/*
 * Banner phải BÁM MÉP TRÊN, sát chân header.
 *
 * `.site-main` có `padding-top: var(--sp-12)` (layout.css). Template nào mở đầu
 * bằng banner thì phải bỏ khoảng đệm đó — làm bằng `:has()` để template mới
 * KHÔNG phải nhớ thêm class nào; quên class là lỗi im lặng (banner tụt xuống,
 * nhìn vẫn "chạy được").
 *
 * Trình duyệt không hỗ trợ `:has()` chỉ thừa một khoảng trắng phía trên banner,
 * không vỡ layout. `page-gioi-thieu.php` vẫn giữ `.site-main--about` riêng —
 * trùng kết quả, không xung đột.
 */
.site-main:has(> .page-hero:first-child) {
	padding-top: 0;
}

/*
 * KHOẢNG CÁCH BANNER → NỘI DUNG: đúng `--hero-gap` (40px), MỌI trang, MỌI khổ.
 *
 * CR 2026-09-11: đo ra ba trang ba con số — Sản phẩm 96px (48 của `.site-main`
 * + 48 của `.product-layout`), Giới thiệu 32px tới sidebar nhưng 72px tới tiêu
 * đề §01, trang tĩnh 72px. Mỗi template tự đệm một kiểu nên không có "chuẩn"
 * nào để so. Nay chốt MỘT luật, và luật đó nằm ở đây chứ không ở `page/*.css`:
 *
 *   1. Banner TỰ mang khoảng cách bằng `margin-bottom`. Chỉ một nơi sinh ra
 *      con số, đổi token là đổi cả site.
 *   2. Phần tử đứng NGAY SAU banner bị ép `padding-top: 0; margin-top: 0`, dù
 *      banner nằm trong `<main>` (page.php, Giới thiệu) hay đứng trước `<main>`
 *      (nhánh Sản phẩm). Nhờ vậy template mới không phải nhớ gì: đệm riêng của
 *      nó bị vô hiệu ở đúng cạnh chạm banner, các cạnh khác giữ nguyên.
 *
 * ⚠️ Hệ quả cho template: khối đầu tiên dưới banner KHÔNG được trông cậy vào
 *    `padding-top` của chính nó (bị xoá). Muốn thêm khoảng thở bên trong thì
 *    đệm ở phần tử CON, hoặc dùng `gap`. Ví dụ Giới thiệu: `.about` không đệm
 *    trên, `.about-section:first-child` cũng không — cả sidebar lẫn tiêu đề §01
 *    cùng bắt đầu ở đúng 40px dưới banner.
 *
 * ⚠️ Độ đặc hiệu cố ý ở mức (0,2,0)–(0,3,0) để thắng mọi `.khoi { padding }`
 *    (0,1,0) trong `page/*.css` bất kể thứ tự nạp. `.container` (layout.css)
 *    khai `padding: 0 var(--gutter)` dạng rút gọn, nạp SAU file này — bộ chọn
 *    một cấp `.page-body` trơn từng thua nó im lặng, nên mọi luật ở đây đều có
 *    ít nhất một cấp cha.
 */
.page-hero {
	margin-bottom: var(--hero-gap);
}

/* Banner đứng TRƯỚC `<main>` (archive-product, single-product). */
.page-hero + .site-main {
	padding-top: 0;
}

.page-hero + .site-main > :first-child,
.site-main > .page-hero + * {
	padding-top: 0;
	margin-top: 0;
}

/* Thân trang tĩnh (page.php). Đệm trên đã do banner lo — chỉ còn đệm dưới. */
.site-main > .page-body {
	padding-block: 0 var(--sp-12);
}

@media (max-width: 767px) {

	/*
	 * 240 chứ không 180 (C-02b v2, đo 390px 2026-09-18): với 180 thì trang mô
	 * tả 1 dòng ra 180, 2 dòng 187, 3 dòng 232 — banner nhấp nhô theo độ dài
	 * chữ khách nhập. 240 nuốt được tiêu đề 2 dòng + mô tả 3 dòng; chỉ trang
	 * chi tiết có thêm eyebrow + meta mới vượt (Dự án chi tiết 265).
	 */
	.page-hero {
		min-height: 240px;
		padding: var(--sp-8) 0 var(--sp-4);
	}

	.page-hero__crumb {
		margin-top: var(--sp-4);
	}
}

/* =========================================================================
   8c. DẢI BREADCRUMB ĐỨNG RIÊNG — trang KHÔNG có banner  (T-605.3)
   ====================================================================== */

/*
 * Dời từ `page/news.css` (T-502) khi trang Cảm ơn thành trang thứ hai dùng
 * — ≥2 trang ⇒ common (CLAUDE.md §5). Dùng khi template mở đầu bằng
 * breadcrumb thay vì `potaco_page_hero()`: chi tiết tin, Cảm ơn.
 *
 * ⚠️ KHÔNG `display: flex` ở dải này: `potaco_breadcrumb()` in `nav >
 *    .container > ol`; nav làm flex item sẽ co theo bề rộng CHỮ (shrink-to-fit)
 *    và tiêu đề bài dài đẩy trang tràn ngang 27px ở 375 (probe-viewport, 3
 *    lượt đo ở T-502). Dải là block thường, cao 48 ra từ padding + dòng chữ.
 *
 * Phần riêng của bài viết (mục cuối = tiêu đề dài, xuống hàng + clamp ở SP)
 * vẫn ở `news.css`, scope `.single-post`.
 */
.breadcrumb-bar {
	min-height: 48px;
	background: var(--c-bg-alt);
	box-sizing: border-box;
}

.breadcrumb-bar .breadcrumb {
	margin: 0;
	padding: 13px 0;   /* 13 + 21 + 13 ≈ 48 (đo 48) */
}

/* Đệm thêm 12px ở SP KHÔNG nằm ở đây: đó là luật cho breadcrumb HAI DÒNG của
   bài viết (tiêu đề dài rơi xuống hàng hai) — ở `news.css`, scope `.single-post`.
   Bar một dòng (Cảm ơn) giữ 48px mọi khổ; đo 2026-09-18 ra 69,5 khi đệm kép. */
@media (max-width: 767px) {
	.breadcrumb-bar .breadcrumb__list {
		flex-wrap: wrap;
	}
}

/* =========================================================================
   9. SECTION HEADER · FILTER CHIP · ACCORDION · EMPTY STATE  (T-219.2)
   ====================================================================== */

.section-header {
	margin-bottom: var(--block-gap);
	text-align: center;   /* chốt MỘT kiểu, không đổi giữa các trang */
}

.section-header__title {
	margin: 0;
	font-family: var(--font-heading);
	font-size: var(--fs-h2);
	color: var(--c-heading);
}

/*
 * Gạch nhấn cam 48×3 — cam gốc hợp lệ vì là đường kẻ, không có chữ đè.
 *
 * ⚠️ ĐÂY LÀ NGUỒN DUY NHẤT của gạch nhấn, dùng cho CẢ HAI kiểu tiêu đề:
 *   • `.section-header__title` — tiêu đề khối dải ngang, canh giữa (trang chủ)
 *   • `.single-block__title`   — tiêu đề section trong trang chi tiết, canh trái
 *
 * Design system §5.4 bắt buộc gạch cam ở MỌI tiêu đề section. Trước
 * 2026-09-09 chỉ kiểu thứ nhất có, nên trên cùng một trang chi tiết sản phẩm
 * dải "ĐỐI TÁC CUNG CẤP" có gạch còn "THÔNG SỐ KỸ THUẬT" thì không. Gộp về
 * một khai báo để lần sau đổi kích thước/màu không phải sửa hai nơi.
 *
 * Chỉ khác nhau ở lề: canh giữa dùng `auto`, canh trái dùng `0`.
 */
.section-header__title::after,
.single-block__title::after {
	content: "";
	display: block;
	width: 48px;
	height: 3px;
	margin-top: 12px;
	background: var(--c-accent);
}

.section-header__title::after {
	margin-right: auto;
	margin-left: auto;
}

.single-block__title::after {
	margin-right: auto;
	margin-left: 0;
}

.section-header__desc {
	max-width: 60ch;
	margin: 12px auto 0;
	color: var(--c-text-muted);
}

/*
 * Cụm chữ được tô màu nhấn bên trong tiêu đề section (vd "Ba Tốt").
 *
 * Đặt ở đây chứ không ở `page/home.css` để mọi tiêu đề section khác dùng lại
 * được. Cam gốc `--c-accent` hợp lệ ở đây vì là chữ trên nền trắng — đo được
 * 4,6:1, khác hẳn trường hợp chữ trắng trên nền cam đã bị cấm ở thẻ "Ba Tốt".
 */
.section-header__accent {
	color: var(--c-accent);
}

/*
 * Nút "Xem tất cả" đặt cuối khối, canh giữa.
 *
 * CR 2026-09-02: link ở góc phải hàng tiêu đề (`.section-header--split`) được
 * thay bằng nút nằm dưới cùng. Ba khối dùng chung mẫu này (Lĩnh vực · Dự án ·
 * Tin tức) nên class ở lớp component, không nhân bản ba lần trong `home.css`.
 */
.section-action {
	margin-top: var(--sp-8);
	text-align: center;
}

/*
 * TIÊU ĐỀ KHỐI "thanh cam trái" — layout Dự án 2026-09-15 (spec single-project
 * 3-logic §0.2). Khác `.section-header__title` (gạch cam DƯỚI, canh giữa) ở chỗ
 * thanh 4×20 đứng BÊN TRÁI, chữ 18/700 navy hoa — dùng cho tiêu đề của thẻ và
 * khối trong trang chi tiết (Thông tin dự án · Dịch vụ đã thực hiện · Mô tả ·
 * Dự án khác). Năm chỗ trên một màn và trang chi tiết sản phẩm có thể dùng
 * lại, nên khai một lần ở đây thay vì năm lần trong `page/project.css`.
 *
 * Biến thể `--split`: hàng tiêu đề có link "Xem tất cả →" bên phải.
 */
.block-title {
	display: flex;
	align-items: center;
	gap: 10px;
	margin: 0 0 var(--sp-5);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: var(--fw-bold);
	line-height: var(--lh-heading);
	text-transform: uppercase;
	color: var(--c-heading);
}

.block-title::before {
	content: "";
	flex: 0 0 auto;
	width: 4px;
	height: 20px;
	background: var(--c-accent);
	border-radius: 2px;
}

.block-title--split {
	justify-content: space-between;
}

/* Tiêu đề chiếm phần còn lại; link "Xem tất cả" dồn sang phải. */
.block-title--split .block-title__text {
	flex: 1 1 auto;
}

.block-title__link {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	min-height: 44px;   /* vùng chạm — F-13 cả-dự-án */
	font-size: var(--fs-sm);
	font-weight: var(--fw-semi);
	text-transform: none;
	color: var(--c-primary);
	text-decoration: none;
}

@media (hover: hover) and (pointer: fine) {

	.block-title__link:hover {
		color: var(--c-accent-strong);
	}
}

/* =========================================================================
   VIDEO TẢI MUỘN  (C-03) — khung poster + nút play
 *
 * ⚠️ Component này TỪNG không có một dòng CSS nào, dù `potaco_lazy_video()`
 *    vẫn in ra ba class. Hệ quả: nút play là `<button>` mặc định của trình
 *    duyệt, nằm SAU ảnh trong luồng nên rơi xuống dưới, lệch trái; còn khung
 *    thì không cao bằng cột chữ bên cạnh nên hai cột so le.
 *
 * ⚠️ Đặt ở `components.css` chứ không `page/home.css`: khối bản đồ trang Liên
 *    hệ dùng chung cơ chế này.
   ====================================================================== */

.lazy-video {
	position: relative;
	display: block;
	flex: 1 1 auto;
	width: 100%;
	/* Cột 1 hàng (SP) không có chiều cao xác định → tỉ lệ giữ khung.
	   Khi nằm trong lưới 2 cột, `height: 100%` bên dưới thắng và khung cao
	   bằng cột chữ — đây là vế sửa "hai cột lệch chiều cao". */
	aspect-ratio: 16 / 9;
	overflow: hidden;
	background: var(--c-primary-900, var(--c-primary-800));
}

.lazy-video__poster {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.lazy-video__play {
	position: absolute;
	top: 50%;
	left: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 72px;
	height: 72px;
	padding: 0 0 0 4px;   /* tam giác ▶ lệch tâm quang học, bù lại 4px */
	font-size: 26px;
	color: var(--c-primary);
	background: var(--c-bg);
	border: 0;
	border-radius: var(--radius-full);
	box-shadow: var(--shadow-md);
	transform: translate(-50%, -50%);
	cursor: pointer;
	transition: var(--transition);
}

/*
 * Đổi MÀU thì áp cho mọi thiết bị; PHÓNG TO thì chỉ khi có chuột thật (F-03).
 *
 * ⚠️ `translate(-50%, -50%)` phải lặp lại trong mỗi khai báo `transform` —
 *    đây là thứ căn giữa nút play, bỏ đi là nút nhảy xuống góc phần tư.
 */
.lazy-video__play:hover,
.lazy-video__play:focus-visible {
	color: var(--c-bg);
	background: var(--c-accent-strong);
}

@media (hover: hover) and (pointer: fine) {

	.lazy-video__play:hover {
		transform: translate(-50%, -50%) scale(1.06);
	}
}

.lazy-video__play:focus-visible {
	transform: translate(-50%, -50%) scale(1.06);
}

.lazy-video__play:focus-visible {
	outline: 2px solid var(--c-accent);
	outline-offset: 3px;
}

/* Iframe do JS chèn vào đúng khung này khi bấm play. */
.lazy-video iframe {
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
}

/*
 * Bản đồ tải muộn — `potaco_lazy_map()` (C-03), dùng ở footer + trang Liên hệ
 * (T-602, spec contact GĐ-02). Khung giữ chỗ cao CỐ ĐỊNH (`--map-h`, nơi dùng
 * đặt lại) để iframe chèn vào không đẩy trang xuống (CLS 0). Trước T-602 khối
 * này không có CSS nào — nút nằm trần trên nền trang.
 */
.lazy-map {
	--map-h: 280px;

	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	height: var(--map-h);
	overflow: hidden;
	background: var(--c-bg-alt);
	border: var(--border-w) solid var(--c-border);
	border-radius: var(--radius-lg);
}

.lazy-map__open {
	gap: 8px;
}

.lazy-map iframe {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
}

/* Không phải Google Maps → chỉ là một link thường, không khung. */
.lazy-map--link {
	display: block;
	height: auto;
	padding: 0;
	background: none;
	border: 0;
}

.filter-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

.filter-chips__item {
	display: inline-flex;
	align-items: center;
	min-height: 36px;
	padding: 8px 20px;
	font-size: var(--fs-sm);
	color: var(--c-text);
	text-decoration: none;
	background: var(--c-bg-alt);
	border-radius: var(--radius-full);
	transition: var(--transition);
}

/*
 * Hover chip — R-06-archive-project F-01 (2026-09-16): trước đó chip là phần tử
 * bấm được DUY NHẤT trên trang không có trạng thái hover. Trong media query để
 * chạm trên điện thoại không dính (F-03 product).
 */
@media (hover: hover) and (pointer: fine) {

	.filter-chips__item:hover {
		color: var(--c-primary);
		background: var(--c-primary-50);
	}
}

.filter-chips__item.is-active {
	color: var(--c-text-invert);
	background: var(--c-primary);
}

/* Term chưa có bài — làm mờ chứ KHÔNG ẩn, để hàng chip không đổi độ dài mỗi
   lần khách thêm bài (spec archive-service §2). */
.filter-chips__item.is-empty {
	opacity: 0.55;
}

.accordion__item {
	border-bottom: var(--border-w) solid var(--c-border);
}

.accordion__summary {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	padding: 16px 0;
	font-weight: var(--fw-semi);
	color: var(--c-heading);
	cursor: pointer;
	list-style: none;
}

.accordion__summary::-webkit-details-marker {
	display: none;
}

.accordion__summary::after {
	content: "+";
	font-size: 20px;
	color: var(--c-accent-strong);
}

.accordion__item[open] .accordion__summary::after {
	content: "×";
}

.accordion__body {
	padding-bottom: 16px;
	color: var(--c-text);
	line-height: var(--lh-body);
}

/* Component BẮT BUỘC dùng chung — phục vụ target Q-10. */
.empty-state {
	padding: var(--sp-12) var(--gutter);
	text-align: center;
}

.empty-state__icon {
	color: var(--c-border-strong);
}

.empty-state__title {
	margin: var(--sp-1) 0 8px;
	font-family: var(--font-heading);
	font-size: var(--fs-h3);
	color: var(--c-heading);
}

.empty-state__desc {
	margin: 0 0 var(--sp-5);
	color: var(--c-text-muted);
}

/* =========================================================================
   10. SIDEBAR  (T-216)
   ====================================================================== */

.sidebar {
	display: flex;
	flex-direction: column;
	gap: var(--block-gap);
}

/*
 * ⚠️ SIDEBAR KHÔNG DÍNH, KHÔNG GIỚI HẠN CHIỀU CAO — chốt 2026-09-19.
 *
 * DoD T-216 từng là "dính khi cuộn, không che footer": `sticky` + `max-height:
 * calc(100vh − header)` + `overflow-y: auto`. Cả BA sidebar dùng luật này đều
 * dính đúng một bug — cột cao hơn khung nhìn thì phần đáy bị xén, sinh thanh
 * cuộn trong (ăn 15px ngang), và `overflow-y: auto` ép thêm thanh cuộn ngang:
 *   · Sản phẩm 2026-09-09 (1920×1080 có admin bar) → ghi đè `static` ở product.css
 *   · Dịch vụ  2026-09-11 (cột 4 khối)               → ghi đè `static` ở service.css
 *   · Tin tức  2026-09-19 (end-user testing: "sidebar có scroll, bị cắt, che khuất")
 * Ba lần cùng một lỗi, hai bản ghi đè chép tay ⇒ đổi ở gốc: sidebar tĩnh, cao
 * theo nội dung; hai bản ghi đè kia đã xoá. `align-self: start` giữ lại để cột
 * không bị grid kéo dài bằng cột nội dung (nền thẻ trắng không trải xuống đáy).
 * Đánh đổi có ý thức: lệch spec "sticky" (home-news E-N05, product ui-spec
 * §6.1, service ui-spec §10) — chọn "thấy đủ" thay vì "dính".
 */
@media (min-width: 992px) {
	.sidebar,
	.sidebar-block--sticky {
		position: static;
		align-self: start;
	}
}

.sidebar-block {
	padding: var(--card-padding);
	background: var(--c-bg);
	border: var(--border-w) solid var(--c-border);
	border-radius: var(--radius-md);
}

.sidebar-block__title {
	margin: 0 0 var(--sp-1);
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	color: var(--c-heading);
}

.sidebar-block__title a {
	color: inherit;
	text-decoration: none;
}

.sidebar-block__list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.sidebar-block__item > a {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 8px;
	padding: 8px 0;
	color: var(--c-text);
	text-decoration: none;
	border-bottom: var(--border-w) solid var(--c-border);
}

.sidebar-block__item > a:hover {
	color: var(--c-primary);
}

.sidebar-block__item.is-active > a {
	font-weight: var(--fw-semi);
	color: var(--c-primary);
}

.sidebar-block__count {
	flex: 0 0 auto;
	min-width: 24px;
	padding: 2px 6px;
	font-size: var(--fs-xs);
	text-align: center;
	color: var(--c-text-muted);
	background: var(--c-bg-alt);
	border-radius: var(--radius-full);
}

.sidebar-block__date {
	display: block;
	font-size: var(--fs-xs);
	color: var(--c-text-muted);
}

/* ---- Danh mục ở sidebar — C-17 v2 `sidebar/cat-nav` (T-216.3) ----
 *
 * MỘT bộ da cho mọi khối "danh mục" ở cột bên: Sản phẩm (2 tầng + count),
 * Dịch vụ (icon), Tin tức (count), FAQ, Giới thiệu con. Chuyển nguyên từ
 * `.product-cats*` (page/product.css, mẫu khách chốt 2026-09-18) — Sản phẩm
 * trước/sau phải giống nhau từng pixel. Ba bộ CSS cũ (`.product-cats`,
 * `.service-cats`, override `.sidebar-block--cats` ở news.css) đã xoá.
 *
 * ⚠️ Ở đây chứ không ở `page/*.css`: khối có mặt trên ≥6 trang + drawer, để
 *    trong file trang thì trang thứ hai ra danh sách trần (bài học `.partners`).
 */

.cat-nav {
	border: var(--border-w) solid var(--c-border);
	border-radius: var(--radius-md);
	background: var(--c-bg);
}

.cat-nav__title {
	margin: 0;
	padding: 14px 16px;
	border-radius: calc(var(--radius-md) - 1px) calc(var(--radius-md) - 1px) 0 0;
	background: var(--c-primary);
	color: var(--c-text-invert);
	font-size: var(--fs-sm);
	font-weight: var(--fw-bold);
	letter-spacing: var(--ls-caps);
	text-transform: uppercase;
}

.cat-nav__title-link {
	color: inherit;
	text-decoration: none;
}

.cat-nav__list,
.cat-nav__children {
	margin: 0;
	padding: 0;
	list-style: none;
}

/*
 * ⚠️ CỐ Ý KHÔNG đặt `max-height` + `overflow-y: auto` cho danh sách này —
 *    bug "sidebar bị cắt ở 1920×1080" (2026-09-09): cap sẽ bật ngay ở cấu hình
 *    người vận hành và cái họ thấy vẫn là danh sách đứt ngang. Danh sách cao
 *    theo nội dung; hộp bọc `.sidebar` đã lo cuộn khi vượt khung nhìn.
 */

.cat-nav__item + .cat-nav__item {
	border-top: var(--border-w) solid var(--c-border);
}

/* Mục cuối bo hai góc dưới theo viền ngoài — bo trên chính `<a>` vì nó là
   thứ có nền khi hover/đang chọn. */
.cat-nav__item:last-child > .cat-nav__row .cat-nav__link,
.cat-nav__item:last-child > .cat-nav__link {
	border-radius: 0 0 calc(var(--radius-md) - 1px) calc(var(--radius-md) - 1px);
}

/* `flex-start`, KHÔNG `space-between` (CR 2026-09-11): số đếm nằm NGAY SAU tên,
   không bị đẩy ra mép phải nơi nó xa cái tên nó đếm và đụng vùng chevron. */
.cat-nav__link {
	display: flex;
	gap: 8px;
	align-items: center;
	justify-content: flex-start;
	min-height: 44px; /* vùng chạm tối thiểu */
	padding: 10px 16px;
	color: var(--c-text);
	font-size: var(--fs-sm);
	text-decoration: none;
	transition: var(--transition);
}

.cat-nav__link.is-current {
	border-left: 3px solid var(--c-accent);
	padding-left: 13px;
	background: var(--c-primary-50);
	color: var(--c-primary);
	font-weight: var(--fw-semi);
}

/* Icon tuỳ chọn — chỉ Dịch vụ truyền (layout 2026-09-09). Không truyền thì
   markup không in, không chừa chỗ. */
.cat-nav__icon {
	flex: 0 0 auto;
	display: inline-flex;
	width: 20px;
	height: 20px;
	color: var(--c-primary-700, var(--c-primary));
}

.cat-nav__icon svg,
.cat-nav__img {
	width: 20px;
	height: 20px;
	object-fit: contain;
}

.cat-nav__name {
	min-width: 0;
}

.cat-nav__count {
	flex: 0 0 auto;
	color: var(--c-text-muted);
	font-size: var(--fs-xs);
}

@media (hover: hover) {
	.cat-nav__link:hover {
		background: var(--c-bg-alt);
		color: var(--c-primary);
	}
}

.cat-nav__link:focus-visible {
	outline: 2px solid var(--c-accent);
	outline-offset: -2px;
}

/* --- Nhánh con (Sản phẩm 2 tầng) --------------------------------------
 *
 * `<summary>` buộc là con đầu của `<details>` nên nằm SAU hàng link; kéo lên
 * cùng hàng bằng `absolute` — chevron là nút độc lập (mở/đóng), tên danh mục
 * vẫn là link riêng (sang trang danh mục). */

.cat-nav__item.has-children {
	position: relative;
}

.cat-nav__item.has-children > .cat-nav__row .cat-nav__link {
	padding-right: 52px; /* chừa chỗ cho chevron, chữ dài không chui xuống dưới nó */
}

.cat-nav__sub {
	border-top: 0;
}

/*
 * ⚠️ Khai TƯỜNG MINH cả căn chỉnh lẫn lề phải ở đây (CR 2026-09-11 — "mũi tên
 *    lệch phải, bị che" ba lần): hộp chạm 44×44, chevron lùi 20px khỏi viền.
 *    `box-sizing: border-box` bắt buộc — theme không có reset phủ tới đây,
 *    thiếu nó hộp phình 64px và nuốt vùng bấm của tên danh mục.
 */
.cat-nav__toggle {
	position: absolute;
	top: 0;
	right: 0;
	box-sizing: border-box;
	display: flex;
	align-items: center;
	justify-content: flex-end;
	width: 44px;
	height: 44px;
	padding: 0 20px 0 0;
	cursor: pointer;
	list-style: none;
}

.cat-nav__toggle::-webkit-details-marker {
	display: none;
}

/* Chevron tự vẽ bằng CSS — không thêm một bộ icon thứ hai cho một mũi tên. */
.cat-nav__toggle::after {
	width: 8px;
	height: 8px;
	border-right: 2px solid var(--c-text-muted);
	border-bottom: 2px solid var(--c-text-muted);
	content: '';
	transform: rotate(45deg) translateY(-2px);
	transition: var(--transition);
}

.cat-nav__sub[open] > .cat-nav__toggle::after {
	transform: rotate(-135deg) translateY(-2px);
}

.cat-nav__toggle:focus-visible {
	outline: 2px solid var(--c-accent);
	outline-offset: -2px;
}

.cat-nav__sub[open] > .cat-nav__children {
	border-top: var(--border-w) solid var(--c-border);
}

.cat-nav__children {
	background: var(--c-bg-alt);
}

.cat-nav__link--child {
	padding-left: 32px;
	font-size: var(--fs-xs);
}

/* Vạch dẫn cho biết đây là nhánh con, không phải danh mục ngang hàng. */
.cat-nav__link--child::before {
	position: absolute;
	margin-left: -14px;
	color: var(--c-border-strong);
	content: '–';
}

.cat-nav__link--child.is-current {
	padding-left: 29px;
}

/* ---- Mục lục (C-08) ---- */

/*
 * ⚠️ Biến thể `--sticky` là bản Ở CỘT BÊN, và nó mới là cái mang hình THẺ TRẮNG
 *    có bóng theo layout `gioi-thieu-v2-20260904.png`. Mục lục nhúng giữa bài
 *    (không có class này) vẫn để trần — không bọc thẻ.
 *
 * ⚠️ `.toc--sticky` TỪNG không có một dòng CSS nào. Cùng họ lỗi với
 *    `.stats-band--about` và `.breadcrumb__sep`: class được in ra từ T-207 mà
 *    chưa ai viết quy tắc cho nó, nên cột mục lục nằm TRẦN trên nền trắng,
 *    không có gì tách nó khỏi nội dung. Phản hồi khách 2026-09-08 ý #2.
 *
 * ⚠️ Tên class hứa `position: sticky` nhưng ở đây CỐ Ý chưa khai — đó là hành vi
 *    cuộn, không phải hình thức, và không nằm trong phạm vi phản hồi này.
 */
.toc--sticky {
	padding: var(--sp-5) 0;
	background: var(--c-bg);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-md);
}

.toc__title {
	margin: 0 0 8px;
	font-family: var(--font-heading);
	font-weight: var(--fw-bold);
	color: var(--c-heading);
}

/* Tiêu đề thụt vào bằng lề trong của thẻ; HÀNG MỤC thì không — hàng đang xem
   phải chạy hết chiều ngang thẻ mới ra được dải nền như layout. */
.toc--sticky .toc__title {
	margin-bottom: var(--sp-2);
	padding-inline: var(--card-padding);
	font-size: var(--fs-sm);
	letter-spacing: var(--ls-caps);
	text-transform: uppercase;
}

.toc__list {
	margin: 0;
	padding: 0;
	list-style: none;
	counter-reset: toc;
}

.toc__link {
	display: block;
	padding: 6px 0;
	font-size: var(--fs-sm);
	color: var(--c-text);
	text-decoration: none;
}

/* ⚠️ Viền trái LUÔN tồn tại, chỉ đổi MÀU khi active — không đổi độ rộng viền.
   Mục lục có scrollspy nên `.is-current` nhảy liên tục khi cuộn; thêm/bớt 3px
   viền là cả cột chữ giật ngang mỗi lần cuộn qua một section. Cùng lý do đã
   chọn `text-decoration` thay `font-weight` cho hover (R-06-gioi-thieu F-01). */
.toc--sticky .toc__link {
	padding: 10px var(--card-padding);
	color: var(--c-heading);
	border-left: 3px solid transparent;
}

.toc__item--l3 .toc__link {
	padding-left: 16px;
	font-size: var(--fs-xs);
}

/*
 * ⚠️ TRẠNG THÁI ĐANG XEM và HOVER phải khác nhau — R-06-gioi-thieu F-01.
 *
 * Bản cũ gộp `:hover` và `.is-current` vào CÙNG một khai báo, nên rê chuột vào
 * mục đang xem thì **không thuộc tính nào đổi** (đo được 0/9).
 *
 * ⚠️ Gạch chân áp cho MỌI mục, kể cả mục đang xem. Nếu hover chỉ đổi nền thì
 *    mục đang xem — vốn đã có nền cam nhạt — lại rơi về đúng lỗi F-01 lần nữa.
 *    Nền xám của hover chỉ dành cho mục KHÔNG phải mục đang xem.
 */
.toc__link:hover,
.toc__link:focus-visible {
	color: var(--c-primary);
	text-decoration: underline;
	text-underline-offset: 3px;
}

.toc--sticky .toc__link:hover:not(.is-current),
.toc--sticky .toc__link:focus-visible:not(.is-current) {
	background: var(--c-bg-alt);
}

/*
 * Mục đang xem: nền cam nhạt + chữ cam + thanh cam bên trái (layout v2).
 *
 * ⚠️ KHÔNG dùng đúng mã cam của layout. Layout tô chữ `#FC6C06` trên nền
 *    `#FFF1E6` — đo được **2,60:1**, trượt AA khá xa. `--c-accent-strong`
 *    `#BF4E05` cũng chỉ **4,41:1**, vẫn dưới ngưỡng 4,5. Dùng
 *    `--c-accent-hover` `#A34204` — **5,68:1**, mắt vẫn đọc ra là cam.
 *    Cùng cách chuẩn hoá mà design-system §1.4 đã áp cho nút cam.
 *
 * ⚠️ Thanh cam bên trái để nguyên `--c-accent` dù nó chỉ 2,88:1 so với nền thẻ:
 *    nó là dấu hiệu THỪA, trạng thái đã được nói bằng cả màu chữ lẫn màu nền.
 *    WCAG 1.4.11 miễn cho chỉ báo trang trí không phải nguồn thông tin duy nhất.
 *
 * ⚠️ Khối này phải đứng SAU khối hover — hai bên cùng độ đặc hiệu (0,2,0), nên
 *    thứ tự là thứ quyết định. Đảo lên trên thì rê chuột vào mục đang xem sẽ
 *    làm chữ cam biến thành navy.
 */
.toc__link.is-current {
	color: var(--c-accent-hover);
	background: var(--c-accent-50);
}

.toc--sticky .toc__link.is-current {
	border-left-color: var(--c-accent);
}

/* ⚠️ Số thứ tự chỉ đổi màu Ở BẢN THẺ. Layout v2 vẽ số navy cho mục thường, cam
   cho mục đang xem — ngược với bản cũ tô cam TẤT CẢ. Giới hạn trong
   `.toc--sticky` để không đụng mục lục nhúng giữa bài của màn khác. */
.toc__num {
	font-weight: var(--fw-bold);
	color: var(--c-accent-strong);
}

.toc--sticky .toc__num {
	color: var(--c-heading);
}

/* `inherit` chứ không gán lại mã cam: số phải đi theo đúng màu của hàng, kể cả
   khi màu hàng đổi sau này. */
.toc--sticky .toc__link.is-current .toc__num {
	color: inherit;
}

/* ---- Ô tìm (C-19) ---- */

.search-box {
	display: flex;
	gap: 8px;
}

.search-box__field {
	flex: 1 1 auto;
	min-width: 0;   /* cho phép input co lại trong flex — thiếu dòng này thì
	                   ô tìm đẩy nút Tìm ra ngoài mép ở khổ hẹp */
}

.search-box--hero {
	max-width: 640px;
	margin: 0 auto;
}

/*
 * ---- Biến thể `icon`: kính lúp NẰM TRONG ô  (2026-09-09) ----
 *
 * Archive sản phẩm vẽ ô tìm không có nút chữ. Làm bằng biến thể chứ không đổi
 * mặc định: `sidebar/news.php` vẫn cần nút chữ "Tìm".
 *
 * ⚠️ `position: relative` đặt trên `<form>`, nút `absolute` neo vào đó. Vùng
 *    chạm giữ 44×44 đúng ngưỡng AA dù icon chỉ 20px, nên ô phải chừa
 *    `padding-right` đủ 44px + 4px thở, nếu không chữ người dùng gõ chui xuống
 *    dưới nút.
 */
.search-box--icon {
	position: relative;
	display: block;
}

.search-box--icon .search-box__field {
	width: 100%;
	padding-right: 48px;
}

.search-box__submit--icon {
	position: absolute;
	top: 50%;
	right: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	color: var(--c-text-muted);
	background: none;
	border: 0;
	border-radius: var(--radius-md);
	transform: translateY(-50%);
	cursor: pointer;
}

.search-box__submit--icon svg {
	width: 20px;
	height: 20px;
}

@media (hover: hover) {
	.search-box__submit--icon:hover {
		color: var(--c-primary);
	}
}

.search-box__submit--icon:focus-visible {
	outline: 2px solid var(--c-accent);
	outline-offset: -2px;
}

/* ---- Dropdown sắp xếp (C-19) ----
 *
 * ⚠️ Component `ui/sort-select` ra đời ở T-218 nhưng KHÔNG có dòng CSS nào cho
 *    tới 2026-09-09 — archive sản phẩm là màn đầu tiên dùng nó, nên tới lúc đó
 *    lỗi mới lộ: `<select>` hiện ra trần theo mặc định trình duyệt, nhãn "Sắp
 *    xếp" rơi ra ngoài đứng cạnh. Thiết kế vẽ MỘT control có viền, bo góc, chữ
 *    "Sắp xếp: Mới nhất" nằm gọn bên trong.
 *
 * Cách dựng: `<form>` đóng vai control (viền + bo + nền), `<label>` và
 * `<select>` nằm trong, `<select>` bỏ hết trang trí mặc định
 * (`appearance: none`) và chevron do `::after` của form tự vẽ.
 */

.sort-select {
	position: relative;
	display: inline-flex;
	align-items: center;
	gap: 4px;
	min-height: 44px;
	padding: 0 34px 0 14px;
	background: var(--c-bg);
	border: var(--border-w) solid var(--c-border);
	border-radius: var(--radius-md);
}

/* Nhãn nằm TRONG control, đọc liền mạch "Sắp xếp: Mới nhất". */
.sort-select__label {
	color: var(--c-text-muted);
	font-size: var(--fs-sm);
	white-space: nowrap;
}

.sort-select__label::after {
	content: ":";
}

.sort-select__control {
	/* `appearance: none` bỏ mũi tên và nền gradient mặc định của hệ điều hành —
	   thiếu dòng này thì trên Windows control có hai mũi tên chồng nhau. */
	appearance: none;
	max-width: 100%;
	padding: 0;
	color: var(--c-text);
	font-family: inherit;
	font-size: var(--fs-sm);
	font-weight: var(--fw-semi);
	background: none;
	border: 0;
	cursor: pointer;
}

/* Chevron tự vẽ — hình vuông xoay 45°, chỉ giữ hai cạnh dưới. */
.sort-select::after {
	content: "";
	position: absolute;
	top: 50%;
	right: 14px;
	width: 7px;
	height: 7px;
	border-right: 2px solid var(--c-text-muted);
	border-bottom: 2px solid var(--c-text-muted);
	transform: translateY(-70%) rotate(45deg);
	pointer-events: none;
}

/*
 * Viền sáng lên khi con trỏ nằm TRONG control — bám `:focus-within` chứ không
 * `:focus` vì phần nhận focus là `<select>` bên trong, còn viền vẽ ở `<form>`.
 */
.sort-select:focus-within {
	border-color: var(--c-primary);
	outline: 2px solid var(--c-accent);
	outline-offset: 2px;
}

.sort-select__control:focus-visible {
	outline: none;   /* viền đã vẽ ở lớp ngoài, hai viền lồng nhau là thừa */
}

/* Nút dự phòng khi tắt JS — `<noscript>` nên chỉ hiện đúng lúc cần. */
.sort-select__submit {
	min-height: 44px;
	padding: 0 12px;
	color: var(--c-primary);
	font-size: var(--fs-sm);
	background: none;
	border: 0;
	cursor: pointer;
}

/* ---- Khối liên hệ cuối trang (C-26) ---- */

.contact-box {
	padding: var(--card-padding);
	text-align: center;
	background: var(--c-primary-50);
	border-radius: var(--radius-md);
}

.contact-box__label {
	margin: 0 0 var(--sp-1);
	color: var(--c-heading);
}

.contact-box__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	justify-content: center;
}

/* =========================================================================
   11. KHỐI TRANG CHI TIẾT  (T-217)
   ====================================================================== */

.single-block {
	margin-bottom: var(--section-gap);
}

/*
 * Tiêu đề section trong trang chi tiết — canh trái, nhỏ hơn tiêu đề khối dải
 * ngang một bậc.
 *
 * ⚠️ Gạch nhấn cam KHÔNG khai ở đây mà ở §9 cùng chỗ với
 *    `.section-header__title::after` — một khai báo cho cả hai kiểu tiêu đề.
 */
.single-block__title {
	margin: 0 0 var(--sp-5);
	font-family: var(--font-heading);
	font-size: var(--fs-h3);
	color: var(--c-heading);
}

/* ---- Lưới thư viện ảnh (C-09) ---- */

.lightbox-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
	gap: 12px;
}

.lightbox-grid__item {
	display: block;
	padding: 0;
	overflow: hidden;
	background: none;
	border: 0;
	border-radius: var(--radius-md);
	cursor: pointer;
}

.lightbox-grid__img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: var(--ar-card);
	object-fit: cover;
	transition: var(--transition);
}

/* F-03: ảnh phóng to rồi đứng luôn ở 1,04 sau khi chạm — trên lưới ảnh thì
   người xem đọc thành "ảnh này đang mở", trong khi lightbox chưa hề mở. */
@media (hover: hover) and (pointer: fine) {

	.lightbox-grid__item:hover .lightbox-grid__img {
		transform: scale(1.04);
	}
}

.lightbox {
	width: min(1100px, 94vw);
	max-width: none;
	padding: 0;
	background: transparent;
	border: 0;
}

.lightbox::backdrop {
	background: rgb(0 0 0 / 80%);
}

.lightbox__bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--sp-1);
	color: var(--c-text-invert);
}

.lightbox__close,
.lightbox__nav {
	width: 44px;
	height: 44px;
	font-size: 24px;
	color: var(--c-text-invert);
	background: rgb(255 255 255 / 15%);
	border: 0;
	border-radius: var(--radius-full);
	cursor: pointer;
}

.lightbox__figure {
	margin: 0;
}

.lightbox__img {
	display: block;
	width: 100%;
	height: auto;
	max-height: 78vh;
	object-fit: contain;
}

.lightbox__caption {
	padding-top: 8px;
	color: var(--c-text-invert);
	text-align: center;
}

/* ---- Danh sách tài liệu (C-10) ---- */

.doc-list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.doc-list__item {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--sp-1);
	padding: 12px 0;
	border-bottom: var(--border-w) solid var(--c-border);
}

.doc-list__name {
	flex: 1 1 200px;
	font-weight: var(--fw-medium);
	color: var(--c-heading);
}

.doc-list__meta {
	font-size: var(--fs-sm);
	color: var(--c-text-muted);
}

/* ---- Chia sẻ ---- */

.share {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px;
}

.share__label {
	color: var(--c-text-muted);
}

.share__btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 36px;
	height: 36px;
	padding: 0 12px;
	font-size: var(--fs-sm);
	font-weight: var(--fw-semi);
	color: var(--c-primary);
	text-decoration: none;
	background: var(--c-primary-50);
	border: 0;
	border-radius: var(--radius-full);
	cursor: pointer;
}

.share__btn:hover {
	color: var(--c-text-invert);
	background: var(--c-primary);
}

/* ---- Bài trước / sau ---- */

.prev-next {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--sp-1);
	margin-top: var(--section-gap);
}

@media (min-width: 768px) {
	.prev-next {
		grid-template-columns: 1fr 1fr;
	}
}

.prev-next__link {
	display: block;
	padding: var(--card-padding);
	color: inherit;
	text-decoration: none;
	border: var(--border-w) solid var(--c-border);
	border-radius: var(--radius-md);
}

.prev-next__link:hover {
	border-color: var(--c-primary);
}

/* Nút "sau" đứng một mình thì đẩy sang phải để hướng đọc vẫn đúng. */
.prev-next__link--next {
	grid-column: -2;
	text-align: right;
}

.prev-next__label {
	display: block;
	font-size: var(--fs-xs);
	color: var(--c-text-muted);
}

.prev-next__title {
	display: block;
	font-weight: var(--fw-semi);
	color: var(--c-heading);
}

/* =========================================================================
   12. CTA BAND  (C-20 · bổ sung ở T-301.1 — D-005)
   
   `potaco_cta_band()` có từ T-201 và `block/cta-band.php` từ T-215.1, nhưng
   không file CSS nào phủ nó — khối in ra chữ trần sát mép trái, hotline hiện
   thành link xanh gạch chân mặc định của trình duyệt. Lộ ra khi trang chủ gọi
   nó lần đầu (T-301.1).

   Đặt ở đây chứ không ở `page/home.css`: `_common` §1.4 dùng khối này ở hầu
   hết các trang, nhét vào CSS riêng của trang chủ là mọi trang khác vẫn hỏng.
   ====================================================================== */

/*
 * ⚠️ KHÔNG đặt `overflow: hidden` ở đây.
 *
 * Thiết kế cho ảnh kỹ sư **nhô lên khỏi mép trên** dải navy (mũ bảo hộ đè lên
 * khối phía trên). Cắt ở cấp section là cụt luôn phần nhô ra. Việc cắt ảnh nền
 * chìm giao cho `.cta-band__bg` tự lo — nó có `overflow: hidden` riêng.
 */
.cta-band {
	position: relative;
	padding: var(--sp-12) 0;
	background-color: var(--c-primary-800);
	color: var(--c-text-invert);
}

/*
 * KHOẢNG CÁCH NỘI DUNG → DẢI CTA Ở <992: đúng `--cta-gap` (30px), MỌI trang.
 * CR end-user testing 2026-09-19 (ảnh Tuyển dụng ở khổ điện thoại).
 *
 * Đo 2026-09-19 ở 390px: trang chủ 48 · Giới thiệu 48 · Dịch vụ 24 · Dự án /
 * Sản phẩm / Tin tức 32 · Tuyển dụng 0 — mỗi trang một kiểu vì khối đứng trước
 * tự đệm dưới (padding hoặc margin) theo ý riêng, còn Tuyển dụng thì không đệm
 * gì nên thẻ cuối dính sát dải navy.
 *
 * Cùng công thức với `--hero-gap` (§8b): dải CTA tự mang `margin-top`, còn
 * phần tử đứng NGAY TRƯỚC nó bị ép về `padding-bottom: 0; margin-bottom: 0`
 * — đệm dưới của khối trước dù to nhỏ ra sao cũng không cộng vào. Template mới
 * KHÔNG tự đệm dưới cho khối cuối trước dải CTA.
 *
 * Chỉ áp ở <992: từ 992 trở lên dải đã có luật riêng cho ảnh nhân vật nhô 56px
 * (`.cta-band--has-media` bên dưới) và mọi trang đã qua 06b với luật đó.
 *
 * Trình duyệt chưa hiểu `:has()` bỏ qua quy tắc ép — dải vẫn cách 30px cộng
 * thêm đệm cũ của khối trước; xấu hơn chút chứ không vỡ.
 */
@media (max-width: 991px) {

	.cta-band {
		margin-top: var(--cta-gap);
	}

	/* Vế thứ hai: Chi tiết dịch vụ / dự án in 1–2 `<script>` JSON-LD ngay
	   trước dải CTA — `:has(+)` bám vào thẻ script (không có hộp) và khối nội
	   dung thật giữ nguyên đệm dưới. "Con áp chót khi bỏ qua script" không
	   phụ thuộc số script; nó tin CTA là con cuối của `<main>` — luật đã có ở
	   `layout.css` (`.site-main:has(> .cta-band:last-child)`). */
	.site-main > :has(+ .cta-band),
	.site-main > :nth-last-child(2 of :not(script)):has(~ .cta-band) {
		padding-bottom: 0;
		margin-bottom: 0;
	}

	/*
	 * Ngoại lệ dải đối tác: slider bên trong dùng `.swiper--breathe` (margin
	 * âm 16px, §14). Ép `padding-bottom: 0` là margin âm đó gộp xuyên qua mép
	 * section và CỘNG vào margin của dải CTA: 30 − 16 = 14px (đo `/du-an/`,
	 * `/san-pham/`, taxonomy). `flow-root` mở BFC nên margin con bị giữ trong
	 * section — hộp section kết thúc đúng mép logo, khoảng cách ra 30.
	 *
	 * ⚠️ Dùng `display` chứ KHÔNG bù bằng `padding-bottom`: selector áp chót ở
	 *    trên có độ đặc hiệu (0,3,1) cao hơn `.site-main > .partners:has(+)`
	 *    (0,3,0) — cùng thuộc tính thì ngoại lệ thua (đã đo ra 14 lần hai).
	 */
	.site-main > .partners:has(+ .cta-band) {
		display: flow-root;
	}
}

/* --- Ảnh nền chìm (CR 2026-09-02) --------------------------------------- */

.cta-band__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
}

.cta-band__bg-img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Phủ navy đậm: ảnh chỉ là kết cấu chìm, chữ vẫn phải đọc được trên ảnh sáng. */
.cta-band--has-bg .cta-band__bg::after {
	content: "";
	position: absolute;
	inset: 0;
	background: rgb(0 30 90 / 88%);
}

/*
 * ⚠️ Canh lề PHẢI dùng đúng công thức của `.container`.
 *
 * Bản cũ viết `width: min(100% - 2*gutter, var(--container))` — cùng cho ra bề
 * rộng tối đa 1200px, nhưng coi 1200px là bề rộng NỘI DUNG (không có padding),
 * trong khi `.container` coi 1200px là bề rộng HỘP rồi thụt vào 24px bằng
 * padding. Kết quả: nội dung CTA bắt đầu sớm hơn đúng một gutter so với mọi
 * khối khác — nền trải full-width nên không ai thấy hộp lệch, chỉ thấy chữ và
 * nút thò ra bên trái.
 *
 * ⚠️ Dùng `padding-inline`/`margin-inline` riêng, KHÔNG dùng shorthand — đó là
 *    đúng cái bẫy đã làm dải số liệu dính mép trái (`margin: 0` xoá mất
 *    `margin: 0 auto` của `.container`).
 */
.cta-band__inner {
	position: relative;
	z-index: 2;
	display: flex;
	flex-direction: column;
	gap: var(--sp-8);
	max-width: var(--container);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

.cta-band__title {
	margin: 0 0 var(--sp-3);
	font-family: var(--font-heading);
	font-size: var(--fs-h2);
	line-height: var(--lh-tight);
	color: var(--c-text-invert);
}

.cta-band__desc {
	margin: 0;
	max-width: 52em;
	line-height: var(--lh-body);
	opacity: 0.9;
}

.cta-band__actions {
	display: flex;
	flex-direction: column;
	gap: var(--sp-4);
	align-items: flex-start;
	margin-top: var(--sp-6);
}

/*
 * Hotline là một NÚT thật (nền trắng, icon điện thoại), không phải chữ đậm.
 *
 * Bản cũ chỉ tô đậm con số nên nó không đọc ra là thứ bấm được — thiết kế vẽ
 * nó ngang hàng với nút cam bên cạnh. Class `.btn btn--on-dark` lo phần khung;
 * ở đây chỉ chỉnh riêng phần chữ số cho to và dễ đọc.
 */
.cta-band__phone {
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: var(--fw-bold);
	white-space: nowrap;
}

.cta-band__phone-icon {
	color: var(--c-accent-strong);
}

.cta-band__phone:hover .cta-band__phone-icon,
.cta-band__phone:focus-visible .cta-band__phone-icon {
	color: var(--c-primary);
}

/*
 * CTA-06 ghi rõ ảnh kỹ sư **chỉ hiện trên PC**. Trước đây không có quy tắc ẩn
 * nào, nên ảnh vẫn đổ xuống giữa khối trên điện thoại.
 */
.cta-band__media {
	display: none;
}

/*
 * ⚠️ Ảnh NHÂN VẬT tách nền — không phải ảnh trong khung.
 *
 * `object-fit: contain` để không bao giờ bị cắt (ảnh trước đây render ở size
 * `potaco-card` 600×400 crop cứng nên mất đầu; nay lấy `full`).
 * `object-position: bottom` + canh đáy để người đứng chạm mép dưới dải như
 * thiết kế, thay vì trôi lơ lửng giữa khối.
 * Bo góc = 0: ảnh trong suốt không có khung để bo.
 */
.cta-band__media img {
	display: block;
	width: 100%;
	height: 100%;
	max-height: 100%;
	object-fit: contain;
	object-position: bottom center;
	border-radius: 0;
}

/*
 * Nút ở khổ điện thoại: FULL-WIDTH, chữ canh giữa — mọi trang (CR 2026-09-19).
 * Trước đó chỉ trang Dịch vụ có luật này (`page/service.css`), các trang khác
 * nút co theo chữ và dồn về mép trái. Luật riêng đó đã gỡ, gộp về đây.
 * `box-sizing` khai tường minh: theme không có `border-box` toàn cục.
 */
@media (max-width: 767px) {

	.cta-band__actions .btn {
		width: 100%;
		justify-content: center;
		box-sizing: border-box;
	}
}

@media (min-width: 768px) {

	.cta-band__actions {
		flex-direction: row;
		/* Ba nút (hotline + cam + phụ, trang Dịch vụ 2026-09-11) không đủ chỗ ở
		   992–1199 thì xuống dòng, KHÔNG đẩy ảnh nhân vật tràn ra ngoài khung
		   (đo được 63px tràn ngang ở 992). Hai nút vẫn một hàng như cũ. */
		flex-wrap: wrap;
		align-items: center;
		gap: var(--sp-6);
	}
}

@media (min-width: 992px) {

	.cta-band {
		padding: var(--sp-16) 0;
	}

	/* Ảnh nhân vật (tuỳ chọn) đứng cạnh nội dung, không đẩy nút xuống dưới. */
	.cta-band__inner {
		flex-direction: row;
		align-items: stretch;
	}

	.cta-band__content {
		flex: 1 1 auto;
		min-width: 0;   /* cho phép co để hàng nút xuống dòng thay vì đẩy ảnh tràn */
		align-self: center;
	}

	/*
	 * Ảnh người **nhô lên khỏi mép trên** dải và chạm mép dưới — đúng thiết kế.
	 *
	 * `margin-bottom` âm bằng đúng padding dưới của `.cta-band` kéo chân ảnh
	 * xuống sát mép; `margin-top` âm lớn hơn padding trên để đầu và mũ bảo hộ
	 * vượt lên trên, đè nhẹ vào khối phía trên.
	 *
	 * ⚠️ Phần nhô ra chỉ tồn tại khi KHÔNG có `overflow: hidden` ở `.cta-band`
	 *    — xem ghi chú ở đầu khối.
	 */
	.cta-band__media {
		position: relative;
		z-index: 3;
		display: flex;
		flex: 0 0 34%;
		align-items: flex-end;
		align-self: stretch;
		min-height: 300px;
		margin-top: calc(-1 * var(--sp-16) - 56px);
		margin-bottom: calc(-1 * var(--sp-16));
		pointer-events: none;   /* ảnh trang trí, không chắn thao tác khối trên */
	}

	/*
	 * Chặn trên cho chiều cao ảnh: hộp chứa nay cao hơn dải (do hai margin âm),
	 * nếu để ảnh giãn theo hộp thì người sẽ to quá và trèo quá sâu lên khối
	 * trên. 420px là mức nhô ~56px so với mép dải — con số này cần soi mắt
	 * chỉnh lại nếu khách đổi ảnh có tỉ lệ khác.
	 */
	.cta-band__media img {
		max-height: 420px;
		margin-inline: auto;
	}

	/*
	 * KHOẢNG TRỐNG CHO PHẦN NHÔ — bug end-user testing 2026-09-19 (Tuyển dụng).
	 *
	 * Đầu + mũ bảo hộ nhô 56px lên trên mép dải là cố ý, nhưng "đè nhẹ vào khối
	 * phía trên" chỉ đúng khi phía trên là khoảng trắng. Đo 8 trang: Tuyển dụng
	 * (thẻ hết hạn cuối), Chi tiết dịch vụ (thẻ liên quan), Liên hệ (bản đồ) có
	 * nội dung ở đúng vùng ảnh ⇒ bị đè. Dải tự chừa 56 + 16 = 72px ở trên khi
	 * có ảnh — khối đứng trước KHÔNG phải tự đệm (cùng tinh thần `--hero-gap`).
	 * Margin cạnh nhau tự gộp: trang đã có 24/32 dưới khối trước ra đúng 72,
	 * không cộng dồn. Chỉ ở ≥992 vì dưới đó ảnh ẩn (`.cta-band__media` none).
	 */
	.cta-band--has-media {
		margin-top: calc(56px + var(--sp-4));
	}

	/* Dải đối tác đứng trước đã có đệm dưới ~114px trong chính nó — đo ở
	   `/du-an/` và `/san-pham/`: ảnh nằm trọn trong khoảng trắng đó. */
	.partners + .cta-band--has-media {
		margin-top: 0;
	}
}

/* =========================================================================
   13. QUY TRÌNH & HÀNH TRÌNH  (C-20 · bổ sung ở T-301.4)

   Hai khối này KHÔNG chỉ của trang chủ: `process` dùng lại ở `single-service`,
   `timeline` dùng lại ở `gioi-thieu` §04. Đặt ở đây thay vì `page/home.css`
   để trang thứ hai không phải chép lại.
   ====================================================================== */

/* ---- Quy trình làm việc (PR-00…PR-04) ---- */

/*
 * ⚠️ `padding-top` 40px chứ không phải `--section-gap` (80px).
 *
 * Khoảng trắng nhìn thấy giữa hai section = padding-bottom của khối trên +
 * padding-top của khối này = 160px trên PC. Khách yêu cầu rút còn ~40px ở
 * đúng chỗ này.
 *
 * KHÔNG đụng token `--section-gap`: nó chi phối nhịp section của cả 25 màn,
 * sửa ở đó là đổi cả website vì một khối. Khối này còn dùng lại ở
 * `single-service` nên chỉ giảm mép TRÊN, giữ nguyên mép dưới.
 */
.process {
	padding: var(--sp-10) 0 var(--section-gap);
	background-color: var(--c-bg);
}

/*
 * ⚠️ SP là timeline DỌC, PC là timeline NGANG (chốt M2 — layout gốc bỏ hẳn
 *    khối này trên mobile, ở đây giữ lại và đổi trục). Mobile-first nên dọc
 *    là mặc định.
 */
.process__list {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--sp-5);
	margin: 0;
	padding: 0;
	list-style: none;
	counter-reset: potaco-step;
}

.process__step {
	position: relative;
	display: flex;
	align-items: center;
	gap: var(--sp-4);
	min-width: 0;
	padding-left: var(--sp-2);
}

.process__num {
	flex: 0 0 auto;
	display: grid;
	place-items: center;
	width: 48px;
	height: 48px;
	border: 2px solid var(--c-primary);
	border-radius: var(--radius-full);
	font-family: var(--font-heading);
	font-weight: var(--fw-bold);
	color: var(--c-primary);
	background-color: var(--c-bg);
}

.process__title {
	font-weight: var(--fw-semi);
	color: var(--c-heading);
	overflow-wrap: anywhere;
}

@media (min-width: 768px) {

	.process__list {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: var(--sp-8) var(--sp-5);
	}

	.process__step {
		flex-direction: column;
		gap: var(--sp-3);
		padding-left: 0;
		text-align: center;
	}
}

@media (min-width: 1200px) {

	.process__list {
		grid-template-columns: repeat(6, minmax(0, 1fr));
	}

	/*
	 * Đường nối giữa các bước. Vẽ bằng `::before` của từng bước trừ bước đầu,
	 * không dùng một đường kẻ nền chạy suốt — đường kẻ nền sẽ thò ra hai đầu
	 * và cắt ngang qua số thứ tự.
	 */
	.process__step::before {
		content: "";
		position: absolute;
		top: 24px;
		right: 50%;
		left: -50%;
		height: 2px;
		background-color: var(--c-border);
	}

	.process__step:first-child::before {
		content: none;
	}

	.process__num {
		position: relative;
		z-index: var(--z-dropdown);
	}
}

/* ---- Hành trình phát triển (AB-06/07) ---- */

.timeline__list {
	display: grid;
	gap: var(--sp-6);
	margin: 0;
	padding: 0;
	list-style: none;
}

.timeline__item {
	position: relative;
	min-width: 0;
	padding-top: var(--sp-5);
	border-top: 2px solid var(--c-border);
}

.timeline__item::before {
	content: "";
	position: absolute;
	top: -7px;
	left: 0;
	width: 12px;
	height: 12px;
	border-radius: var(--radius-full);
	background-color: var(--c-accent);
}

.timeline__year {
	display: block;
	font-family: var(--font-heading);
	font-size: var(--fs-h3);
	font-weight: var(--fw-bold);
	color: var(--c-primary);
}

.timeline__title {
	display: block;
	margin-top: var(--sp-1);
	font-weight: var(--fw-semi);
	color: var(--c-heading);
}

.timeline__desc {
	margin: var(--sp-1) 0 0;
	font-size: var(--fs-sm);
	color: var(--c-text-muted);
}

/* ---- Biến thể DỌC — chỉ trang Giới thiệu §04 --------------------------- *
 *
 * ⚠️ Bản trước dùng lại y nguyên trang trí của biến thể NGANG cho cột dọc:
 *    mỗi mốc là một khối chiếm hết chiều ngang, gạch `border-top` 2px vắt
 *    ngang phía trên và chấm nằm ở góc trái của gạch đó. Xếp chồng bốn khối
 *    như vậy ra bốn gạch ngang rời — KHÔNG phải một trục thời gian.
 *
 *    Layout v2 vẽ đúng một đường ray DỌC chạy suốt, chấm cam nằm trên ray,
 *    năm và mô tả nằm cùng hàng bên phải ray. Nên `border-top` của mốc bỏ đi
 *    và đường kẻ xoay theo trục.
 *
 * ⚠️ Ray vẽ theo TỪNG ĐOẠN nối hai chấm liên tiếp (`__item::after`, mốc cuối
 *    tắt), KHÔNG phải một vạch chạy suốt `<ol>`. Vạch suốt thì mép dưới của nó
 *    là mép dưới danh sách, mà chấm cuối lại nằm ở ĐẦU mốc cuối — nên ray thò
 *    quá chấm cuối đúng bằng chiều cao mốc đó, và mốc có mô tả 2 dòng thì đoạn
 *    thừa dài hơn cả khoảng cách giữa hai mốc. Đoạn nối thì tự dừng đúng chấm
 *    cuối ở mọi độ dài nội dung.
 *
 * Số đo lấy từ spec frontend §12: ray 2px `--c-border`, chấm 12px `--c-accent`.
 * Ray đặt `left: 5px` để tâm ray (6px) trùng tâm chấm (0 → 12px).
 */
.timeline--vertical .timeline__list {
	gap: var(--sp-5);
}

.timeline--vertical .timeline__item {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	column-gap: var(--sp-4);
	align-items: baseline;
	padding-top: 0;
	padding-left: var(--sp-8);
	border-top: 0;
}

.timeline--vertical .timeline__item::before {
	top: var(--sp-1);
	left: 0;
	/* Chấm đè lên ray, không để ray cắt ngang giữa chấm. */
	z-index: var(--z-base);
}

/* Đoạn ray nối chấm của mốc này xuống chấm của mốc kế: cao bằng chính mốc
   cộng đúng khoảng `gap` của danh sách. */
.timeline--vertical .timeline__item::after {
	content: "";
	position: absolute;
	top: var(--sp-1);
	left: 5px;
	width: 2px;
	height: calc(100% + var(--sp-5));
	background-color: var(--c-border);
}

.timeline--vertical .timeline__item:last-child::after {
	content: none;
}

/* Năm là NHÃN của dòng, không phải tiêu đề khối — hạ về cỡ chữ thường in đậm
   như layout v2, nếu không nó lấn át chính nội dung mốc bên cạnh. */
.timeline--vertical .timeline__year {
	grid-column: 1;
	font-size: var(--fs-body);
}

/* `margin: 0` chứ không chỉ `margin-top` — `<h3>` còn mang margin ĐÁY mặc định
   của theme, cộng với `margin-top` của mô tả thành ~26px chen giữa tiêu đề mốc
   và mô tả của chính nó. Bốn mốc là ~100px chiều cao thừa, trái với spec §12
   "không làm timeline quá cao". */
.timeline--vertical .timeline__title {
	grid-column: 2;
	margin: 0;
}

.timeline--vertical .timeline__desc {
	grid-column: 2;
}

/* Ngang: 2 cột từ 576px, 4 cột từ 992px. Dọc: luôn 1 cột. */
@media (min-width: 576px) {

	.timeline--horizontal .timeline__list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 992px) {

	.timeline--horizontal .timeline__list {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}
}

/* =========================================================================
   14. ICON  (C-28 · T-224)

   Icon vẽ bằng `stroke="currentColor"` nên nó tự lấy màu chữ của chỗ đang
   đứng — trên nền navy thì trắng, trong thẻ thì màu nhấn. Không cần biến thể
   sáng/tối, và cũng không được đặt `color` cứng ở đây.
   ====================================================================== */

/*
 * ⚠️ KHÔNG đặt `width`/`height` ở đây, kể cả `auto`.
 *
 * Kích thước icon do thuộc tính `width`/`height` trên chính thẻ `<svg>` quyết
 * định, vì mỗi chỗ gọi cần một cỡ khác nhau (badge 20, số liệu 32, lĩnh vực
 * 40). Bản đầu viết `width: auto; height: auto` với ý "để tự nhiên" — nhưng
 * CSS thắng thuộc tính HTML, nên `auto` làm SVG giãn ra lấp đầy ô chứa: icon
 * khối "Ba Tốt" phình lên gần 150px và chiếm hết thẻ.
 */
.potaco-icon {
	display: inline-block;
	flex: 0 0 auto;
	vertical-align: middle;
}

/* Icon trong hero và dải số liệu ăn theo màu nhấn, không phải màu chữ. */
.hero__stat-icon.potaco-icon,
.stats-band__icon.potaco-icon {
	color: var(--c-accent);
}

/* Icon lĩnh vực và quy trình dùng màu thương hiệu trên nền sáng. */
.fields__item-icon.potaco-icon,
.process__icon.potaco-icon,
.why__icon.potaco-icon {
	color: var(--c-primary);
}

/* Vòng tròn mang icon thay vì số — nền màu thương hiệu cho icon nổi lên. */
.process__num--icon {
	color: var(--c-text-invert);
	background-color: var(--c-primary);
	border-color: var(--c-primary);
}

.process__num--icon .potaco-icon {
	color: var(--c-text-invert);
}

/* =========================================================================
   14. DẢI SỐ LIỆU  (C-16 · chuyển từ page/home.css 2026-09-03)

   ⚠️ Vì sao nằm ở đây chứ không ở CSS riêng của trang chủ: template-part
      `block/stats-band.php` dùng ở HAI màn — trang chủ (dải giữa trang) và
      trang Giới thiệu (§01 và §06). CSS nằm trong `page/home.css` thì màn Giới
      thiệu nhận markup mà KHÔNG có style: nền navy biến mất, chữ trắng thành
      chữ xám trên nền trắng. Đo được lúc soi ảnh T-302.1 — `s01-stats` có
      `background-color: rgba(0,0,0,0)`.

      Cùng một lỗi với `.lazy-video` và `.section-header--split`: markup có,
      CSS đặt sai chỗ. Quy tắc rút ra: block dùng ở ≥2 màn thì CSS phải ở
      `components.css`, đúng như `process` và `timeline` đã làm ở §13.
   ====================================================================== */

/* =========================================================================
 * 2. DẢI SỐ LIỆU GIỮA TRANG — ST-00, ST-01
 *
 * Cùng dữ liệu với `.hero__stats` nhưng khác vai trò: đây là một section
 * riêng trên nền xanh đậm, hiển thị ĐỦ 5 mục. Không gộp class với hero vì
 * hai chỗ khác nền, khác cỡ chữ và khác số cột ở mọi breakpoint.
 * ====================================================================== */

.stats-band {
	position: relative;
	padding: var(--sp-12) 0;
	overflow: hidden;
	background-color: var(--c-primary-900, var(--c-primary-800));
	color: var(--c-text-invert);
}

/* --- Ảnh nền chìm (CR 2026-09-02) -------------------------------------- */

.stats-band__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * Lớp phủ navy đậm: ảnh chỉ là kết cấu chìm phía sau, số liệu vẫn phải đọc
 * được. Đo trên ảnh sáng nhất — không đạt thì tăng độ phủ, đừng giảm độ đậm
 * của chữ.
 */
.stats-band--has-bg::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	background: rgb(0 24 66 / 88%);
}

.stats-band__list {
	position: relative;
	z-index: 2;
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--sp-8) var(--sp-6);
	/*
	 * ⚠️ `margin: 0 auto`, KHÔNG phải `margin: 0`.
	 *
	 * Phần tử này mang cả class `container`, mà `.container` canh giữa bằng
	 * `margin: 0 auto`. Bản cũ khai `margin: 0` — shorthand nên xoá luôn vế
	 * `auto`; `max-width` vẫn còn nên cả dải bị bó đúng bề rộng container
	 * nhưng dính mép TRÁI của section full-width. Phần padding ngay dưới đã
	 * được viết tách (`padding-top`/`padding-bottom`) đúng vì lý do này, chỉ
	 * riêng margin dùng shorthand nên lọt.
	 */
	margin: 0 auto;
	padding-top: 0;
	padding-bottom: 0;
	list-style: none;
}

/* Icon TRÁI · số + nhãn PHẢI, cả cụm canh giữa ô — như thiết kế.
   Đồng bộ với `.hero__stat`: cùng một bộ số liệu, không được hiển thị hai
   kiểu ở hai chỗ trên cùng một trang. */
.stats-band__item {
	display: flex;
	flex-direction: row;
	gap: var(--sp-3);
	align-items: center;
	justify-content: center;
	min-width: 0;
	text-align: left;
}

.stats-band__body {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
}

/* Không có cột icon bên trái thì số + nhãn canh giữa ô — layout v2 vẽ dải §01
   trang Giới thiệu như vậy. Bố cục "icon trái · chữ phải" chỉ đúng khi CÓ icon. */
.stats-band--no-icon .stats-band__item {
	text-align: center;
}

.stats-band__num {
	font-family: var(--font-heading);
	font-size: var(--fs-h2);
	font-weight: var(--fw-bold);
	line-height: var(--lh-tight);
	color: var(--c-accent);
}

.stats-band__label {
	font-size: var(--fs-sm);
	font-weight: var(--fw-medium);
	letter-spacing: var(--ls-caps);
	text-transform: uppercase;
	opacity: 0.88;
	overflow-wrap: anywhere;
}

/* ≥768px: 3 mục hàng trên, phần còn lại tự dồn (wireframe “3+2”). */
@media (min-width: 768px) {

	.stats-band__list {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

/* ≥992px: 5 mục một hàng. */
@media (min-width: 992px) {

	.stats-band {
		padding: var(--sp-16) 0;
	}

	.stats-band__list {
		grid-template-columns: repeat(5, minmax(0, 1fr));
	}
}

/* =========================================================================
   14. SLIDER DÙNG CHUNG — chấm phân trang · mũi tên  (R-06-layout F-04 · F-06)
   ====================================================================== */

/*
 * ⚠️ Đặt ở lớp component, KHÔNG ở CSS từng trang.
 *
 * Trước đây chỉ slider hero khai màu chấm (`page/home.css` §1); slider "Dự án
 * tiêu biểu" khai mỗi vị trí, nên chấm rơi về mặc định của vendor:
 *
 *     đang xem : #007AFF  ← `--swiper-theme-color`, màu xanh iOS
 *     còn lại  : #000000
 *
 * Không màu nào có trong `_tokens.css` — đó là màu DUY NHẤT trên toàn trang chủ
 * không thuộc bảng thương hiệu. Một slider được chăm, slider kia bị quên; đặt ở
 * đây thì slider thứ ba thêm sau tự đúng thay vì lại quên một lần nữa.
 *
 * ⚠️ Độ đặc hiệu (0,0,2,0) để thắng `swiper.min.css` — file vendor nạp SAU css
 *    theme (WordPress in nó ở cuối trang), bằng đặc hiệu thì nó thắng.
 */
.swiper .swiper-pagination-bullet {
	width: 10px;
	height: 10px;
	background: var(--c-primary);
	opacity: 0.28;
	transition: var(--transition);
}

.swiper .swiper-pagination-bullet-active {
	background: var(--c-accent);
	opacity: 1;
}

/*
 * Chấm và mũi tên đều là ĐIỀU KHIỂN — bấm được thì phải cho biết là bấm được.
 * Đo trước khi sửa: 0/9 thuộc tính đổi khi hover. R-06-layout F-06.
 */
@media (hover: hover) and (pointer: fine) {

	.swiper .swiper-pagination-bullet:hover {
		opacity: 0.6;
	}

	.swiper .swiper-pagination-bullet-active:hover {
		opacity: 1;
	}
}

/*
 * Mũi tên: hover đổi NỀN + VIỀN, không đổi kích thước.
 *
 * Đổi kích thước thì nút nhảy khỏi vị trí ngay dưới con trỏ — và vì nút neo
 * `top: 50%` với `margin-top` âm cố định, phóng to còn làm nó lệch tâm.
 *
 * `:not(.swiper-button-disabled)`: ở slide đầu/cuối Swiper tự gắn class đó và
 * đặt `pointer-events: none`. Nút đang tắt mà vẫn sáng lên khi rê chuột là nói
 * dối người dùng rằng bấm được.
 */
@media (hover: hover) and (pointer: fine) {

	.swiper-button-prev:not(.swiper-button-disabled):hover,
	.swiper-button-next:not(.swiper-button-disabled):hover {
		color: var(--c-text-invert);
		background-color: var(--c-primary);
		border-color: var(--c-primary);
	}
}

.swiper-button-prev:focus-visible,
.swiper-button-next:focus-visible {
	color: var(--c-text-invert);
	background-color: var(--c-primary);
	border-color: var(--c-primary);
}

/* Vendor không khai `transition` cho hai nút này nên đổi nền là nhảy khựng. */
.swiper-button-prev,
.swiper-button-next {
	transition: var(--transition);
}

/* =========================================================================
   15. SPLIT — bố cục "một bên ẢNH · một bên NỘI DUNG"   (C-29 · T-302.3.3)
   ====================================================================== */

/*
 * ⚠️ MỘT component cho BỐN chỗ: §07 · §08 · §09 · §10 của trang Giới thiệu.
 *
 * Layout v2 cho cả bốn section này cùng một hình dạng — chỉ khác bên đặt ảnh và
 * nội dung bên trong. Viết bốn bản riêng là đúng thứ `/wp-06b-review` L3 chặn ở
 * ngưỡng "cùng hình dạng ≥3 nơi = finding 🔴", và cũng là cách bản sửa ở một
 * section không bao giờ lan sang ba section kia.
 *
 * Chỉ khai BỐ CỤC. Nội dung bên trong (cây tổ chức, danh sách cam kết, lưới
 * chứng chỉ, lưới phẩm chất) giữ nguyên markup riêng của từng section — chúng
 * thật sự khác nhau, gom vào đây mới là trừu tượng hoá sai chỗ.
 */
.split {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--sp-6);
	align-items: center;
}

@media (min-width: 992px) {

	.split {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
		gap: var(--sp-8);
	}

	/*
	 * Ảnh bên TRÁI: đảo thứ tự bằng `order`, không đảo thứ tự trong HTML.
	 * Thứ tự đọc của trình đọc màn hình và của bàn phím phải giữ nguyên
	 * "nội dung trước, ảnh minh hoạ sau" ở mọi biến thể.
	 */
	.split--media-left .split__media {
		order: -1;
	}
}

/*
 * ⚠️ Nhánh THIẾU ẢNH — bắt buộc, không phải tuỳ chọn.
 *
 * Cả 5 option ảnh của trang này đang trống trong DB (khách chưa nhập). Không có
 * nhánh này thì ở ≥992px lưới vẫn chia đôi và nội dung co lại còn nửa chiều
 * ngang, chừa một nửa trống trơn — đúng kiểu "sống sót mà vỡ bố cục" mà
 * `CLAUDE.md` §0.4 nhắm tới.
 *
 * PHP không in `.split__media` khi thiếu ảnh, nên `.split__content` thành con
 * duy nhất và chiếm trọn chiều ngang.
 */
.split__content:only-child {
	grid-column: 1 / -1;
}

.split__media {
	min-width: 0;
}

.split__content {
	min-width: 0;
}

/*
 * Ảnh: tỉ lệ khai bằng modifier để không mỗi nơi một kiểu.
 * `object-fit: cover` + `aspect-ratio` giữ khung ổn định kể cả khi khách tải
 * lên ảnh sai tỉ lệ — không có nó thì mỗi ảnh một chiều cao, hai cột lệch nhau.
 */
.split__img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: var(--radius-lg);
	object-fit: cover;
}

.split--16-9 .split__img { aspect-ratio: 16 / 9; }
.split--4-3  .split__img { aspect-ratio: 4 / 3; }
.split--3-4  .split__img { aspect-ratio: 3 / 4; }

/* --- Biến thể `about`: nền SÁNG, 5 số MỘT HÀNG  (layout v2 · T-302.3.5) ---
 *
 * ⚠️ Class `stats-band--about` vốn ĐÃ được `stats-band.php` in ra từ T-302.1,
 *    nhưng chưa bao giờ có CSS — nên §01 và §06 của trang Giới thiệu đều lấy
 *    nền navy của bản mặc định. Đây đúng loại "CSS viết cho class không tồn
 *    tại" ngược chiều: class tồn tại mà CSS không có. Cùng họ với lỗi
 *    `.breadcrumb__sep` (R-06-layout F-02).
 *
 * Layout v2 vẽ hai dải này trên nền sáng, viền mảnh, số cam — khác hẳn dải
 * navy tràn nền của trang chủ.
 */
.stats-band--about {
	padding: var(--sp-6);
	background-color: var(--c-bg);
	color: var(--c-text);
	border: var(--border-w) solid var(--c-border);
	border-radius: var(--radius-lg);
}

/* Nền sáng thì lớp phủ ảnh nền của bản navy không còn nghĩa — tắt hẳn. */
.stats-band--about.stats-band--has-bg::before {
	content: none;
}

.stats-band--about .stats-band__label {
	color: var(--c-text-muted);
}

/*
 * `padding` đã nằm ở chính khối, nên phần `container` bên trong không được
 * thêm gutter nữa — cộng dồn thì số liệu thụt vào giữa một cách vô lý.
 */
.stats-band--about .stats-band__list {
	padding-inline: 0;
	gap: var(--sp-5) var(--sp-4);
}

@media (min-width: 992px) {

	/*
	 * FIVE cột — 5 số liệu trên MỘT hàng theo layout v2. Bản mặc định dùng
	 * `repeat(5, ...)` ở dải này cho trang chủ; khai lại ở đây vì §06 chỉ chiếm
	 * NỬA chiều ngang nên phải hạ xuống 2 cột, xem quy tắc ngay dưới.
	 */
	.stats-band--about .stats-band__list {
		grid-template-columns: repeat(5, minmax(0, 1fr));
	}

	/*
	 * §06: dải số liệu nằm trong cột trái của `.split`, rộng ~410px — MỖI SỐ
	 * MỘT HÀNG.
	 *
	 * Nhồi 5 số một hàng như trang chủ thì mỗi ô còn ~70px và "KHÁCH HÀNG &
	 * ĐỐI TÁC" vỡ 4 dòng. Bản trước hạ xuống lưới 2×2, nhưng lưới đó chỉ cao
	 * bằng nửa hộp navy bên phải nên hai cột lệch hẳn chiều cao.
	 *
	 * Xếp dọc từng hàng thì mỗi số có trọn chiều ngang cột (nhãn không bao giờ
	 * phải xuống dòng), và `grid-auto-rows: 1fr` chia đều chiều cao còn lại cho
	 * các hàng — nhờ đó cột trái cao đúng bằng cột phải. Chiều cao đó do
	 * `.about-capacity` cấp, xem `page/about.css` §7.
	 *
	 * ⚠️ `1fr` chứ không phải `auto`: `auto` co về vừa nội dung nên dù hộp có
	 *    cao bằng cột phải thì các hàng vẫn dồn lên trên, chừa khoảng trống ở
	 *    đáy thẻ.
	 */
	.split .stats-band--about .stats-band__list {
		grid-template-columns: minmax(0, 1fr);
		grid-auto-rows: 1fr;
		/*
		 * ⚠️ `row-gap: 0` đi CÙNG CẶP với vạch ngăn ngay dưới, không tách rời.
		 *
		 *    Vạch vẽ bằng `border-top` nên nó nằm ở MÉP TRÊN của hàng. Còn giữ
		 *    `row-gap` 20px của bản mặc định thì khoảng trống rơi hết về phía
		 *    trên vạch: vạch dính sát số bên dưới và hở một quãng với số bên
		 *    trên — lệch hẳn, mà nhìn thoáng qua chỉ thấy "hơi sai sai".
		 *
		 *    Bỏ gap thì vạch nằm đúng ranh giới hàng; các hàng đã là `1fr` bằng
		 *    nhau và nội dung canh giữa theo chiều dọc, nên khoảng thở trên và
		 *    dưới mỗi vạch tự cân.
		 */
		row-gap: 0;
	}

	/* Vạch ngăn giữa các số — chỉ giữa, không có vạch ở đầu và cuối danh sách,
	   nên dùng `+` chứ không phải `border-bottom` cho mọi hàng. */
	.split .stats-band--about .stats-band__item + .stats-band__item {
		border-top: var(--border-w) solid var(--c-border);
	}

	/*
	 * Canh TRÁI, không canh giữa: bốn hàng xếp dọc thì icon phải thẳng một cột
	 * dọc. Giữ `justify-content: center` của bản mặc định là mỗi hàng tự canh
	 * giữa theo bề rộng nội dung riêng, nên bốn icon lệch nhau mỗi hàng một ít.
	 */
	.split .stats-band--about .stats-band__item {
		justify-content: flex-start;
	}
}

/* =========================================================================
   12b. DẢI ĐỐI TÁC  (C-24) — chuyển từ `page/home.css` §9 ngày 2026-09-09
   =========================================================================

   ⚠️ VÌ SAO NÓ Ở ĐÂY chứ không ở `page/home.css`:

   `template-parts/block/partners.php` là component dùng chung. Khi dựng trang
   chủ tôi để toàn bộ ~165 dòng CSS của nó trong `page/home.css`, vì lúc đó nó
   chỉ chạy ở một trang. Tới khi archive sản phẩm gọi lại cùng block thì dải
   "ĐỐI TÁC CUNG CẤP" hiện ra KHÔNG CÓ MỘT DÒNG STYLE NÀO — logo xếp dọc, tràn
   ngang, mất hẳn slider. Người vận hành báo 2026-09-09.

   Đây là dạng thứ hai của cùng một lỗi gốc: "component dùng chung nhưng CSS
   nạp sai chỗ". Ba dạng còn lại: CSS không tồn tại (`.sort-select`), CSS có
   nhưng không khớp thiết kế (`.info-table`), tự chế class trùng vai component
   đã có (`.section-title`).

   ⇒ LUẬT: block nào nằm trong `template-parts/block/` thì CSS của nó thuộc
     file này, kể cả khi hôm nay mới có một trang dùng.
   ====================================================================== */

.partners {
	padding: var(--section-gap) 0;
	background-color: var(--c-bg);
}

/*
 * Lớp bọc mới: chứa CẢ track lẫn hai nút mũi tên. Chỗ chừa cho mũi tên phải
 * nằm ở đây chứ không ở `.partners__track` — nút neo vào lớp này nên mới ra
 * được ngoài vùng logo (và không bị `overflow: hidden` của Swiper cắt).
 */
.partners__slider {
	position: relative;
}

@media (min-width: 768px) {

	.partners__slider {
		padding: 0 48px;
	}
}

/*
 * CHỖ THỞ DỌC CHO SWIPER — utility dùng chung  (R-06-archive-project F-03, 2026-09-16)
 *
 * `.swiper` của vendor là `overflow: hidden`, cao ĐÚNG bằng slide ⇒ bóng đổ /
 * nhấc 2px khi hover bị xén phẳng ở mép trên–dưới. Chữa bằng `padding` dọc +
 * `margin` âm cùng số: chiều cao hộp không đổi, mũi tên neo `top: 50%` đứng yên.
 *
 * ⚠️ Mẹo này từng chép tay ở BA nơi (`.fields__list--slider`, `.partners__track`,
 *    `.project-related__slider`) với ba con số — 06b bắt D2. Nay MỘT class,
 *    khối nào cần khác 16px thì đặt `--breathe` trên chính khối đó.
 *
 * ⚠️ Bắt buộc `.swiper` trong selector: `swiper.min.css` in ở footer nên nạp SAU
 *    css theme, `.swiper { padding: 0 }` cùng độ đặc hiệu sẽ thắng nếu chỉ ghi
 *    một class.
 */
.swiper.swiper--breathe {
	padding: var(--breathe, 16px) 0;
	margin: calc(-1 * var(--breathe, 16px)) 0;
}

/*
 * Ô logo đối tác: chỗ thở qua `.swiper--breathe` (16px đủ cho bóng hover
 * `0 4px 10px`; `margin` âm cùng số nên `.partners__slider` không đổi chiều
 * cao, mũi tên neo `top: 50%` đứng yên). Không chừa chỗ cho mũi tên ở đây —
 * xem `.partners__slider`. Bản chép tay `padding/margin 16` từng nằm ở đây
 * (trước F-03 06b Dự án, `4a1e353`) đã gỡ 2026-09-18 — đo 5 trang có dải đối
 * tác: không đổi pixel nào.
 */
.partners__track.swiper {
	position: relative;
}

.partners__track .swiper-slide {
	width: 160px;
	height: auto;
}

/*
 * CR 2026-09-02: bỏ viền, dùng đổ bóng.
 *
 * ⚠️ Nền section trắng và nền ô cũng trắng, nên sau khi bỏ viền thì BÓNG là
 *    thứ duy nhất phân định ô với nền — dùng `--shadow-md` chứ không phải
 *    `--shadow-sm`, mức nhạt hơn làm ô biến mất và logo trông như trôi tự do.
 */
/*
 * ⚠️ Bóng "CHẶT", KHÔNG dùng `--shadow-md`.
 *
 * `--shadow-md` là `0 4px 16px / .08`: blur 16px **bằng đúng** khoảng cách giữa
 * hai ô (`spaceBetween: 16` của Swiper), nên bóng hai ô cạnh nhau phủ kín khe
 * hở và pool xuống dưới — mắt đọc thành một mảng xám liền chứ không phải bóng
 * của từng thẻ. Cùng lúc, alpha .08 lại quá nhạt để dựng cạnh thẻ trắng trên
 * nền trắng, nên lúc không hover ô trông như không có bóng.
 *
 * Bóng dưới đây blur nhỏ hơn khe hở nhiều lần nên không thể loang, alpha nhỉnh
 * hơn nên cạnh thẻ hiện rõ ngay ở trạng thái thường. Tổng lượng xám vẫn ít hơn.
 *
 * ⚠️ Ghi đè CỤC BỘ, không sửa token: `--shadow-md` còn dùng ở `.card:hover`,
 *    nút play video, header khi cuộn.
 */
.partners__item {
	display: grid;
	place-items: center;
	height: 80px;
	padding: var(--sp-3);
	border: 0;
	border-radius: var(--radius-md);
	background-color: var(--c-bg);
	box-shadow: 0 1px 2px rgb(0 24 66 / 10%), 0 2px 6px rgb(0 24 66 / 8%);
	transition: var(--transition);
}

/*
 * Ô logo có thể là thẻ `<a>` (đối tác có website).
 * Hover đổi MÀU NỀN ô — không nhân bóng lên, vì bóng to là loang lại.
 */
/*
 * F-03: bọc `:hover` trong media query — dải logo vuốt được bằng ngón tay, nên
 * đây là khối bị chạm nhiều nhất trên điện thoại. Ô vừa vuốt qua mà giữ nền
 * xanh nhạt + bóng dày thì đọc thành "đối tác này đang được chọn".
 * `:focus-visible` giữ ngoài để người dùng bàn phím vẫn thấy ô đang tới.
 */
@media (hover: hover) and (pointer: fine) {

	a.partners__item:hover {
		background-color: var(--c-primary-50);
		box-shadow: 0 2px 4px rgb(0 24 66 / 12%), 0 4px 10px rgb(0 24 66 / 10%);
	}
}

a.partners__item:focus-visible {
	background-color: var(--c-primary-50);
	box-shadow: 0 2px 4px rgb(0 24 66 / 12%), 0 4px 10px rgb(0 24 66 / 10%);
}

a.partners__item:focus-visible {
	outline: 2px solid var(--c-accent);
	outline-offset: 2px;
}

/*
 * `contain` chứ không `cover`: logo đối tác có đủ tỉ lệ — bộ seed cố ý có một
 * logo rất ngang (400×80) và một logo vuông. `cover` sẽ cắt mất chữ trong logo.
 */
.partners__logo {
	max-width: 100%;
	max-height: 56px;
	width: auto;
	height: auto;
	object-fit: contain;
}

/*
 * ⚠️ Mũi tên CHỈ có từ 768px — spec §2 sự kiện E-H04 ghi breakpoint `≥768`.
 *
 * Dưới ngưỡng đó dải logo vuốt được bằng ngón tay nên mũi tên là thừa, mà
 * `.swiper-button-*` của Swiper là `position: absolute` canh giữa hai mép —
 * ở 390px chúng nằm ĐÈ THẲNG lên logo đầu và logo cuối.
 */
.partners__nav.swiper-button-prev,
.partners__nav.swiper-button-next {
	display: none;
}

@media (min-width: 768px) {

	.partners__nav.swiper-button-prev,
	.partners__nav.swiper-button-next {
		display: flex;
		width: 36px;
		height: 36px;
		margin-top: -18px;
		border: 1px solid var(--c-border);
		border-radius: var(--radius-full);
		color: var(--c-primary);
		background-color: var(--c-bg);
	}

	/* Neo vào mép của `.partners__slider` — tức NGOÀI hàng logo. */
	.partners__nav.swiper-button-prev {
		left: 0;
	}

	.partners__nav.swiper-button-next {
		right: 0;
	}
}

.partners__nav.swiper-button-prev::after,
.partners__nav.swiper-button-next::after {
	font-size: 14px;
	font-weight: var(--fw-bold);
}

/* =========================================================================
   13. BOX TƯ VẤN Ở CỘT BÊN  (T-304 · T-501)
   `sidebar/service-consult.php` — Dịch vụ (variant service: hotline + email
   dạng dòng) và Tin tức (variant news: khối hotline lớn). Chuyển từ
   `page/service.css` §7 khi nhánh Tin tức bắt đầu dùng chung (T-501).
   ====================================================================== */

.service-consult {
	padding: 20px;
	color: var(--c-text-invert);
	background: var(--c-primary-800, var(--c-primary));
	border: 0;
	border-radius: var(--radius-md);
}

.service-consult__title {
	display: flex;
	flex-direction: column;
	margin: 0 0 8px;
	font-family: var(--font-heading);
	font-size: var(--fs-h4);
	font-weight: var(--fw-bold);
	line-height: 1.3;
	text-transform: uppercase;
	color: inherit;
}

.service-consult__desc {
	margin: 0 0 14px;
	font-size: var(--fs-sm);
	line-height: 1.5;
	color: rgba(255, 255, 255, 0.85);
}

.service-consult__btn {
	display: flex;
	justify-content: center;
	width: 100%;
	min-height: 42px;
	box-sizing: border-box;
}

.service-consult__lines {
	margin: 14px 0 0;
	padding: 0;
	list-style: none;
}

.service-consult__line {
	display: flex;
	align-items: center;
	gap: 10px;
	min-height: 32px;
	color: var(--c-text-invert);
	font-size: var(--fs-sm);
	text-decoration: none;
}

.service-consult__line svg {
	flex: 0 0 18px;
	width: 18px;
	height: 18px;
}

@media (hover: hover) and (pointer: fine) {

	.service-consult__line:hover {
		text-decoration: underline;
	}
}

/* ---- Biến thể Tin tức: nhãn + số hotline lớn (spec pixel v2 §A8) ---- */

.service-consult--news {
	position: relative;
	overflow: hidden;
	border-radius: var(--radius-lg);
}

/* Hoạ tiết bản vẽ chìm — CSS thuần, không tải ảnh, đủ mờ để không đè chữ. */
.service-consult--news::before {
	content: "";
	position: absolute;
	inset: 0;
	background-image:
		linear-gradient(rgba(255, 255, 255, 0.06) 1px, transparent 1px),
		linear-gradient(90deg, rgba(255, 255, 255, 0.06) 1px, transparent 1px);
	background-size: 28px 28px;
	pointer-events: none;
}

.service-consult--news > * {
	position: relative;
}

.service-consult__hotline {
	display: flex;
	align-items: center;
	gap: 12px;
	margin-top: 16px;
	color: var(--c-text-invert);
	text-decoration: none;
}

.service-consult__hotline-icon {
	flex: 0 0 24px;
	color: var(--c-accent);
}

.service-consult__hotline-text {
	display: flex;
	flex-direction: column;
}

.service-consult__hotline-label {
	font-size: var(--fs-xs);
	opacity: 0.8;
}

.service-consult__hotline-num {
	font-family: var(--font-heading);
	font-size: 20px;
	font-weight: var(--fw-bold);
	line-height: 1.2;
	color: var(--c-accent);
}

@media (hover: hover) and (pointer: fine) {

	.service-consult__hotline:hover .service-consult__hotline-num {
		text-decoration: underline;
	}
}
