/* ============================================================
   墨讀 · Mặc Độc — landing
   Nền GIẤY, cùng chất liệu với app (frontend/src/styles.css): mực
   trên giấy, son cho đúng những chỗ app cũng dùng son. Người đi từ
   landing sang màn đăng nhập của app phải thấy vẫn là một nhà.
   Bản trước là "mặt bàn tối, sản phẩm là vật sáng duy nhất" — đẹp,
   nhưng mở app ra thì mọi thứ đảo màu, và đó là lý do nó bị thay.
   Vật NỔI trên trang (thẻ giấy có viền mảnh + bóng) vẫn là sản
   phẩm hoặc bằng chứng về sản phẩm; chữ thì nằm thẳng trên giấy.
   ============================================================ */

/* ---------- chữ: TỰ HOST, đã cắt ----------
   Trước đây nạp từ Google Fonts và đo được ~810KB: tám tệp con Noto Serif SC
   để vẽ đúng 42 chữ Hán, cộng Newsreader đầy đủ. Nay ~150KB, và quan trọng
   không kém — mất luôn một tệp CSS bên thứ ba đang CHẶN VẼ TRANG cùng hai
   lượt preconnect. Tái tạo bằng `scripts/cat-font.sh` (kèm bước dựng glyph
   pinyin thanh ba mà Newsreader không có); giấy phép OFL của cả hai bộ chữ
   nằm ở `/font/OFL.txt`.
   `font-display: swap` giữ nguyên: chữ phải đọc được ngay, kể cả khi font
   chưa về. Đó cũng là lý do stack dự phòng phải là serif thật (Georgia),
   không phải `serif` chung chung. */
