/*
 * mini-clone fixes — gforces "responsive-image" sizing
 *
 * The model-tab and offer-carousel images use the gforces "responsive-image"
 * markup whose box dimensions + <source srcset> are normally injected at runtime
 * by an external gforces loader (auto.netdirector.co.uk) that we intentionally
 * do NOT self-host. Without that JS the <img> (object-fit:cover; max-width:none;
 * no width/height; empty srcset) renders at its intrinsic size — model images
 * shrink and offer images look blurry / wrongly cropped.
 *
 * These rules replace the JS sizing natively: put the aspect-ratio on the <img>
 * itself (derived from the existing aspect-ratio-* container class) and let every
 * wrapper be a plain auto-height block. Everything is scoped under the
 * aspect-ratio-* container classes, so any responsive-image without a ratio
 * context is left untouched (no risk of collapsing it). The hero (billboard)
 * uses the gforces css-bg-image pattern and IS affected — fixed separately below.
 *
 * WARNING — do NOT move the aspect-ratio back onto div.responsive-image and do
 * NOT reintroduce height:100% on the figure/picture/img chain. That combination
 * makes the box take its height from the ratio while its children take their
 * height from the box: a circular sizing dependency. Blink resolves it silently,
 * WebKit (every iPhone) resolves it by inflating the grid column instead — the
 * homepage model images rendered ~2000-2950px wide inside a 390px viewport, the
 * page became horizontally scrollable and everything below "MEET THE FAMILY."
 * looked blank. Measured with tools/qa/webkit-mobile-check.mjs; mini-vietnam.com
 * in the same engine stays at scrollWidth 390.
 */
.aspect-ratio-4-3 div.responsive-image img.responsive-image { aspect-ratio: 4 / 3; }
.aspect-ratio-11-5 div.responsive-image img.responsive-image { aspect-ratio: 11 / 5; }
.aspect-ratio-16-9 div.responsive-image img.responsive-image { aspect-ratio: 16 / 9; }

/* Offer carousel is 16:9 on desktop (wrapper class) but 4:3 on mobile. */
@media (max-width: 767px) {
	.cycle-features div.responsive-image img.responsive-image { aspect-ratio: 4 / 3; }
}

.aspect-ratio-4-3 div.responsive-image,
.aspect-ratio-11-5 div.responsive-image,
.aspect-ratio-16-9 div.responsive-image,
.aspect-ratio-4-3 div.responsive-image figure.responsive-image,
.aspect-ratio-11-5 div.responsive-image figure.responsive-image,
.aspect-ratio-16-9 div.responsive-image figure.responsive-image,
.aspect-ratio-4-3 div.responsive-image picture,
.aspect-ratio-11-5 div.responsive-image picture,
.aspect-ratio-16-9 div.responsive-image picture { display: block; width: 100%; height: auto; }

.aspect-ratio-4-3 div.responsive-image img.responsive-image,
.aspect-ratio-11-5 div.responsive-image img.responsive-image,
.aspect-ratio-16-9 div.responsive-image img.responsive-image { display: block; width: 100%; height: auto; object-fit: cover; }

/* ---------------------------------------------------------------------------
 * Hero billboard (.item.MINI) — distortion fix.
 * The gforces loader that would paint each slide as a background-image (cover)
 * on .image is intentionally not self-hosted, so the raw <img class="css-bg-image">
 * shows with the CSS-default object-fit:fill. The jQuery cycle carousel forces an
 * inline slide height, giving the <img> a box wider than 16:9 → a 16:9 source gets
 * stretched horizontally (looks vertically squished). object-fit:cover makes the
 * image keep its aspect ratio and fill the box (overflow cropped, no stretch).
 * ------------------------------------------------------------------------- */
.item.MINI .image img.css-bg-image { object-fit: cover; object-position: center; }

/* ---------------------------------------------------------------------------
 * Showroom (visit-us) — CMS-driven listing + detail.
 * Bản gốc trả 403 cho các trang này nên không có markup để pixel-perfect; đây là
 * layout sạch theo grid của theme, đủ để nhân viên showroom dùng CMS thoải mái.
 * ------------------------------------------------------------------------- */
.mini-showroom-archive,
.mini-showroom-single { padding: 40px 0 60px; }

.mini-sr-listing-title,
.mini-sr-title { font-size: 28px; line-height: 1.2; margin: 0 0 28px; }

