/* =====================================================================
   preview-v4.css — Mockup TechShop bản "MƯỢT + ĐÃ" (v4)
   Gốc: preview-v3.css (giữ nguyên tokens/phong cách đã duyệt).
   Sửa theo _REDESIGN-PLAN-v4.md + CONTRACT-v4.md:
     A) Mượt lại: bỏ scroll-snap toàn trang · bỏ animate filter:blur() ·
        bỏ transition background trên body · giảm backdrop-filter navbar
        (14→8) + contain:paint · content-visibility cho .section ·
        will-change chỉ qua .is-anim.
     B) Hook mới v4: #bg-veil · W2 hscroll · W4 mask · W5 pin (giữ) ·
        W6 parallax (giữ) · W7 marquee3d · W8 chapter-progress ·
        html.has-smooth · reduce-fx / prefers-reduced-motion cập nhật.
     C) Giữ nguyên: topbar/nav/hero/hotspot/gallery/zoom/news/footer/
        intro/progress-bar/music-start/#vf-top/page-transition/cursor.
   Thuần CSS, không framework, chạy file:// được.
   ===================================================================== */

/* ---------- 0) TOKENS (giữ nguyên v2) ---------- */
:root {
  --paper: #f1f3f5;
  --paper-2: #e4e8ed;
  --white: #fff;
  --ink: #101620;
  --ink-2: #3e4653;
  --ink-3: #4d5665;
  --line: rgba(16, 22, 32, .14);
  --night: #0f1721;
  --night-2: #17222f;
  --fg: #f0f3f6;
  --fg-dim: #b6bfca;
  --blue: #0b5cab;
  --sky: #58b6ea;
  --glow: rgba(88, 182, 234, .20);
  --r-box: 6px;
  --r-lg: 8px;
  --khung: 1312px;
  --t-display: clamp(2.2rem, 1.6rem + 2.6vw, 4.25rem);
  --t-h2: clamp(1.6rem, 1.2rem + 1.4vw, 2.375rem);
  --t-h3: clamp(1.15rem, 1.05rem + .5vw, 1.5rem);
  --t-body: clamp(.9375rem, .9rem + .22vw, 1.0625rem);
  --t-lead: clamp(1rem, .95rem + .3vw, 1.1875rem);
  --section-y: clamp(2rem, 1.7rem + 2vw, 4rem);
}

/* ---------- 1) RESET ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }

/* A1) BỎ scroll-snap toàn trang (v3: html{scroll-snap-type:y proximity}).
   v4 CHỈ giữ snap NGANG ở .gallery-track. Rule .snap-sec đã xoá. */

body {
  margin: 0;
  font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  font-size: var(--t-body);
  line-height: 1.6;
  color: var(--ink);
  background: var(--paper);
  /* A3) BỎ transition background-color/color của body (v3 dòng 54).
     v4 đổi nền bằng lớp phủ #bg-veil (opacity) — không repaint cả trang. */
}
body.on-dark { background: var(--night); color: var(--fg); }

/* B8) JS bật khi tự lo cuộn mượt nhân tạo → tắt smooth gốc của trình duyệt */
html.has-smooth { scroll-behavior: auto; }

/* A6) will-change CHỈ bật qua class .is-anim do JS thêm (và gỡ sau khi xong) */
.is-anim { will-change: transform, opacity; }

img { max-width: 100%; display: block; }
a { color: var(--blue); text-decoration: none; }
a:hover { color: var(--sky); }
h1, h2, h3, h4 { line-height: 1.15; margin: 0 0 .5em; font-weight: 800; letter-spacing: -.01em; }
ul { margin: 0; padding: 0; list-style: none; }
button { font-family: inherit; }

.khung { width: min(var(--khung), 100% - 2.5rem); margin-inline: auto; }

.skip-link {
  position: absolute; left: 1rem; top: -3rem; z-index: 2000;
  background: var(--blue); color: #fff; padding: .5rem 1rem;
  border-radius: var(--r-box); transition: top .2s ease;
}
.skip-link:focus { top: 1rem; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

/* ---------- 2) THANH TIẾN TRÌNH CUỘN ---------- */
.scroll-progress, #scroll-progress {
  position: fixed; top: 0; left: 0; z-index: 1600;
  height: 3px; width: 100%; transform-origin: left center;
  transform: scaleX(0);
  background: linear-gradient(90deg, var(--blue), var(--sky));
}

/* ---------- 3) INTRO VEIL ---------- */
#intro {
  position: fixed; inset: 0; z-index: 3000;
  display: grid; place-items: center;
  background: var(--night);
}
#intro.is-out { animation: intro-out .8s cubic-bezier(.76, 0, .24, 1) .85s forwards; }
.intro-bar {
  width: min(320px, 62vw); height: 3px; border-radius: 999px;
  background: linear-gradient(90deg, var(--blue), var(--sky));
  transform: scaleX(0); transform-origin: left center;
  animation: intro-fill .85s ease-in-out forwards;
}
@keyframes intro-fill { to { transform: scaleX(1); } }
@keyframes intro-out { to { transform: translateY(-100%); opacity: 0; visibility: hidden; } }

/* ---------- 4) TOPBAR + NAVBAR ---------- */
.topbar {
  position: sticky; top: 0; z-index: 1500;
  background: rgba(255, 255, 255, .92);
  /* A4) giảm backdrop-filter 14 → 8 px + contain: paint (cách ly repaint) */
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  contain: paint;
  border-bottom: 1px solid var(--line);
}
body.on-dark .topbar { background: rgba(15, 23, 33, .92); border-bottom-color: rgba(240, 243, 246, .14); }
body.on-dark .topbar .logo, body.on-dark .topbar .hotline, body.on-dark .topbar .nav a { color: var(--fg); }
body.on-dark .topbar .nav a:hover, body.on-dark .topbar .nav a.is-active { color: var(--sky); }
body.on-dark .topbar .sound-btn, body.on-dark .topbar .reduce-btn, body.on-dark .topbar .nav-toggle {
  background: var(--night-2); color: var(--fg); border-color: rgba(240, 243, 246, .25);
}
.topbar-inner { display: flex; align-items: center; gap: 1.25rem; min-height: 64px; }
.logo { font-size: 1.35rem; font-weight: 800; letter-spacing: .06em; color: var(--ink); display: flex; align-items: center; gap: .5rem; }
.logo .dot { width: 10px; height: 10px; border-radius: 50%; background: var(--blue); box-shadow: 0 0 12px var(--glow); }
.nav { display: flex; gap: 1.1rem; align-items: center; flex: 1; }
.nav a { color: var(--ink-2); font-weight: 600; font-size: .95rem; padding: .35rem 0; border-bottom: 2px solid transparent; }
.nav a:hover, .nav a.is-active { color: var(--blue); border-bottom-color: var(--blue); }
.topbar-tools { display: flex; align-items: center; gap: .75rem; }
.hotline { font-weight: 700; color: var(--ink); white-space: nowrap; }
.hotline span { color: var(--blue); }
body.on-dark .hotline span { color: var(--sky); }
.sound-btn, .reduce-btn {
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid var(--line); background: var(--white);
  font-size: 1.05rem; cursor: pointer; color: var(--ink);
  display: grid; place-items: center;
  transition: border-color .2s, box-shadow .2s, transform .2s;
}
.sound-btn:hover, .reduce-btn:hover { border-color: var(--blue); box-shadow: 0 0 0 4px var(--glow); transform: translateY(-1px); }
.sound-btn.is-on, .reduce-btn.is-on { border-color: var(--blue); box-shadow: 0 0 0 4px var(--glow); }
.nav-toggle {
  display: none; margin-left: auto;
  background: none; border: 1px solid var(--line); border-radius: var(--r-box);
  width: 40px; height: 40px; cursor: pointer; font-size: 1.1rem; color: var(--ink);
}

/* ---------- 5) HERO ---------- */
.hero {
  position: relative; overflow: hidden;
  min-height: 88vh;
  display: flex; align-items: center;
  background: radial-gradient(1100px 520px at 78% 18%, rgba(11, 92, 171, .35), transparent 62%), var(--night);
  color: var(--fg);
}
.hero::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 120px;
  background: linear-gradient(180deg, transparent, var(--paper));
  pointer-events: none;
}
.hero-glow {
  position: absolute; top: -10%; right: -5%;
  width: 520px; height: 520px; border-radius: 50%;
  background: radial-gradient(circle, rgba(88, 182, 234, .25), transparent 65%);
  filter: blur(10px); pointer-events: none;
}
.hero-inner { position: relative; z-index: 2; display: grid; grid-template-columns: 1.15fr .85fr; gap: 2.5rem; align-items: center; padding-block: var(--section-y); }
.hero-kicker {
  display: inline-flex; align-items: center; gap: .5rem;
  border: 1px solid rgba(240, 243, 246, .25); border-radius: 999px;
  padding: .3rem .9rem; font-size: .8rem; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--fg-dim);
}
.hero-kicker .live { width: 8px; height: 8px; border-radius: 50%; background: var(--sky); animation: pulse 1.6s ease-in-out infinite; }
.hero-title { font-size: var(--t-display); margin: 1rem 0 .4em; color: var(--fg); min-height: 2.2em; }

/* T2) TYPEWRITER — chữ hiện từng ký tự + con trỏ nhấp nháy */
.type { display: block; }
.type::after {
  content: ""; display: inline-block;
  width: 3px; height: .9em; margin-left: .12em;
  background: var(--sky); vertical-align: -.08em;
  animation: type-caret 1s step-end infinite;
}
@keyframes type-caret { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }

.hero-sub { font-size: var(--t-lead); color: var(--fg-dim); max-width: 34rem; margin: 0 0 1.75rem; }
.hero-ctas { display: flex; flex-wrap: wrap; gap: .75rem; margin-bottom: 2.25rem; }
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  padding: .8rem 1.6rem; border-radius: var(--r-box);
  font-weight: 700; font-size: 1rem; cursor: pointer; border: 1px solid transparent;
  transition: transform .15s ease, box-shadow .15s ease, background .15s ease, border-color .15s ease;
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn-primary { background: var(--blue); color: #fff; }
.btn-primary:hover { color: #fff; background: #0d69c4; box-shadow: 0 10px 26px rgba(11, 92, 171, .45); }
.btn-ghost { border-color: rgba(240, 243, 246, .35); color: var(--fg); background: transparent; }
.btn-ghost:hover { color: #fff; border-color: var(--sky); box-shadow: 0 0 0 4px var(--glow); }

.hero-stats { display: flex; flex-wrap: wrap; border-top: 1px solid rgba(240, 243, 246, .18); padding-top: 1.5rem; }
.hero-stat { padding-right: 2rem; margin-right: 2rem; border-right: 1px solid rgba(240, 243, 246, .18); }
.hero-stat:last-child { border-right: 0; margin-right: 0; padding-right: 0; }
.hero-stat b { display: block; font-size: clamp(1.6rem, 1.2rem + 1.4vw, 2.375rem); font-weight: 800; color: var(--fg); line-height: 1.1; }
.hero-stat span.lbl { display: block; font-size: .85rem; font-weight: 400; color: var(--fg-dim); }

/* P1) ẢNH BỒNG BỀNH */
[data-float] { animation: float 7s ease-in-out infinite alternate; }
@keyframes float { from { transform: translateY(-10px); } to { transform: translateY(14px); } }

.hero-shot { position: relative; text-align: center; }
.hero-shot img {
  width: 100%; max-width: 520px; height: auto; margin-inline: auto;
  filter: drop-shadow(0 40px 60px rgba(0, 0, 0, .55));
}
.hero-badge {
  position: absolute; top: 6%; left: 2%;
  background: var(--blue); color: #fff; font-weight: 700; font-size: .85rem;
  padding: .35rem .9rem; border-radius: var(--r-box);
  box-shadow: 0 8px 24px rgba(11, 92, 171, .5);
}
.hero-chip {
  position: absolute; bottom: 10%; right: 0;
  background: var(--night-2); border: 1px solid rgba(240, 243, 246, .2);
  color: var(--fg); padding: .55rem 1rem; border-radius: var(--r-box); font-size: .9rem;
  box-shadow: 0 12px 30px rgba(0, 0, 0, .4);
}
.hero-chip b { color: var(--sky); }

/* P2) HOTSPOT — chấm + vòng ping, định vị bằng --x/--y */
.hotspot {
  position: absolute; left: var(--x, 50%); top: var(--y, 50%);
  width: 18px; height: 18px; margin: -9px 0 0 -9px;
  border-radius: 50%; border: 0; padding: 0; cursor: pointer;
  background: var(--sky); box-shadow: 0 0 0 4px var(--glow);
  z-index: 3;
}
.hotspot::after {
  content: ""; position: absolute; inset: -4px;
  border-radius: 50%; border: 2px solid var(--sky);
  animation: hotspot-ping 2s cubic-bezier(0, 0, .2, 1) infinite;
}
@keyframes hotspot-ping {
  0% { transform: scale(.6); opacity: 1; }
  75%, 100% { transform: scale(2.4); opacity: 0; }
}
.hotspot-tip {
  position: absolute; bottom: calc(100% + 12px); left: 50%; transform: translateX(-50%) translateY(6px);
  background: var(--night-2); color: var(--fg);
  border: 1px solid rgba(240, 243, 246, .2); border-radius: var(--r-box);
  padding: .6rem .85rem; font-size: .85rem; line-height: 1.45; text-align: left;
  width: max-content; max-width: 240px;
  box-shadow: 0 12px 30px rgba(0, 0, 0, .4);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .25s ease, transform .25s ease, visibility .25s;
  z-index: 20;
}
.hotspot-tip b { display: block; color: var(--sky); margin-bottom: .15rem; }
.hotspot:hover .hotspot-tip, .hotspot:focus-visible .hotspot-tip,
.hotspot.is-open .hotspot-tip { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0); }

.scroll-cue {
  position: absolute; left: 50%; bottom: 1.25rem; transform: translateX(-50%);
  color: var(--fg-dim); font-size: 1.4rem; z-index: 5;
  animation: cue-bounce 2.2s ease-in-out infinite;
}
@keyframes cue-bounce { 0%, 100% { transform: translate(-50%, 0); opacity: .75; } 50% { transform: translate(-50%, 10px); opacity: 1; } }

/* ---------- 6) MARQUEE (thanh chạy chữ dẹt — giữ v3) ---------- */
.marquee {
  background: var(--paper-2);
  border-block: 1px solid var(--line);
  overflow: hidden; padding: .8rem 0;
}
.marquee-track {
  display: inline-flex; gap: 3rem; white-space: nowrap;
  font-weight: 800; font-size: .82rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink);
  animation: marquee 42s linear infinite;
}
.marquee:hover .marquee-track { animation-play-state: paused; }
@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* ---------- 7) SECTION CHUNG ---------- */
.section {
  padding-block: var(--section-y);
}
/* A5) TỐI ƯU: chỉ áp content-visibility cho section KHÔNG chứa khối ghim.
   ⚠️ Nếu áp lên section chứa .pin (cao ~500vh), trình duyệt ước lượng 900px
   rồi phình lên ~5000px khi vào khung nhìn → NHẢY CHIỀU CAO TRANG = cuộn giật.
   ⚠️ `.cf` (coverflow 3D) CŨNG do JS đặt `height` = vh + (n-1)*stepPx, nên phải
   loại khỏi `content-visibility` — nếu không, trình duyệt giữ chiều cao ước lượng
   900px cho tới khi section vào khung nhìn, rồi nhảy sang chiều cao thật của JS
   ⇒ thanh cuộn nhảy + mọi phép đo scroll bị lệch ⇒ cuộn giật.
   Nếu trình duyệt không hỗ trợ :has() thì rule không khớp → an toàn (không tối ưu). */