@font-face {
  font-family: "Newsreader";
  /* Còn nguyên trục opsz — mặt chữ này vẽ cả tiêu đề 83px lẫn thân bài 17px,
     nên `font-optical-sizing: auto` ở body có thứ để làm việc. */
  src: url("/font/newsreader-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Newsreader";
  /* opsz ghim ở 16: mặt này chỉ dùng cho vài cụm in đậm cỡ ~17px. */
  src: url("/font/newsreader-500.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Newsreader";
  /* Cắt hẹp về ASCII + nguyên âm có dấu thanh pinyin: bản nghiêng dùng ở ĐÚNG
     .kn-pinyin và .kn-en. Có test khoá điều đó — dùng nghiêng cho chữ tiếng
     Việt sẽ rơi về Georgia nghiêng ngay giữa câu. */
  src: url("/font/newsreader-italic-400.woff2") format("woff2");
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: "Noto Serif SC";
  /* Chỉ những chữ trang dùng, giữ trục wght: 400 thân bài · 600 con dấu và
     chữ trong khung nghĩa · 700 chữ hiệu. */
  src: url("/font/noto-serif-sc.woff2") format("woff2");
  font-weight: 200 900; font-style: normal; font-display: swap;
}

:root {
  /* Giấy & mực — CHÍNH LÀ token của app (--paper, --paper-deep, --paper-card,
     --ink, --ink-soft, --hairline, --cinnabar), đổi tên sang tiếng Việt cho
     cùng lối với phần còn lại của landing. */
  --nen:      #efe9dc;   /* app --paper: nền trang */
  --nen-sau:  #e7dfce;   /* app --paper-deep: tấm nền sau vật minh hoạ */
  --the:      #f5f1e8;   /* app --paper-card: thẻ giấy nổi */
  --muc:      #211e18;   /* app --ink: chữ chính */
  --muc-mo:   #4c473c;   /* app --ink-soft: thân bài */
  /* KHÔNG phải --ink-faint (#8b8270) của app: màu đó chỉ đạt 3,14:1 trên giấy.
     App dùng nó cho nhãn phụ trong giao diện đã đăng nhập; landing là trang
     công khai và chú thích ở đây là chữ người ta cần đọc, nên hạ tối tới khi
     đạt AA trên CẢ ba mặt giấy (4,84:1 trên mặt tối nhất --nen-sau). */
  --muc-nhat: #665e4e;
  --chi:      #d8cfba;   /* app --hairline: kẻ chỉ mảnh */
  /* Viền của Ô NHẬP và ô đánh dấu. Không dùng --chi: WCAG 1.4.11 đòi ranh
     giới của thứ bấm/gõ được đạt 3:1 với nền, --chi chỉ ~1,3:1 — ô email sẽ
     tan vào tấm giấy. #8b8270 đạt 3,37:1 trên --the. */
  --vien:     #8b8270;

  /* son — app --cinnabar. Chữ Hán-Việt, liên kết, nhãn mục, nút. */
  --son:      #b23529;
  --son-dam:  #b23529;   /* nền nút + con dấu; tách tên để đổi riêng được */
  /* vàng — app --gold. Chỉ để trang trí (viền trái câu đang nghe, y như
     `.vcue.active` của app), KHÔNG BAO GIỜ làm màu chữ: 2,69:1. */
  --vang:     #a98a52;

  /* "Noto Serif SC" PHẢI có trong ngăn xếp này, không chỉ ở --serif-cn.
     Newsreader không có glyph Hán, nên một chữ Hán lẫn trong câu tiếng Việt
     rơi xuống font hệ thống — đo bằng CDP: chữ hiệu 墨讀 ở CHÂN TRANG từng vẽ
     bằng Noto Sans CJK JP, một mặt chữ KHÔNG CHÂN và của tiếng Nhật.
     Trình duyệt chọn font theo TỪNG KÝ TỰ, nên đặt sau Newsreader là đúng:
     chữ Latin vẫn Newsreader, chỉ chữ Hán mới rơi sang đây. */
  --serif:    "Newsreader", "Noto Serif SC", Georgia, "Times New Roman", serif;
  --serif-cn: "Noto Serif SC", "Songti SC", serif;

  --bong-the:  0 1px 2px rgba(33, 30, 24, 0.05), 0 8px 24px rgba(33, 30, 24, 0.06);  /* app --shadow-card */
  --bong-sheet: 0 -2px 40px rgba(33, 30, 24, 0.18);                                /* app --shadow-sheet */

  /* Thang chữ theo Elements of Typographic Style — tỉ lệ quãng năm (1.5)
     ở đầu thang, thu dần về 1.25 ở thân bài. */
  /* Sàn 2.25rem chứ không phải 2.6rem: ở 320px, 41,6px không đủ chỗ cho
     "Học tiếng Trung" trong 280px và dòng vỡ thành "Học tiếng / Trung" — cắt
     đúng giữa cụm. 10.5vw giữ gần nguyên cỡ ở 390 (41px). */
  --t-display: clamp(2.25rem, 10.5vw, 5.2rem);
  --t-lon:     clamp(1.9rem, 4.6vw, 2.9rem);
  --t-vua:     clamp(1.25rem, 2.4vw, 1.5rem);
  --t-than:    clamp(1.0rem, 1.6vw, 1.125rem);
  --t-nho:     0.875rem;

  --long:      clamp(20px, 5.5vw, 32px);   /* lề trong khung */
  --khoang:    clamp(72px, 12vw, 128px);   /* khoảng giữa các mục */
  --khung-max: 1140px;                      /* = --shell-max-desktop của app */
  /* Bề rộng tối đa của KHỐI CHỮ khi trang còn một cột (điện thoại, iPad dọc).
     Chỉ chặn chữ — tiêu đề, lời hứa, biểu mẫu — không chặn các tấm minh hoạ:
     ở iPad Pro dọc (1024) tấm 720px cạnh thẻ 960px làm mép phải so le cả trang. */
  --cot:       720px;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/* Không để một chữ đứng trơ ở dòng cuối ("…lời người / nói."). Trình duyệt
   chưa hỗ trợ thì ngắt như thường — không mất gì. */
p, li, summary, figcaption { text-wrap: pretty; }

html { scrollbar-gutter: stable; -webkit-text-size-adjust: 100%; }

body {
  background-color: var(--nen);
  color: var(--muc);
  font-family: var(--serif);
  font-size: var(--t-than);
  line-height: 1.65;          /* serif cần thoáng hơn sans */
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* Vân giấy — CÙNG thủ pháp và cùng số với body của app: hai vệt màu lệch
     tâm cực nhạt + nhiễu mờ, để giấy không phẳng lì như một khối màu. */
  background-image:
    radial-gradient(circle at 18% 12%, rgba(178, 53, 41, 0.035), transparent 38%),
    radial-gradient(circle at 86% 78%, rgba(93, 122, 104, 0.04), transparent 42%),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.035'/%3E%3C/svg%3E");
  background-attachment: fixed;
}

/* MÀU LINK GỐC. Từng KHÔNG có luật `a` nào ở mức gốc, nên một liên kết trong
   <p class="than"> rơi về màu mặc định của trình duyệt — xanh dương đậm, tương
   phản khoảng 1,3:1 trên nền tối hồi đó. Lỗi này không thuộc về một lớp nào,
   nó thuộc về việc thiếu một mặc định; nên đặt ở gốc. */
a { color: var(--son); text-underline-offset: 3px; }

/* Một glyph Hán đứng cạnh chữ Latin thổi phồng hộp dòng nó nằm trong (~1.45x ở
   cùng font-size), và font dự phòng còn đổi hộp dòng mà không đổi nét — nên
   cùng một trang lệch một kiểu lúc font chưa nạp, lệch kiểu khác sau khi nạp.
   `line-height: 1` chốt hộp dòng, ô vuông cố định ở nơi gọi mới là thứ căn với
   hàng xóm. Lý do đầy đủ nằm trong frontend/src/styles.css của app.
   CỐ Ý KHÔNG có font-size ở đây và CỐ Ý KHÔNG nudge bằng transform. */
.cjk-mark {
  display: inline-grid;
  place-items: center;
  align-self: center;
  font-family: var(--serif-cn);
  line-height: 1;
}

/* LỀ NGANG CỦA CẢ TRANG NẰM Ở ĐÂY, và chỉ ở đây.
   Mọi lớp dùng CHUNG phần tử với .khung (.hero, .muc, .form-khoi, .chan…) PHẢI
   dùng `margin-block` / `padding-block`, KHÔNG BAO GIỜ dùng shorthand `margin`
   hay `padding`: shorthand đặt lại cả bốn cạnh, nên nó xoá sạch trục ngang mà
   .khung vừa đặt — cùng độ đặc hiệu, đứng sau nên thắng, không có cảnh báo nào.
   Đã xảy ra HAI lần: `padding` làm cả trang dính mép trái ở điện thoại, rồi
   `margin` trong .form-khoi và .chan xoá mất `margin-inline: auto` nên biểu mẫu
   và chân trang văng sang sát mép trái ở màn rộng — mà ở điện thoại thì không
   thấy, vì ở đó `auto` vốn đã bằng 0.
   Có test tĩnh khoá điều này: xem `noi-dung.test.js`. */
.khung { width: 100%; max-width: var(--khung-max); margin-inline: auto; padding-inline: var(--long); }

/* "Hán-Việt" KHÔNG được ngắt dòng ở dấu gạch nối. Nó là thuật ngữ trung tâm của
   cả luận điểm bán hàng, và trình duyệt coi gạch nối là chỗ ngắt hợp lệ nên nó
   vỡ thành "Hán-" / "Việt" ngay ở tiêu đề — đã xảy ra hai lần trên cùng một
   màn hình 1440px. */
.lien { white-space: nowrap; }
/* Ghim từng CỤM chứ không ghim cả câu: dòng phụ dưới nút màn đầu từng rớt đúng
   chữ "email" xuống một dòng riêng ở MỌI bề rộng. */
.nowrap { white-space: nowrap; }

/* ============================================================
   BỐ CỤC THEO LOẠI MÀN
   - Điện thoại: một cột.
   - iPad dọc (820, 1024): VẪN một cột, chặn ở --cot. iPad Pro dọc rộng 1024
     — đủ để chia hai cột, nhưng chia ra thì màn đầu thành hai cột hẹp dưới
     một khoảng trống cao 1366px. Đúng lỗi app đã gặp ở màn đăng nhập, và
     app sửa bằng đúng điều kiện `orientation: landscape` dưới đây.
   - iPad ngang (1180, 1366) và máy tính: hai cột.
   Mọi nhánh hai cột dùng CÙNG MỘT điều kiện, để không có khổ nào một mục đã
   chia cột còn mục bên cạnh chưa.
   ============================================================ */

/* ---------- masthead: chữ hiệu y như app (KhungCong.jsx / .brand) ---------- */
.dau-trang {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding-block: 22px 18px;
  border-bottom: 1px solid var(--chi);
}
.hieu { display: flex; align-items: center; gap: 14px; color: var(--muc); text-decoration: none; }
.hieu .glyph {
  font-family: var(--serif-cn); font-weight: 700; font-size: clamp(24px, 6vw, 30px);
  line-height: 1; letter-spacing: 2px; color: var(--muc);
}
/* Giãn 0.42em như `.brand .latin` của app. Căn baseline với chữ hiệu ăn ở
   app vì hai thứ cùng một hàng flex `align-items: baseline`; ở đây hàng có cả
   con dấu, nên căn giữa hàng và để chữ nhỏ tự đứng giữa. */
.hieu .ten {
  font-size: 12.5px; letter-spacing: 0.42em; text-transform: uppercase;
  color: var(--muc-nhat); font-weight: 500;
}

/* Con dấu viền: đúng `.brand .seal` của app — ô vuông viền son, chữ son,
   nghiêng -4°. Bản trước là con dấu ĐẶC ở góc PHẢI, lặp lại chính chữ hiệu
   bên trái. */
.dau {
  width: 30px; height: 30px;
  border: 1.5px solid var(--son); border-radius: 5px;
  color: var(--son); font-size: 17px; font-weight: 600;
  transform: rotate(-4deg);
}

/* Link đăng ký ở masthead. CHỈ từ 760px: ở điện thoại nút màn đầu đã nằm
   trong tầm mắt ngay dưới, hai lời mời trong một màn 390px là nhiễu. */
.dau-cta {
  display: none;
  font-size: var(--t-nho); color: var(--muc); text-decoration: none;
  padding: 10px 16px; border: 1px solid var(--vien); border-radius: 6px;
  transition: border-color 0.16s, color 0.16s;
}
.dau-cta:hover { border-color: var(--son); color: var(--son); }
.dau-cta:focus-visible { outline: 2px solid var(--son); outline-offset: 3px; }
@media (min-width: 760px) { .dau-cta { display: inline-block; } }

/* ---------- hero ---------- */
/* Điện thoại và iPad dọc: một cột, lời hứa rồi tới sản phẩm.
   Màn nằm ngang từ 1000px: HAI CỘT — lời hứa trái, tờ giấy demo phải, cùng
   một tầm mắt. */
.hero { padding-block: clamp(44px, 9vw, 96px) 0; }
.hero .loi-hua { max-width: var(--cot); }

@media (min-width: 1000px) and (orientation: landscape) {
  .hero {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: clamp(40px, 5vw, 72px);
    /* `center` khoá chiều dọc hai cột vào nhau: tờ giấy bên phải cao thấp
       theo từ đang chạm, nên mỗi lần chạm sang từ khác thì TIÊU ĐỀ VÀ NÚT
       bên trái cũng bị đẩy — đo được 25px ở 1194px. `start` cắt sợi dây đó. */
    align-items: start;
  }
  .hero .to-giay { margin-top: 0; }
  /* --t-display neo theo `vw`, đúng khi h1 chiếm cả bề ngang. Ở đây nó chỉ
     còn nằm trong một cột ~520px, nên tính theo cả màn hình là tính sai vật
     chứa: đo ở 1194px từng được h1 cao 529px trong khung 834px, đẩy câu phụ
     đề xuống dưới mép màn hình cùng với nút đăng ký. Cỡ chữ ở đây neo theo
     cột, không theo màn hình. */
  .hero .dinh-vi { font-size: clamp(2.9rem, 4.6vw, 4.1rem); }
}

.dinh-vi {
  font-size: var(--t-display);
  line-height: 1.06;
  letter-spacing: -0.022em;
  font-weight: 400;
  color: var(--muc);
}
/* Nhãn mục: đúng `.eyebrow` của app — viết hoa, giãn rộng, màu son. */
.nhan-hero, .nhan-muc {
  color: var(--son); font-size: 12.5px; font-weight: 500;
  letter-spacing: 0.3em; text-transform: uppercase; line-height: 1.6;
}
.nhan-hero { margin-bottom: 16px; }
/* Nhãn màn đầu DÀI gấp ba nhãn mục (43 ký tự). Ở 0.3em nó vỡ hai dòng ngay cả
   ở 1366px và để "VIỆT" đứng một mình; nhãn dài thì giãn hẹp lại. */
.nhan-hero { letter-spacing: 0.14em; }
.nhan-muc { margin-bottom: 12px; }

/* Nét bút loang dưới câu định vị. Đây là chuyển động DUY NHẤT tự chạy trên cả
   trang — mọi mục khác hiện thẳng, không trượt-mờ. Hiệu ứng trượt-mờ rải đều
   từng mục là dấu hiệu trang máy sinh, và nó làm người đọc phải đợi nội dung.
   (Chữ sáng dần ở mục video chạy theo CUỘN, tức là do người đọc kéo.) */
.net-but { display: block; width: min(420px, 78%); height: 14px; margin-block: 18px 0; overflow: visible; }
.net-but path {
  fill: none; stroke: var(--son); stroke-width: 3.5; stroke-linecap: round;
  stroke-dasharray: 300; stroke-dashoffset: 300;
  animation: ve-net 1.1s cubic-bezier(0.25, 0.6, 0.3, 1) 0.35s forwards;
}
@keyframes ve-net { to { stroke-dashoffset: 0; } }

.phu-de {
  margin-block: 26px 0; max-width: 46ch;
  font-size: var(--t-vua); line-height: 1.55; color: var(--muc-mo);
}
.phu-de strong { color: var(--muc); font-weight: 500; }

.hero-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 20px; margin-block: 30px 0; }
.hero-cta .nut { margin: 0; }
.hero-cta-phu { font-size: var(--t-nho); color: var(--muc-nhat); }

/* Điểm dừng thứ hai, ngay sau ba thẻ sản phẩm. */
.giua-cta { margin-block: 40px 0; }
.giua-cta .nut { margin: 0; }

/* ---------- tờ giấy demo ----------
   Khuôn của MÀN ĐĂNG NHẬP app (`.spec`): đoạn văn trong một thẻ giấy, khung
   nghĩa trồi lên đè mép dưới thẻ, viền son phía trên — đúng cảnh người ta
   thấy trong reader khi chạm một từ. Ai đi từ đây sang màn đăng nhập thấy
   cùng một tờ giấy, cùng câu báo. */
.to-giay { position: relative; margin-block: clamp(36px, 7vw, 56px) 0; }
/* Tấm nền sau tờ giấy: `.gate-art` của app. Ở điện thoại thì không — tấm nền
   ăn thêm hai lề trong một màn 390px, và đoạn chữ Hán mất chỗ đúng lúc nó
   cần chỗ nhất. */
@media (min-width: 700px) {
  .to-giay { padding: clamp(28px, 4vw, 44px) clamp(24px, 3.4vw, 40px); background: var(--nen-sau); border-radius: 22px; }
}

.to-giay-bai {
  background: var(--the); border: 1px solid var(--chi); border-radius: 14px;
  box-shadow: var(--bong-the);
  /* Đáy dày hơn đỉnh: khung nghĩa đè lên 22px cuối. */
  padding: 22px clamp(20px, 4vw, 28px) 40px;
}
.nhan-demo {
  margin-bottom: 6px; font-size: 11px; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--muc-nhat);
}

.doan-demo {
  font-family: var(--serif-cn);
  font-size: clamp(1.25rem, 4.6vw, 1.5rem);
  /* 2.25 chứ không phải 2.15: mỗi <button class="hz"> lấy chiều cao từ hộp
     dòng này, và 20px × 2.15 = 43px — dưới chuẩn chạm 44px của iOS ở MỌI bề
     rộng điện thoại. Đây là ô bấm CHÍNH của cả trang. Nới bằng line-height
     chứ không bằng padding: padding sẽ kéo nền của từ đang chọn tràn sang
     dòng trên và dòng dưới. */
  line-height: 2.25;
  letter-spacing: 0.01em;
  color: var(--muc);
}
/* Chữ Hán cấm bắt đầu một dòng bằng dấu đóng câu. Mỗi token ở đây là một
   <button> (inline-block) nên trình duyệt coi ranh giới giữa nút và dấu câu
   là chỗ ngắt dòng hợp lệ và bỏ qua luật đó — kết quả là dấu 。 rơi xuống một
   dòng riêng. demo.js gói mỗi nút cùng dấu câu theo sau vào .cum. */
.cum { white-space: nowrap; }

.hz {
  cursor: pointer; border: 0; background: none; padding: 0 1px;
  font: inherit; color: inherit; border-radius: 3px;
  transition: color 0.15s, background 0.15s;
}
.hz:hover { color: var(--son); background: rgba(178, 53, 41, 0.08); }
/* `.hz-tinh` là 经济 trong HTML TĨNH (trước khi demo.js chạy, hoặc khi JS
   tắt): tô sẵn để khung nghĩa bên dưới có chỗ trỏ về. Cùng màu với
   `.spec-hit` của màn đăng nhập. */
.hz.dang-chon, .hz-tinh { color: var(--son); background: rgba(178, 53, 41, 0.12); border-radius: 3px; }
.hz:focus-visible { outline: 2px solid var(--son); outline-offset: 2px; }

/* Khung nghĩa — cùng thứ tự tầng với WordSheet của app: chữ, pinyin,
   Hán-Việt, nghĩa Việt, nghĩa Anh. Hình: `.spec-sheet` của màn đăng nhập. */
.khung-nghia {
  /* Tối đa 560px và nằm giữa, như `.sheet` của app (width: min(560px, 100%)):
     trên iPad dọc tờ giấy rộng 900px, một khung nghĩa kéo hết bề ngang cho
     năm dòng chữ ngắn là một mảng trống — và app không bao giờ trông như vậy. */
  position: relative; margin-block: -22px 0; margin-inline: auto;
  width: min(560px, calc(100% - 2 * clamp(8px, 2.4vw, 14px)));
  padding: 20px clamp(18px, 4vw, 24px) 22px;
  background: var(--the); border-radius: 14px; border-top: 3px solid var(--son);
  box-shadow: var(--bong-sheet);
  /* CHỖ NÀY ĐƯỢC ĐẶT TRƯỚC, không co theo nội dung. Mỗi từ cho một khung nghĩa
     cao thấp khác nhau, nên không đặt trước thì tờ giấy nhảy mỗi lần chạm
     sang từ khác — ở điện thoại nó kéo theo mọi thứ bên dưới, ở bố cục hai
     cột nó kéo cả tấm nền.
     Số dưới đây là TRẦN ĐO ĐƯỢC trên mọi từ demo × mọi khổ soát, không phải
     số ước lượng. Đo lại bằng scripts/do-khung-nghia.mjs sau MỖI lần sinh lại
     demo-data.json hoặc đổi cỡ chữ / lề trong khung nghĩa; quên đo lại thì
     tờ giấy nhảy trở lại y như cũ.
     HAI giá trị: ở điện thoại nghĩa Anh dài nhất (表现, 10 nghĩa) vỡ thành
     nhiều dòng hơn; màn rộng thì khung rộng hơn nên trần thấp hơn. Cái giá:
     từ mở sẵn (经济) ngắn, nên dưới nó luôn có một khoảng giấy trống ~50px —
     rẻ hơn một tờ giấy nhảy, và KHÔNG được chữa bằng cách cắt bớt nghĩa Anh
     (demo phải hiện đúng thứ app hiện — xem demo.js). */
  min-height: 358px;   /* trần đo 2026-09-21: 表现 ở 320px */
}
@media (min-width: 700px) {
  .khung-nghia { min-height: 313px; }   /* trần đo 2026-09-21: 表现 ở mọi khổ ngang */
}
/* Từ đây xuống là BẢN SAO số đo của WordSheet trong app
   (frontend/src/styles.css, các luật `.sheet .*`). Không phải "lấy cảm hứng":
   demo này tồn tại để người xem biết trước app trông thế nào, nên mỗi con số
   lệch đi là một lời hứa sai. Có test đọc thẳng CSS của app để so. */
.kn-tu {
  font-family: var(--serif-cn); font-size: clamp(2rem, 7vw, 2.4rem);
  /* app: `.sheet .word` dùng font-weight 600 — không có nó thì chữ Hán ở đây
     mảnh hơn hẳn trong app, và đó là thứ đập vào mắt đầu tiên. */
  font-weight: 600; line-height: 1.1; color: var(--muc);
}
.kn-pinyin { margin-top: 12px; font-size: 1.3rem; color: var(--muc-mo); font-style: italic; }
.kn-hv { margin-top: 2px; font-size: 1.15rem; color: var(--son); }

/* Nhãn: app dùng 11px, giãn chữ 0.2em, VIẾT HOA. */
.kn-hv .nhan, .kn-en .nhan {
  display: inline-block; margin-right: 9px; font-size: 11px;
  letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--muc-nhat); font-style: normal; vertical-align: middle;
}