.mini-sr-cards {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
	gap: 24px;
}
.mini-sr-card {
	border: 1px solid #e2e2e2;
	border-radius: 4px;
	padding: 24px;
	background: #fff;
}
.mini-sr-card-name { font-size: 18px; margin: 0 0 12px; }
.mini-sr-card-name a { color: #1c1c1c; text-decoration: none; }
.mini-sr-card-name a:hover { text-decoration: underline; }
.mini-sr-card-address { color: #555; margin: 0 0 12px; }
.mini-sr-card-contact { list-style: none; margin: 0 0 12px; padding: 0; }
.mini-sr-card-contact li,
.mini-sr-contact li { margin: 0 0 6px; }
.mini-sr-card-more a { font-weight: 600; text-decoration: none; }

/* Detail */
.mini-sr-grid {
	display: grid;
	grid-template-columns: 1fr 1.2fr;
	gap: 40px;
	align-items: start;
}
.mini-sr-label { font-size: 16px; text-transform: uppercase; letter-spacing: .04em; margin: 0 0 8px; }
.mini-sr-block { margin: 0 0 24px; }
.mini-sr-address p { color: #444; margin: 0; }
.mini-sr-contact ul { list-style: none; margin: 0; padding: 0; }
.mini-sr-dept { font-weight: 600; display: inline-block; min-width: 64px; }
.mini-sr-contact a,
.mini-sr-card-contact a { color: #1c1c1c; text-decoration: none; }
.mini-sr-contact a:hover,
.mini-sr-card-contact a:hover { text-decoration: underline; }
.mini-sr-map iframe {
	width: 100%;
	min-height: 360px;
	border: 0;
	display: block;
}
.mini-sr-map-placeholder {
	width: 100%;
	min-height: 360px;
	display: flex;
	align-items: center;
	justify-content: center;
	background: #f3f3f3;
	color: #888;
}
.mini-sr-back { margin: 32px 0 0; }
.mini-sr-back a { text-decoration: none; font-weight: 600; }

@media (max-width: 767px) {
	.mini-sr-grid { grid-template-columns: 1fr; gap: 28px; }
}

/* SP5b — Fluent Forms lead form, áp diện mạo giống MINI (nút đen bo nhẹ, input
   viền xám mảnh, font kế thừa). Chấp nhận lệch nhỏ so với form gốc capture. */
.fluentform .ff-el-group { margin-bottom: 1.25rem; }
.fluentform .ff-el-input--label label { font-weight: 600; font-size: .9rem; }
.fluentform .ff-el-form-control {
	width: 100%;
	padding: .75rem 1rem;
	border: 1px solid #c4c4c4;
	border-radius: 2px;
	background: #fff;
	font: inherit;
	color: #1a1a1a;
}
.fluentform .ff-el-form-control:focus {
	border-color: #1a1a1a;
	outline: none;
	box-shadow: none;
}
.fluentform .ff-btn-submit {
	background: #1a1a1a;
	color: #fff;
	border: none;
	border-radius: 2px;
	padding: .85rem 2.5rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: .04em;
	cursor: pointer;
}
.fluentform .ff-btn-submit:hover { background: #000; }
.ff-message-success {
	padding: 1rem 1.25rem;
	border: 1px solid #1a1a1a;
	background: #f5f5f5;
	color: #1a1a1a;
}

/* ---------------------------------------------------------------------------
 * Footer 4 cột kiểu THACO (thay 4 cột MINI gốc trong khối link-block.groups-4):
 *   1) Logo + thông tin công ty  2) CHÍNH SÁCH & ĐIỀU KHOẢN
 *   3) VỀ CÔNG TY                4) KẾT NỐI VỚI CHÚNG TÔI (social)
 * Kế thừa nền đen + màu chữ + font <h4 class="title"> của footer gốc.
 *
 * Khối này nằm TRONG .toggle__company-information (nút "QUICK LINKS"). GIỮ NGUYÊN
 * cơ chế gập/mở gốc của gforces (nút QUICK LINKS + toggle-body ẩn/mở) trên MỌI
 * kích thước — KHÔNG ép mở, KHÔNG ẩn nút, để người dùng tự bấm như bản gốc MINI.
 * ------------------------------------------------------------------------- */

/* 4 cột giãn cách ĐỀU nhau. KHÔNG dùng flex-grow (làm cột rộng hơn nội dung →
 * khoảng trống dồn lệch về 1 phía). Mỗi cột co theo nội dung (flex:0 1 auto) +
 * justify-content:space-between → khoảng cách giữa 4 khối luôn bằng nhau ở mọi
 * bề rộng. Cột 1 (logo + info) đặt basis 360px đủ chứa dòng "MST | Ngày cấp". */
.link-block.groups-4 { display: flex !important; justify-content: space-between; gap: 32px; align-items: flex-start; }
.link-block.groups-4 .link-group { float: none !important; width: auto; flex: 0 1 auto; }
.link-block.groups-4 .link-group.mini-foot-about { flex: 0 1 360px; min-width: 320px; }

.mini-foot-logo { display: inline-block; margin: 0 0 18px; }
.mini-foot-logo img { display: block; max-width: 190px; height: auto; }

/* Dòng tiêu đề: tên công ty in đậm + MST + Ngày cấp, ngăn bằng dấu | mờ. */
.mini-fi-head {
	margin: 0 0 16px;
	font-size: 15px;
	line-height: 1.5;
}
.mini-fi-head strong { font-weight: 700; }
.mini-fi-sep { opacity: .45; margin: 0 2px; }

/* Danh sách liên hệ: mỗi dòng 1 icon + nội dung, canh icon thẳng đầu dòng. */
.mini-fi-list {
	list-style: none;
	margin: 0;
	padding: 0;
}
.mini-fi-list li {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	font-size: 14px;
	line-height: 1.5;
	margin: 0 0 12px;
}
.mini-fi-list li:last-child { margin-bottom: 0; }
.mini-fi-ico {
	flex: 0 0 auto;
	margin-top: 1px;
	opacity: .85;
}
.mini-fi-val { color: inherit; }
.mini-fi-list a { color: inherit; text-decoration: none; }
.mini-fi-list a:hover { text-decoration: underline; }

/* Cột 4 — social: nút tròn viền mảnh, icon trắng kế thừa màu chữ footer. */
.mini-foot-social {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
}
.mini-foot-social li { margin: 0; }
.mini-foot-social a {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 38px;
	height: 38px;
	border: 2px solid rgba(255, 255, 255, .6);
	border-radius: 50%;
	color: inherit;
	transition: background .2s, border-color .2s;
}
.mini-foot-social a:hover { background: rgba(255, 255, 255, .14); border-color: #fff; }
/* Mọi icon social dùng SVG inline (font gforces master-v10 không self-host). */
.mini-foot-social .icon-social { display: inline-flex; align-items: center; justify-content: center; color: inherit; line-height: 1; }
.mini-foot-social .icon-social svg { display: block; width: 18px; height: 18px; }
.mini-foot-social-txt { font-size: 15px; font-weight: 700; line-height: 1; }

@media (max-width: 767px) {
	.link-block.groups-4 { flex-direction: column; justify-content: flex-start; gap: 24px; }
	.link-block.groups-4 .link-group.mini-foot-about,
	.link-block.groups-4 .link-group:not(.mini-foot-about) { width: 100%; flex: none; min-width: 0; }
	.mini-foot-about { margin-bottom: 24px; }
}

/* ---------------------------------------------------------------------------
 * Trang Tin tức (page-tin-tuc.php) — lưới card bài viết.
 * Dùng chung nguồn dữ liệu với carousel tin tức trang chủ. Card: ảnh 16:9 +
 * ngày + tiêu đề + tóm tắt + "ĐỌC TIẾP". Hover nâng nhẹ + ảnh zoom mượt.
 * ------------------------------------------------------------------------- */
/* Selector ghép 2 class, và `margin: 0` là BẮT BUỘC: khối bọc mang cả class
   `.row-fluid` nên nhận `margin: 0 -10px` của lưới gforces, triệt tiêu đúng lề
   10px của `.container` mà KHÔNG có ô `.span*` nào bên trong để trả lại. Hậu quả
   đã đo ở khung 375px: h1 "Tin tức" và cả 2 tiêu đề chuyên mục nằm ở lề 0, ảnh
   thẻ tin tràn sát hai mép. Lý do đầy đủ của cơ chế này ghi ở khối
   `.row-fluid.mini-cms-wrap` cuối file (kể cả chuyện phải ghép 2 class vì
   compressedmini.min.css được nạp lần thứ hai SAU file này). */
.mini-news-archive { padding: 3rem 0 4rem; }

/* ⚠️ Chỉ áp từ 991px xuống. Trên desktop, lề âm -10px lại đang kéo khối tin về
   ĐÚNG mạch dọc của site (đo ở 1265px: tiêu đề ở 37, logo và chữ trang tĩnh ở
   40); bỏ lề âm ở đó thì tiêu đề nhảy sang 57, lệch 20px so với mọi thứ quanh
   nó. Lỗi "chữ dán mép" chỉ gây hại khi khung hẹp, nên vá đúng chỗ nó gây hại. */
@media (max-width: 991px) {
	.row-fluid.mini-news-archive {
		margin-left: 0;
		margin-right: 0;
		padding-left: 10px;
		padding-right: 10px;
	}
}
.mini-news-title { font-size: 32px; line-height: 1.2; margin: 0 0 12px; }
.mini-news-intro { margin: 0 0 32px; color: #444; }

/* Mỗi chuyên mục (category) là 1 mục lớn, cách nhau bằng khoảng + tiêu đề có gạch dưới. */
.mini-news-section { margin: 0 0 56px; }
.mini-news-section:last-child { margin-bottom: 0; }
.mini-news-section-title {
	font-size: 24px;
	line-height: 1.2;
	font-weight: 700;
	margin: 0 0 24px;
	padding: 0 0 12px;
	border-bottom: 2px solid #1a1a1a;
}

.mini-news-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 32px 28px;
}
.mini-news-card { background: #fff; }
.mini-news-card-link {
	display: flex;
	flex-direction: column;
	height: 100%;
	color: #1a1a1a;
	text-decoration: none;
}
.mini-news-thumb {
	display: block;
	position: relative;
	width: 100%;
	aspect-ratio: 16 / 9;
	overflow: hidden;
	background: #ececec;
}
.mini-news-thumb .mini-news-img,
.mini-news-thumb img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	transition: transform .45s cubic-bezier(.2, .7, .3, 1);
}
.mini-news-thumb-empty { display: block; width: 100%; height: 100%; background: #e4e4e4; }
.mini-news-card-link:hover .mini-news-img,
.mini-news-card-link:hover img { transform: scale(1.05); }

.mini-news-body { display: flex; flex-direction: column; flex: 1 1 auto; padding: 18px 2px 0; }
.mini-news-date { font-size: 12px; letter-spacing: .04em; text-transform: uppercase; color: #888; margin: 0 0 8px; }
.mini-news-card-title { font-size: 17px; line-height: 1.35; font-weight: 700; margin: 0 0 10px; }
.mini-news-excerpt { font-size: 14px; line-height: 1.6; color: #555; margin: 0 0 16px; }
.mini-news-more {
	margin-top: auto;
	font-size: 13px;
	font-weight: 700;
	letter-spacing: .06em;
	text-transform: uppercase;
	border-bottom: 2px solid #1a1a1a;
	padding-bottom: 2px;
	align-self: flex-start;
}
.mini-news-card-link:hover .mini-news-card-title { text-decoration: underline; }
.mini-news-empty { color: #888; padding: 24px 0; }

/* Phân trang của archive.php (the_posts_pagination). Bộ CSS gforces KHÔNG có style cho
   .page-numbers (đã kiểm), nên thiếu khối này thì phân trang hiện ra là một dãy số trần
   dính liền nhau — bấm được nhưng khách không nhận ra đó là nút bấm. */
.mini-news-pagination { margin: 40px 0 0; }
.mini-news-pagination .nav-links {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	align-items: center;
	/* Căn giữa đặt tay có chủ ý: class 'pagination' của gforces (chỗ duy nhất có
	   text-align:center) KHÔNG còn trên thẻ <nav> này — lý do đã đo ghi trong archive.php.
	   Mà kể cả nếu còn thì text-align cũng không căn được flex item. */
	justify-content: center;
}
.mini-news-pagination .page-numbers {
	display: inline-block;
	min-width: 40px;
	padding: 9px 12px;
	border: 1px solid #d5d5d5;
	text-align: center;
	font-size: 14px;
	line-height: 1.2;
	color: #111;
	text-decoration: none;
}
.mini-news-pagination a.page-numbers:hover { border-color: #111; }
.mini-news-pagination .page-numbers.current {
	background: #111;
	border-color: #111;
	color: #fff;
	font-weight: 700;
}
.mini-news-pagination .page-numbers.dots {
	border-color: transparent;
	padding-left: 4px;
	padding-right: 4px;
}

@media (max-width: 991px) {
	.mini-news-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 575px) {
	.mini-news-grid { grid-template-columns: 1fr; }
	.mini-news-title { font-size: 26px; }
}

/**
 * Chuyển model mượt (MEET THE FAMILY, .tabs.model-range).
 * gforces đổi tab bằng display none→block (cứng, "nhảy"). Pane khi hiện ra
 * (.active = display:block) chạy fade-in + trượt nhẹ lên → chuyển êm thay vì
 * giật. Chỉ animate pane VÀO (pane ra display:none ngay, không transition được).
 * Tôn trọng prefers-reduced-motion: tắt animation cho người cần giảm chuyển động.
 *
 * ⚠️ `min-width: 979px` là BẮT BUỘC, không phải để cho đẹp. Cả animation này chỉ
 * đúng khi khối là tab thật — tức là chỉ pane active được hiện, 8 pane kia
 * display:none. Điều đó chỉ còn đúng từ 979px trở lên: compressedmini.min.css của
 * site gốc có `@media (max-width: 978px) { .blut--001A .tab-content { display: grid } }`
 * và ẩn `ul.tab-nav`, nên từ 978px xuống CẢ 9 PANE cùng hiện, xếp dọc thành một cột
 * cao 3405px. Khi đó "active" không còn ẩn cái nào, mà model-tabs-autoplay.js thì
 * vẫn click vào nav (đã ẩn) mỗi 6s để xoay active.
 *
 * Hậu quả đã đo ở khung 390px, trước khi giới hạn breakpoint: pane active đứng
 * nguyên `opacity: 0` suốt thời gian nó active — không phải fade 0.45s rồi hiện —
 * nên một ô xe BIẾN MẤT thành lỗ trắng 378px, và cái lỗ đó nhảy xuống dọc danh
 * sách theo nhịp autoplay (đo được active xoay 2 → 3 → 8). Đo hai chiều để chắc:
 * bật file này thì opacity pane active = 0, tắt file này thì = 1.
 *
 * ⚠️⚠️ VÌ SAO KEYFRAME KHÔNG CÒN `opacity` — đây mới là gốc rễ, breakpoint ở trên
 * chỉ là hệ quả. Trình duyệt TIẾT CHẾ animation ở mọi tài liệu không hiển thị:
 * tab nền, iframe ẩn, và quan trọng nhất là WEBVIEW TRONG ỨNG DỤNG (Zalo,
 * Facebook) — nơi rất nhiều khách mở link. Khi bị tiết chế, animation vẫn báo
 * `playState: "running"` nhưng `currentTime` ĐỨNG YÊN Ở 0 vô thời hạn, nên
 * trình duyệt áp đúng khung hình đầu. Khung hình đầu có `opacity: 0` thì nội dung
 * TRẮNG VĨNH VIỄN.
 *
 * Sự cố thật 2026-08-28: khách mở trang chủ bằng webview trên iPhone, khối ngay
 * dưới "MEET THE FAMILY" trắng xoá. Pane `.active` là pane đầu (`tab-m15-content`)
 * → đúng ô đó.
 *
 * ⚠️ Bỏ `animation-fill-mode: both` là KHÔNG ĐỦ — đã thử và đo lại: `fill: none`
 * mà computed opacity vẫn = 0, vì fill-mode chỉ chi phối lúc TRƯỚC/SAU animation,
 * còn khi animation đang "chạy" (dù đứng hình) thì keyframe vẫn thắng. Cách duy
 * nhất đúng là ĐỪNG ĐỂ opacity trong keyframe.
 *
 * Nay chỉ animate `transform`. Bị đóng băng ở khung đầu thì hậu quả tệ nhất là
 * pane nằm lệch 10px — vẫn đọc được, vẫn thấy ảnh xe. Nguyên tắc chung cho cả
 * theme: hiệu ứng trang trí KHÔNG BAO GIỜ được là thứ duy nhất khiến nội dung
 * hiện ra. Đừng đưa `opacity` (hay `visibility`) trở lại keyframe này.
 */
@media (prefers-reduced-motion: no-preference) and (min-width: 979px) {
	.tabs.model-range .tab-pane.active {
		animation: miniModelTabFade 0.45s ease;
	}
	@keyframes miniModelTabFade {
		from { transform: translateY(10px); }
		to   { transform: none; }
	}
}

/**
 * Trang /models/ — hiện ĐỦ thông số mỗi model (.new-model-tabs .jumps-cycle).
 * Mỗi pane có 1 list spec (Chỗ ngồi / Hành lý / Công suất / Quãng đường) bọc
 * trong widget gforces "jumpsCycle". Khi pane active, JS gforces biến list thành
 * carousel xoay 1 spec/lần: thêm 1 slide nhân bản (.cycle-sentinel) để giữ chiều
 * cao, set các slide còn lại display:none + position:absolute, container kẹp chiều
 * cao = 1 dòng. NHƯNG data-cycle-timeout rỗng → carousel KHÔNG tự xoay → kẹt vĩnh
 * viễn ở spec đầu (chỉ "Chỗ ngồi"), các spec sau bị ẩn → trông như "thiếu nội dung".
 *
 * Data KHÔNG thiếu — chỉ bị carousel ẩn. Ở đây ép hiện toàn bộ spec dạng list dọc
 * tĩnh: bỏ display:none + absolute trên mọi .item, để container co theo nội dung.
 * Ẩn riêng slide nhân bản .cycle-sentinel để không lặp lại spec đầu. Rule sentinel
 * đặt SAU rule .item (cùng specificity) để display:none thắng cho slide nhân bản.
 */
.new-model-tabs .jumps-cycle .cycle {
	height: auto !important;
}
.new-model-tabs .jumps-cycle .cycle > .item {
	display: block !important;
	position: relative !important;
	visibility: visible !important;
	opacity: 1 !important;
	top: auto !important;
	left: auto !important;
}
.new-model-tabs .jumps-cycle .cycle > .cycle-sentinel {
	display: none !important;
}

/**
 * Trang chi tiết (single-model) — khối spec ở hero (template-parts/model/hero.php)
 * dùng CÙNG widget jumpsCycle "cycle-overview-custom" như /models/ nhưng KHÔNG nằm
 * trong .new-model-tabs nên rule trên không phủ tới → spec hero cũng bị carousel co
 * lại còn 1 dòng ("Chỗ ngồi"). Ép hiện toàn bộ spec tĩnh y hệt, scope qua class
 * .cycle-overview-custom (chỉ dải spec, KHÔNG đụng carousel ảnh/gallery khác).
 */
.jumps-cycle.cycle-overview-custom .cycle {
	height: auto !important;
}
.jumps-cycle.cycle-overview-custom .cycle > .item {
	display: block !important;
	position: relative !important;
	visibility: visible !important;
	opacity: 1 !important;
	top: auto !important;
	left: auto !important;
}
.jumps-cycle.cycle-overview-custom .cycle > .cycle-sentinel {
	display: none !important;
}

/* ===========================================================================
 * THANH QUICK LINKS (pre-footer) — self-host thay module gforces ngoài.
 * Bám SÁT bản gốc: thanh gọn 1 hàng LUÔN hiển thị — social (nút tròn đen, dùng
 * NGUYÊN CSS circle + hover-màu của gforces gốc) bên trái; link pháp lý + nút
 * QUICK LINKS bên phải. Bấm QUICK LINKS → class .mini-qf-open: footer 4 cột
 * trượt xuống mượt + chevron xoay lên; bấm lại để đóng (không cần nút "Thu gọn").
 *
 * Icon: glyph font mini-asia của gforces (.icon-facebook:before…) computed RỖNG
 * trong clone → không render đáng tin. Vì vậy social đặt SVG trắng tự host LÊN
 * TRÊN circle gốc (span chỉ giữ class .icon-social = z-index:1, ĐÃ bỏ class
 * .icon-$platform để glyph không bao giờ render đè → hết nhân đôi). Chevron
 * QUICK LINKS dùng tam giác CSS + suppress glyph .toggle-company .icon::before.
 * !important để thắng compressedmini.min.css (gforces) load sau ở header.
 * ======================================================================== */
#pre-footer-wrap .container-wrap { background: #fff; }

/* hàng thanh gọn: social trái — link + QUICK LINKS dồn phải, căn giữa theo dọc */
#pre-footer-wrap .row-r2gei {
	display: flex !important;
	flex-direction: row !important; /* thắng class gforces flex--container-direction-column */
	align-items: center;
	flex-wrap: wrap;
	gap: 4px 28px;
	padding: 8px 24px;
	border-top: 1px solid #e6e6e6;
}
#pre-footer-wrap .row-r2gei .social-icons  { order: 1; float: none !important; width: auto !important; padding: 0 !important; }
#pre-footer-wrap .row-r2gei .site-links    { order: 2; margin-left: auto; float: none !important; width: auto !important; padding: 0 !important; }
#pre-footer-wrap .row-r2gei .toggle-company { order: 3; margin-left: auto; float: none !important; width: auto !important; padding: 0 !important; }
#pre-footer-wrap .social-icons .inner { float: none !important; width: auto !important; padding: 0 !important; }
/* Khi panel QUICK LINKS mở: ẩn social + link pháp lý ở thanh gọn (panel 4 cột
 * đã có social + link riêng) — chỉ chừa nút QUICK LINKS để đóng lại. */
#pre-footer-wrap.mini-qf-open .row-r2gei .social-icons,
#pre-footer-wrap.mini-qf-open .row-r2gei .site-links { display: none !important; }

/* social: giữ NGUYÊN circle đen 45px + hover-màu brand của gforces gốc; chỉ
   chuẩn hoá chiều cao ul (gốc ép 104px quá cao cho thanh gọn) + đặt SVG trắng lên */
#pre-footer-wrap .mus--004A .social-icons ul { height: auto !important; gap: 4px; margin: 0; }
#pre-footer-wrap .social-icons .mini-soc { display: flex; align-items: center; justify-content: center; }
#pre-footer-wrap .social-icons .mini-soc svg { width: 20px; height: 20px; fill: #fff; display: block; }
#pre-footer-wrap .social-icons .mini-foot-social-txt { color: #fff; font-weight: 700; font-size: 16px; line-height: 1; }

/* link pháp lý */
#pre-footer-wrap .site-links { height: auto !important; }
#pre-footer-wrap .mini-qf-links { display: flex; flex-wrap: nowrap; align-items: center; gap: 2px 24px; list-style: none; margin: 0; padding: 0; height: auto !important; }
/* gforces ép li line-height:104px (cao gấp đôi) → kéo về 45px cho cân thanh gọn */
#pre-footer-wrap .mini-qf-links li { margin: 0; padding: 0; list-style: none; line-height: 45px !important; white-space: nowrap; }
#pre-footer-wrap .mini-qf-links a { color: #1a1a1a; text-decoration: none; font-size: 14px; line-height: 45px; transition: color .2s ease; }
#pre-footer-wrap .mini-qf-links a:hover { color: #000; text-decoration: underline; }

/* nút QUICK LINKS + chevron tam giác (suppress glyph gforces → không nhân đôi) */
#pre-footer-wrap .toggle-company a {
	display: inline-flex; align-items: center; gap: 9px;
	color: #1a1a1a; font-weight: 400; font-size: 14px; letter-spacing: .04em;
	text-transform: uppercase; text-decoration: none; line-height: 45px; cursor: pointer;
}
#pre-footer-wrap .toggle-company a:hover { color: #000; }
#pre-footer-wrap .toggle-company .icon::before { content: none !important; }
#pre-footer-wrap .toggle-company .icon {
	display: inline-block; width: 0 !important; height: 0 !important; font-size: 0 !important;
	border-left: 5px solid transparent; border-right: 5px solid transparent;
	border-top: 6px solid currentColor;
	transition: transform .3s ease;
}
#pre-footer-wrap.mini-qf-open .toggle-company .icon { transform: rotate(180deg) !important; }

/* footer 4 cột: ẩn mặc định, trượt xuống khi mở */
#pre-footer-wrap .toggle__company-information .toggle-heading { display: none !important; }
#pre-footer-wrap .toggle__company-information .toggle-body {
	display: block !important;
	overflow: hidden;
	max-height: 0;
	opacity: 0;
	transition: max-height .5s ease, opacity .4s ease;
}
/* gforces có rule specificity cao hơn ép max-height:0 → cần !important để mở */
#pre-footer-wrap.mini-qf-open .toggle__company-information .toggle-body {
	max-height: 2400px !important;
	opacity: 1 !important;
}

/* ---------------------------------------------------------------------------
   ĐIỆN THOẠI: thanh gọn phải XẾP DỌC, không nhồi 1 hàng.
   Rule `flex-direction: row !important` ở trên viết cho desktop nhưng KHÔNG có
   @media nên nó đè luôn cả mobile — đúng chỗ này là gốc lỗi. Ở 390px, ba khối
   (social + link pháp lý + nút QUICK LINKS) chen một hàng làm cột link co còn
   108px, chữ tràn khỏi mép phải.

   Bản gốc của hãng giải quyết bằng chính class `flex--container-direction-column`
   có sẵn trong markup ta (`footer.php` đã copy đủ class) — chỉ bị rule trên
   triệt tiêu. Nên ở đây trả lại đúng hành vi gốc, cùng ngưỡng `@sm` = 768px
   mà gforces dùng (`block--container@sm`), chứ không tự đặt 640px.

   Khối 640px cũ chỉ thu nhỏ chữ và khoảng cách — KHÔNG giải được, vì ba khối
   vẫn nằm cùng hàng. Đừng quay lại cách đó.

   Lợi ích kèm theo đã đo được: ở bố cục 1 hàng, nút QUICK LINKS nằm sát mép
   phải-dưới nên bị hai nút nổi Zalo/Gọi (`inc/contact-fab.php`) CHE MẤT vùng
   bấm — Playwright báo thẳng "mini-fab … intercepts pointer events", tức khách
   dùng điện thoại không bấm mở được footer. Xếp dọc, nút trải hết chiều ngang
   nên nửa trái luôn bấm được.

   LỀ TRÁI/PHẢI phải đặt trên TỪNG KHỐI CON, không đặt trên hàng: markup mang
   sẵn class tiện ích `pl-0` (`.pl-0{padding-left:0!important}` trong CSS gforces)
   ngay trên `.row-r2gei`, nên `padding` viết cho hàng bị nuốt sạch mà không báo
   lỗi — đo ra `padding: 6px 0px 14px` và chữ dính mép trái. Site hãng cũng đặt
   `padding-left: 20px` trên `.toggle-company` và `.social-icons`, không đặt ở hàng.

   KHOẢNG AN TOÀN 124px Ở ĐÁY: hai nút nổi Zalo/Gọi là `position: fixed`, đã đo
   chiếm dải cao 120px sát đáy khung nhìn, từ x=328 trở sang phải. Khi cuộn hết
   trang, mũi tên mở QUICK LINKS rơi đúng vào dải đó → khách bấm không ra. Chèn
   khoảng trống cuối trang đẩy chân trang lên trên vùng nút, không cần JS.
   Đo lại bằng: node tools/qa/webkit-fab-de.mjs <url>
   --------------------------------------------------------------------------- */
@media (max-width: 767px) {
	#pre-footer-wrap { padding-bottom: 124px !important; }
	#pre-footer-wrap .row-r2gei {
		flex-direction: column !important;
		align-items: stretch;
		flex-wrap: nowrap;
		gap: 0;
		padding: 0 0 18px !important;
	}
	/* bỏ `margin-left: auto` của bố cục 1 hàng, nếu không hai khối vẫn bị dồn phải */
	#pre-footer-wrap .row-r2gei .site-links,
	#pre-footer-wrap .row-r2gei .toggle-company { margin-left: 0; }
	/* !important để thắng `padding: 0 !important` của bố cục 1 hàng ở khối trên */
	#pre-footer-wrap .row-r2gei .social-icons,
	#pre-footer-wrap .row-r2gei .site-links,
	#pre-footer-wrap .row-r2gei .toggle-company { padding: 0 20px !important; }
	#pre-footer-wrap .row-r2gei .social-icons { padding-top: 16px !important; padding-bottom: 16px !important; }
	/* mỗi link một dòng trọn chiều ngang, cao 44px cho vừa đầu ngón tay */
	#pre-footer-wrap .mini-qf-links { flex-wrap: wrap; gap: 0; }
	#pre-footer-wrap .mini-qf-links li { line-height: 44px !important; width: 100%; }
	#pre-footer-wrap .mini-qf-links a { line-height: 44px; display: block; }
	#pre-footer-wrap .toggle-company a {
		display: flex;
		justify-content: space-between;
		line-height: 48px;
		width: 100%;
	}
}

/* ---------- Chống bot ---------- */
/* Honeypot: phải ẩn với người nhưng vẫn nằm trong form để bot điền vào.
   Không dùng type="hidden" — bot thường bỏ qua input hidden, đúng cái ta muốn nó điền.
   Không dùng display:none đơn lẻ: một số bot lọc theo đúng luật đó. */
.mini-hp {
	position: absolute !important;
	left: -9999px !important;
	top: auto !important;
	width: 1px !important;
	height: 1px !important;
	overflow: hidden !important;
	opacity: 0 !important;
	pointer-events: none !important;
}

/* ============================================================
   POPUP
   Hộp thoại nổi do CPT `popup` sinh ra. Markup ở inc/popups.php,
   hành vi ở assets/js/mini-popup.js.
   z-index cực cao là CỐ Ý: chủ project có thể nhúng widget chat
   qua trang "Tracking & mã nhúng", popup phải nằm trên chúng.
   ============================================================ */
.mini-popup[hidden] { display: none; }

.mini-popup {
	position: fixed;
	inset: 0;
	z-index: 2147483000;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 16px;
	opacity: 0;
	transition: opacity .18s ease;
}

.mini-popup.is-open { opacity: 1; }

.mini-popup__backdrop {
	position: absolute;
	inset: 0;
	background: rgba(0, 0, 0, .62);
	border: 0;
	padding: 0;
	margin: 0;
	cursor: pointer;
}

.mini-popup__box {
	position: relative;
	z-index: 1;
	width: 100%;
	max-width: 460px;
	max-height: 90vh;
	overflow-y: auto;
	-webkit-overflow-scrolling: touch;
	background: #fff;
	border-radius: 4px;
	box-shadow: 0 18px 48px rgba(0, 0, 0, .32);
	transform: translateY(12px);
	transition: transform .18s ease;
}

.mini-popup.is-open .mini-popup__box { transform: translateY(0); }

.mini-popup__close {
	position: absolute;
	top: 6px;
	right: 6px;
	z-index: 2;
	width: 40px;
	height: 40px;
	display: flex;
	align-items: center;
	justify-content: center;
	background: rgba(255, 255, 255, .92);
	border: 0;
	border-radius: 50%;
	font-size: 24px;
	line-height: 1;
	color: #111;
	cursor: pointer;
}

.mini-popup__close:hover { background: #fff; }
.mini-popup__close:focus-visible { outline: 2px solid #111; outline-offset: 2px; }

.mini-popup__image {
	display: block;
	width: 100%;
	height: auto;
	border-radius: 4px 4px 0 0;
}

.mini-popup__body { padding: 22px 24px 24px; }

.mini-popup__title {
	margin: 0 0 10px;
	font-size: 22px;
	line-height: 1.25;
	font-weight: 700;
	color: #111;
}

.mini-popup__text {
	margin: 0 0 16px;
	font-size: 15px;
	line-height: 1.55;
	color: #444;
}

.mini-popup__cta {
	display: inline-block;
	padding: 12px 22px;
	background: #111;
	color: #fff;
	font-size: 15px;
	font-weight: 600;
	text-decoration: none;
	border-radius: 2px;
}

.mini-popup__cta:hover { background: #000; color: #fff; }

/* Form Fluent Forms trong popup: thu nhỏ khoảng cách cho vừa hộp,
   và cho nút Gửi chiếm hết chiều ngang vì ngón tay bấm dễ hơn. */
.mini-popup__form .ff-el-group { margin-bottom: 12px; }
.mini-popup__form .ff-btn-submit { width: 100%; }

@media (max-width: 480px) {
	.mini-popup { padding: 10px; align-items: flex-end; }
	.mini-popup__box { max-height: 94vh; }
	.mini-popup__body { padding: 18px 16px 20px; }
	.mini-popup__title { font-size: 19px; }
}

/* ---- Khối nội dung riêng của showroom dưới bài ưu đãi ---- */
.mini-offer-local {
	background: #f4f4f4;
	border-top: 3px solid #000;
	margin-top: 2rem;
	padding: 2.5rem 0;
}
.mini-offer-local__title {
	font-size: 1.5rem;
	letter-spacing: .02em;
	margin: 0 0 1rem;
	text-transform: uppercase;
}
.mini-offer-local__body p:last-child { margin-bottom: 0; }
.mini-offer-local__phone {
	font-size: 1.125rem;
	font-weight: 700;
	margin-top: 1.25rem;
}
.mini-offer-local__phone a { text-decoration: underline; }
@media (max-width: 767px) {
	.mini-offer-local { padding: 1.75rem 0; }
	.mini-offer-local__title { font-size: 1.25rem; }
}

/* ============================================================
   NÚT LIÊN HỆ NỔI — Zalo + Gọi
   Markup ở inc/contact-fab.php (hook wp_footer priority 4).
   Port từ dự án FINANCE (.chatbox-fab), bỏ phần chatbox.

   z-index 1010 KHÔNG phải con số cho đẹp — nó được CHỌN từ các
   giá trị đã ĐO trong compressedmini.min.css của site gốc:
     .slide-out-toggle>.toggle-body  2000  ← menu mobile (hamburger)
     .modal                          1050
     header-container>header         1015
     nội dung thường                 auto
   Đặt 1010 để hai nút nằm TRÊN mọi nội dung nhưng DƯỚI menu mobile
   và modal. Nếu đặt z-index rất cao (bản nháp đầu dùng 2147482000)
   thì khi khách mở menu hamburger trên điện thoại, hai nút nổi lên
   ĐÈ TRÊN tấm menu đang mở — lỗi thấy được, không có cảnh báo nào.
   Popup của theme (2147483000) vẫn phủ lên đúng như một modal nên
   không cần xử lý riêng.

   Đã ĐO: `.button.whatsapp-sticky` của site gốc (bottom:30px;
   right:30px; 64px) CÓ trong header.php nhưng mang class `hidden`
   (display:none!important) nên KHÔNG chồng chỗ. Nếu sau này ai bỏ
   class đó thì hai nút sẽ đè nhau — đổi `bottom` ở đây, đừng đổi
   z-index.
   ============================================================ */
.mini-fab {
	position: fixed;
	bottom: 18px;
	z-index: 1010;
	display: flex;
	flex-direction: column;
	gap: 12px;
	align-items: center;
}

/* Bên nào do admin chọn — ô "Vị trí 2 nút nổi" trong menu Liên hệ & chia sẻ.
   Khoảng cách theo trục ngang tách hẳn thành hai class thay vì viết
   `right:18px` ở khối chung rồi để bản `--left` ghi đè bằng `right:auto`:
   cách ghi đè khiến bố cục phụ thuộc vào THỨ TỰ khai trong file, chỉ cần một
   lần sắp xếp lại CSS là hai nút dính cả hai bên. Hai nhánh rời nhau thì
   không có gì phải ghi đè. */
.mini-fab--right { right: 18px; }
.mini-fab--left  { left: 18px; }

.mini-fab__btn {
	position: relative;
	width: 52px;
	height: 52px;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	color: #fff;
	text-decoration: none;
	box-shadow: 0 8px 22px -8px rgba(0, 0, 0, .45);
	transition: transform .2s, box-shadow .2s;
}

.mini-fab__btn:hover,
.mini-fab__btn:focus {
	color: #fff;
	transform: scale(1.1);
	box-shadow: 0 12px 28px -8px rgba(0, 0, 0, .55);
}

.mini-fab__btn--zalo { background: #0068ff; }
.mini-fab__btn--call { background: #16a34a; }
.mini-fab-zalo { display: block; }

/* Vòng sóng lan toả. background:inherit + z-index:-1 để vòng sóng lấy đúng
   màu của từng nút và nằm DƯỚI nút, không che icon. */
.mini-fab__btn::before {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: 50%;
	background: inherit;
	z-index: -1;
	animation: miniFabPulse 2.4s ease-out infinite;
}

@keyframes miniFabPulse {
	0%   { transform: scale(1);   opacity: .45; }
	70%  { transform: scale(1.5); opacity: 0; }
	100% { transform: scale(1.5); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
	.mini-fab__btn::before { animation: none; opacity: 0; }
	.mini-fab__btn { transition: none; }
}

@media (max-width: 767px) {
	.mini-fab { bottom: 14px; gap: 10px; }
	.mini-fab--right { right: 14px; }
	.mini-fab--left  { left: 14px; }
	.mini-fab__btn { width: 48px; height: 48px; }
	.mini-fab-zalo { width: 36px; }
}

/* ==========================================================================
   Lề ngang của khối nội dung do nhân viên tự viết (page.php, single.php,
   single-offer.php, single-model.php — nhánh fallback, KHÔNG phải HTML tĩnh)

   Lưới của site gốc là kiểu Bootstrap 2: `.container` có `margin: 0 10px`, và
   `.row-fluid` có `margin: 0 -10px` để TRIỆT TIÊU đúng khoản đó — khoản 10px ấy
   được trả lại bởi `padding: 0 10px` của các ô `.span*` bên trong. Bốn template
   fallback trên dùng `.row-fluid` làm khối bọc nhưng KHÔNG có ô `.span*` nào bên
   trong, nên lề âm không có gì bù: chữ dán sát mép màn hình (đo được lề trái = 0
   trên iPhone 375px, trong khi mọi trang tĩnh của site là 20).

   Nặng hơn: nội dung dán từ editor thường chứa thêm `.row-fluid` (bài đồng bộ về
   có 14 khối) → lề âm -10px áp LẦN THỨ HAI trên một khối đã hết chỗ triệt tiêu
   → khối rộng 395px trong khung 375px, trang KÉO NGANG được 10px. Đã đo trước và
   sau: `scrollWidth` 385 → 375, và 16 khối chữ dịch từ lề 0 sang lề 20, khớp
   đúng số đo của trang tĩnh /about-us/.

   Vì sao vá ở khối bọc chứ không ở `.mini-cms-content .row-fluid`: vá bên trong
   chỉ chữa phần tràn, còn tiêu đề / ngày / strapline do template tự in vẫn dán
   mép. Cần CẢ HAI khai báo, và cộng ra đúng 20px: `margin: 0` bỏ lề âm nên khối
   bọc nằm đúng trong `.container` (10→365), rồi `padding: 0 10px` cho ruột ở
   20→355 — chính là con số đo được ở trang tĩnh.

   `.row-fluid` được GIỮ trong class list: nó còn mang clearfix cho nội dung có
   float. Chỉ vô hiệu hoá phần lề âm.

   ⚠️ Vì sao selector phải là `.row-fluid.mini-cms-wrap` chứ không phải
   `.mini-cms-wrap` cho gọn: `compressedmini.min.css` của site gốc được nạp HAI
   lần — header.php:160 và MỘT LẦN NỮA ở footer.php:488, tức là SAU file này. Rule
   `.row-fluid { margin: 0 -10px }` ở lần nạp thứ hai có cùng độ ưu tiên với một
   selector `.mini-cms-wrap` trần, nên nó thắng theo thứ tự nguồn và lề âm không
   bị vô hiệu hoá. Đã đo: bản viết trần cho ra lề chữ 10px thay vì 20px, KHÔNG có
   lỗi nào báo. Ghép hai class lại là (0,2,0) > (0,1,0) nên thắng chắc chắn.

   ⚠️ Và vì sao chỉ áp từ 991px xuống: trên desktop chính lề âm đó lại đang kéo
   khối về đúng mạch dọc của site (đo ở 1265px: chữ trang tĩnh và logo đều ở 40,
   khối này ở 37). Bỏ lề âm trên desktop thì nội dung nhảy sang 57 — sửa một lỗi
   ở khung hẹp mà tạo một lỗi lệch mạch ở khung rộng.
   ========================================================================== */
@media (max-width: 991px) {
	.row-fluid.mini-cms-wrap {
		margin-left: 0;
		margin-right: 0;
		padding-left: 10px;
		padding-right: 10px;
	}
}

/* ==========================================================================
   Vùng bấm của 4 nút trên thanh đầu trang BẢN ĐIỆN THOẠI (Gọi, Chỉ đường,
   đổi ngôn ngữ, mở menu — header.php:423, khối `.container-dqlqp`).

   Bản capture để thẻ <a> chỉ to bằng đúng icon: đo ở khung 375px được 25×25px
   cho Gọi và Chỉ đường, 24×24 cho nút menu, và 17×14 cho nút EN. Khuyến nghị
   của cả Apple (44pt) và Google (48dp) là 44–48px; 17×14 thì ngón tay bấm 3 lần
   mới trúng 1. Ô <div> bọc ngoài đã rộng sẵn 38×57 (46 cho nút menu) và đang
   BỎ TRỐNG — chỉ cần cho thẻ <a> nở ra bằng ô đó là xong, không phải nới layout.

   Đã đo cả hai chiều: 4 nút đều thành 38×44 / 46×44, `elementFromPoint` trúng
   thẻ <a> ở cả 5 điểm (tâm + 4 hướng), các ô <div> vẫn đứng nguyên chỗ
   (209/247/285/323) và trang không kéo ngang. `min-width: 100%` (không phải
   44px) là có chủ ý: 44px làm 4 vùng bấm CHỒNG LÊN NHAU 6px mỗi cặp — đo được
   điểm bên phải nút Gọi lại rơi vào nút Chỉ đường, tức là đổi lỗi "khó bấm"
   thành lỗi "bấm sai nút", tệ hơn.

   Icon KHÔNG dịch một pixel: nó là glyph của font `mini-asia` in qua `::before`
   của thẻ <i>, mà thẻ <i> đã có `text-align: center` sẵn, và chiều cao vẫn là
   25px ở đúng toạ độ cũ. Nở ngang thẻ <i> chỉ nở cái hộp, glyph vẫn nằm giữa.

   ⚠️ Đừng đổi sang cách "phủ vùng bấm bằng `::before` tuyệt đối" — đã thử và
   THẤT BẠI: `.btn` có `overflow: hidden`, ô phủ 44px bị cắt về đúng 25px nên
   vùng bấm KHÔNG to ra chút nào, dù CSS áp thành công và mọi giá trị computed
   đều đúng. Chỉ có phép thử `elementFromPoint` mới lộ ra. Và `::after` của
   `.btn` đã bị bản gốc dùng (hiệu ứng hover) — không được chiếm.

   Không cần `@media`: cả khối `.container-dqlqp` mang class `u-hidden-md-up`
   nên từ 768px trở lên nó đã `display: none`, rule ở đây không với tới bản
   desktop (bản desktop dùng `.u-hidden-sm-down`, là một thẻ <a> khác có nhãn).
   ========================================================================== */
.container-dqlqp .button > a.btn {
	display: flex;
	align-items: center;
	justify-content: center;
	min-width: 100%;
	min-height: 44px;
}

/* ==========================================================================
   Trang /models/ — ảnh đại diện mẫu xe bị "mất đầu mất đuôi" trên điện thoại
   --------------------------------------------------------------------------
   Ảnh xe ở mỗi hàng KHÔNG phải thẻ <img>, mà là một CSS sprite: ô
   `h4::after` rộng 120px cao 90px là "cửa sổ" nhìn vào ảnh ghép
   `new-listing-models-sprite.webp` (kích thước thật 11952 × 386).

   Ảnh ghép được phóng theo `background-size` tính bằng PHẦN TRĂM, nhưng vị
   trí từng khung lại tính bằng PIXEL TUYỆT ĐỐI (0, -598px, -838px, -958px,
   -1078px, -1198px, -1319px, -2161px). Nên chỉ cần sai tỉ lệ phóng là MỌI
   khung trượt đi, cửa sổ rơi vào giữa hai xe → nhìn thấy hai nửa xe.

   Bản `compressedmini.min.css` ta chụp về mang giá trị lỗi thời `2214%`,
   trong khi ảnh ghép đi kèm cần `2309%`. Bằng chứng nằm ngay trong chính
   file đó: rule anh em `.tab-nav > li > a::before` (bản desktop, cùng ảnh
   ghép, cùng khung 120×90, cùng dải offset) đã dùng `2309%`. Site hãng hiện
   tại cũng phục vụ `2309%` cho cả hai. Đã đối chiếu: ảnh ghép hai bên là
   CÙNG MỘT FILE (cùng hash, 11952 × 386) — chỉ CSS lệch.

   Sửa ở đây thay vì sửa `site-assets/` vì `site-assets/` không nằm trong git
   nên deploy code-only sẽ không mang thay đổi đó lên server.

   ⚠️ Đừng "sửa" bằng cách đổi các `background-position` cho khớp `2214%`:
   sẽ phải chỉnh 8 giá trị và lần sau hãng cập nhật ảnh ghép là hỏng lại.

   ⚠️ BẮT BUỘC `!important`: `compressedmini.min.css` được nạp HAI LẦN — lần
   hai ở `footer.php`, tức SAU `mini-fixes.css`. Hai rule có cùng độ ưu tiên
   (0,4,2) nên bản gforces nạp sau luôn thắng. Bản đầu tôi viết không có
   `!important` và deploy lên production vẫn ra `2214%` dù file đúng md5 —
   không có lỗi nào báo. Đo bằng `node tools/qa/webkit-sprite-info.mjs <url>`.
   ========================================================================== */
[class*='new'].listing .new-model-tabs .toggle-heading h4::after {
	background-size: 2309% auto !important;
}

/* ==========================================================================
   Ảnh trong bài bị bóp méo — sai ở BIẾN THỂ ẢNH ĐÃ LƯU, không sai ở bố cục
   --------------------------------------------------------------------------
   Đã đo cùng một ảnh trên hai site, CSS giống hệt nhau: khung 350×233,
   `aspect-ratio: 3/2`, `object-fit` mặc định là `fill`. Khác nhau ở FILE:

     hãng : .../w_350,h_233,dpr_2.0,q_auto,c_fill,.../j01_dimensions.jpg → 700×466 (3:2)
     ta   : .../q_auto,c_fill,f_auto,fl_lossy/.../j01_dimensions.jpg     → 800×800 (1:1)

   Cloudinary `c_fill` là "cắt giữa cho vừa khung". Hãng truyền kèm `w_`/`h_`
   nên máy chủ cắt sẵn thành 3:2. Bản ta chụp về rụng mất `w_`/`h_` nên máy chủ
   trả ảnh nguyên khổ; nhét ảnh 1:1 vào khung 3:2 với `fill` là bóp dẹt 50%.

   `object-fit: cover` chính là `c_fill` làm ở phía trình duyệt (cùng cắt giữa),
   nên đây KHÔNG phải mẹo che lỗi mà là dựng lại đúng hành vi của hãng.
   Đã quét 11 trang: 22 ảnh lệch tỉ lệ > 8%. Ảnh nào đã đúng tỉ lệ thì `cover`
   cho ra kết quả y hệt `fill`, nên áp cho cả lớp `.responsive-image` là an toàn
   (42/43 ảnh mỗi trang mang lớp này).

   Không sửa bằng cách tải lại ảnh đúng khổ vào `site-assets/`: thư mục đó
   không nằm trong git và deploy code-only bỏ qua, nên bản vá sẽ không lên
   được server và sẽ mất khi nhân bản site.

   ⚠️ BẮT BUỘC `!important` — xem lý do ở khối ngay trên (CSS gforces nạp 2 lần).
   Đo bằng: node tools/qa/webkit-anh-lech.mjs <gốc-url> <các-đường-dẫn>
   ========================================================================== */
img.responsive-image {
	object-fit: cover !important;
}

/* ==========================================================================
   Tên mẫu xe ở đầu trang bị chữ trắng trên nền trắng — CỐ Ý LỆCH KHỎI BẢN GỐC
   --------------------------------------------------------------------------
   Khối tiêu đề mang class `color-white` (dành cho chữ đè lên ảnh nền tối) nhưng
   lại nằm trong `div.layout-1` nền `#f7f7f7`. Đo được: chữ `rgb(255,255,255)`
   trên nền `rgb(247,247,247)` — tương phản gần bằng 0, tên xe gần như tàng hình.

   ĐÃ ĐỐI CHỨNG: site hãng mini-vietnam.com bị Y HỆT. Đây KHÔNG phải lỗi ta gây
   ra khi clone, mà là lỗi sẵn có của bản gốc. Vẫn sửa, vì tên xe không đọc được
   trên trang bán xe là hỏng chức năng, không phải khác biệt thẩm mỹ.

   Phạm vi cố ý hẹp: CHỈ `.jump-intro` (khối tên xe đầu trang). Đã quét 7 trang,
   mọi `.jump-intro` đều nằm trên nền sáng (L=247). KHÔNG đụng các khối
   `.jump-custom.jump-one…seven`: chữ trắng ở đó nằm ĐÈ LÊN ẢNH nên đang đúng —
   máy quét báo chúng "nền sáng" là báo động giả, vì ảnh là thẻ <img> chứ không
   phải `background-image`.
   Đo lại bằng: node tools/qa/webkit-chu-trang.mjs <gốc-url> <các-đường-dẫn>
   ========================================================================== */
.jump.jump-intro.grouped-text.color-white,
.jump.jump-intro.grouped-text.color-white .title,
.jump.jump-intro.grouped-text.color-white .title span {
	color: #1a1a1a !important;
}

/* ==========================================================================
   Trang chủ "ảnh khổng lồ + trắng trang" TRONG LÚC CHỜ JS
   --------------------------------------------------------------------------
   Đo được trên WebKit/iPhone 13, so hai trạng thái cùng một URL:

     khối `.jumps-cycle.cycle-features`   chưa có JS: 6645px   sau khi JS chạy: 814px
     cả trang                             chưa có JS: 12342px  sau khi JS chạy: 6326px

   Nguyên nhân: `div.cycle` chứa 10 `div.item` xếp DỌC trong HTML. Carousel chỉ
   thành hình khi JS của gforces bọc chúng vào `.cycle-carousel-wrap` (đo được:
   con trực tiếp của `.cycle` từ 10 → 2). Trước thời điểm đó không có quy tắc CSS
   nào giữ khung, nên 10 slide xổ hết ra: mỗi ảnh chiếm trọn bề ngang và giữa các
   slide là những mảng trắng lớn. Trên máy dev việc này qua trong ~2,6 giây nên
   không thấy; trên iPhone dùng mạng di động nó kéo dài đủ lâu để khách nhìn thấy,
   và tải lại thì lúc gặp lúc không — đúng như phản ánh "lúc bị lúc không".

   Cách vá: chỉ giữ slide đầu cho tới khi JS dựng xong carousel. Sau khi JS chạy,
   con thứ 2 của `.cycle` là `.cycle-carousel-wrap` chứ không còn là `.item`, nên
   quy tắc tự hết tác dụng — không cần class trạng thái, không cần JS phụ.

   ⚠️ Phạm vi CỐ Ý hẹp ở `.jumps-cycle`. KHÔNG áp cho `.cyclr.banner` (băng-rôn
   đầu trang): khối đó sau khi JS chạy vẫn để 4 `div.item` làm con TRỰC TIẾP của
   `.cycle`, dùng chung quy tắc sẽ ẩn mất 3 slide băng-rôn vĩnh viễn. Đã đo:
   băng-rôn cao 558px ở CẢ HAI trạng thái nên vốn không có lỗi này.

   ⚠️ BẮT BUỘC `!important` — CSS gforces nạp 2 lần, bản ở footer.php nạp SAU
   mini-fixes.css nên cùng độ ưu tiên là ta thua.
   Đo lại bằng: node tools/qa/webkit-lech-bo-cuc.mjs <url>
   ========================================================================== */
.jumps-cycle .cycle > .item:nth-child(n + 2) {
	display: none !important;
}

/* ==========================================================================
   Bảng con của mục TIN TỨC neo lệch sang trái ~214px (trông như thuộc mục
   "ĐĂNG KÝ LÁI THỬ")

   Gốc rễ, đã đo bằng tools/qa/do-menu-va-chu-dinh.mjs:
     DỊCH VỤ  -> cssLeft=0px      cssRight=-196px  lệch  -16px  (đúng)
     TIN TỨC  -> cssLeft=-198px   cssRight=0px     lệch -214px  (sai)
   Con số khớp chính xác phép tính neo mép phải: li.left 779 + li.width 86
   - submenu.width 300 = 565 = đúng toạ độ đo được.

   Thủ phạm là một dòng trong compressedmini.min.css:
     .nav>li.dropdown-align-right .dropdown-menu,
     .nav>li:last-child .dropdown-menu { left:auto; right:0 }
   Mục cuối danh sách thì bảng con tự neo mép phải. Ở site gốc mục cuối sát lề
   phải nên hợp lý; ở site này TIN TỨC (đặt cuối theo yêu cầu chủ project) còn
   cách lề phải cả nghìn pixel nên thành sai.

   ⚠️ BẮT BUỘC `!important`: đã đo thứ tự nạp CSS trên trang mẫu xe là
   compressedmini → mini-fixes → compressedmini (nạp LẦN HAI, ở footer.php).
   Bản gforces nạp SAU ta, nên cùng độ ưu tiên là ta thua.

   Không sửa bằng cách bỏ TIN TỨC khỏi vị trí cuối — vị trí đó là yêu cầu của
   chủ project. Cũng không bám `li:last-child` (thứ tự mục có thể đổi) hay
   `.tin-tức` (class có dấu, phải escape trong CSS mới khớp).
   Đo lại bằng: node tools/qa/do-menu-va-chu-dinh.mjs <url>
   ========================================================================== */
.nav > li.mini-dropdown-left > .dropdown-menu {
	left: 0 !important;
	right: auto !important;
}

/* ==========================================================================
   Chữ đè lên nhau trong khối teaser ở trang chi tiết mẫu xe

   Triệu chứng: tiêu đề lớn đè lên đoạn văn và lên nút "Khám phá thêm".
   Đo trên 7 trang (tools/qa/do-pham-vi-height0.mjs): chỉ trang CHI TIẾT mẫu xe
   bị — all-electric-mini-cooper 65 khối, mini-countryman 70, mini-cooper-3-door
   30; còn /, /models/, /offers/, /services/ đều 0.

   Gốc rễ (tools/qa/do-nguon-chieu-cao.mjs): JS gforces gán INLINE
   `style="height:0px"` cho span.strapline và span.content để chuẩn bị hiệu ứng
   mở dần, rồi script vỡ giữa đường — console có 2 lỗi thật:
     Uncaught SyntaxError: querySelector('> .cycle-pager') is not a valid selector
     Uncaught TypeError:  Cannot read properties of null (reading 'querySelectorAll')
   Không ai mở height nữa, cha giữ 0 vĩnh viễn, còn chữ con vẫn vẽ ra ngoài
   (overflow visible) nên chồng lên phần bên dưới. Đo được:
     span.strapline  cao   0px  <- nội dung thật  47px
     span.content    cao  18px  <- nội dung thật 145px

   ⚠️ KHÔNG phải do việc dọn/dịch 8 trang mẫu xe gây ra. Đã kiểm chứng bằng cách
   phục hồi mini-countryman.html về bản GỐC chưa dọn (5507956~1) rồi đo lại trên
   local: vẫn ĐÚNG 70 khối tràn, vẫn đúng 2 lỗi JS đó, chữ tiếng Anh
   "SLEEK AND DYNAMIC EXTERIOR." Lỗi có sẵn trong bản capture của site gốc. Bản
   dịch tiếng Việt thậm chí tràn ÍT hơn (163px -> 127px). Đừng đi tìm lỗi trong
   model-bodies/, và đừng revert bản dịch.

   ⚠️ BẮT BUỘC `!important` vì phải thắng thuộc tính `style` INLINE do JS gán —
   đây là trường hợp `!important` là cách duy nhất, không phải cho tiện.

   Phạm vi CỐ Ý hẹp ở con TRỰC TIẾP của `.text__inner`: `.content` là một trong
   những tên class phổ biến nhất của bộ CSS này, áp rộng ra là đụng vào layout
   khác. Cái mất duy nhất là hiệu ứng mở dần — mà hiệu ứng đó đang vỡ sẵn nên
   không mất gì thật.
   Đo lại bằng: node tools/qa/do-pham-vi-height0.mjs <url> <đường-dẫn...>
   ========================================================================== */
.text__inner > .strapline,
.text__inner > .content {
	height: auto !important;
}