.section:not(:has(.pin)):not(:has(.hscroll)):not(:has(.cf)) {
  content-visibility: auto;
  contain-intrinsic-size: 1px 900px;
}
.section-dark { background: var(--night); color: var(--fg); }
.section-paper2 { background: var(--paper-2); }
.section-head { max-width: 46rem; margin-bottom: 2.25rem; }
.section-head .eyebrow {
  display: inline-block; font-size: .8rem; font-weight: 800; letter-spacing: .16em;
  text-transform: uppercase; color: var(--blue); margin-bottom: .6rem;
}
.section-dark .section-head .eyebrow { color: var(--sky); }
.section-head h2 { font-size: var(--t-h2); }
.section-head p { color: var(--ink-3); font-size: var(--t-lead); margin: 0; }
.section-dark .section-head p { color: var(--fg-dim); }

/* Khối trang trí parallax (-0.2) */
.deco-ring {
  position: absolute; border-radius: 50%;
  border: 2px solid rgba(11, 92, 171, .18);
  pointer-events: none;
}

/* ---------- 8) LƯỚI SẢN PHẨM + TILT MẠNH ---------- */
.product-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.25rem; }
.product-card {
  position: relative;
  background: var(--white); border: 1px solid var(--line); border-radius: var(--r-lg);
  overflow: hidden; cursor: pointer;
  transition: box-shadow .25s ease, border-color .25s ease;
  transform-style: preserve-3d;
}
.product-card:hover { box-shadow: 0 26px 52px rgba(16, 22, 32, .2); border-color: rgba(11, 92, 171, .45); z-index: 2; }
.card-media { position: rFelative; background: var(--paper); padding: 1.4rem; display: grid; place-items: center; overflow: hidden; }
.card-media img { width: 100%; height: auto; transition: transform .3s ease; transform: translateZ(24px); }
.product-card:hover .card-media img { transform: translateZ(24px) scale(1.06); }
.card-badge {
  position: absolute; top: .75rem; left: .75rem;
  background: var(--ink); color: #fff; font-size: .75rem; font-weight: 800;
  padding: .25rem .6rem; border-radius: var(--r-box); letter-spacing: .04em;
}

/* P5) TILT-GLARE — vệt sáng + spotlight theo --gx/--gy do JS set trên .product-card */
.tilt-glare {
  position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background:
    linear-gradient(115deg, transparent 30%, rgba(255, 255, 255, .28) 46%, rgba(255, 255, 255, .05) 54%, transparent 70%),
    radial-gradient(260px circle at var(--gx, 50%) var(--gy, 50%), var(--glow), transparent 65%);
  transition: opacity .25s ease;
  z-index: 3;
}
.product-card:hover .tilt-glare { opacity: 1; }

.card-body { padding: 1.1rem 1.25rem 1.35rem; }
.card-cat { font-size: .78rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); }
.card-title { font-size: 1.02rem; font-weight: 700; color: var(--ink); margin: .35rem 0 .5rem; min-height: 2.6em; }
.card-prices { display: flex; align-items: baseline; gap: .6rem; }
.price-old { color: var(--ink-3); text-decoration: line-through; font-size: .9rem; }
.price-new { color: #d0021b; font-weight: 800; font-size: 1.25rem; }
.card-buy {
  display: block;                    /* anchor là inline → width:100% vô hiệu */
  margin-top: .9rem; width: 100%; border: 0; cursor: pointer;
  background: var(--blue); color: #fff; font-weight: 700; font-size: .95rem;
  padding: .65rem 1rem; border-radius: var(--r-box);
  text-align: center; text-decoration: none; box-sizing: border-box;
  transition: background .15s ease, box-shadow .15s ease, transform .15s ease;
}
.card-buy:hover { background: #0d69c4; box-shadow: 0 8px 20px rgba(11, 92, 171, .4); }
.card-buy:active { transform: scale(.98); }

/* ---------- 9) S1) PIN/STICKY — W5) storytelling nhiều cảnh ---------- */
/* v4: .pin{height:auto} — JS (B) set min-height theo số panel + chiều cao khung nhìn */
.pin { position: relative; height: auto; }
.pin-inner {
  position: sticky; top: 0; height: 100vh; overflow: hidden;
  display: flex; flex-direction: column; justify-content: center;
  background:
    radial-gradient(900px 460px at 82% 20%, rgba(11, 92, 171, .30), transparent 60%),
    var(--night);
  color: var(--fg);
}
.pin-panel {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  padding: var(--section-y) 0;
  opacity: 0; transform: translateY(40px) scale(.97);
  transition: opacity .5s ease, transform .5s ease;
  pointer-events: none;
}
.pin-panel:first-child { opacity: 1; transform: none; } /* fallback khi chưa có JS */
.pin-panel.is-active { opacity: 1; transform: none; pointer-events: auto; }
.pin-panel-card {
  display: grid; grid-template-columns: auto 1fr; gap: 2rem; align-items: center;
  max-width: 900px; margin-inline: auto; padding: 2.5rem;
  background: var(--night-2); border: 1px solid rgba(240, 243, 246, .12);
  border-radius: var(--r-lg);
}
.pin-num {
  font-size: clamp(4rem, 3rem + 4vw, 7.5rem); font-weight: 800; line-height: 1;
  color: transparent; -webkit-text-stroke: 2px rgba(88, 182, 234, .55);
}
.pin-panel-card h3 { font-size: var(--t-h2); margin-bottom: .5rem; }
.pin-panel-card p { margin: 0; color: var(--fg-dim); font-size: var(--t-lead); max-width: 34rem; }
.pin-progress {
  display: flex; gap: .6rem; justify-content: center;
  position: absolute; bottom: 2rem; left: 0; right: 0;
}
.pin-progress i {
  width: 34px; height: 4px; border-radius: 999px;
  background: rgba(240, 243, 246, .2); transition: background .3s ease;
}
.pin-progress i.on { background: var(--sky); }

/* ---------- 10) P3) GALLERY TRƯỢT NGANG + P4) ZOOM ---------- */
.gallery { position: relative; }
.gallery-track {
  display: flex; gap: 1.25rem;
  overflow-x: auto; scroll-behavior: smooth;
  scroll-snap-type: x proximity; /* A1) snap DUY NHẤT còn lại của v4 */
  padding-bottom: 1rem;
  scrollbar-width: none;
}
.gallery-track::-webkit-scrollbar { display: none; }
/* FIX CONTRACT: JS thêm .is-dragging khi người dùng kéo gallery */
.gallery-track.is-dragging { cursor: grabbing; scroll-behavior: auto; scroll-snap-type: none; }
.gallery-item {
  position: relative; flex: 0 0 min(420px, 82vw);
  margin: 0; overflow: hidden;
  border-radius: var(--r-lg); border: 1px solid rgba(240, 243, 246, .14);
  scroll-snap-align: start;
  background: var(--night-2);
}
.gallery-item img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; transition: transform .45s ease, filter .45s ease; }
.gallery-item:hover img { transform: scale(1.05); }
/* FIX CONTRACT: JS thêm .is-zoom khi hover ảnh có [data-zoom] */
.gallery-item img.is-zoom { transform: scale(1.15); }
.gallery-cap {
  position: absolute; inset: auto 0 0 0; padding: 2.2rem 1.1rem .9rem;
  background: linear-gradient(180deg, transparent, rgba(15, 23, 33, .88));
  color: #fff; font-weight: 700; font-size: .95rem;
}
.gallery-btn {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 5;
  width: 46px; height: 46px; border-radius: 50%; border: 0; cursor: pointer;
  background: var(--blue); color: #fff; font-size: 1.4rem; line-height: 1;
  box-shadow: 0 10px 26px rgba(11, 92, 171, .45);
  transition: background .15s ease, transform .15s ease;
}
.gallery-btn:hover { background: #0d69c4; transform: translateY(-50%) scale(1.06); }
.gallery-btn[data-gallery-prev] { left: -.75rem; }
.gallery-btn[data-gallery-next] { right: -.75rem; }

/* P4) ZOOM ẢNH */
[data-zoom] { cursor: zoom-in; }
.zoom-overlay {
  position: fixed; inset: 0; z-index: 2900;
  display: grid; place-items: center; padding: 2rem;
  background: rgba(15, 23, 33, .92);
  opacity: 0; visibility: hidden;
  transition: opacity .3s ease, visibility .3s;
  cursor: zoom-out;
}
.zoom-overlay.is-open { opacity: 1; visibility: visible; }
.zoom-overlay img {
  max-width: min(1100px, 92vw); max-height: 86vh; width: auto; height: auto;
  border-radius: var(--r-lg);
  box-shadow: 0 30px 80px rgba(0, 0, 0, .6);
}

/* ---------- 11) TIN TỨC ---------- */
.news-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.25rem; }
.news-card {
  background: var(--white); border: 1px solid var(--line); border-radius: var(--r-lg);
  overflow: hidden; transition: transform .2s ease, box-shadow .2s ease;
}
.news-card:hover { transform: translateY(-5px); box-shadow: 0 18px 40px rgba(16, 22, 32, .14); }
.news-media { background: var(--paper); overflow: hidden; }
.news-media img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; transition: transform .45s ease; }
.news-card:hover .news-media img { transform: scale(1.05); }
.news-body { padding: 1.15rem 1.25rem 1.4rem; }
.news-date { font-size: .82rem; font-weight: 700; color: var(--blue); letter-spacing: .06em; text-transform: uppercase; }
.news-title { font-size: 1.05rem; margin: .45rem 0 0; }
.news-card a.news-title-link { color: inherit; }
.news-card a.news-title-link:hover { color: var(--blue); }

/* ---------- 12) FOOTER ---------- */
.site-footer { background: var(--night); color: var(--fg-dim); padding: var(--section-y) 0 2rem; }
.footer-grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1.1fr; gap: 2rem; }
.site-footer h4 { color: var(--fg); font-size: 1rem; margin-bottom: 1rem; }
.site-footer a { color: var(--fg-dim); }
.site-footer a:hover { color: #fff; }
.footer-brand p { margin: .5rem 0 1rem; font-size: .95rem; }
.footer-brand .hotline-dark { font-weight: 800; color: #fff; font-size: 1.15rem; }
.social-row { display: flex; gap: .6rem; margin-top: 1.25rem; }
.social-row a {
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid rgba(240, 243, 246, .25); display: grid; place-items: center;
  font-size: .95rem; transition: border-color .2s, color .2s, transform .2s;
}
.social-row a:hover { border-color: var(--sky); color: var(--sky); transform: translateY(-2px); }
.footer-copyright {
  border-top: 1px solid rgba(240, 243, 246, .12);
  margin-top: 2.5rem; padding-top: 1.5rem;
  display: flex; flex-wrap: wrap; gap: .75rem; justify-content: space-between;
}
.footer-copyright span { font-size: .85rem; }

/* ---------- 13) S4) SCROLL-DRIVEN (CSS có fallback) ----------
   Chỉ áp trong @supports; phần tử vẫn hiển thị bình thường
   khi trình duyệt chưa hỗ trợ (JS sẽ có fallback riêng).
   v4: BỎ filter: blur() — chỉ còn opacity + transform. */
@supports (animation-timeline: view()) {
  .sd-rise {
    animation: sd-rise linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 40%;
  }
  .sd-fade {
    animation: sd-fade linear both;
    animation-timeline: view();
    animation-range: entry 0% cover 35%;
  }
}
@keyframes sd-rise {
  from { opacity: 0; transform: translateY(56px) scale(.96); }
  to { opacity: 1; transform: none; }
}
@keyframes sd-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* ---------- 14) REVEAL (v4: CHỈ opacity + transform, KHÔNG blur/will-change) ---------- */
[data-reveal] {
  opacity: 0;
  transform: translateY(48px) scale(.97);
  transition: opacity .65s cubic-bezier(.22, 1, .36, 1), transform .65s cubic-bezier(.22, 1, .36, 1);
  transition-delay: var(--rd, 0ms);
}
[data-reveal="left"] { transform: translateX(-48px) scale(.97); }
[data-reveal="right"] { transform: translateX(48px) scale(.97); }
[data-reveal="top"] { transform: translateY(-48px) scale(.97); }
[data-reveal="zoom"] { transform: scale(.92); }
[data-reveal].is-in { opacity: 1; transform: none; }

/* ---------- 15) W2) CUỘN NGANG KHI LĂN DỌC ---------- */
.hscroll { position: relative; }
.hscroll-pin {
  position: sticky; top: 0; height: 100vh; overflow: hidden;
  display: flex; align-items: center;
}
.hscroll-track {
  display: flex; gap: 2rem;
  padding-inline: max(1.25rem, calc((100vw - var(--khung)) / 2));
  will-change: transform; /* chỉ trên track đang được JS dịch — gỡ khi tĩnh */
}
.hscroll-panel {
  flex: 0 0 min(560px, 84vw);
  background: var(--night-2); border: 1px solid rgba(240, 243, 246, .12);
  border-radius: var(--r-lg); padding: 2rem; color: var(--fg);
}
/* Ảnh tỉ lệ 4/3 (cao nhất trong dải thường dùng) → thấy rõ chi tiết sản phẩm.
   `height: auto` là BẮT BUỘC: thuộc tính width/height="640/480" trong HTML tạo
   presentational hint height:480px, đè aspect-ratio → ảnh vẫn cao 480px nếu thiếu.
   Chỉnh tay: 21/9 < 16/9 < 3/2 < 16/10 < 4/3 (thấp → cao). */
.hscroll-panel img {
  width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--r-box);
}