/* Vạch ngăn Ở TRONG khung nghĩa, đúng chỗ app đặt (`.sheet .meanings`): nó
   tách phần NHẬN MẶT CHỮ (chữ, pinyin, Hán-Việt) khỏi phần NGHĨA. */
.kn-vi {
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--chi);
  font-size: 1.25rem; line-height: 1.4; color: var(--muc);
}
/* app: in nghiêng. CỐ Ý lệch app đúng một chỗ — màu. App dùng --ink-faint,
   chỉ đạt 3,14:1; landing là trang công khai nên giữ --muc-mo (7,63:1). */
.kn-en { margin-top: 8px; font-size: 1rem; font-style: italic; color: var(--muc-mo); }

.goi-y {
  margin-block: 16px 0; text-align: center;
  font-size: var(--t-nho); color: var(--muc-nhat);
}

/* ---------- mục chung ---------- */
.muc { padding-block: var(--khoang) 0; }
.tieu-de {
  font-size: var(--t-lon); font-weight: 400; line-height: 1.15;
  letter-spacing: -0.015em; text-wrap: balance; max-width: 22ch; color: var(--muc);
}
.than { margin-block: 20px 0; max-width: 62ch; color: var(--muc-mo); }
.than + .than { margin-top: 14px; }
.than strong { color: var(--muc); font-weight: 500; }

/* ---------- Hán-Việt: cách cũ / cách mới ----------
   Thay cho ba đoạn văn. Hai ô cạnh nhau cho thấy luận điểm thay vì kể nó:
   qua tiếng Anh là HAI lần chuyển, qua Hán-Việt là MỘT. */
.so-sanh { display: grid; gap: 16px; margin-block: 36px 0; }
@media (min-width: 700px) { .so-sanh { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; } }

.cach { border-radius: 14px; padding: clamp(22px, 4vw, 30px); }
.cach-cu { background: var(--nen-sau); }
.cach-moi {
  background: var(--the); border-top: 3px solid var(--son);
  box-shadow: var(--bong-the);
}
.cach-nhan {
  font-size: 11px; letter-spacing: 0.2em; text-transform: uppercase; color: var(--muc-nhat);
}
.cach-moi .cach-nhan { color: var(--son); }

/* Dòng "đường đi" của nghĩa: chữ → (bước) → chữ. Mũi tên là SVG chứ không
   phải ký tự "→": U+2192 không có trong bộ Newsreader đã cắt, rơi về font hệ
   thống, và một glyph lạ nằm giữa dòng là lệch hộp dòng — xem .cjk-mark. */
.duong {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px;
  margin-block: 18px 0; min-height: 3.2rem;
}
.duong .han { font-family: var(--serif-cn); font-size: clamp(1.9rem, 6vw, 2.3rem); line-height: 1.2; }
.duong .buoc-giua { font-size: var(--t-vua); color: var(--muc-nhat); }
.duong .dich { font-size: clamp(1.5rem, 4.4vw, 1.9rem); line-height: 1.2; color: var(--son); }
.cach-cu .han { color: var(--muc-mo); }
.cach-cu .dich { color: var(--muc-nhat); font-size: var(--t-vua); }
.mui { width: 22px; height: 12px; flex: none; color: var(--muc-nhat); }
.mui path { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.cach-moi .mui { color: var(--son); }

.cach-loi { margin-block: 16px 0; font-size: 1rem; line-height: 1.55; color: var(--muc-mo); max-width: 44ch; }

/* Thêm vài cặp từ: dải chip chứ không phải bảng — bảng cũ đứng một cột bên
   phải và để lại một hố trống dưới nó ở mọi màn rộng. */
.cap-tu {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px;
  margin-block: 20px 0; list-style: none;
}
@media (min-width: 700px) { .cap-tu { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.cap {
  display: grid; gap: 2px; padding: 14px 16px;
  border: 1px solid var(--chi); border-radius: 12px;
}
.cap .han { font-family: var(--serif-cn); font-size: 1.6rem; line-height: 1.25; color: var(--muc); }
.cap .viet { font-size: 1.1rem; color: var(--son); line-height: 1.3; }
.cap .nghia { font-size: var(--t-nho); color: var(--muc-nhat); line-height: 1.4; }

/* ---------- ba bước ----------
   Ba THẺ cao bằng nhau, ảnh cắt gọn trong một khung tỉ lệ cố định ở đáy
   thẻ. Bản trước để ảnh theo tỉ lệ gốc: ảnh ôn tập dài hơn hai ảnh kia
   180px, cả hàng thành răng cưa. */
.buoc-loat { display: grid; gap: 18px; margin-block: 36px 0; list-style: none; }
.buoc {
  display: grid; overflow: hidden;
  background: var(--the); border: 1px solid var(--chi); border-radius: 14px;
  box-shadow: var(--bong-the);
}
.buoc-chu { padding: clamp(22px, 4vw, 28px); }
.buoc-so {
  width: 30px; height: 30px; margin-bottom: 14px;
  border: 1.5px solid var(--son); border-radius: 50%;
  color: var(--son); font-size: 0.9rem; font-weight: 500;
  display: grid; place-items: center; line-height: 1;
}
.buoc h3 { font-size: var(--t-vua); font-weight: 400; line-height: 1.25; color: var(--muc); }
.buoc p { margin-block: 8px 0; font-size: 1rem; line-height: 1.55; color: var(--muc-mo); }

/* Khung ảnh: tỉ lệ của hai ảnh ngang (780×668), ảnh ôn tập (780×854, dọc)
   đứng GỌN bên trong thay vì bị cắt — phần đáy của nó là ba nút đánh giá,
   chính thứ cho thấy ôn tập làm gì. Nền khung lấy đúng màu mép ảnh đó để dải
   hai bên không lộ thành viền. */
.buoc-anh {
  aspect-ratio: 780 / 668; overflow: hidden;
  background: #ede7da; border-top: 1px solid var(--chi);
}
.buoc-anh img {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: top center;
}
.buoc-anh img.vua { object-fit: contain; }

/* iPad dọc: thẻ nằm NGANG, chữ trái ảnh phải — ba thẻ dọc cao 600px mỗi cái
   xếp chồng ở 820–1024 là ba màn cuộn cho ba câu. */
@media (min-width: 700px) {
  /* Ghim BỀ RỘNG cột ảnh, giữ đúng tỉ lệ khung — không ghim chiều cao. Hai
     cách sai đã thử: cột ảnh co giãn theo nửa thẻ thì ảnh ôn tập (dọc) kéo
     thẻ cao 540px ở 1024; ghim cao 300px thì cột 380–480px cắt ảnh "đọc bài"
     ngang giữa một dòng chữ Hán. 360px × tỉ lệ 780/668 = khung 308px, vừa
     khít hai ảnh ngang. */
  .buoc { grid-template-columns: minmax(0, 1fr) minmax(0, 360px); align-items: center; }
  .buoc-anh { border-top: 0; border-left: 1px solid var(--chi); }
}
@media (min-width: 1000px) and (orientation: landscape) {
  .buoc-loat { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
  .buoc { grid-template-columns: none; grid-template-rows: 1fr auto; align-items: start; }
  .buoc-anh { border-left: 0; border-top: 1px solid var(--chi); height: auto; min-height: 0; aspect-ratio: 780 / 668; }
}

/* ---------- đọc cùng video ---------- */
.doi { display: grid; gap: clamp(32px, 5vw, 64px); }
@media (min-width: 1000px) and (orientation: landscape) {
  .doi { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: center; }
}

/* Minh hoạ lời thoại — HTML chứ không phải ảnh, và KHÔNG có khung video:
   khung YouTube là hình của người khác, không đưa lên trang công khai.
   Hình dạng theo transcript của app: mỗi câu một dòng kèm mốc giờ, câu đang
   nghe nổi trên thẻ giấy với viền trái vàng (`.vcue.active`), chữ chưa nói
   mờ .38 và sáng lên khi được nói (`.hz.unspoken/.spoken`). */
.loi-thoai {
  padding: clamp(18px, 3.4vw, 32px);
  background: var(--nen-sau); border-radius: 22px;
}
.lt-dau {
  display: flex; align-items: center; gap: 9px; margin-bottom: 12px;
  font-size: var(--t-nho); color: var(--muc-nhat);
}
.lt-dau .cham { width: 8px; height: 8px; border-radius: 50%; background: var(--son); flex: none; }
.lt-cau {
  display: grid; grid-template-columns: 44px minmax(0, 1fr); align-items: baseline;
  padding: 8px 12px 8px 10px; border-left: 2px solid transparent; border-radius: 4px;
}
.lt-gio { font-size: 13px; color: var(--muc-nhat); }
.lt-chu { font-family: var(--serif-cn); font-size: clamp(1.1rem, 3.6vw, 1.3rem); line-height: 1.9; color: var(--muc); }
.lt-cau.dang-nghe { background: var(--the); border-left-color: var(--vang); box-shadow: var(--bong-the); }
/* Trạng thái ĐỨNG YÊN — thứ mọi người thấy khi trình duyệt không chạy được
   hoạt ảnh theo cuộn, hoặc đã bật giảm chuyển động: nửa câu đã nói. */
.dang-nghe .ch { opacity: 0.38; }
.dang-nghe .ch.da { opacity: 1; }
.loi-thoai figcaption { margin-block: 14px 0; font-size: var(--t-nho); color: var(--muc-nhat); }

/* Chữ sáng dần theo CUỘN: mỗi chữ có một đoạn riêng trên dòng thời gian
   view() của chính nó, lệch nhau theo --i. Không vòng lặp, không JS — người
   đọc kéo tới đâu câu sáng tới đó. `view()` vô danh chứ không đặt tên: tên
   timeline phải khai báo trong `timeline-scope` của thanh neo (có test), và
   ở đây không cần — mỗi chữ tự theo dõi chính nó. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .dang-nghe .ch {
      animation: ch-sang linear both;
      animation-timeline: view();
      animation-range: cover calc(34% + var(--i, 0) * 2.2%) cover calc(36% + var(--i, 0) * 2.2%);
    }
  }
}
@keyframes ch-sang { from { opacity: 0.38; } to { opacity: 1; } }
.dang-nghe .ch:nth-child(2)  { --i: 1; }
.dang-nghe .ch:nth-child(3)  { --i: 2; }
.dang-nghe .ch:nth-child(4)  { --i: 3; }
.dang-nghe .ch:nth-child(5)  { --i: 4; }
.dang-nghe .ch:nth-child(6)  { --i: 5; }
.dang-nghe .ch:nth-child(7)  { --i: 6; }
.dang-nghe .ch:nth-child(8)  { --i: 7; }
.dang-nghe .ch:nth-child(9)  { --i: 8; }
.dang-nghe .ch:nth-child(10) { --i: 9; }
.dang-nghe .ch:nth-child(11) { --i: 10; }
.dang-nghe .ch:nth-child(12) { --i: 11; }

/* ---------- FAQ: tiêu đề trái, câu hỏi phải ----------
   Bản trước đặt FAQ trong một cột hẹp căn giữa — mép trái của nó thụt vào
   168px so với mọi mục khác trên trang. Giờ nó bám cùng lưới. */
.faq { display: grid; gap: 8px 48px; }
@media (min-width: 1000px) and (orientation: landscape) {
  .faq { grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); align-items: start; }
}
.faq details { border-top: 1px solid var(--chi); padding-block: 18px; }
.faq details:last-child { border-bottom: 1px solid var(--chi); }
.faq summary {
  cursor: pointer; color: var(--muc); font-size: var(--t-vua); line-height: 1.35;
  padding-inline: 28px; position: relative;
  /* Dấu ▶ mặc định là ::marker nằm TRONG dòng chữ, nên câu hỏi dài xuống dòng
     thì dòng hai chui xuống dưới dấu. Tự vẽ dấu ở lề trái để cả câu thụt treo. */
  list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::before {
  content: ""; position: absolute; left: 4px; top: 0.42em;
  border-left: 8px solid var(--son); border-block: 5.5px solid transparent;
  transition: transform 0.16s;
}
.faq details[open] > summary::before { transform: rotate(90deg); }
.faq summary:focus-visible { outline: 2px solid var(--son); outline-offset: 4px; border-radius: 2px; }
.faq details p { margin: 12px 28px 0; color: var(--muc-mo); max-width: 62ch; }

/* ---------- biểu mẫu: một tấm phiếu giấy ---------- */
.form-khoi { padding-block: var(--khoang) 0; }
.phieu {
  /* Một cột 560px nằm GIỮA tấm phiếu khi trang còn một cột: ở iPad dọc tấm
     phiếu rộng 960px, dồn chữ và ô nhập sang trái là để một mảng trống 400px
     bên phải. Ô email 560px vẫn đủ cho mọi địa chỉ. */
  display: grid; gap: clamp(28px, 4vw, 56px);
  grid-template-columns: minmax(0, 560px); justify-content: center;
  padding: clamp(24px, 5vw, 48px);
  background: var(--the); border: 1px solid var(--chi); border-radius: 18px;
  box-shadow: var(--bong-the);
}
@media (min-width: 1000px) and (orientation: landscape) {
  /* Cột trái (lời mời + mốc) cao hơn biểu mẫu ~200px. Căn giữa theo chiều
     dọc thì biểu mẫu không trôi lên góc trên, để lại một mảng trống dưới nó. */
  .phieu { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); justify-content: stretch; align-items: center; }
}

/* ---------- mốc thời gian, trong cột trái của phiếu ---------- */
.moc { margin-block: 28px 0; padding-block: 20px 0; border-top: 1px solid var(--chi); }
.moc-nhan { font-size: var(--t-nho); color: var(--muc-nhat); letter-spacing: 0.04em; }
.moc-gia { margin-top: 2px; font-size: var(--t-lon); line-height: 1.15; color: var(--son); }
.moc-phu { margin-top: 12px; font-size: var(--t-nho); line-height: 1.6; color: var(--muc-mo); max-width: 56ch; }

/* Ba câu trấn an ngay DƯỚI nút gửi — đúng lúc người ta phân vân có nên đưa
   email không. Cả ba đều là sự thật kiểm được ở /rieng-tu; có test buộc
   chúng khớp nhau. */
.yen-tam { margin-block: 22px 0; padding-block: 16px 0; border-top: 1px solid var(--chi); list-style: none; }
.yen-tam li { font-size: var(--t-nho); color: var(--muc-mo); line-height: 1.5; padding-left: 20px; position: relative; }
.yen-tam li + li { margin-top: 8px; }
.yen-tam li::before { content: "·"; position: absolute; left: 6px; color: var(--son); font-size: 1.3em; line-height: 1.05; }

.o { display: block; }
.o > .nhan { display: block; margin-bottom: 8px; font-size: var(--t-nho); color: var(--muc-mo); }

input[type="email"] {
  width: 100%; padding: 13px 15px;
  font-family: var(--serif); font-size: 1.0625rem;
  color: var(--muc); background: #fbf8f1;
  border: 1px solid var(--vien); border-radius: 6px;
}
input[type="email"]::placeholder { color: var(--muc-nhat); }
input[type="email"]:focus-visible { outline: 2px solid var(--son); outline-offset: 1px; border-color: transparent; }

/* padding-block 10px đẩy vùng bấm lên 48px. Đo được 43px khi chưa có nó —
   dưới chuẩn chạm 44px của iOS, mà đây lại là ô BẮT BUỘC về pháp lý: bấm trượt
   ô này là người dùng gửi hỏng rồi bỏ đi, và ta mất một email vì một pixel. */
.dong-y {
  display: flex; align-items: flex-start; gap: 11px;
  margin-block: 18px 0; padding-block: 10px; cursor: pointer;
}
.dong-y input { margin-top: 5px; accent-color: var(--son-dam); flex: none; width: 17px; height: 17px; }
.dong-y span { font-size: var(--t-nho); line-height: 1.55; color: var(--muc-mo); max-width: 56ch; }

.nut {
  display: inline-block; text-decoration: none; text-align: center;
  margin: 22px 0 0; padding: 14px 30px;
  font-family: var(--serif); font-size: 1.0625rem; letter-spacing: 0.01em;
  /* <button> KHÔNG thừa kế line-height của body — nó dùng `normal`. Đo được:
     thẻ <a> cao 58px, thẻ <button> cao 47px, cùng một lớp .nut. Đặt thẳng ở
     đây thì hai loại thẻ mới cao bằng nhau. */
  line-height: 1.2;
  color: var(--the); background: var(--son-dam);
  /* 6px, cùng thang với ô nhập email ngay phía trên nó. KHÔNG viên nhộng:
     kéo rộng hết bề ngang ở điện thoại thì hai đầu tròn thành hai nửa đường
     tròn, tỉ lệ 5,7 — hình đó đọc ra là dải băng chứ không phải nút bấm. */
  border: 1px solid var(--son-dam); border-radius: 6px;
  cursor: pointer; transition: transform 0.16s, filter 0.16s;
}
.nut:hover { filter: brightness(1.08); }
.nut:active { transform: scale(0.98); }
.nut:focus-visible { outline: 2px solid var(--son); outline-offset: 3px; }

/* Ở bước cuối của một biểu mẫu, nút phải là thứ khó bấm trượt nhất trên màn
   hình. Đo được 249px = 64% bề ngang ở 390px khi chưa có luật này. */
@media (max-width: 759px) {
  .nut { width: 100%; }
}

/* Honeypot: ẩn khỏi mắt VÀ khỏi trình đọc màn hình, nhưng vẫn nằm trong form.
   `display:none` bị một số bot bỏ qua có chủ ý, nên dùng cách đẩy ra ngoài. */
.bay { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* Ẩn mặc định, hiện khi fragment của URL trỏ đúng vào id. Function chuyển
   hướng về `/#loi-<mã>` sau một lượt gửi hỏng, nên câu lỗi hiện ra mà không
   cần một dòng JS nào — và trình duyệt tự cuộn tới đúng chỗ. */
.loi {
  display: none;
  margin: 0 0 18px; padding: 12px 15px;
  border-left: 3px solid var(--son); background: rgba(178, 53, 41, 0.07);
  color: var(--muc); font-size: var(--t-nho); line-height: 1.5;
  border-radius: 0 6px 6px 0;
  scroll-margin-top: 24px;
}
.loi:target { display: block; }

/* ---------- chân trang ---------- */
.chan {
  margin-block: var(--khoang) 0; padding-block: 28px 44px;
  border-top: 1px solid var(--chi);
  font-size: var(--t-nho); color: var(--muc-nhat);
}
.chan a { color: var(--muc-mo); text-underline-offset: 3px; }
/* Link ĐỨNG MỘT MÌNH trong một đoạn là một ô bấm thật, không phải chữ trong
   câu — đo được 14px, dưới xa chuẩn chạm 44px. Link nằm giữa câu (CC-CEDICT)
   thì không đụng tới: WCAG miễn trừ đúng trường hợp đó, và nới nó ra sẽ phá
   nhịp dòng chữ. */
.chan p > a:only-child { display: inline-block; padding-block: 11px; }
.chan p + p { margin-top: 10px; }
.chan-luoi { display: grid; gap: 18px; }
@media (min-width: 760px) {
  .chan-luoi { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); gap: 48px; }
}

/* ---------- trang phụ ---------- */
.trang-phu { padding-block: clamp(40px, 9vw, 76px) 0; }
.trang-phu h1 { font-size: var(--t-lon); font-weight: 400; line-height: 1.2; letter-spacing: -0.015em; margin-bottom: 16px; }
.trang-phu h2 { margin: 34px 0 10px; font-size: var(--t-vua); font-weight: 500; }
.trang-phu p, .trang-phu li { color: var(--muc-mo); max-width: 62ch; }
.trang-phu p + p { margin-top: 12px; }
.trang-phu ul { margin: 10px 0 0 1.1em; }
.trang-phu li { margin-bottom: 7px; }
.trang-phu b { color: var(--muc); font-weight: 500; }
.quay-lai {
  display: inline-block; margin-top: 34px; padding-block: 9px;
  color: var(--son); text-underline-offset: 4px;
}

/* ---------- thanh neo đáy (điện thoại) ---------- */
/* Mặc định KHÔNG có thanh. Nó chỉ bật ở trình duyệt vừa hiện được vừa GIẤU
   được nó khi biểu mẫu đã vào tầm mắt — vì một thanh cố định không giấu được
   sẽ nằm đè lên đúng cái nút gửi ở cuối trang, tức là tự bắn vào chân.
   Nơi không hỗ trợ thì không có thanh, và hai CTA tĩnh (màn đầu + giữa trang)
   vẫn làm xong việc. Đây là nâng cấp, không phải điều kiện. */
.thanh-neo { display: none; }

@supports (timeline-scope: --form-hien) {
  @media (max-width: 899px) and (prefers-reduced-motion: no-preference) {
    /* CẢ HAI tên mốc phải nằm trong scope. Thiếu một cái thì mốc đó không
       phân giải được, hoạt ảnh gắn với nó im lặng không chạy, và thanh neo
       hiện ngay từ đầu trang — không có cảnh báo nào. Đã xảy ra. */
    body { timeline-scope: --form-hien, --hero-roi; }
    #dangky { view-timeline-name: --form-hien; }

    .hero-cta { view-timeline-name: --hero-roi; }

    .thanh-neo {
      display: block; position: fixed; inset: auto 0 0 0; z-index: 20;
      padding: 10px var(--long) calc(10px + env(safe-area-inset-bottom));
      background: rgba(239, 233, 220, 0.94);
      backdrop-filter: blur(8px);
      border-top: 1px solid var(--chi);

      /* Nằm ngoài màn hình cho tới khi được gọi. Vị trí mặc định phải là ẨN:
         nếu một trong hai hoạt ảnh dưới đây không chạy, thứ còn lại là một
         thanh không bao giờ hiện — phiền, nhưng vô hại. Mặc định HIỆN thì
         hỏng ngược lại: một thanh không bao giờ tắt, đè lên nút gửi. */
      transform: translateY(110%);

      /* HAI mốc, không phải một, vì thanh này có hai câu hỏi khác nhau:
           lên  — khi CTA ở màn đầu đã trôi khỏi màn hình (trước đó nó chỉ là
                  bản sao của một nút đang nhìn thấy);
           xuống — khi biểu mẫu chớm vào tầm mắt (từ đó trở đi nó chỉ còn là
                  vật cản nằm trên chính nút gửi).
         Cả hai cùng lái `transform`, nên khung hình khuyết của hoạt ảnh sau
         lấy giá trị từ hoạt ảnh trước — chúng nối nhau chứ không giành nhau. */
      animation: neo-len linear both, neo-xuong linear both;
      animation-timeline: --hero-roi, --form-hien;
      animation-range: exit 0% exit 100%, cover 0% cover 20%;
    }
    .thanh-neo .nut { margin: 0; width: 100%; }

    /* CTA giữa trang bị ẩn Ở ĐÂY, và chỉ ở đây. Nó nằm đúng vùng cuộn mà
       thanh neo đang hiện, nên hai nút đỏ y hệt nhau xếp chồng lên nhau cách
       nhau một sợi chỉ — trông như trang bị hỏng. Ẩn nó BÊN TRONG khối
       @supports là có chủ ý: trình duyệt nào không dựng được thanh neo thì
       vẫn giữ CTA giữa trang, không mất điểm dừng nào. */
    .giua-cta { display: none; }
  }
}
@keyframes neo-len   { to { transform: translateY(0); } }
@keyframes neo-xuong { to { transform: translateY(110%); } }

/* ---------- tôn trọng người tắt hiệu ứng ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important; scroll-behavior: auto !important;
  }
  /* Nét bút phải HIỆN SẴN, không phải ẩn mãi mãi — không hiệu ứng nào được là
     điều kiện để nhìn thấy nội dung. */
  .net-but path { stroke-dashoffset: 0; }
}

/* Gợi ý dưới ô email: lời mời khớp theo email của tài khoản Google (ADR 0013),
   nên người đăng ký bằng một email khác sẽ nhận thư mời mà không vào được. */
.o-phu { display: block; margin-top: 8px; font-size: var(--t-nho); color: var(--muc-nhat); }