.hscroll-hint {
  position: absolute; bottom: 2rem; left: 50%; transform: translateX(-50%);
  color: var(--fg-dim); font-size: .9rem; letter-spacing: .1em; text-transform: uppercase;
}

/* ---------- 16) W4) MASK REVEAL — chữ trồi lên sau mặt nạ ---------- */
.mask-line { display: block; overflow: hidden; }
.mask-inner {
  display: block;
  transform: translateY(110%);
  transition: transform .9s cubic-bezier(.22, 1, .36, 1);
}
[data-mask].is-in .mask-inner { transform: none; }
[data-mask].is-in .mask-line:nth-child(2) .mask-inner { transition-delay: .08s; }
[data-mask].is-in .mask-line:nth-child(3) .mask-inner { transition-delay: .16s; }
[data-mask].is-in .mask-line:nth-child(4) .mask-inner { transition-delay: .24s; }
[data-mask].is-in .mask-line:nth-child(5) .mask-inner { transition-delay: .32s; }

/* ---------- 17) W6) PARALLAX ĐA LỚP — chỉ cần .is-anim lo will-change ---------- */
/* [data-parallax] dịch bằng translate3d do JS set; không style tĩnh ở đây. */

/* ---------- 18) W7) MARQUEE CHẠY NGANG ---------- */
/* Nền xanh đậm riêng: dải chữ đang nằm trần trên nền trang nên thiếu điểm nhấn.
   Dùng gradient nhẹ để không phẳng lì; chữ chuyển sang trắng cho đủ tương phản. */
.marquee3d {
  overflow: hidden; padding: 2.5rem 0;
  background: linear-gradient(90deg, var(--night) 0%, var(--blue) 55%, var(--night) 100%);
}
.marquee3d-track {
  display: inline-flex; gap: 3rem; white-space: nowrap;
  font-weight: 800; font-size: clamp(1.6rem, 1rem + 2vw, 2.6rem);
  letter-spacing: .06em; text-transform: uppercase; color: var(--fg);
  animation: marquee3d 34s linear infinite;
}
.marquee3d-item { opacity: .92; }
.marquee3d:hover .marquee3d-track { animation-play-state: paused; }
@keyframes marquee3d {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* ---------- 19) W8) TIẾN TRÌNH THEO CHƯƠNG ---------- */
.chapter-progress {
  position: fixed; right: 1.25rem; top: 50%; transform: translateY(-50%);
  z-index: 1500; display: flex; flex-direction: column; align-items: center; gap: .6rem;
  font-weight: 800; font-size: .8rem; letter-spacing: .08em; color: var(--ink-2);
}
.chapter-bar {
  width: 3px; height: 120px; background: rgba(16, 22, 32, .15);
  border-radius: 999px; overflow: hidden;
}
.chapter-bar i { display: block; width: 100%; height: 0; background: var(--blue); transition: height .15s linear; }
body.on-dark .chapter-progress { color: var(--fg-dim); }
body.on-dark .chapter-bar { background: rgba(240, 243, 246, .18); }
body.on-dark .chapter-bar i { background: var(--sky); }

/* ---------- 20) NỀN ĐỔI MÀU — lớp phủ #bg-veil (thay transition body) ---------- */
.bg-veil {
  position: fixed; inset: 0; z-index: -1;
  background: var(--night);
  opacity: 0; pointer-events: none;
  transition: opacity .5s ease;
}
.bg-veil.is-dark { opacity: 1; }

/* ---------- 21) T3) GLOW THEO CHUỘT + T4) CON TRỎ TUỲ BIẾN ---------- */
.cursor-glow {
  position: fixed; inset: 0; z-index: 1400;
  pointer-events: none;
  background: radial-gradient(340px circle at var(--mx, 50%) var(--my, 50%), var(--glow), transparent 65%);
  opacity: 0; transition: opacity .4s ease;
}
.cursor-glow.is-active { opacity: 1; }

.cursor, .cursor-dot {
  position: fixed; top: 0; left: 0; z-index: 2100;
  border-radius: 50%; pointer-events: none;
  opacity: 0; transition: opacity .3s ease;
}
.cursor {
  width: 36px; height: 36px; margin: -18px 0 0 -18px;
  border: 2px solid var(--sky);
  transition: opacity .3s ease, width .2s ease, height .2s ease, margin .2s ease, border-color .2s ease;
}
.cursor-dot {
  width: 6px; height: 6px; margin: -3px 0 0 -3px;
  background: var(--sky);
}
.cursor.is-active, .cursor-dot.is-active { opacity: .9; }
/* FIX CONTRACT: JS thêm .has-cursor trên <html> để hiện con trỏ tuỳ biến */
html.has-cursor .cursor, html.has-cursor .cursor-dot { opacity: .9; }
.cursor.is-hover {
  width: 52px; height: 52px; margin: -26px 0 0 -26px;
  border-color: var(--blue); background: var(--glow);
}
/* Trên nền tối vẫn thấy rõ */
body.on-dark .cursor { border-color: var(--sky); }
body.on-dark .cursor-dot { background: var(--sky); }

/* Ẩn con trỏ tuỳ biến trên thiết bị cảm ứng */
@media (hover: none), (pointer: coarse) {
  .cursor, .cursor-dot, .cursor-glow { display: none !important; }
}

/* ---------- 22) T5) OVERLAY CHUYỂN TRANG ---------- */
.page-transition {
  position: fixed; inset: 0; z-index: 2800;
  background: var(--night);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .35s ease, visibility .35s;
}
.page-transition.is-leaving { opacity: 1; visibility: visible; pointer-events: auto; }
.page-transition.is-entrance { animation: pt-entrance .5s ease .05s both; }
@keyframes pt-entrance { from { opacity: 1; } to { opacity: 0; visibility: hidden; } }

/* ---------- 23) NHẠC NỀN — nút dự phòng khi autoplay bị chặn ---------- */
.music-start {
  position: fixed; left: 50%; bottom: 2rem; transform: translateX(-50%);
  z-index: 3100;
  border: 0; cursor: pointer;
  background: var(--blue); color: #fff;
  font-weight: 700; font-size: 1rem;
  padding: .85rem 1.75rem; border-radius: 999px;
  box-shadow: 0 14px 36px rgba(11, 92, 171, .55);
  transition: background .15s ease, transform .15s ease, box-shadow .15s ease;
  animation: float 4s ease-in-out infinite alternate;
}
.music-start:hover { background: #0d69c4; transform: translateX(-50%) translateY(-2px); box-shadow: 0 18px 44px rgba(11, 92, 171, .65); }
.music-start[hidden] { display: none; }

/* ---------- 24) BACK TO TOP (JS tạo #vf-top) ---------- */
#vf-top {
  position: fixed; right: 1.25rem; bottom: 1.25rem; z-index: 1500;
  width: 46px; height: 46px; border-radius: 50%; border: 0; cursor: pointer;
  background: var(--blue); color: #fff; font-size: 1.15rem;
  opacity: 0; visibility: hidden; transform: translateY(12px);
  transition: opacity .25s, transform .25s, visibility .25s, box-shadow .15s;
  box-shadow: 0 10px 26px rgba(11, 92, 171, .45);
}
#vf-top.vf-show { opacity: 1; visibility: visible; transform: translateY(0); }
#vf-top:hover { box-shadow: 0 14px 34px rgba(11, 92, 171, .6); }

/* =====================================================================
   FIX CONTRACT v4 — khoá class/selector giữa HTML, CSS và JS
   ===================================================================== */

/* C5) NÚT "GIẢM HIỆU ỨNG" — JS toggle class .reduce-fx trên <html> */
html.reduce-fx { scroll-snap-type: none; }
html.reduce-fx [data-float],
html.reduce-fx .cursor-glow,
html.reduce-fx .marquee-track,
html.reduce-fx .marquee3d-track,
html.reduce-fx .hotspot::after,
html.reduce-fx .type::after,
html.reduce-fx #intro { animation: none !important; }
html.reduce-fx .cursor, html.reduce-fx .cursor-dot, html.reduce-fx .cursor-glow { display: none !important; }
html.reduce-fx [data-reveal] { opacity: 1 !important; transform: none !important; }
html.reduce-fx .mask-inner { transform: none !important; }
html.reduce-fx .pin { height: auto; }
html.reduce-fx .pin-inner { position: static; height: auto; overflow: visible; }
html.reduce-fx .pin-panel { position: static; opacity: 1; transform: none; pointer-events: auto; padding: 1rem 0; }
html.reduce-fx .pin-progress { display: none; }
html.reduce-fx .hscroll-pin { position: static; height: auto; }
html.reduce-fx .hscroll-track { flex-direction: column; transform: none !important; }

/* C7) FALLBACK SCROLL-DRIVEN — cho trình duyệt không hỗ trợ animation-timeline
   (Firefox/Safari). JS thêm .sd-fallback trên <html>, rồi .is-in khi vào khung nhìn.
   Lưu ý: .marquee mang class sd-fade → chỉ ẩn khi có html.sd-fallback (an toàn khi không có JS).
   v4: BỎ filter: blur() — chỉ còn opacity + transform. */
html.sd-fallback .sd-rise { opacity: 0; transform: translateY(56px) scale(.96); transition: opacity .7s cubic-bezier(.22,1,.36,1), transform .7s cubic-bezier(.22,1,.36,1); }
html.sd-fallback .sd-rise.is-in { opacity: 1; transform: none; }
html.sd-fallback .sd-fade { opacity: 0; transition: opacity .7s ease; }
html.sd-fallback .sd-fade.is-in { opacity: 1; }

/* ---------- 25) RESPONSIVE ---------- */
@media (max-width: 1024px) {
  .hero-inner { grid-template-columns: 1fr; text-align: center; }
  .hero-sub { margin-inline: auto; }
  .hero-ctas, .hero-stats { justify-content: center; }
  .hero-stat { padding-inline: 1.25rem; margin-inline: 0; border-right: 0; }
  .hero-shot { order: -1; }
  .hero-shot img { max-width: 380px; }
  .product-grid { grid-template-columns: repeat(2, 1fr); }
  .pin-panel-card { grid-template-columns: 1fr; gap: 1rem; padding: 1.75rem; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 900px) {
  .chapter-progress { display: none; } /* W8: ẩn thanh chương trên màn hẹp */
}

@media (max-width: 640px) {
  .nav {
    position: absolute; top: 100%; left: 0; right: 0;
    display: none; flex-direction: column; align-items: flex-start;
    background: var(--white); border-bottom: 1px solid var(--line);
    padding: 1rem 1.25rem; gap: .75rem;
  }
  body.on-dark .nav { background: var(--night-2); border-bottom-color: rgba(240, 243, 246, .14); }
  .nav.open { display: flex; }
  .nav-toggle { display: grid; place-items: center; }
  .topbar-inner { flex-wrap: nowrap; gap: .5rem; min-height: 60px; }
  /* .topbar có contain:paint → nội dung thừa bị CẮT, không tạo scrollbar.
     Vì vậy phải thu gọn công cụ để không tràn: ẩn hotline, nén CTA, thu icon. */
  .hotline { display: none; }
  .topbar-tools { gap: .4rem; flex-wrap: nowrap; }
  .sound-btn, .reduce-btn, .nav-toggle { width: 34px; height: 34px; font-size: .95rem; flex: 0 0 auto; }
  .logo { font-size: 1.1rem; flex: 0 0 auto; }
  .nav-toggle { margin-left: 0; }
  .product-grid, .news-grid { grid-template-columns: 1fr; }
  .hero { min-height: auto; }
  .hero-glow { width: 320px; height: 320px; }

  /* Pin trên mobile: bỏ ghim, các panel xếp dọc bình thường */
  .pin { height: auto; }
  .pin-inner { position: static; height: auto; overflow: visible; }
  .pin-panel { position: static; opacity: 1; transform: none; pointer-events: auto; padding: 1rem 0; }
  .pin-progress { display: none; }

  /* W2 hscroll trên mobile: bỏ pin, xếp dọc */
  .hscroll-pin { position: static; height: auto; }
  .hscroll-track { flex-direction: column; transform: none !important; }
}

/* ---------- 26) REDUCED MOTION — tắt TOÀN BỘ ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; scroll-snap-type: none; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
  [data-reveal] { opacity: 1 !important; transform: none !important; }
  [data-float], .cursor-glow { animation: none !important; }
  .type::after { animation: none !important; }
  #intro { display: none !important; }
  .cursor, .cursor-dot, .cursor-glow { display: none !important; }
  .pin { height: auto; }
  .pin-inner { position: static; height: auto; overflow: visible; }
  .pin-panel { position: static; opacity: 1; transform: none; pointer-events: auto; padding: 1rem 0; }
  .pin-progress { display: none; }
  /* v4: mask hiện thẳng + hscroll xếp dọc */
  .mask-inner { transform: none !important; }
  .hscroll-pin { position: static; height: auto; }
  .hscroll-track { flex-direction: column; transform: none !important; }
  @supports (animation-timeline: view()) {
    .sd-rise, .sd-fade { animation: none !important; }
  }
}

/* =====================================================================
   PHẦN v5 — BỔ SUNG STYLE CHO CÁC KHỐI MỚI (A/CSS sở hữu)
   Bám CONTRACT-v5.md mục 3 + _REDESIGN-PLAN-v5.md.
   KHÔNG xoá/đổi bất kỳ token, class, keyframe hay nhánh nào của v4 ở trên.
   KHÔNG đặt content-visibility lên .hero / .banner / .stats-strip / .consult.
   ===================================================================== */

/* ---------- 27) CTA NAVBAR — nút "Đặt lịch tư vấn" trong .topbar-tools ---------- */
.nav-cta {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--blue); color: #fff;
  font-weight: 700; font-size: .92rem; line-height: 1;
  white-space: nowrap; padding: .6rem 1.1rem;
  border-radius: var(--r-box); border: 1px solid transparent;
  transition: background .15s ease, box-shadow .15s ease, transform .15s ease;
}
.nav-cta:hover { color: #fff; background: #0d69c4; box-shadow: 0 8px 20px rgba(11, 92, 171, .42); transform: translateY(-1px); }
.nav-cta:active { transform: translateY(0); }
/* Trên nền tối vẫn giữ đúng tông --blue để nổi bật cạnh hotline */
body.on-dark .nav-cta { color: #fff; }

/* ---------- 28) HERO v5 — copy trái + stage phải + dải label:value ---------- */
.hero.hero-v5 {
  min-height: min(92vh, 920px);
  background:
    radial-gradient(1200px 640px at 84% 10%, rgba(11, 92, 171, .42), transparent 64%),
    var(--night);
}
/* Hero v5 nối xuống section tối kế tiếp → đổi dải mờ chân hero sang tông night */
.hero.hero-v5::after {
  height: 140px;
  background: linear-gradient(180deg, transparent, var(--night));
}
/* Quầng sáng trang trí (thuần gradient — KHÔNG animate filter: blur) */
.hero-v5-glow {
  position: absolute; top: -18%; right: -10%;
  width: clamp(320px, 42vw, 620px); aspect-ratio: 1 / 1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(88, 182, 234, .28), transparent 66%);
  pointer-events: none;
}
.hero-v5-inner {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: 1.15fr .85fr;
  gap: clamp(1.5rem, 1rem + 3vw, 3.5rem);
  align-items: center;
  padding-block: clamp(2.5rem, 2rem + 4vw, 5rem);
}
/* Grid item mặc định min-width:auto → canvas có intrinsic width sẽ kéo cột
   rộng hơn viewport. Ép min-width:0 để cột co đúng theo khung. */
.hero-v5-inner > * { min-width: 0; }
.hero-v5-copy { position: relative; min-width: 0; }
.hero-v5-title {
  font-size: var(--t-display);
  margin: 1rem 0 .5em; color: var(--fg); min-height: 2.2em;
}
.hero-v5-sub {
  font-size: var(--t-lead); color: var(--fg-dim);
  max-width: 36rem; margin: 0 0 1.75rem;
}
.hero-v5-ctas { display: flex; flex-wrap: wrap; gap: .75rem; margin-bottom: 2rem; }
/* Dải label:value ngay trong hero (giống trang mẫu) */
.hero-v5-specs {
  display: flex; flex-wrap: wrap; align-items: stretch;
  border-top: 1px solid rgba(240, 243, 246, .18);
  padding-top: 1.5rem; row-gap: 1.25rem;
}
.hero-v5-spec {
  padding-right: clamp(1rem, .5rem + 1.5vw, 2rem);
  margin-right: clamp(1rem, .5rem + 1.5vw, 2rem);
  border-right: 1px solid rgba(240, 243, 246, .18);
}
.hero-v5-spec:last-child { border-right: 0; margin-right: 0; padding-right: 0; }
.hero-v5-spec b {
  display: block; font-size: clamp(1.5rem, 1.15rem + 1.4vw, 2.25rem);
  font-weight: 800; color: var(--fg); line-height: 1.1;
}
.hero-v5-spec .lbl { display: block; font-size: .85rem; font-weight: 400; color: var(--fg-dim); }
.hero-v5-stage { position: relative; display: grid; place-items: center; min-width: 0; }
.hero-v5-shot {
  position: relative; width: 100%; text-align: center;
  max-width: clamp(340px, 36vw, 600px);   /* cùng bề ngang với khung model */
  margin-inline: auto;
  min-width: 0;
}
/* Slot giữ chỗ: quyết định KÍCH THƯỚC và VỊ TRÍ model. Model là fixed nên
   slot này là "neo" duy nhất — mọi thay đổi kích thước đều qua slot. */
.hero-3d-slot {
  width: 100%;
  aspect-ratio: 4 / 3;
  pointer-events: none;
}
.hero-v5-shot img {
  width: 100%; max-width: clamp(320px, 34vw, 560px); height: auto; margin-inline: auto;
  filter: drop-shadow(0 40px 60px rgba(0, 0, 0, .55));
}
/* Nhãn + giá: vị trí do JS đặt qua --bd-x/--bd-y/--cp-x/--cp-y (xem mục 28b). */

/* ---------- 28b) HERO 3D — LỚP "STUDIO FLOOR" PHỦ TOÀN MÀN HÌNH ----------
   Dựng theo đúng cấu trúc trang mẫu (section#hero > div.studio-floor.sticky > canvas):
   canvas 3D phủ KÍN viewport và ĐỨNG YÊN khi cuộn, thay vì bị nhốt trong
   một khung 4:3 ở cột phải. Hero cuộn qua thì lớp này ẩn đi.

   - KHÔNG viền, KHÔNG nền, KHÔNG box-shadow → model "nổi" thật trên trang.
   - pointer-events:none trên lớp phủ để KHÔNG chặn navbar / nút bấm;
     chỉ vùng .hero-3d-hit (quanh thân máy) bắt chuột để kéo xoay.
   - Không dùng will-change:transform (lớp phủ kín màn hình → tốn VRAM vô ích). */
.hero-3d {
  /* v5.2: KHỐI GHIM — lớp này nằm TRONG .hero-pin-inner (sticky) nên dùng
     absolute thay vì fixed. Khối ghim cao đúng 100svh, canvas phủ kín nó và
     trình duyệt tự ghim/nhả theo cuộn → không cần JS tính vị trí mỗi frame. */
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;                    /* trên nền khối ghim, DƯỚI 3 cảnh chữ (z-index 3) */
  border: 0; background: none; box-shadow: none; outline: none;
  pointer-events: none;          /* cả lớp phủ không chặn chuột; chỉ .hero-3d-hit bắt */
  opacity: 0;
  transition: opacity .55s ease;
}
.hero-3d.is-placed { opacity: 1; }
/* Ẩn khi hero đã cuộn qua. Chỉ dùng opacity + pointer-events;
   việc loại khỏi Tab/trình đọc màn hình do JS làm (aria-hidden + tabindex),
   KHÔNG dùng visibility vì sẽ cắt mất hiệu ứng mờ dần. */
.hero-3d.is-outside { opacity: 0; pointer-events: none; }
/* Canvas phủ kín lớp; KHÔNG nền, KHÔNG viền.
   z-index:0 + các nhãn z-index:2 → nhãn LUÔN nằm trên model, không bị canvas vẽ đè
   (canvas được append SAU các nhãn nên mặc định sẽ đè lên chúng). */
.hero-3d canvas {
  position: absolute; inset: 0; z-index: 0;
  display: block; width: 100% !important; height: 100% !important;
  background: transparent !important;
  pointer-events: none;
}
/* Nhãn, chip giá, gợi ý, trạng thái tải: nổi TRÊN canvas */
.hero-3d .hero-badge,
.hero-3d .hero-chip,
.hero-3d-hint,
.hero-3d-load { z-index: 2; }
/* Vùng bắt chuột để kéo xoay — chỉ quanh thân máy, không phủ cả trang */
.hero-3d-hit {
  /* Phủ KÍN khối ghim: kéo ở bất kỳ đâu trong hero cũng xoay được model —
     đúng hành vi trang mẫu. Không sợ chặn nút bấm vì mọi thứ bấm được đều nằm
     ở lớp trên: .hero-scene (3), .hero-swatches/.hero-cue (4), navbar (1500).
     KHÔNG đặt left/top/width/height ở đây bằng JS nữa (inline style sẽ đè CSS). */
  position: absolute;
  inset: 0;
  pointer-events: auto;
  cursor: grab;
  touch-action: pan-y;           /* vẫn cho cuộn dọc trang trên mobile */
}
.hero-3d.is-dragging .hero-3d-hit { cursor: grabbing; }
/* v5.4: rê lên model → con trỏ "pointer" (báo hiệu tương tác được). Chỉ bật khi JS
   raycast xác nhận chuột CHẠM mesh model (class .is-hover), không phải nền. */
.hero-3d.is-hover .hero-3d-hit { cursor: pointer; }
.hero-3d.is-hover.is-dragging .hero-3d-hit { cursor: grabbing; }
.hero-3d.is-outside .hero-3d-hit { pointer-events: none; }
/* Bóng mềm dưới chân sản phẩm — JS đặt --sh-x/--sh-y/--sh-w theo hình chiếu thật */
.hero-3d::after {
  content: "";
  position: absolute;
  left: var(--sh-x, 70%); top: var(--sh-y, 72%);
  width: var(--sh-w, 30%); height: 30px;
  transform: translate(-50%, -50%);
  background: radial-gradient(ellipse at center, rgba(0, 0, 0, .62) 0%, rgba(0, 0, 0, .28) 45%, rgba(0, 0, 0, 0) 76%);
  filter: blur(8px);
  pointer-events: none;
  opacity: 0; transition: opacity .8s ease;
}
.hero-3d.is-ready::after { opacity: 1; }
/* Ảnh dự phòng (khi không có WebGL): đặt cùng chỗ model, KHÔNG phủ kín màn hình.
   Dùng `.hero-3d .hero-3d-fallback` (0,2,0) để THẮNG `.hero-v5-shot img`.
   MẶC ĐỊNH ẨN (opacity:0): ảnh JPG có nền trắng, nếu hiện trong lúc chờ tải .glb
   sẽ thành một ô trắng giữa nền tối. Chỉ hiện khi thực sự rơi vào chế độ khung ảnh. */
.hero-3d .hero-3d-fallback {
  position: absolute;
  left: var(--fx-x, 68%); top: var(--fx-y, 50%);
  width: auto; height: var(--fx-h, 52vh);
  max-width: 46vw;
  margin: 0;
  transform: translate(-50%, -50%);
  object-fit: contain;
  opacity: 0;
  filter: drop-shadow(0 30px 46px rgba(0, 0, 0, .5));
  transition: opacity .5s ease;
}
.hero-3d.is-ready .hero-3d-fallback { display: none; }
/* Chế độ DỰ PHÒNG 24 khung ảnh: dùng bộ PNG ĐÃ TÁCH NỀN (data-frames-png)
   nên alpha thật → không cần mask, không lộ quầng trắng, không "khung". */
.hero-3d.is-frames .hero-3d-fallback {
  display: block;
  opacity: 1;
}
.hero-3d.is-frames::after { opacity: .6; }
/* Nhãn + giá: JS chiếu hộp bao model ra màn hình rồi đặt --bd-x/--bd-y/--cp-x/--cp-y
   → luôn bám đúng thân máy ở mọi kích thước viewport, không hardcode %.
   PHẢI reset bottom/right của rule gốc, nếu không phần tử bị kéo dãn thành hộp lớn. */
.hero-3d .hero-badge {
  left: var(--bd-x, 56%); top: var(--bd-y, 26%);
  right: auto; bottom: auto;
  transform: translateY(-50%);
}
.hero-3d .hero-chip {
  left: var(--cp-x, 56%); top: var(--cp-y, 74%);
  right: auto; bottom: auto;
  transform: translateY(-50%);
}
.hero-3d-hint {
  position: absolute; left: auto; right: 3%; bottom: 8%; transform: none;
  font-size: .78rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: rgba(240, 243, 246, .55); white-space: nowrap;
  pointer-events: none; transition: opacity .5s ease;
}
.hero-3d-hint::before { content: "↻ "; }
.hero-3d-hint.is-hidden { opacity: 0; }
.hero-3d-load {
  position: absolute; left: 70%; top: 50%; transform: translate(-50%, -50%);
  font-size: .85rem; color: var(--fg-dim);
  background: rgba(15, 23, 33, .72); padding: .4rem .9rem; border-radius: 999px;
}
.hero-3d-load[hidden] { display: none; }

/* ---------- 28c) HERO GHIM — CUỘN LÀ XOAY MODEL ----------
   Dựng đúng hành vi trang mẫu:
     section (250svh) > .hero-pin-inner (sticky, 100svh) > canvas + 3 cảnh + dải màu
   Trình duyệt tự lo việc GHIM/NHẢ; JS chỉ đọc tiến độ cuộn để xoay model + đổi cảnh.

   ⚠️ KHÔNG đặt overflow:hidden lên .hero-pin — nó biến section thành khối cuộn và
   position:sticky sẽ chết. Việc cắt tràn giao cho .hero-pin-inner. */
.hero.hero-v5.hero-pin {
  /* --hero-top = chiều cao navbar. JS đo lại và ghi đè con số mặc định này.
     Kéo hero LÊN 0 để nó bắt đầu ngay đỉnh trang (navbar sticky nằm đè lên trên,
     z-index 1500) — đúng cách trang mẫu làm. Nếu không kéo lên, khối ghim cao
     100svh sẽ bắt đầu ở y=navbar nên bị tràn xuống dưới đáy màn hình ~65px. */
  --hero-top: 65px;
  margin-top: calc(-1 * var(--hero-top));
  height: calc(250svh - var(--hero-top));   /* 2,5 màn hình — đúng trang mẫu */
  min-height: 0;
  display: block;                /* cha cũ là flex → phải về block thì sticky mới chạy */
  overflow: visible;             /* BẮT BUỘC: ghi đè .hero{overflow:hidden} */
  align-items: stretch;
  background: var(--night);
}
.hero.hero-v5.hero-pin::after { display: none; }   /* dải mờ chân hero cũ không còn dùng */
/* Nền "sàn studio" đặt ở KHỐI GHIM (không đặt ở section) để nền ĐỨNG YÊN suốt
   quá trình cuộn — đúng cảm giác studio của trang mẫu. */
.hero-pin-inner {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  background:
    radial-gradient(1200px 620px at 78% 4%, rgba(11, 92, 171, .40), transparent 62%),
    linear-gradient(180deg, #0b1622 0%, #0e1c2b 64%, #0a1420 100%);
}
/* Lưới sàn mờ dần lên trên — thuần trang trí, không bắt chuột */
.hero-pin-inner::before {
  content: "";
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(240, 243, 246, .055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(240, 243, 246, .055) 1px, transparent 1px);
  background-size: 68px 68px;
  -webkit-mask-image: linear-gradient(180deg, transparent 46%, #000 84%);
  mask-image: linear-gradient(180deg, transparent 46%, #000 84%);
}

/* --- 3 cảnh chữ chồng lên nhau --- */
.hero-scenes { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
.hero-scene {
  position: absolute; inset: 0;
  opacity: 0;
  pointer-events: none;
  /* KHÔNG dùng transition: độ mờ do JS đặt theo từng frame (bám tiến độ cuộn) */
}
/* ⚠️ TUYỆT ĐỐI KHÔNG đặt pointer-events:auto cho CẢ một cảnh.
   Lớp cảnh phủ kín khối ghim, nếu cảnh nhận chuột thì nó nuốt hết sự kiện và
   vùng kéo xoay model (nằm dưới, z-index 1) không bao giờ nhận được pointerdown
   → đúng lỗi "cuộn thì xoay được mà kéo tay thì không".
   Chỉ mở lại cho ĐÚNG các phần tử bấm được VÀ CHỈ Ở CẢNH ĐANG HIỆN.
   Nếu bỏ điều kiện .is-on thì nút của cảnh đang ẩn (opacity 0) vẫn nằm đè lên
   nút của cảnh đang hiện và cướp cú bấm — đã bắt được lỗi này khi kiểm thử. */
.hero-scene.is-on a, .hero-scene.is-on button { pointer-events: auto; }
.hero-scene-in {
  height: 100%;
  display: flex; flex-direction: column; justify-content: center;
  padding-block: clamp(5rem, 3.5rem + 6vw, 8rem) clamp(4rem, 3rem + 4vw, 6rem);
}
.hero-scene-in-b { justify-content: flex-end; }
.hero-scene-left { max-width: 40rem; min-width: 0; }
.hero-scene-bottom { max-width: min(34rem, 100%); display: grid; gap: .7rem; justify-items: start; }

.hero-scene-h {
  font-size: clamp(1.6rem, 1.1rem + 2.2vw, 2.6rem);
  font-weight: 800; line-height: 1.15; color: var(--fg); margin: 0;
}
.hero-scene-p { color: var(--fg-dim); margin: 0; max-width: 32rem; }

.hero-pcard {
  margin-top: .6rem;
  display: grid; gap: .25rem; justify-items: start;
  padding: .9rem 1.2rem;
  border: 1px solid rgba(240, 243, 246, .18);
  border-radius: var(--r-box);
  background: rgba(11, 22, 34, .55);
  text-decoration: none;
  transition: border-color .2s ease, transform .2s ease;
}
.hero-pcard:hover { border-color: var(--sky); transform: translateY(-2px); }
.hero-pcard-eyebrow { font-size: .66rem; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; color: rgba(240, 243, 246, .5); }
.hero-pcard-name { font-size: 1.05rem; color: var(--fg); }
.hero-pcard-price { font-size: .92rem; color: var(--fg-dim); }
.hero-pcard-price b { color: var(--sky); }
.hero-pcard-cta { font-size: .85rem; font-weight: 700; color: var(--sky); }

/* --- CẢNH 2: số liệu bày 2 bên như trang mẫu --- */
.hero-stats-grid {
  position: absolute; inset: 0;
  display: grid; grid-template-columns: 1fr 1fr;
  align-content: center; align-items: center;
  /* Canh số liệu ĐÚNG TRỤC với .khung — khớp tiêu đề cảnh 1/3 và dòng chú thích.
     Riêng lề phải luôn chừa sàn 6rem cho chỉ báo chương "01 / 11" nằm sát mép
     phải (chỉ báo chỉ hiện ở màn >900px; ở khoảng 900–1312px thì .khung còn rộng
     hơn viewport nên nếu không có mức sàn này số liệu sẽ chồng lên chỉ báo). */
  padding-inline:
    max(1.25rem, calc((100vw - var(--khung)) / 2))
    max(6rem, calc((100vw - var(--khung)) / 2));
  padding-block: 4rem;
}
.hero-stat-big { justify-self: start; }
.hero-stat-col { justify-self: end; display: grid; gap: clamp(1.25rem, 1rem + 2.5vw, 2.75rem); text-align: right; }
.hero-stat-big b, .hero-stat-sm b {
  display: block; font-weight: 800; color: var(--fg); line-height: 1;
  font-variant-numeric: tabular-nums;   /* số đếm không nhảy bề ngang */
}
.hero-stat-big b { font-size: clamp(2.6rem, 1.6rem + 5vw, 6rem); }
.hero-stat-sm b { font-size: clamp(1.6rem, 1.1rem + 2.4vw, 3rem); }
.hero-stat-big b i, .hero-stat-sm b i {
  font-style: normal; font-weight: 700; color: var(--sky);
  font-size: .42em; margin-left: .18em; letter-spacing: .02em;
}
.hero-stat-big .lbl, .hero-stat-sm .lbl {
  display: block; margin-top: .45rem;
  font-size: .78rem; font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
  color: rgba(240, 243, 246, .55);
}
.hero-stats-cap {
  position: absolute; left: 0; right: 0; bottom: clamp(3.5rem, 2.5rem + 3vw, 5.5rem);
  /* margin-inline:auto là để .khung tự canh giữa — KHÔNG đặt margin:0 vì sẽ
     ghi đè và dính chú thích vào sát mép trái. */
  margin-block: 0; margin-inline: auto;
  color: var(--fg-dim); font-size: .95rem;
}
.hero-stats-cap b { color: var(--fg); }

/* --- DẢI MÀU VỎ: cố định góc phải-dưới suốt hero (như trang mẫu) --- */
.hero-swatches {
  position: absolute;
  right: clamp(1rem, .4rem + 1.8vw, 2.5rem);
  bottom: clamp(1rem, .4rem + 1.8vw, 2.5rem);
  z-index: 4;
  display: grid; gap: .5rem; justify-items: end;
  text-align: right;
  pointer-events: auto;
}
.hero-swatches[hidden] { display: none; }
.hero-sw-lbl { font-size: .62rem; font-weight: 700; letter-spacing: .18em; text-transform: uppercase; color: rgba(240, 243, 246, .45); }
.hero-sw-name { font-size: .86rem; font-weight: 600; color: var(--fg); }
.hero-sw-chips { display: flex; gap: .5rem; }
.hero-sw {
  width: 26px; height: 26px; padding: 0;
  border-radius: 50%;
  background: var(--sw, #ccc);
  border: 2px solid rgba(240, 243, 246, .3);
  cursor: pointer;
  transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease;
}
.hero-sw:hover { transform: translateY(-2px); }
.hero-sw.is-on { border-color: var(--sky); box-shadow: 0 0 0 3px rgba(88, 182, 234, .3); }

/* --- Gợi ý "CUỘN" ở giữa-dưới --- */
.hero-cue {
  position: absolute; left: 50%; bottom: clamp(1.1rem, .8rem + 1vw, 2rem);
  transform: translateX(-50%);
  z-index: 4;
  display: grid; justify-items: center; gap: .5rem;
  font-size: .62rem; font-weight: 700; letter-spacing: .22em; text-transform: uppercase;
  color: rgba(240, 243, 246, .6); text-decoration: none;
  transition: opacity .45s ease;
}
.hero-cue-line {
  position: relative; display: block;
  width: 1px; height: 44px; overflow: hidden;
  background: linear-gradient(180deg, rgba(88, 182, 234, .55), rgba(88, 182, 234, 0));
}
.hero-cue-line::after {
  content: ""; position: absolute; left: 0; top: -60%;
  width: 100%; height: 60%;
  background: var(--sky);
  animation: hero-cue-drop 1.9s ease-in-out infinite;
}
@keyframes hero-cue-drop {
  0% { transform: translateY(0); opacity: 0; }
  25% { opacity: 1; }
  100% { transform: translateY(300%); opacity: 0; }
}
.hero-cue.is-hidden { opacity: 0; pointer-events: none; }

/* --- Màn ≤1024px: model chiếm nửa trên, MỌI nội dung chữ dồn xuống đáy ---
   Trên màn hẹp, hero chỉ còn 1 cột nên nếu canh chữ giữa màn hình thì model sẽ
   đè lên chữ (đã thấy khi kiểm tra ở 390px). Dồn chữ xuống đáy là cách chắc chắn
   không chồng, và giữ được đúng thứ tự model-trên / chữ-dưới. */
@media (max-width: 1024px) {
  .hero-scene-in { justify-content: flex-end; padding-block: 2.5rem 6.5rem; }
  .hero-scene-in-b { padding-block: 2.5rem 8.5rem; }   /* chừa chỗ cho dải màu vỏ */
  .hero-scene-bottom { max-width: 100%; }
  .hero-stat-big .lbl, .hero-stat-sm .lbl { font-size: .68rem; letter-spacing: .1em; }

  /* Cảnh 2: số liệu cũng dồn xuống đáy, chú thích đẩy LÊN TRÊN số liệu bằng order */
  .hero-scene[data-scene="2"] {
    display: flex; flex-direction: column; justify-content: flex-end;
    padding-block: 3rem 8.5rem;
  }
  .hero-stats-grid {
    position: static; grid-template-columns: 1fr;
    row-gap: 1.25rem; padding: 0 1.25rem;
  }
  .hero-stat-big, .hero-stat-col { justify-self: center; text-align: center; }
  .hero-stat-col { grid-auto-flow: column; gap: 1.5rem; }
  .hero-stats-cap { position: static; order: -1; margin: 0 0 1.1rem; padding-inline: 1.25rem; }

  .hero-swatches { right: .9rem; bottom: .9rem; }
  .hero-sw { width: 22px; height: 22px; }
  .hero-cue { display: none; }
}
/* Mobile hẹp: rút ngắn vùng ghim + lưới sàn dày hơn cho khỏi rối */
@media (max-width: 768px) {
  .hero.hero-v5.hero-pin { --hero-top: 61px; height: calc(150svh - var(--hero-top)); }
  .hero-pin-inner::before { background-size: 48px 48px; }
}
/* Giảm chuyển động: tắt nhịp chạy của vạch "CUỘN" (JS cũng tắt vòng xoay theo cuộn) */
@media (prefers-reduced-motion: reduce) {
  .hero-cue-line::after { animation: none; }
}

/* ---------- 29) SECTION-HEAD CANH GIỮA ---------- */
.section-head-c { max-width: 46rem; margin-inline: auto; text-align: center; }
.section-head-c p { margin-inline: auto; }

/* ---------- 30) DẢI THÔNG SỐ NỔI BẬT (#thong-so — nền tối) ---------- */
.specstrip-sec { position: relative; }
.specstrip-sec .section-head-c .eyebrow { color: var(--sky); }
.specstrip-sec .section-head-c h2 { color: var(--fg); }
.specstrip-sec .section-head-c p { color: var(--fg-dim); }
.specstrip {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, .5rem + 1.5vw, 2rem);
  border-top: 1px solid rgba(240, 243, 246, .16);
  border-bottom: 1px solid rgba(240, 243, 246, .16);
  padding-block: clamp(1.5rem, 1rem + 2vw, 2.5rem);
}
.specstrip-item { text-align: center; padding-inline: .5rem; }
.specstrip-item + .specstrip-item { border-left: 1px solid rgba(240, 243, 246, .16); }
.specstrip-item b {
  display: block; font-size: clamp(2rem, 1.4rem + 2.4vw, 3.5rem);
  font-weight: 800; color: var(--sky); line-height: 1.05;
}
.specstrip-item .lbl { display: block; margin-top: .35rem; font-size: .95rem; color: var(--fg-dim); }

/* ---------- 31) VIEWER 360° — kéo xoay 24 khung + 8 swatch ---------- */
.viewer360-sec { position: relative; }
.viewer360 {
  display: grid; grid-template-columns: minmax(0, 1fr) 320px;
  gap: clamp(1.25rem, .5rem + 2vw, 2.5rem); align-items: start;
}
.viewer360-stage {
  position: relative; overflow: hidden; cursor: grab;
  aspect-ratio: 4 / 3;
  display: grid; place-items: center;
  background: radial-gradient(680px 380px at 50% 28%, var(--white), var(--paper-2));
  border: 1px solid var(--line); border-radius: var(--r-lg);
  touch-action: pan-y; /* cho phép cuộn dọc trang, chặn kéo ngang mặc định */
}
.viewer360-stage.is-dragging { cursor: grabbing; }
/* 24 khung 360° đều là ảnh VUÔNG 512×512. Nếu để <img> nằm trong luồng (grid item)
   thì `height: 100%` KHÔNG resolve (stage cao theo `aspect-ratio`, không có height xác
   định) → ảnh phình cao hơn hộp 4/3 rồi bị `overflow: hidden` của stage CẮT mất phần
   trên/dưới của sản phẩm. Định vị TUYỆT ĐỐI để % tính theo hộp đã có kích thước của
   stage → `object-fit: contain` co TRỌN sản phẩm vào khung (2 dải trống 2 bên là
   bình thường vì ảnh vuông nằm trong hộp 4/3). */
.viewer360-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: contain;
  user-select: none; -webkit-user-drag: none;
}
.viewer360-hint {
  position: absolute; left: 50%; bottom: 1rem; transform: translateX(-50%);
  background: rgba(16, 22, 32, .78); color: #fff;
  font-size: .85rem; font-weight: 600; letter-spacing: .02em;
  padding: .45rem .95rem; border-radius: 999px; white-space: nowrap;
  pointer-events: none;
  transition: opacity .3s ease, visibility .3s ease;
}
.viewer360-hint.is-hidden { opacity: 0; visibility: hidden; }
.viewer360-load {
  position: absolute; top: 1rem; left: 50%; transform: translateX(-50%);
  background: rgba(16, 22, 32, .78); color: #fff;
  font-size: .8rem; padding: .3rem .8rem; border-radius: 999px;
}
.viewer360-load[hidden] { display: none; }
.viewer360-side { display: flex; flex-direction: column; gap: .85rem; }
.viewer360-name { font-size: var(--t-h3); margin: 0; color: var(--ink); }
.viewer360-prices { display: flex; align-items: baseline; gap: .6rem; }
.viewer360-colors { display: flex; flex-wrap: wrap; gap: .6rem; }
.v360-swatch {
  width: 34px; height: 34px; padding: 0; border-radius: 50%;
  background: var(--sw, var(--paper-2));
  border: 2px solid var(--line); cursor: pointer;
  transition: border-color .2s ease, box-shadow .2s ease, transform .15s ease;
}
.v360-swatch:hover { border-color: var(--ink-3); transform: translateY(-1px); }
.v360-swatch:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.v360-swatch.is-active { border-color: var(--blue); box-shadow: 0 0 0 3px var(--glow); }
.viewer360-note { margin: 0; font-size: .875rem; color: var(--ink-3); }

/* ---------- 31b) ZOOM TOÀN KHUNG cho viewer 360° (overlay do JS tạo, prefix .v360-zoom) ---------- */
/* Badge gợi ý "bấm để phóng to" — JS gắn .is-zoomable, KHÔNG cần sửa markup Razor */
.viewer360-stage.is-zoomable::after {
  content: "⤢";
  position: absolute; top: .75rem; right: .75rem; z-index: 2;
  width: 34px; height: 34px; display: grid; place-items: center;
  background: rgba(16, 22, 32, .72); color: #fff;
  border-radius: 50%; font-size: 1rem; line-height: 1;
  pointer-events: none;
}
/* z-index 2900: TRÊN navbar/scroll-progress (1500/1600) và overlay chuyển trang (2800),
   cùng tầng .zoom-overlay có sẵn, dưới intro veil (3000) */
.v360-zoom {
  position: fixed; inset: 0; z-index: 2900;
  display: grid; place-items: center; padding: clamp(1rem, 4vw, 3rem);
  background: rgba(15, 23, 33, .92);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .3s ease, visibility .3s;
  cursor: zoom-out;
}
.v360-zoom.is-open { opacity: 1; visibility: visible; pointer-events: auto; }
.v360-zoom img {
  max-width: min(1200px, 94vw); max-height: 88vh; width: auto; height: auto;
  object-fit: contain; cursor: default;
  border-radius: var(--r-lg);
  box-shadow: 0 30px 80px rgba(0, 0, 0, .6);
}
.v360-zoom-close {
  position: absolute; top: clamp(.75rem, 2vw, 1.5rem); right: clamp(.75rem, 2vw, 1.5rem);
  width: 44px; height: 44px; display: grid; place-items: center;
  border: 1px solid rgba(255, 255, 255, .35); border-radius: 50%;
  background: rgba(16, 22, 32, .72); color: #fff;
  font-size: 1.15rem; line-height: 1; cursor: pointer;
}
.v360-zoom-close:hover { background: var(--blue); border-color: var(--blue); }
.v360-zoom-close:focus-visible { outline: 2px solid var(--sky); outline-offset: 2px; }
html.reduce-fx .v360-zoom { transition: none; }

/* ---------- 32) BANNER FULL-WIDTH (#banner — KHÔNG content-visibility) ---------- */
.banner {
  position: relative; overflow: hidden;
  min-height: clamp(360px, 52vh, 560px);
  display: grid; place-items: center;
  text-align: center; color: #fff;
  background: var(--night); /* nền dự phòng khi ảnh chưa tải */
}
/* Overscan -8%: JS scale 0.92→1.08 → ảnh luôn phủ kín, không hở mép khi thu nhỏ */
.banner-media { position: absolute; inset: -8%; }
.banner-media img { width: 100%; height: 100%; object-fit: cover; }
.banner-veil {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(15, 23, 33, .55), rgba(15, 23, 33, .74) 55%, rgba(15, 23, 33, .88));
}
.banner-inner { position: relative; z-index: 2; padding-block: clamp(2.5rem, 2rem + 3vw, 4rem); }
.banner-kicker {
  display: inline-block; font-size: .8rem; font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--sky); margin-bottom: .75rem;
}
.banner-title { font-size: var(--t-h2); color: #fff; margin: 0 0 .6em; }
.banner-sub {
  max-width: 44rem; margin: 0 auto 1.75rem;
  color: rgba(240, 243, 246, .86); font-size: var(--t-lead);
}
.banner-ctas { display: flex; flex-wrap: wrap; gap: .75rem; justify-content: center; }

/* ---------- 33) SO SÁNH THÔNG SỐ (#so-sanh — bảng rút gọn 4 thẻ) ---------- */
.compare { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.25rem; }
.compare-card {
  display: flex; flex-direction: column;
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r-lg); overflow: hidden;
  transition: box-shadow .25s ease, border-color .25s ease;
  transform-style: preserve-3d;
}
.compare-card:hover { box-shadow: 0 20px 44px rgba(16, 22, 32, .16); border-color: rgba(11, 92, 171, .4); z-index: 2; }
.compare-media {
  background: #f7f9fb; padding: 1rem; overflow: hidden;
  aspect-ratio: 4 / 3; display: grid; place-items: center;
}
.compare-media img { width: 100%; height: 100%; object-fit: contain; transform: translateZ(18px); transition: transform .3s ease; }
.compare-card:hover .compare-media img { transform: translateZ(18px) scale(1.05); }
.compare-name { font-size: 1.02rem; font-weight: 700; color: var(--ink); margin: .95rem 0 .35rem; padding-inline: 1.1rem; min-height: 2.6em; }
.compare-rows { margin: 0; padding: 0 1.1rem; }
.compare-row {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  padding: .55rem 0; border-bottom: 1px solid var(--line);
}
.compare-row:last-child { border-bottom: 0; }
.compare-row dt { color: var(--ink-3); font-size: .9rem; }
.compare-row dd { margin: 0; font-weight: 700; color: var(--ink); font-size: .95rem; text-align: right; }
.compare-cta { margin: 1rem 1.1rem 1.25rem; margin-top: auto; font-weight: 700; font-size: .95rem; color: var(--blue); }
.compare-cta:hover { color: var(--sky); }

/* ---------- 34) LƯỚI SẢN PHẨM + "Xem toàn bộ" (tinh chỉnh như trang mẫu) ---------- */
/* Ảnh lớn hơn, nền sáng hơn, badge giữ nguyên, nút Chọn mua full-width (đã có sẵn) */
.card-media {
  aspect-ratio: 4 / 3;
  background: #f7f9fb;
  padding: 1rem;
}
.card-media img { width: 100%; height: 100%; object-fit: contain; }
.product-card { background: var(--white); }
.product-card:hover { box-shadow: 0 22px 46px rgba(16, 22, 32, .16); }
.grid-more { display: flex; justify-content: center; margin-top: 2rem; }
.btn-ghost-dark { border-color: rgba(16, 22, 32, .35); color: var(--ink); background: transparent; }
.btn-ghost-dark:hover { color: var(--blue); border-color: var(--blue); background: rgba(11, 92, 171, .06); box-shadow: 0 0 0 4px var(--glow); }

/* ---------- 35) PIN PANEL MEDIA (#cong-nghe — ảnh cạnh thẻ nội dung) ---------- */
/* Chỉ đổi bố cục khi panel THỰC SỰ có ảnh → an toàn nếu thiếu .pin-panel-media */
.pin-panel:has(.pin-panel-media) {
  grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
  gap: clamp(1.25rem, .5rem + 2vw, 2.5rem);
  padding-inline: 1.25rem;
}
.pin-panel:has(.pin-panel-media) .pin-panel-card { max-width: none; width: 100%; }
.pin-panel-media {
  width: 100%; max-width: 460px; margin-inline: auto;
  border-radius: var(--r-lg); overflow: hidden;
  border: 1px solid rgba(240, 243, 246, .14);
  background: var(--night-2);
}
.pin-panel-media img { width: 100%; aspect-ratio: 4 / 3; height: auto; object-fit: cover; }

/* ---------- 36) DẢI SỐ LIỆU THUYẾT PHỤC (#so-lieu — KHÔNG content-visibility) ---------- */
.stats-strip {
  position: relative; color: var(--fg);
  background: linear-gradient(180deg, var(--night), var(--night-2));
  padding-block: clamp(2.5rem, 2rem + 3vw, 4.5rem);
}
.stats-grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem; text-align: center;
}
.stats-item { padding-inline: .75rem; }
.stats-item + .stats-item { border-left: 1px solid rgba(240, 243, 246, .16); }
.stats-item b {
  display: block; font-size: clamp(2.25rem, 1.5rem + 3vw, 4rem);
  font-weight: 800; color: var(--sky); line-height: 1;
}
.stats-lbl {
  display: block; margin-top: .5rem; font-size: .95rem;
  letter-spacing: .06em; text-transform: uppercase; color: var(--fg-dim);
}

/* ---------- 37) FORM TƯ VẤN (#tu-van — KHÔNG content-visibility) ---------- */
.consult { background: var(--paper); padding-block: var(--section-y); }
.consult-grid {
  display: grid; grid-template-columns: 1fr 1.1fr;
  gap: clamp(1.5rem, .5rem + 3vw, 3.5rem); align-items: start;
}
.consult-head .eyebrow {
  display: inline-block; font-size: .8rem; font-weight: 800; letter-spacing: .16em;
  text-transform: uppercase; color: var(--blue); margin-bottom: .6rem;
}
.consult-head h2 { font-size: var(--t-h2); }
.consult-head p { color: var(--ink-3); font-size: var(--t-lead); margin: 0 0 .5rem; }
.consult-hotline {
  display: inline-block; margin-top: .5rem;
  font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2.25rem);
  font-weight: 800; color: var(--blue); letter-spacing: .01em;
}
.consult-hotline:hover { color: var(--sky); }
.consult-form {
  display: grid; gap: 1rem;
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: clamp(1.25rem, 1rem + 1vw, 2rem);
}
.field { display: grid; gap: .4rem; }
.field label { font-weight: 600; font-size: .95rem; color: var(--ink); }
.field .req { color: #d0021b; }
.field input, .field select {
  width: 100%; font: inherit; color: var(--ink);
  background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--r-box); padding: .7rem .85rem;
  transition: border-color .2s ease, box-shadow .2s ease, background .2s ease;
}
.field input:focus, .field select:focus {
  outline: none; background: var(--white);
  border-color: var(--blue); box-shadow: 0 0 0 4px var(--glow);
}
.field-err { font-size: .85rem; color: #b00020; min-height: 1.1em; }
.field:not(.is-invalid) .field-err { display: none; }
.field.is-invalid input, .field.is-invalid select {
  border-color: #d0021b; box-shadow: 0 0 0 3px rgba(208, 2, 27, .14);
}
.consult-submit { width: 100%; margin-top: .25rem; }
.consult-consent { margin: 0; font-size: .85rem; color: var(--ink-3); }
.consult-consent a { text-decoration: underline; }
.consult-status {
  margin: 0; min-height: 1.2em; font-size: .95rem; font-weight: 600;
  opacity: 0; transform: translateY(6px); transition: opacity .3s ease, transform .3s ease;
}
.consult-status.is-ok { opacity: 1; transform: none; color: #1a7f37; }

/* ---------- 38) FOOTER — link "Lên đầu trang ↑" ---------- */
.footer-top {
  margin-left: auto; white-space: nowrap;
  font-weight: 700; font-size: .85rem; color: var(--fg-dim);
  transition: color .2s ease, transform .2s ease;
}
.footer-top:hover { color: var(--sky); transform: translateY(-2px); }

/* ---------- 39) RESPONSIVE BỔ SUNG CHO KHỐI v5 ---------- */
@media (max-width: 1024px) {
  .hero-v5-inner { grid-template-columns: 1fr; text-align: center; }
  .hero-v5-sub { margin-inline: auto; }
  .hero-v5-ctas, .hero-v5-specs { justify-content: center; }
  .hero-v5-spec { padding-inline: 1.25rem; margin-inline: 0; border-right: 0; }
  .hero-v5-stage { order: -1; }
  .compare { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 900px) {
  .viewer360 { grid-template-columns: 1fr; }
  .viewer360-side { max-width: none; }
  .consult-grid { grid-template-columns: 1fr; }
  .pin-panel:has(.pin-panel-media) { grid-template-columns: 1fr; }
  .pin-panel-media { max-width: 100%; }
}

@media (max-width: 640px) {
  /* CTA navbar vẫn hiện — thu gọn chữ + khoảng đệm */
  .nav-cta { font-size: .78rem; padding: .5rem .7rem; }
  /* Hero: chữ phải vừa 390px — hạ cỡ, cho phép ngắt từ dài, siết khung */
  .hero-v5-title { font-size: clamp(1.7rem, 1.2rem + 3.6vw, 2.4rem); overflow-wrap: break-word; }
  .hero-v5-sub { font-size: 1rem; }
  .hero-v5-inner { padding-block: 2rem 2.5rem; gap: 1.25rem; }
  /* Hero 3D: vị trí/kích thước do JS tính theo viewport (hàm layout()).
     Ở đây chỉ chỉnh cỡ chữ nhãn cho vừa màn hẹp. */
  .hero-v5-shot { max-width: 100%; }
  /* Model xếp trên, phần chữ nằm dưới → đảm bảo chữ không bị model che */
  .hero-v5-copy { position: relative; z-index: 3; }
  .hero-v5-stage { z-index: 1; }
  .hero-3d .hero-badge { font-size: .76rem; padding: .3rem .7rem; }
  /* Chip giá: ẩn trên mobile — giá đã có ở thẻ sản phẩm, giữ lại sẽ đè tiêu đề */
  .hero-3d .hero-chip { display: none; }
  .hero-3d-hint { font-size: .7rem; }
  /* Dải thông số + dải số liệu: xếp dọc, đường kẻ chuyển từ dọc sang ngang */
  .specstrip { grid-template-columns: 1fr; }
  .specstrip-item + .specstrip-item {
    border-left: 0; border-top: 1px solid rgba(240, 243, 246, .16);
    margin-top: .25rem; padding-top: 1.25rem;
  }
  .stats-grid { grid-template-columns: 1fr; }
  .stats-item + .stats-item {
    border-left: 0; border-top: 1px solid rgba(240, 243, 246, .16);
    padding-top: 1rem;
  }
  .compare { grid-template-columns: 1fr; }
  .banner { min-height: 0; }
  .banner-inner { padding-block: clamp(2.5rem, 2rem + 4vw, 3.5rem); }
  .banner-title { font-size: var(--t-h3); }
}

/* ---------- 40) GIẢM HIỆU ỨNG BỔ SUNG CHO KHỐI v5 ---------- */
/* Nút "giảm hiệu ứng" (class .reduce-fx do JS thêm trên <html>) */
html.reduce-fx .viewer360-hint,
html.reduce-fx .consult-status,
html.reduce-fx .v360-swatch,
html.reduce-fx .compare-card,
html.reduce-fx .compare-media img,
html.reduce-fx .card-media img,
html.reduce-fx .footer-top { transition: none !important; }
html.reduce-fx .consult-status { opacity: 1; transform: none; }

/* Nhánh prefers-reduced-motion BỔ SUNG — giữ nguyên khối mục 26 ở trên */
@media (prefers-reduced-motion: reduce) {
  /* Banner (parallax/scale do JS lo) + hint 360° + form: không chuyển động */
  .banner-media, .banner-veil { transform: none !important; }
  .viewer360-hint, .consult-status, .v360-swatch, .compare-card, .compare-media img { transition: none !important; }
  .consult-status { opacity: 1; transform: none; }
  .viewer360-hint.is-hidden { opacity: 0; visibility: hidden; }
  /* Hero 3D: vẫn hiện model (JS đã tắt tự xoay) nhưng bỏ mọi chuyển động phụ */
  .hero-3d-hint { display: none; }
}

/* ============================================================================
   40) VÁ NHỎ: THANH MENU KHÔNG NGẮT CHỮ & KHÔNG TRÀN KHUNG
   ----------------------------------------------------------------------------
   Đo thật ở cổng 5112 ngày 2026-10-18 (Chrome headless, giả lập badge giỏ "12"):
     • `.khung` rộng cố định 1312px (mục 1: `--khung`) → chỗ cho menu + khối công cụ
       chỉ có 1122px, nhưng thiết kế gốc cần ~1198px ⇒ TRÀN 76px rồi bị `contain: paint`
       của `.topbar` CẮT.
     • `.nav a` thiếu `white-space: nowrap` → chữ menu tự ngắt 2 dòng: "Trang / chủ"…
     • link "Đăng nhập / Đăng ký" trong `.topbar-tools` cũng ngắt 2 dòng.
     • 641–1100px: menu ngang cần ~700px, không đời nào vừa → TRÀN tới 380px.
   Vá: (1) chặn ngắt chữ ở cả menu lẫn khối công cụ;
       (2) thu nhẹ gap/cỡ chữ — vẫn giữ ĐỦ mọi mục của thiết kế;
       (3) 641–1100px: cho menu thu thành nút ☰ (đúng như hành vi mobile ≤640px).
   ⚠️ Mọi media query đều kèm `min-width: 641px` để không giẫm khối mobile ở mục 25.
   ========================================================================== */
.nav a { white-space: nowrap; }
.topbar-tools > * { white-space: nowrap; }

@media (min-width: 641px) {
  .nav { gap: .5rem; }
  .nav a { font-size: .88rem; }
  .topbar-tools { gap: .5rem; }
  .nav-cta { font-size: .84rem; padding: .55rem .85rem; }
  .hotline { font-size: .88rem; }
}

/* 641–1100px: không đủ chỗ cho menu ngang → dùng lại đúng kiểu menu xổ xuống của mobile */
@media (min-width: 641px) and (max-width: 1100px) {
  .nav {
    position: absolute; top: 100%; left: 0; right: 0;
    display: none; flex-direction: column; align-items: flex-start;
    background: var(--white); border-bottom: 1px solid var(--line);
    padding: 1rem 1.25rem; gap: .75rem;
  }
  body.on-dark .nav { background: var(--night-2); border-bottom-color: rgba(240, 243, 246, .14); }
  .nav.open { display: flex; }
  .nav-toggle { display: grid; place-items: center; margin-left: 0; }
  .topbar-inner { gap: .5rem; }
  .logo { flex: 0 0 auto; }
}

@media (min-width: 641px) and (max-width: 1320px) {
  .nav-cta { display: none; }
}
@media (min-width: 641px) and (max-width: 1120px) {
  .topbar .hotline { display: none; }
}

/* ≤560px (điện thoại nhỏ): logo + nút ☰ + 2 nút tròn + 2 link tài khoản KHÔNG đủ chỗ
   (đo được: tràn 80px ở 480, 50px ở 390, 80px ở 360). Thu gọn dần:
   bỏ nút CTA (trang chủ vẫn có CTA ở hero + mục "Đặt lịch tư vấn"),
   bỏ link "Đăng ký" (vào được từ ngay trang Đăng nhập), nén logo/nút/khoảng cách. */
@media (max-width: 560px) {
  .nav-cta { display: none; }
  .topbar .hotline { display: none; }
  .logo { font-size: 1rem; }
  .sound-btn, .reduce-btn, .nav-toggle { width: 32px; height: 32px; }
  .topbar-tools { gap: .35rem; }
  .topbar-tools a[href$="/TaiKhoan/DangKy"] { display: none; }
}
@media (max-width: 400px) {
  .topbar-inner { gap: .35rem; }
  .logo { font-size: .95rem; }
  .sound-btn, .reduce-btn, .nav-toggle { width: 30px; height: 30px; }
}

/* ============================================================================
   20) COVERFLOW 3D — #bo-suu-tap
   ----------------------------------------------------------------------------
   Thay dải cuộn ngang `.hscroll` bằng coverflow cong 3D vẽ bằng three.js
   (engine: wwwroot/js/ts-coverflow.js — hợp đồng: docs/CONTRACT-coverflow.md).

   Nguyên tắc:
     • `.cf` do JS đặt `height` = vh + (n-1) * stepPx. `.cf-stage` sticky 100svh
       nằm trong đó → cuộn dọc trong section = trượt ngang các tấm.
     • JS thêm `.is-live` khi WebGL dựng xong. KHÔNG có `.is-live`
       (reduce-fx / không WebGL / JS lỗi) → `.cf-stage` ẩn, `.cf-list` hiện
       thành lưới 4 cột: trang vẫn dùng được, link + ảnh thật vẫn cho SEO.
     • `.cf-list` chứa link/ảnh THẬT. Khi live chỉ ẩn khỏi mắt
       (clip-path) — screen reader vẫn đọc được, Google vẫn index được.
     • Section này nền `--paper-2` (sáng) nên chữ dùng `--ink`, nhấn `--blue`.
       Không hard-code màu mới: tái dùng token ở :root.
   ========================================================================== */

/* --- 20.1 KHUNG GỐC ------------------------------------------------------ */
.cf {
  position: relative;
  min-height: 100svh;
  /* Tạo stacking context riêng: canvas (z-index auto) không đè lên navbar/overlay
     của section khác, và .cf-list ẩn (position:absolute) không trôi ra ngoài. */
  isolation: isolate;
}
/* Chế độ dự phòng (chưa/không live): KHÔNG giữ 100svh, nếu không sẽ có một
   khoảng trống cao bằng màn hình phía trên lưới ảnh. */
.cf:not(.is-live) { min-height: 0; }

/* --- 20.2 SÂN KHẤU (sticky) --------------------------------------------- */
.cf-stage {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  /* Vuốt DỌC vẫn cuộn trang bình thường (engine chỉ chặn ngang khi kéo).
     Thiếu dòng này, mobile sẽ "khoá" trang khi chạm vào canvas. */
  touch-action: pan-y;
}
.cf-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* --- 20.3 LỚP PHỦ (chữ + nút) ------------------------------------------- */
/* pointer-events:none để chuột/kéo xuyên qua lớp phủ tới canvas.
   CHỈ 3 control bên dưới bật lại pointer-events:auto. */
.cf-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  /* Đệm TRÊN phải lớn hơn navbar: .topbar là `position: sticky; top: 0`
     (min-height 64px) nên nó luôn nằm đè lên đỉnh `.cf-stage`.
     5.25rem = 84px = 64px navbar + 20px thở. */
  padding: 5.25rem clamp(1rem, 3vw, 3rem) clamp(1rem, 3vw, 2.5rem);
  z-index: 2;
}

/* Hàng trên: nút "Xem tất cả" (phải) + dòng gợi ý (trái).
   Tiêu đề section đã có ở .section-head phía trên nên overlay không lặp lại.
   Gợi ý để ở ĐÂY chứ không để ở đáy: góc dưới bên trái là chỗ nút mở khoá âm
   thanh `#scroll-sfx-unlock` của ts-scroll-sfx.js — trước đây hai thứ đè nhau.
   row-reverse để nút ra phải mà không phải đảo thứ tự trong HTML. */
.cf-head {
  display: flex;
  flex-direction: row-reverse;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.cf-head > div { min-width: 0; }

/* Nhãn nhỏ trên tiêu đề — cùng ngôn ngữ với .eyebrow của .section-head */
/* --- 20.4 PILL: "Xem tất cả" + "Xem sản phẩm" --------------------------- */
.cf-all,
.cf-open {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .45rem;
  padding: .7rem 1.25rem;
  border-radius: 999px;
  font-size: .92rem;
  font-weight: 700;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  pointer-events: auto;           /* bắt buộc: .cf-overlay đang none */
  transition: transform .18s ease, border-color .18s ease,
              background .18s ease, box-shadow .18s ease, color .18s ease;
}
/* Nền trắng mờ + viền --line — đồng bộ với .btn-ghost-dark */
.cf-all {
  background: rgba(255, 255, 255, .66);
  border: 1px solid var(--line);
  color: var(--ink);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.cf-all:hover {
  transform: translateY(-2px);
  border-color: var(--blue);
  color: var(--blue);
  box-shadow: 0 10px 24px rgba(11, 92, 171, .16);
}
/* CTA chính: nền --blue, chữ trắng */
.cf-open {
  background: var(--blue);
  border: 1px solid var(--blue);
  color: #fff;
}
/* Hover: giữ đúng --blue (không thêm mã màu mới) — nhấn bằng nhấc lên + quầng sáng */
.cf-open:hover {
  transform: translateY(-2px);
  background: var(--blue);
  border-color: var(--blue);
  color: #fff;
  box-shadow: 0 12px 28px rgba(11, 92, 171, .34);
}

/* --- 20.5 CHÂN OVERLAY: danh mục + tên + đếm + tiến trình --------------- */
/* 2 cột: tên sản phẩm bên trái, cụm điều khiển bên phải — CÙNG một hàng
   (tiết kiệm ~60px chiều cao so với xếp dọc, nhờ đó tấm 3D không bị chữ đè). */
.cf-foot {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "meta side"
    "bar  bar";
  align-items: end;
  gap: .7rem 1.5rem;
}
.cf-meta {
  grid-area: meta;
  min-width: 0;
  transition: opacity .32s ease, transform .32s cubic-bezier(.22, 1, .36, 1);
}
.cf-meta.is-swap {
  opacity: 0;
  transform: translateY(-8px);
}
.cf-cat {
  margin: 0 0 .2rem;
  text-transform: uppercase;
  letter-spacing: .2em;
  font-size: .78rem;
  font-weight: 700;
  color: var(--ink-3);
}
/* ĐIỂM NHẤN của section: tên sản phẩm đang active, cỡ lớn, tracking âm.
   Cỡ tối đa 3.5rem (không phải 4.5rem): tên dài nhất trong dữ liệu
   ("Máy chơi game PlayStation 4", 27 ký tự) vẫn vừa MỘT hàng mà không
   tràn sang cột điều khiển bên phải. */
.cf-name {
  margin: 0;
  font-weight: 800;
  letter-spacing: -.045em;
  line-height: .95;
  font-size: clamp(1.5rem, .95rem + 2.6vw, 3.5rem);
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cf-side {
  grid-area: side;
  display: flex;
  align-items: center;
  gap: 1rem;
  justify-content: flex-end;
  padding-bottom: .35rem;
}
.cf-count {
  margin: 0;
  font-variant-numeric: tabular-nums;
  font-size: .95rem;
  font-weight: 600;
  color: var(--ink-3);
}
.cf-count b {
  font-size: 1.6rem;
  font-weight: 800;
  color: var(--ink);
}

/* Nút bật/tắt âm thanh — tròn 44×44 (đủ lớn để chạm trên mobile) */
.cf-sound {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, .6);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  pointer-events: auto;           /* bắt buộc: .cf-overlay đang none */
  transition: transform .18s ease, border-color .18s ease, background .18s ease;
}
.cf-sound:hover {
  transform: translateY(-2px);
  border-color: var(--blue);
  background: rgba(255, 255, 255, .85);
}
.cf-sound[aria-pressed="true"] {
  border-color: var(--blue);
  color: var(--blue);
}

/* Thanh tiến trình mảnh: nền --line, phần chạy màu --blue do JS đặt width */
.cf-bar {
  grid-area: bar;
  position: relative;
  height: 1px;
  background: var(--line);
}
.cf-bar i {
  position: absolute;
  inset-block: 0;
  left: 0;
  height: 3px;
  top: -1px;
  width: 0;
  background: var(--blue);
  border-radius: 999px;
  transition: width .45s cubic-bezier(.22, 1, .36, 1);
}

/* Dòng gợi ý — nằm trong .cf-head, canh phải, cỡ nhỏ, màu dịu */
.cf-hint {
  margin: 0;
  font-size: .82rem;
  color: var(--ink-3);
}
.cf-hint-mob { display: none; }

/* --- 20.6 TRẠNG THÁI LIVE (engine đã dựng xong) ------------------------- */
/* Ẩn .cf-list khỏi mắt nhưng GIỮ cho screen reader + crawler */
.cf.is-live .cf-list {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.cf.is-live .cf-stage { cursor: grab; }
.cf.is-live.is-drag .cf-stage { cursor: grabbing; }

/* --- 20.7 DỰ PHÒNG: LƯỚI 4 CỘT (không live) ----------------------------- */
.cf:not(.is-live) .cf-stage { display: none; }

.cf:not(.is-live) .cf-list,
html.reduce-fx .cf-list {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
  padding-inline: 1.25rem;
  /* `.cf` là khối full-bleed (ngoài `.khung`) nên lưới dự phòng phải tự canh
     theo đúng bề rộng `.khung`: 1312px nội dung + 2×1.25rem đệm = khớp tuyệt đối
     với mọi `.khung` khác trong trang, ở mọi bề rộng màn hình. */
  max-width: calc(var(--khung) + 2.5rem);
  margin-inline: auto;
}
.cf:not(.is-live) .cf-card,
html.reduce-fx .cf-card {
  display: block;
  height: 100%;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--r-box);
  overflow: hidden;
  box-shadow: 0 8px 20px rgba(16, 22, 32, .08);
  color: var(--ink);
  text-decoration: none;
  transition: transform .22s ease, box-shadow .22s ease, border-color .22s ease;
}
.cf:not(.is-live) .cf-card:hover,
html.reduce-fx .cf-card:hover {
  transform: translateY(-3px);
  border-color: rgba(11, 92, 171, .45);
  box-shadow: 0 18px 36px rgba(16, 22, 32, .16);
  color: var(--ink);
}
/* Ảnh thẻ: nền tảng dùng chung cho cả 2 chế độ (live vẫn layout đúng nếu bị
   clip-path che). Khi ở lưới dự phòng mới ép vuông 1:1 như ảnh engine dùng. */
.cf-card img {
  width: 100%;
  height: auto;
  border-radius: var(--r-box);
  display: block;
}
/* Ảnh vuông 1:1 đúng như ảnh engine dùng (900×900) */
.cf:not(.is-live) .cf-card img,
html.reduce-fx .cf-card img {
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--r-box) var(--r-box) 0 0;
}
.cf-card-t {
  display: block;
  padding: .6rem .75rem;
  font-weight: 600;
  font-size: .9rem;
  line-height: 1.35;
}

/* reduce-fx: chắc chắn không còn canvas chiếm chỗ */
html.reduce-fx .cf-stage { display: none; }
html.reduce-fx .cf { min-height: 0; }
/* Phòng hờ: nếu người dùng bật "giảm hiệu ứng" ĐÚNG LÚC engine đang live
   (JS gỡ .is-live không kịp), vẫn phải trả .cf-list về lưới nhìn thấy được —
   nếu thiếu rule này, `.cf.is-live .cf-list` (clip-path) sẽ thắng và lưới
   thành một ô 1×1 vô hình. */
html.reduce-fx .cf.is-live .cf-list {
  position: static;
  width: auto;
  height: auto;
  overflow: visible;
  clip-path: none;
  white-space: normal;
}

/* --- 20.8 RESPONSIVE ---------------------------------------------------- */
@media (max-width: 900px) {
  .cf:not(.is-live) .cf-list,
  html.reduce-fx .cf-list { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
  .cf:not(.is-live) .cf-list,
  html.reduce-fx .cf-list { grid-template-columns: 1fr; }
}

/* ≤767px: canvas dọc hơn, chữ phải nhỏ lại và xuống dòng cho vừa 390px */
@media (max-width: 767px) {
  .cf-hint-desk { display: none; }
  .cf-hint-mob { display: inline; }
  /* Màn hẹp: navbar vẫn 64px nhưng chữ nhỏ hơn → đệm trên 4.75rem là đủ */
  .cf-overlay { padding: 4.75rem 1rem 1rem; }
  /* Màn hẹp không đủ chỗ 1 hàng ngang → nút trên, gợi ý dưới, cùng dồn phải */
  .cf-head {
    flex-direction: column;
    align-items: flex-end;
    gap: .5rem;
  }
  /* Chân overlay về 1 cột: tên trên, điều khiển dưới */
  .cf-foot {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "meta"
      "side"
      "bar";
    gap: .6rem;
  }
  /* Tên dài (>= 20 ký tự) cho xuống tối đa 2 dòng thay vì cắt bằng "…" */
  .cf-name {
    font-size: clamp(1.4rem, 1rem + 5vw, 2.4rem);
    letter-spacing: -.03em;
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
  }
  /* Đếm + CTA dàn hai đầu, nút loa đứng riêng bên trái */
  .cf-side {
    justify-content: space-between;
    gap: .6rem;
    flex-wrap: wrap;
    padding-bottom: 0;
  }
  .cf-all { font-size: .85rem; padding: .6rem 1rem; }
  .cf-open { font-size: .85rem; padding: .6rem 1rem; }
}

/* --- 20.9 GIẢM CHUYỂN ĐỘNG ---------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .cf-bar i,
  .cf-meta { transition: none !important; }
}

/* --- 20.10 NÚT "LÊN ĐẦU TRANG" ------------------------------------------
   #vf-top là `position: fixed` ở góc phải dưới (32px) nên nó đè lên nút
   "Xem sản phẩm" của overlay khi coverflow đang ghim. JS gắn `.cf-onscreen`
   lên <html> đúng lúc .cf nằm trong khung nhìn → ẩn nút đi. Selector
   `html.cf-onscreen #vf-top` (1,1,1) mạnh hơn `#vf-top.vf-show` (1,1,0)
   nên không cần !important. */
/* Thanh "chương 07 / 11" (fixed, right: 1.25rem) cũng nằm đè lên tấm 3D bên
   phải. Ẩn suốt lúc coverflow ghim — nó vốn chỉ để định vị chương, không cần
   khi đang ở trong một section ghim. */
html.cf-onscreen .chapter-progress {
  opacity: 0;
  visibility: hidden;
  transition: opacity .2s ease, visibility .2s ease;
}
html.cf-onscreen #vf-top {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateY(8px);
}
/* Nút dự phòng "Bật âm thanh cuộn" (ts-scroll-sfx tạo khi bị chặn autoplay)
   cũng nằm đè lên chân overlay. Trong coverflow không cần nó: nút loa
   `.cf-sound` của overlay vừa bật `ts-sound` vừa là cú chạm thật để mở khoá
   AudioContext, nên nó thay thế đúng chức năng. Ra khỏi section thì nút
   dự phòng hiện lại như cũ. */
html.cf-onscreen #scroll-sfx-unlock {
  display: none;
}

/* ============================================================================
   21) CỔNG ĐỒNG Ý ÂM THANH — #sound-gate
   ----------------------------------------------------------------------------
   Trình duyệt (Chrome/Edge/Safari) KHÔNG cho phát audio trước một hành động
   thật của người dùng. Cổng này vừa là lời mời, vừa là cú chạm mở khoá:
   bấm nút → AudioContext + nhạc nền + mọi hiệu ứng chạy được.

   • Mỗi PHIÊN TAB một lần: sessionStorage 'ts-sound-gate' = 'ok'.
   • Không có JS → `.sg-gate` giữ `display: none`, trang vẫn dùng được bình
     thường (không khoá cứng người dùng khi JS lỗi).
   • Khoá cuộn bằng `html.sg-lock { overflow: hidden }` — gắn bởi script inline
     ngay sau markup, TRƯỚC khung hình đầu tiên nên không thấy nội dung nhấp nháy.
   • z-index 4000: trên intro veil (3000), page-transition (2800), navbar (1500).
     Con trỏ trang trí (2100) được nâng lên 4100 để vẫn thấy trên cổng.
   ========================================================================== */

html.sg-lock { overflow: hidden; overscroll-behavior: none; }
html.sg-lock body { overscroll-behavior: none; }
/* Con trỏ tuỳ biến phải nằm TRÊN cổng, nếu không nó biến mất sau lớp phủ */
html.sg-lock .cursor,
html.sg-lock .cursor-dot { z-index: 4100; }

.sg-gate {
  display: none;                 /* JS/inline script bật bằng html.sg-lock */
  position: fixed;
  inset: 0;
  z-index: 4000;
  padding: clamp(1rem, 4vw, 3rem);
  overflow: auto;
  background:
    radial-gradient(900px 520px at 78% 8%, rgba(88, 182, 234, .20), transparent 62%),
    radial-gradient(760px 480px at 12% 88%, rgba(11, 92, 171, .26), transparent 60%),
    var(--night);
  overscroll-behavior: contain;
}
/* Flex + margin:auto thay cho place-items:center — khi nội dung CAO HƠN màn
   hình (điện thoại nằm ngang) thì nó bám mép trên và cuộn được, không bị cắt
   mất phần đầu như căn giữa bằng grid. */
html.sg-lock .sg-gate {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Lưới mảnh như hero cho có chất "kỹ thuật" */
.sg-gate::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(240, 243, 246, .05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(240, 243, 246, .05) 1px, transparent 1px);
  background-size: 72px 72px;
  mask-image: radial-gradient(60% 60% at 50% 50%, #000 40%, transparent 100%);
  -webkit-mask-image: radial-gradient(60% 60% at 50% 50%, #000 40%, transparent 100%);
}

.sg-card {
  position: relative;
  z-index: 1;
  width: min(560px, 100%);
  margin: auto;                  /* căn giữa; hết chỗ trống → bám mép trên */
  text-align: center;
  animation: sg-in .62s cubic-bezier(.16, 1, .3, 1) both;
}
@keyframes sg-in {
  from { opacity: 0; transform: translateY(18px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

/* --- 21.1 DẢI SÓNG NHỊP (dấu hiệu "có âm thanh") ------------------------ */
.sg-eq {
  display: inline-flex;
  align-items: flex-end;
  gap: 5px;
  height: 42px;
  margin-bottom: 1.25rem;
}
.sg-eq i {
  display: block;
  width: 5px;
  border-radius: 999px;
  background: linear-gradient(180deg, var(--sky), var(--blue));
  transform-origin: bottom;
  animation: sg-eq 1.15s ease-in-out infinite;
}
.sg-eq i:nth-child(1) { height: 34%; animation-delay: -.10s; }
.sg-eq i:nth-child(2) { height: 100%; animation-delay: -.42s; }
.sg-eq i:nth-child(3) { height: 62%; animation-delay: -.76s; }
.sg-eq i:nth-child(4) { height: 86%; animation-delay: -.28s; }
.sg-eq i:nth-child(5) { height: 46%; animation-delay: -.58s; }
@keyframes sg-eq {
  0%, 100% { transform: scaleY(.32); opacity: .62; }
  50%      { transform: scaleY(1);   opacity: 1; }
}

/* --- 21.2 CHỮ ------------------------------------------------------------ */
.sg-eyebrow {
  margin: 0 0 .55rem;
  font-size: .78rem;
  font-weight: 800;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--sky);
}
.sg-title {
  margin: 0 0 .9rem;
  font-size: clamp(1.7rem, 1.15rem + 2.4vw, 2.9rem);
  line-height: 1.08;
  letter-spacing: -.035em;
  font-weight: 800;
  color: var(--fg);
  text-wrap: balance;
}
.sg-desc {
  margin: 0 auto 1.75rem;
  max-width: 34rem;
  font-size: var(--t-body);
  line-height: 1.6;
  color: var(--fg-dim);
  text-wrap: pretty;             /* tránh dòng cuối chỉ có 1–2 chữ */
}

/* --- 21.3 NÚT ĐỒNG Ý (mục tiêu chạm ≥ 48px) ----------------------------- */
.sg-accept {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .6rem;
  min-height: 56px;
  padding: 1rem 2.1rem;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--blue), #0d6fc4 55%, var(--sky));
  color: #fff;
  font: inherit;
  font-size: clamp(.98rem, .93rem + .2vw, 1.08rem);
  font-weight: 800;
  letter-spacing: -.01em;
  cursor: pointer;
  box-shadow: 0 16px 40px rgba(11, 92, 171, .48), inset 0 1px 0 rgba(255, 255, 255, .22);
  transition: transform .18s ease, box-shadow .18s ease, filter .18s ease;
}
.sg-accept:hover {
  transform: translateY(-2px);
  box-shadow: 0 22px 52px rgba(11, 92, 171, .58), inset 0 1px 0 rgba(255, 255, 255, .28);
  filter: brightness(1.05);
}
.sg-accept:active { transform: translateY(0) scale(.985); }
.sg-accept:focus-visible {
  outline: 2px solid rgba(88, 182, 234, .72);
  outline-offset: 4px;
}
.sg-accept-ico {
  font-size: 1.18em;
  line-height: 1;
  filter: drop-shadow(0 2px 6px rgba(0, 0, 0, .3));
}

.sg-note {
  margin: 1.15rem 0 0;
  font-size: .82rem;
  color: rgba(182, 191, 202, .8);
}

/* --- 21.4 TRẠNG THÁI ĐÓNG ---------------------------------------------- */
.sg-gate.is-out {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity .5s ease, visibility .5s ease;
}
.sg-gate.is-out .sg-card { animation: none; transform: scale(1.015); transition: transform .5s ease; }

/* --- 21.5 MÀN HẸP / GIẢM CHUYỂN ĐỘNG ----------------------------------- */
@media (max-width: 480px) {
  .sg-eq { height: 34px; margin-bottom: 1rem; }
  .sg-desc { font-size: .95rem; }
  .sg-accept { width: 100%; padding: 1rem 1.25rem; }
}
@media (prefers-reduced-motion: reduce) {
  .sg-card { animation: none; }
  .sg-eq i { animation: none; transform: scaleY(.7); }
  .sg-gate.is-out,
  .sg-gate.is-out .sg-card { transition: none; }
}
/* Công tắc "giảm hiệu ứng" của chính site (ts-reduce-fx = '1') */
html.reduce-fx .sg-card { animation: none; }
html.reduce-fx .sg-eq i { animation: none; transform: scaleY(.7); }

/* Màn THẤP (điện thoại nằm ngang, laptop 13" thu nhỏ): nén lại để vừa 1 màn */
@media (max-height: 620px) {
  .sg-eq { height: 26px; margin-bottom: .5rem; }
  .sg-eq i { width: 4px; }
  .sg-eyebrow { margin-bottom: .35rem; font-size: .7rem; }
  .sg-title { margin-bottom: .5rem; font-size: clamp(1.3rem, .95rem + 1.8vw, 1.85rem); }
  .sg-desc { margin-bottom: 1rem; font-size: .9rem; line-height: 1.45; }
  .sg-accept { min-height: 48px; padding: .7rem 1.6rem; font-size: .95rem; }
  .sg-note { margin-top: .7rem; font-size: .76rem; }
}
