/* ═══════════════════════════════════════════════════════════════════════════
 *  TRANG KHÁCH — LỚP NÂNG CẤP GIAO DIỆN
 *  Nạp SAU styles.css. Xem src/app/dang-ky/layout.tsx.
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * ── VÌ SAO LÀ MỘT TỆP ĐÈ, KHÔNG PHẢI SỬA THẲNG styles.css ────────────────
 *
 * `public/dang-ky/styles.css` là bản CHÉP NGUYÊN 5.263 dòng của
 * dangkykham.ivfpc.com. Giá trị của nó không nằm ở chỗ nó đẹp, mà ở chỗ nó
 * GIỐNG HỆT bản đang chạy thật — nghi giao diện lệch thì `diff` một phát là
 * ra. Sửa thẳng vào đó là đốt mất công cụ chẩn đoán duy nhất của trang này.
 *
 * Nên tệp đó giữ nguyên từng byte, còn mọi thay đổi nằm ở đây. Ba thứ có
 * được nhờ vậy:
 *
 *   • Lùi lại = xoá MỘT dòng <link> ở layout.tsx. Không cần git, không cần
 *     dựng lại. Đúng thứ cần có khi phát hiện lỗi lúc 8 giờ sáng, giữa lúc
 *     khách đang đăng ký.
 *   • Đọc tệp này là đọc ĐÚNG những gì đã đổi, không phải lội qua 5.263 dòng
 *     để tìm.
 *   • So bản cũ với bản mới trên cùng một máy: comment một dòng link.
 *
 * ── QUY TẮC KHI VIẾT VÀO ĐÂY ──────────────────────────────────────────────
 *
 * styles.css phần lớn dùng bộ chọn MỘT LỚP (`.panel`, `.doc-card`). Tệp này
 * nạp sau nên bộ chọn cùng độ chọn lọc là THẮNG — không cần `!important`, và
 * đừng dùng nó. Chỗ nào styles.css viết `.booking-layout .panel` (289 chỗ có
 * từ hai lớp trở lên) thì ở đây phải viết đủ hai lớp cho bằng.
 *
 * styles.css có 45 khối `@media`. Đè một thuộc tính đã bị đổi trong media
 * query thì phải đè LẠI trong đúng media query đó, nếu không bản đè chỉ đúng
 * ở khổ màn hình mặc định.
 */

/* ═══════════════════════════════════════════════════════════════════════════
 *  1. TOKEN
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Tiền tố `--vip-` là CỐ Ý, không phải để cho khác người.
 *
 * styles.css có BA khối `:root` xếp chồng, khối sau đè khối trước. Hậu quả là
 * `--teal` — cái tên nói "xanh mòng két" — đến khối thứ ba đã mang giá trị
 * `#8a2e6d`, tức là TÍM. Mọi quy tắc viết `var(--teal)` giờ vẽ ra màu tím, và
 * ai đọc mã cũng hiểu sai ở lần đầu.
 *
 * Sửa `--teal` về đúng nghĩa của nó thì hàng chục bề mặt đổi màu cùng lúc,
 * theo cách không lường trước được. Nên tệp này KHÔNG đụng vào bộ biến cũ:
 * nó dựng một bộ mới, tên nói đúng nghĩa, và mọi thứ viết mới đều bám vào bộ
 * mới. Bộ cũ ở lại nguyên vẹn cho những chỗ chưa chuyển.
 */

:root {
  /* ── Màu thương hiệu, lấy từ pixel của logo ────────────────────────── */
  --vip-man: #a44683; /* tím mận — khối vuông và chữ PHƯƠNG CHÂU */
  --vip-man-dam: #88386c;
  --vip-man-sau: #5d284a;
  --vip-man-tham: #38152c;
  --vip-hong: #e17fae; /* hồng — hoạ tiết phôi */
  --vip-hong-nhat: #fbe9f1;
  --vip-mongket: #007c94; /* xanh mòng két — chữ IVF */
  --vip-mongket-dam: #036278;

  /* ── Mặt phẳng ─────────────────────────────────────────────────────── */
  /*
   * Nền KEM (#fdfaf7) chứ không phải trắng.
   *
   * Trang này là một biểu mẫu dài 5.500px toàn thẻ trắng. Trên nền trắng thì
   * thẻ và nền là một khối, mắt phải dò theo viền mới biết một phần bắt đầu
   * từ đâu — mà đây là biểu mẫu bảy phần, biết mình đang ở phần nào là việc
   * quan trọng nhất. Nền kem đẩy thẻ trắng nổi lên mà không cần bóng nặng,
   * và ấm hơn nên hợp với tông tím mận hơn hẳn xám lạnh.
   */
  --vip-nen: #fdfaf7;
  --vip-nen-chim: #f6efe9;
  --vip-the: #ffffff;
  --vip-vien: #efe4ea;
  --vip-vien-dam: #ddcbd6;

  /* ── Chữ ───────────────────────────────────────────────────────────── */
  /* Tương phản trên --vip-the: chu 14.2:1 · chu-mo 5.6:1 · chu-nhat 3.5:1
     (chu-nhat chỉ dùng cho chữ ≥18px và phần trang trí). */
  --vip-chu: #261c23;
  --vip-chu-mo: #6d5f68;
  --vip-chu-nhat: #9c8d96;

  /* ── Độ nổi ────────────────────────────────────────────────────────── */
  /* Bóng pha sắc tím mận. Bóng đen thuần trên nền kem ra màu bùn. */
  --vip-noi-1: 0 1px 2px rgba(59, 25, 45, 0.05), 0 2px 6px rgba(59, 25, 45, 0.04);
  --vip-noi-2: 0 2px 4px rgba(59, 25, 45, 0.05), 0 8px 20px rgba(59, 25, 45, 0.06);
  --vip-noi-3: 0 4px 8px rgba(59, 25, 45, 0.06), 0 16px 38px rgba(59, 25, 45, 0.09);
  --vip-noi-4: 0 8px 16px rgba(59, 25, 45, 0.08), 0 30px 66px rgba(59, 25, 45, 0.14);

  /* ── Bo góc ────────────────────────────────────────────────────────── */
  /*
   * styles.css bo góc bằng những con số lẻ nhặt rải rác: 27px, 23px, 18px,
   * 13px, 21px… Không có bậc nào là bội của bậc nào, nên hai thẻ lồng nhau
   * bao giờ cũng lệch đường cong. Thang dưới đây có bậc rõ ràng.
   */
  --vip-bo-1: 8px;
  --vip-bo-2: 12px;
  --vip-bo-3: 16px;
  --vip-bo-4: 20px;
  --vip-bo-5: 28px;

  /* ── Chuyển động ───────────────────────────────────────────────────── */
  --vip-nhanh: 140ms;
  --vip-vua: 240ms;
  --vip-cham: 420ms;
  --vip-vao: cubic-bezier(0.16, 0.84, 0.44, 1);
  --vip-ra: cubic-bezier(0.5, 0, 0.75, 0);
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  2. LƯỚI AN TOÀN CHO HIỆU ỨNG HIỆN DẦN
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * ĐÂY LÀ SỬA LỖI, KHÔNG PHẢI TRANG TRÍ. Đọc kỹ trước khi gỡ.
 *
 * styles.css dòng 1252 viết:
 *
 *     .reveal-ready            { opacity:0; transform:translateY(24px) }
 *     .reveal-ready.is-visible { opacity:1; transform:none }
 *
 * Bảy phần của biểu mẫu mang `.reveal-ready`, và lớp `.is-visible` chỉ được
 * thêm vào khi một `IntersectionObserver` trong dang-ky.tsx báo phần đó đã
 * lọt vào khung nhìn.
 *
 * Nghĩa là: TOÀN BỘ BIỂU MẪU ĐĂNG KÝ VÔ HÌNH cho tới khi observer chạy. Nếu
 * observer không bao giờ chạy, khách nhìn thấy một trang chỉ có ảnh bìa và
 * khoảng trống — không có lỗi nào báo ra, không có gì để họ hiểu, và không
 * có cách nào đăng ký.
 *
 * dang-ky.tsx có phòng hờ, nhưng chỉ cho MỘT trường hợp:
 *
 *     if (!('IntersectionObserver' in window)) { hiện hết; return }
 *
 * Tức là chỉ đỡ được khi trình duyệt KHÔNG CÓ API đó. Không đỡ được trường
 * hợp API có mặt mà callback không bao giờ được gọi — chuyện vẫn xảy ra
 * trong vài webview nhúng (Zalo, Facebook, một số trình duyệt trong ứng dụng
 * ngân hàng), ở WebView Android đời cũ, và khi một tiện ích chặn quảng cáo
 * can thiệp quá tay. Đúng cái quan sát được khi dựng bản này: một observer
 * mới tinh đặt lên phần tử nằm GIỮA khung nhìn vẫn không hề chạy.
 *
 * Khách của phòng khám phần lớn mở đường dẫn từ tin nhắn Zalo, tức là vào
 * thẳng webview của Zalo. Đây không phải trường hợp hiếm về lý thuyết.
 *
 * CÁCH ĐỠ: một hoạt ảnh CSS có ĐỘ TRỄ, kết thúc ở trạng thái HIỆN.
 *
 *   • Hoạt ảnh CSS không cần JavaScript, không cần observer, không cần gì cả
 *     ngoài trình duyệt vẽ được trang.
 *   • `both` giữ khung hình đầu trong lúc trễ (vẫn mờ, hiệu ứng còn nguyên)
 *     và giữ khung hình cuối sau khi chạy xong (hiện, và ở lại hiện).
 *   • Observer chạy được thì `.is-visible` tắt hoạt ảnh và hiện ngay — nhanh
 *     hơn nhiều so với 2,4 giây, nên trong trình duyệt bình thường KHÔNG AI
 *     nhìn thấy lưới an toàn này hoạt động.
 *
 * 2,4 giây: đủ dài để observer thắng trong mọi trình duyệt lành mạnh, đủ
 * ngắn để người dùng webview hỏng không kịp kết luận trang bị lỗi.
 *
 * Đánh đổi: những phần nằm sâu dưới trang cũng hiện sau 2,4 giây, nên khi
 * khách cuộn tới thì chúng đã hiện sẵn, không còn hiệu ứng mờ dần. Chấp
 * nhận. Đây là biểu mẫu nhận thông tin cá nhân, không phải trang trình diễn
 * — nội dung phải hiện ra, và không được phụ thuộc vào hoạt ảnh.
 */
@media (prefers-reduced-motion: no-preference) {
  .reveal-ready {
    animation: vip-luoi-an-toan var(--vip-cham) var(--vip-vao) 2.4s both;
  }
  .reveal-ready.is-visible {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

@keyframes vip-luoi-an-toan {
  from {
    opacity: 0;
    transform: translateY(24px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/*
 * Máy bật "giảm chuyển động" thì styles.css không hề khai `.reveal-ready`
 * (cả khối nằm trong `@media (prefers-reduced-motion:no-preference)`), nên
 * nội dung vốn đã hiện. Vẫn khai lại ở đây cho chắc: quy tắc này rẻ, mà cái
 * giá của việc đoán sai là một trang trắng.
 */
@media (prefers-reduced-motion: reduce) {
  .reveal-ready,
  .reveal-ready.is-visible {
    opacity: 1;
    transform: none;
    animation: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  3. NỀN VÀ NHỊP CHỮ
 * ═══════════════════════════════════════════════════════════════════════════ */

body {
  background: var(--vip-nen);
  color: var(--vip-chu);
  /*
   * Dấu tiếng Việt chồng hai tầng (ẫ, ệ, ỡ) cao hơn chữ Latin thường, nên
   * dòng sát nhau là dấu chạm chân dòng trên. Trang này còn có tiếng Khmer,
   * Nhật, Hàn, Trung — cả bốn đều cao hơn Latin nữa.
   */
  line-height: 1.6;
}

/*
 * Chữ số ĐỀU BỀ NGANG.
 *
 * Trang có lưới lịch, bảng khung giờ và ô ngày sinh. Với chữ số tỷ lệ thì
 * "11" hẹp hơn "07" vài pixel, nên cột ngày trong lưới lịch răng cưa và mắt
 * không dóng thẳng xuống được.
 */
.exam-cal,
.date-pick,
.sched,
.schedule-matrix,
.schedule-slot,
.birth-date-dialog {
  font-variant-numeric: tabular-nums;
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  4. VÒNG TIÊU ĐIỂM
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * styles.css đã có `:focus-visible{outline:3px solid rgba(164,70,131,.32)}`.
 * Vấn đề là độ mờ 32%: trên nền kem nó ra tương phản khoảng 1.6:1 với nền,
 * dưới xa mức 3:1 mà WCAG đòi cho phần chỉ báo. Người đi bằng phím Tab qua
 * một biểu mẫu bảy phần cần thấy rõ mình đang đứng ở ô nào.
 *
 * Hai vòng lồng nhau — một vòng trắng sát rồi một vòng mận — để chỉ báo đọc
 * được trên CẢ nền trắng của thẻ lẫn nền tím đậm của hero.
 */
:focus-visible {
  outline: 2px solid var(--vip-man);
  outline-offset: 2px;
  border-radius: var(--vip-bo-1);
}

.hero :focus-visible,
.site-footer :focus-visible {
  outline-color: #ffffff;
}


/* ═══════════════════════════════════════════════════════════════════════════
 *  KHUNG TRANG — đầu trang, ngôn ngữ, hero, chứng nhận, chân trang
 *  (gốc: vip-parts/1-khung.css)
 * ═══════════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════════
 *  KHUNG TRANG — đầu trang · chọn ngôn ngữ · hero · dải chứng nhận · chân trang
 *  Nối vào cuối vip.css. Không sửa styles.css, không sửa .tsx.
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * ── BỐI CẢNH: styles.css LÀ NĂM BẢN THIẾT KẾ CHỒNG LÊN NHAU ───────────────
 *
 * `styles.css` không phải một bảng kiểu, nó là năm lần thử nghiệm nối đuôi
 * ("Direction v2", "v3", "v4", "Final brand consolidation"…). `.site-header`
 * được khai LẠI ở dòng 76, 1349, 1578, 1942 và 3192; `.portrait-frame` ở dòng
 * 383, 1466, 1734, 2033 và 3317. Bản cuối thắng, và bản cuối thường không
 * giống bản đầu chút nào — `.portrait-frame` mở đầu là một vòm bo 195px, kết
 * thúc là một thẻ trắng vuông bo 30px có thanh chú thích ở dưới.
 *
 * Nên MỌI dòng dưới đây đều được viết sau khi đọc bản khai CUỐI CÙNG của lớp
 * đó, không phải bản đầu tiên. Ai sửa tiếp cũng phải làm vậy:
 *
 *     grep -n "\.ten-lop" public/dang-ky/styles.css     ← xem HẾT, lấy dòng cuối
 *
 * ── VIỆC CỦA TỆP NÀY ──────────────────────────────────────────────────────
 *
 * Hero đang khá ổn nên KHÔNG dựng lại: vẫn dải xanh mòng két, vẫn thẻ ảnh bác
 * sĩ, vẫn thanh chạy ngang. Ba thứ được siết lại:
 *
 *   1. Bớt lớp trang trí chạy cùng lúc. Hero đang có tám lớp nền chồng nhau
 *      (lưới kẻ, hạt nhiễu, ba vòng tròn, hai quầng sáng, chữ IVF viền rỗng)
 *      trong đó hai lớp đang ĐỘNG vô hạn. Trên máy yếu mỗi lớp là một lần vẽ
 *      lại mỗi khung hình.
 *   2. Tương phản chữ trên nền tối. Vài chỗ đang không đạt WCAG — xem chú
 *      thích ở từng nơi, có kèm tỷ số đo được.
 *   3. Cỡ chữ tối thiểu. Trang có chữ 9px và 10px. Khách của phòng khám hiếm
 *      muộn phần lớn ngoài 30, nhiều người đọc trên điện thoại ngoài nắng.
 *
 * ── BA LỚP TRONG DANH SÁCH MÀ TỆP NÀY CỐ Ý KHÔNG TÔ ───────────────────────
 *
 *   • `.credentials-bar` `.credentials-inner` `.credentials-label`
 *     Không có trong DOM. `dang-ky.tsx` chỉ dựng `.credentials-cluster`; bản
 *     `-bar` là kiểu cũ của v2 và đã bị `display:none` ở dòng 1577.
 *
 *   • `.foot-plate` `.foot-logo` `.foot-accred-img`
 *     Cũng không có trong DOM. Chân trang hiện chỉ còn `.foot-tag` và các
 *     dòng `.foot-accred`. Tô những lớp này là viết mã chết.
 *
 *   • `.clinic-badge` `.privacy-badge`
 *     CÓ trong DOM nhưng dòng 2073 viết `display:none!important`. Bật lại thì
 *     phải dùng `!important` — luật của đợt này cấm. Muốn hiện lại hai thẻ đó
 *     thì phải sửa `styles.css`, tức là một quyết định khác, không phải việc
 *     của lớp đánh bóng.
 *
 *   • `.skip-link`
 *     Có kiểu ở `styles.css` dòng 59 nhưng KHÔNG có nút nào dựng nó — không
 *     `dang-ky.tsx`, không `lich-cua-toi`, không đâu cả. Cùng một lý do với
 *     `.foot-plate` ở trên: một lớp không có nút trong DOM thì tô nó là tô
 *     cho không khí. Ngày nào có người thêm lối tắt vào JSX thì tô cùng lúc,
 *     lúc đó mới nhìn được nó hiện ra thế nào khi bấm Tab.
 *
 * ── LƯU Ý CHO NGƯỜI SỬA TIẾP ──────────────────────────────────────────────
 *
 * `/lich-cua-toi` nạp `styles.css` NHƯNG KHÔNG nạp `vip.css` (xem
 * `src/app/lich-cua-toi/page.tsx` dòng 62 so với `src/app/dang-ky/layout.tsx`
 * dòng 112). Nên `.header-cta` ở dưới hiện chưa chạm được pixel nào: nơi duy
 * nhất dùng nó là `/lich-cua-toi`. Vẫn tô, vì khác với `.skip-link` thì nó CÓ
 * một nút thật đang hiện trên màn hình khách — chỉ thiếu đúng một dòng
 * `<link>` — và hai trang phải trông như một với khách.
 */

/* ═══════════════════════════════════════════════════════════════════════════
 *  1. MÉP TRANG
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * `.wrap` đổi padding ngang ba lần theo khổ màn (30 → 22 → 16). Dải chứng
 * nhận ở đầu trang cần TRÀN RA hết mép trên điện thoại, tức là cần đúng con
 * số đó với dấu trừ. `styles.css` dòng 2140 gõ cứng `margin:0 -16px` — đúng
 * ở dưới 700px, nhưng trong khoảng 701–760px thì `.wrap` đang đệm 22px, nên
 * dải chứng nhận thụt vào 6px mỗi bên và lộ ra hai vệt trắng ở hai mép.
 *
 * Ghi con số vào một biến đặt ngay trên `.wrap` thì chỗ nào cần "đúng bằng
 * mép trang" chỉ việc đọc biến, không phải nhớ ba con số.
 */
.wrap {
  --vip-mep: 30px;
}
@media (max-width: 920px) {
  .wrap {
    --vip-mep: 22px;
  }
}
@media (max-width: 700px) {
  .wrap {
    --vip-mep: 16px;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  2. THANH ĐẦU TRANG
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * ── VIỀN TRÊN: 6px NĂM CHẶNG MÀU → 3px BA CHẶNG ──────────────────────────
 *
 * Bản cuối vẽ viền trên dày 6px chuyển qua năm chặng màu, cộng thêm một dải
 * gradient 2px nữa ở `::after` ngay dưới. Hai dải cầu vồng cách nhau đúng
 * chiều cao thanh đầu trang, và chúng là thứ ĐẬM MÀU NHẤT trên một trang mà
 * phần còn lại toàn kem với trắng — mắt nhìn vào trang này thấy thanh màu
 * trước, thấy logo sau.
 *
 * Giảm còn một dải 3px, ba chặng, đi từ mận sâu sang hồng. Vẫn là màu thương
 * hiệu, vẫn nhận ra ngay, nhưng thôi tranh chỗ với logo.
 *
 * ── BỎ backdrop-filter ────────────────────────────────────────────────────
 *
 * Nền thanh đầu trang đang là trắng 97% CỘNG `backdrop-filter:blur(22px)
 * saturate(1.35)`. Ở 97% đục thì cái blur không ai nhìn thấy — nhưng trình
 * duyệt vẫn phải dựng một lớp hợp thành riêng và lọc lại toàn bộ vùng phía
 * sau MỖI KHUNG HÌNH khi khách cuộn, mà thanh này `position:sticky` nên nó
 * cuộn suốt 5.500px biểu mẫu. Trên máy Android tầm thấp qua 3G đó là thứ đắt
 * nhất trong cả trang mà không đổi lại được một pixel nào.
 *
 * ── BÓNG ĐỔ ĐANG NGƯỢC ────────────────────────────────────────────────────
 *
 * `.site-header` (dòng 1948) có bóng `0 14px 42px`, còn `.site-header.scrolled`
 * (dòng 95) có bóng `0 12px 34px` — NHỎ HƠN. Vì `.site-header.scrolled` có độ
 * chọn lọc cao hơn nên nó luôn thắng, kết quả là cuộn xuống thì bóng CO LẠI.
 * Ngược hoàn toàn với thứ bóng đổ dùng để nói: nó có mặt khi có nội dung chui
 * xuống dưới. Đứng yên thì phẳng, cuộn rồi mới nổi lên.
 */
.site-header {
  border-top: 3px solid transparent;
  border-bottom: 1px solid var(--vip-vien);
  /* Hai lớp: lớp padding-box là mặt giấy, lớp border-box lộ ra ở đúng phần
     viền trong suốt phía trên. Đổi một lớp là mất dải màu, nên `.scrolled`
     bên dưới phải chép lại đủ cả hai. */
  background:
    linear-gradient(var(--vip-the), var(--vip-the)) padding-box,
    linear-gradient(90deg, var(--vip-man-sau), var(--vip-man) 45%, var(--vip-hong)) border-box;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  transition: box-shadow var(--vip-vua) var(--vip-vao);
}
.site-header.scrolled {
  background:
    linear-gradient(var(--vip-the), var(--vip-the)) padding-box,
    linear-gradient(90deg, var(--vip-man-sau), var(--vip-man) 45%, var(--vip-hong)) border-box;
  box-shadow: var(--vip-noi-2);
}

/*
 * Dải gradient thứ hai ở `::after`. Thanh đầu trang đã có viền trên 3px và
 * viền dưới 1px; thêm một dải nữa là ba đường kẻ ngang trong 116px.
 * `::after` là lớp trang trí `position:absolute`, tắt nó không động gì tới
 * luồng bố cục.
 */
.site-header::after {
  display: none;
}

/* Đè cả hai bản khai cũ cùng lúc: dòng 1861 viết 4px, dòng 2121 viết 5px, và
   vì 2121 đứng sau nên ở dưới 700px đang là 5px. */
@media (max-width: 760px) {
  .site-header {
    border-top-width: 3px;
  }
}

/*
 * `filter:drop-shadow(...)` trên một thẻ <img> buộc trình duyệt phải đọc kênh
 * alpha của ảnh rồi vẽ lại — đắt hơn hẳn `box-shadow` trên một hộp. Mà cái
 * bóng đó cũng làm logo trông như một miếng sticker dán lên giấy chứ không
 * phải logo in trên giấy.
 *
 * `border-radius` không để trang trí: nó cho vòng tiêu điểm bám theo đúng
 * hình khi khách đi bằng phím Tab.
 */
.brand {
  border-radius: var(--vip-bo-2);
}
.brand-logo {
  filter: none;
}

/*
 * `.header-cta` — hiện chỉ có ở `/lich-cua-toi`, xem chú thích đầu tệp.
 * Chuyển gradient hai màu về một màu đặc: nút cao 48px thì mắt không đọc được
 * chuyển màu, chỉ thấy nó "hơi bẩn" so với nút một màu.
 *
 * KHÔNG đụng `min-height`/`padding`: dòng 1625 đã để 48px và 11px 20px — đè
 * xuống 46px là làm vùng chạm NHỎ ĐI, ngược hẳn với việc của đợt này.
 */
.header-cta {
  color: var(--vip-the);
  background: var(--vip-man);
  box-shadow: var(--vip-noi-1);
  font-size: 14px;
  font-weight: 700;
  transition:
    background-color var(--vip-nhanh) var(--vip-vao),
    box-shadow var(--vip-vua) var(--vip-vao),
    transform var(--vip-nhanh) var(--vip-vao);
}
.header-cta:hover {
  background: var(--vip-man-dam);
  box-shadow: var(--vip-noi-2);
  transform: translateY(-1px);
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  3. CHỌN NGÔN NGỮ
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Đây là thứ khách Khmer, Nhật, Hàn, Trung phải bấm TRƯỚC KHI đọc được bất kỳ
 * chữ nào khác trên trang. Nếu họ không tìm ra nó, phần còn lại của trang có
 * đẹp đến đâu cũng không dùng được. Nên nút này được nâng lên 14px và ô trong
 * danh sách lên 15px — không phải cho đẹp, mà vì người đang đọc nó là người
 * KHÔNG đọc được ngôn ngữ đang hiển thị và chỉ có lá cờ với tên bản ngữ để
 * bám vào.
 *
 * `min-height`/`padding` giữ nguyên của dòng 1632 (48px · 10px 15px). Đè
 * xuống 46px là làm vùng chạm nhỏ đi, ngược với chính lý do vừa nêu.
 */
.lang-btn {
  border: 1px solid var(--vip-vien-dam);
  color: var(--vip-man-sau); /* 11.2:1 trên nền trắng */
  box-shadow: none;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.5;
  transition:
    border-color var(--vip-nhanh) var(--vip-vao),
    background-color var(--vip-nhanh) var(--vip-vao),
    box-shadow var(--vip-vua) var(--vip-vao);
}
.lang-btn:hover {
  border-color: var(--vip-man);
  background: var(--vip-hong-nhat);
  box-shadow: var(--vip-noi-1);
}
/* Mũi chỉ xuống đang để `opacity:.68` — trên nền trắng ra khoảng 2:1, dưới
   mức 3:1 mà WCAG đòi cho một phần đồ hoạ mang nghĩa ("bấm vào đây mở ra"). */
.lang-btn svg {
  color: var(--vip-chu-mo); /* 5.6:1 */
  opacity: 1;
}

/*
 * Cờ là ký tự emoji, và Windows KHÔNG có phông cờ — 🇻🇳 hiện ra thành hai chữ
 * "VN". Hai chữ rộng hơn một emoji, nên nút ngôn ngữ đổi bề ngang mỗi lần
 * khách đổi ngôn ngữ, và cả `.header-actions` nhảy theo. `min-width` cố định
 * một ô cho cờ, rộng bao nhiêu cũng nằm gọn trong đó.
 */
.lang-flag {
  min-width: 1.4em;
  /* Dòng 157 để `line-height:1` — vừa khít cho một emoji, cụt cho hai chữ
     "VN" hoặc cho tên bản ngữ có dấu chồng tầng. */
  line-height: 1.25;
  text-align: center;
}

.lang-menu {
  min-width: 246px;
  padding: 8px;
  border: 1px solid var(--vip-vien-dam);
  border-radius: var(--vip-bo-4);
  background: var(--vip-the);
  box-shadow: var(--vip-noi-3);
}
.lang-menu li {
  gap: 12px;
  /* min-height chứ không phải height: "ភាសាខ្មែរ" cao hơn "Tiếng Việt" vì
     tiếng Khmer xếp phụ âm chân xuống dưới dòng cơ sở.

     Và `line-height` phải nới ở ĐÂY, không phải trong khối `html[lang="km"]`
     ở cuối tệp: danh sách này bày CẢ SÁU tên bản ngữ cùng lúc, nên dòng
     "ភាសាខ្មែរ" có mặt kể cả khi trang đang chạy tiếng Việt. Nới theo
     `html[lang]` là chỉ đúng cho người đã đổi sang tiếng Khmer rồi — tức là
     đúng cho đúng người KHÔNG cần nó nữa. */
  min-height: 46px;
  padding: 10px 12px;
  border-radius: var(--vip-bo-2);
  color: var(--vip-chu);
  font-size: 15px;
  font-weight: 500;
  line-height: 1.7;
}
.lang-menu li:hover,
.lang-menu li:focus {
  background: var(--vip-hong-nhat);
}

/*
 * SỬA LỖI, KHÔNG PHẢI TRANG TRÍ.
 *
 * `styles.css` dòng 186 viết `.lang-menu li:hover,.lang-menu li:focus{...;
 * outline:none}`. Mỗi `<li>` có `tabIndex={0}`, tức là đi bằng phím Tab được —
 * nhưng `outline:none` ở đó xoá sạch vòng tiêu điểm, kể cả vòng `:focus-visible`
 * mà `vip.css` dựng, vì `.lang-menu li:focus` (0,2,1) chọn lọc cao hơn
 * `:focus-visible` (0,1,0).
 *
 * Kết quả: người dùng bàn phím mở danh sách sáu ngôn ngữ ra và KHÔNG THẤY mình
 * đang đứng ở dòng nào. Quy tắc dưới đây đúng (0,2,1) và đứng sau nên thắng.
 * `outline-offset` âm để vòng nằm bên trong — danh sách có `overflow:auto`,
 * vòng ở ngoài sẽ bị cắt mất.
 */
.lang-menu li:focus-visible {
  outline: 2px solid var(--vip-man);
  outline-offset: -2px;
}

/*
 * Ngôn ngữ đang chọn trước giờ chỉ được nói bằng MÀU NỀN. Người mù màu, người
 * đang ra nắng, hoặc màn hình rẻ tiền đều không phân biệt được hồng rất nhạt
 * với trắng. Thêm một dấu tích dựng bằng hai cạnh viền xoay 45° — không cần
 * thêm chữ vào JSX, không cần emoji, và nó là HÌNH nên đọc được ở mọi độ sáng.
 */
.lang-menu li[aria-selected="true"] {
  color: var(--vip-man-sau);
  background: var(--vip-hong-nhat);
  font-weight: 700;
}
.lang-menu li[aria-selected="true"]::after {
  flex: none;
  width: 6px;
  height: 11px;
  margin-left: auto;
  border: solid var(--vip-man);
  border-width: 0 2px 2px 0;
  content: "";
  transform: translateY(-2px) rotate(45deg);
}

@media (max-width: 760px) {
  /* Dòng 2147 HẠ vùng chạm từ 48px (dòng 1632) xuống 44px đúng ở khổ mà
     người ta chạm bằng ngón tay chứ không phải trỏ chuột. Trả lại 48px —
     bằng khổ máy tính, và hàng đầu trang cao 68px nên chỗ vẫn còn thừa. */
  .lang-btn {
    min-width: 48px;
    min-height: 48px;
    padding: 9px 12px;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  4. DẢI CHỨNG NHẬN (JCI · RTAC · WATSON)
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Đây là tài sản tin cậy lớn nhất của trang: ba con dấu quốc tế mà khách
 * không kiểm chứng được nhưng nhận ra. KHÔNG được thu nhỏ. Mọi con số chiều
 * cao ảnh (80px · 68px · 58px · 52px) ở `styles.css` được giữ nguyên vẹn —
 * tệp này không đụng tới `height` của `.credentials-logos` ở bất kỳ khổ nào.
 *
 * Chỉ đổi hai thứ:
 *
 *   • Bỏ `drop-shadow` trên ảnh — cùng lý do với logo thương hiệu ở trên, và
 *     ở đây còn tệ hơn: bóng dưới một con dấu chứng nhận làm nó trông như ảnh
 *     dán vào, đúng thứ cảm giác không được phép có ở chỗ này.
 *   • Cho nó một khung viền mảnh. Ba con dấu đang trôi giữa khoảng trắng của
 *     thanh đầu trang, không có gì nói "đây là một cụm". Một đường viền mảnh
 *     bo góc biến nó thành một tấm biển — cùng ngôn ngữ hình với tấm biển
 *     chứng nhận treo ở sảnh phòng khám.
 *
 * Bề ngang: cũ `max-width:560px` không đệm. Mới 620px đệm 22px mỗi bên →
 * lòng trong 576px, RỘNG HƠN cũ 16px. Khung viền không lấy mất chỗ của ảnh.
 */
.credentials-cluster {
  max-width: 620px;
  padding: 8px 22px;
  border: 1px solid var(--vip-vien);
  border-radius: var(--vip-bo-4);
  background: var(--vip-nen);
}
.credentials-logos {
  filter: none;
}

/*
 * Từ 1040px trở xuống cột giữa hẹp lại còn `minmax(280px,1fr)` và ảnh đã bắt
 * đầu phải co theo bề ngang. Lúc đó 44px đệm là 44px ảnh bị mất — nên bỏ
 * khung, trả hết chỗ cho ba con dấu.
 */
@media (max-width: 1040px) {
  .credentials-cluster {
    max-width: none;
    padding: 6px 0;
    border-color: transparent;
    background: transparent;
  }
}

/*
 * Dưới 760px dải chứng nhận rơi xuống thành hàng thứ hai của thanh đầu trang
 * và tràn hết bề ngang. Ba việc ở đây:
 *
 *   • `height:68px` → `min-height`. Ô này có chứa `.credentials-kicker`, và
 *     dù nhãn đó đang bị ẩn thì chiều cao cứng vẫn là một cái bẫy chờ sẵn cho
 *     lần ai đó bật lại nhãn ở tiếng Khmer.
 *   • `margin:0 -16px` gõ cứng ở dòng 2140 chỉ đúng dưới 700px. Trong khoảng
 *     701–760px `.wrap` đệm 22px nên dải thụt vào 6px mỗi bên. Đọc `--vip-mep`
 *     thì đúng ở cả hai khoảng.
 *   • Vạch phân cách trên. Hai hàng đầu trang đang là một khối trắng cao
 *     136px trên điện thoại; một đường mảnh cộng nền kem tách chúng ra thành
 *     "logo" và "chứng nhận" thay vì một tảng liền.
 *
 * Quy tắc này phải đứng SAU khối 1040px ở trên: media query không cộng độ
 * chọn lọc, nên ở 700px cả hai khối cùng đúng và khối viết sau thắng.
 */
@media (max-width: 760px) {
  .credentials-cluster {
    height: auto;
    min-height: 68px;
    margin-inline: calc(var(--vip-mep) * -1);
    padding: 5px var(--vip-mep);
    /* `border:0` trước rồi mới dựng lại cạnh trên: khối 1040px ở trên mới chỉ
       làm viền trong suốt, mà viền trong suốt vẫn ăn 1px mỗi bên. Ở dưới
       700px `styles.css` dòng 1878 đã tự viết `border:0`, nhưng trong khoảng
       701–760px thì không — nên phải tự lo. */
    border: 0;
    border-top: 1px solid var(--vip-vien);
    /* Bo góc phải về 0 CÙNG LÚC. Dải này vừa được kéo tràn ra hai mép màn
       hình; giữ 20px của khối gốc thì hai góc trên bị vát ngay tại mép kính,
       để lộ hai vệt trắng của thanh đầu trang và bẻ cụt hai đầu đường kẻ
       1px. `styles.css` có `border-radius:0` ở dòng 1878 nhưng nó nằm TRƯỚC
       tệp này nên thua — phải viết lại. */
    border-radius: 0;
    background: var(--vip-nen);
  }
}
@media (max-width: 410px) {
  /* Giữ đúng 62px của dòng 2156, chỉ đổi sang min-height. */
  .credentials-cluster {
    min-height: 62px;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  5. HERO — NỀN VÀ CÁC LỚP TRANG TRÍ
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * ── VÌ SAO PHẢI ĐẨY CHỖ SÁNG SANG PHẢI ───────────────────────────────────
 *
 * Dải nền cũ kết thúc ở `#008eaa`. Đo thử: trắng NGUYÊN CHẤT trên `#008eaa`
 * chỉ được 3,85:1 — dưới mức 4,5:1 mà WCAG đòi cho chữ thường. Nghĩa là ở nửa
 * phải của hero thì không có màu chữ nào hợp lệ, kể cả trắng tinh. Mà từ
 * 1040px trở xuống hero xếp một cột, chữ trải hết bề ngang và đi thẳng vào
 * đúng vùng đó.
 *
 * Dải mới giữ nguyên tông xanh mòng két IVF, chỉ đẩy chặng sáng nhất ra sát
 * mép phải (nơi có thẻ ảnh bác sĩ, không có chữ) và làm đầu trái sâu hơn.
 * Vùng chữ giờ nằm giữa `#00252f` và `#005a6e`:
 *
 *     trắng trên #00252f  →  ~17:1
 *     trắng trên #005a6e  →   7,8:1
 *     trắng trên #00738b  →   5,5:1   (mép ngoài cùng chữ với tới)
 *
 * Đủ đường lùi để `.hero-sub` dùng trắng pha mờ mà vẫn đạt. `.trust-strip`
 * thì KHÔNG — nó nằm ở đáy cột chữ, đúng phía dải nền sáng lên, và ở khổ
 * điện thoại còn được lót thêm một nền trắng 6%; xem mục 7.
 */
.hero {
  background:
    radial-gradient(circle at 84% 16%, rgba(120, 235, 247, 0.2), transparent 24rem),
    radial-gradient(circle at 96% 86%, rgba(0, 190, 215, 0.18), transparent 28rem),
    linear-gradient(116deg, #00252f 0%, #003f4f 30%, #005a6e 58%, #00738b 84%, #00819c 100%);
}

/*
 * ĐẾM LẠI SỐ LỚP TRANG TRÍ.
 *
 * Hero đang chồng: `::before` vòng tròn 610px · `::after` lưới kẻ 48px ·
 * `.hero-grain` hạt nhiễu · `.hero-aura-one` vòng tròn 660px có ba lớp quầng ·
 * `.hero-aura-two` quầng xanh · `.orbit-one` vòng 455px · `.orbit-two` vòng
 * 175px · `.hero-visual::before` chữ "IVF" viền rỗng 210px. Tám lớp, trong đó
 * BA lớp cùng là vòng tròn viền mảnh.
 *
 * Không xoá lớp nào (xoá là đổi cấu trúc), chỉ hạ giọng: lưới kẻ và hạt nhiễu
 * lùi xuống mức chỉ còn thấy khi nhìn kỹ, và `.hero-aura-one` thôi làm vòng
 * tròn thứ ba — nó trở lại thành một mảng sáng mờ, để `::before` và hai
 * `.orbit-*` giữ độc quyền ngôn ngữ hình tròn.
 */
.hero::after {
  opacity: 0.26;
}
.hero-grain {
  opacity: 0.055;
}
/* `filter:blur(1px)` trên một hộp 660px bắt trình duyệt dựng riêng một lớp
   hợp thành để làm mờ đúng 1px — không ai nhìn ra, máy vẫn phải trả. */
.hero-aura {
  filter: none;
}
.hero-aura-one {
  border-color: transparent;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.055), transparent 66%);
  box-shadow: none;
}
/* `.hero-aura-two` (quầng xanh góc dưới trái) CỐ Ý không đụng tới. Bản cũ là
   `rgba(114,229,240,.3)`; thử hạ xuống .22 rồi so hai ảnh chụp cạnh nhau thì
   không phân biệt được — một quầng mờ 420px sau lớp chữ thì 8% độ mờ không
   ai thấy. Đổi mà không ai thấy thì chỉ là thêm một dòng phải bảo trì. */
/* Chữ "IVF" viền rỗng nằm sau thẻ ảnh bác sĩ. Ở độ mờ .13 nó cắt ngang mặt
   người trong ảnh; .09 thì vẫn còn ở đó mà không tranh nữa. */
.hero-visual::before {
  -webkit-text-stroke: 1px rgba(255, 255, 255, 0.09);
}
/* Gạch ngang mở đầu đang có `box-shadow:0 0 28px rgba(255,255,255,.24)` — một
   vệt phát sáng, đúng thứ hào nhoáng mà trang y tế phải tránh. */
.hero-copy::before {
  box-shadow: none;
}

/*
 * CHIỀU CAO HERO. Cộng lại: đệm trên 62 + `min-height` 650 + đệm dưới 92 =
 * 804px. Trên laptop 13" (vùng nhìn ~740px) thì hero chiếm trọn màn hình đầu
 * và khách phải cuộn mù mới biết bên dưới có biểu mẫu. Đây là trang để ĐĂNG
 * KÝ, không phải trang giới thiệu.
 *
 * 62 + 580 + 78 = 720px — vẫn là một hero đàng hoàng, nhưng đã ló ra phần đầu
 * của khối tiếp theo. Thẻ ảnh bác sĩ cao 510px nên 580 vẫn thừa chỗ.
 */
.hero-grid {
  min-height: 580px;
  padding-bottom: 78px;
}
@media (max-width: 760px) {
  /* Dòng 1888 để 86px. Trên điện thoại `.hero-actions` bị ẩn (dòng 3379) nên
     phần dưới hero trống hơn hẳn — 74px vẫn thừa chỗ cho thanh chạy 36px. */
  .hero-grid {
    padding-bottom: 74px;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  6. HERO — NHỊP CHỮ
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * ── DÒNG CHỮ 76px VỚI line-height 1,04 ───────────────────────────────────
 *
 * Tiếng Việt xếp dấu hai tầng: "Đ" có nét ngang, "ệ" có mũ cộng dấu nặng,
 * "ữ" có râu cộng ngã. Tiêu đề thật là "Đăng ký khám – Đánh giá chức năng
 * sinh sản" — hai dòng, và ở 1,04 thì dấu ngã của dòng dưới chạm chân chữ
 * dòng trên. 1,1 là mức thấp nhất còn an toàn cho tiếng Việt ở cỡ này.
 *
 * ── BÓNG CHỮ 52px ĐỘ NHOÈ ────────────────────────────────────────────────
 *
 * `0 16px 52px` không phải bóng, nó là một quầng tối mờ to bằng chữ. Nó không
 * làm chữ dễ đọc hơn (quá nhoè để tăng tương phản ở mép nét) mà chỉ làm cả
 * khối tiêu đề trông đục. Bóng ngắn và gọn thì thực sự tách chữ khỏi nền.
 *
 * ── 76px → 64px ──────────────────────────────────────────────────────────
 *
 * Ở 76px, "Đăng ký khám – Đánh giá chức năng sinh sản" vắt thành ba dòng trên
 * màn 1280. 64px cho hai dòng, và hai dòng thì `text-wrap:balance` mới có
 * việc để làm.
 */
.hero-title {
  max-width: 680px;
  font-size: clamp(44px, 4.6vw, 64px);
  letter-spacing: -0.015em;
  line-height: 1.1;
  text-shadow: 0 2px 16px rgba(0, 28, 36, 0.34);
}
@media (max-width: 760px) {
  .hero-title {
    font-size: clamp(34px, 9vw, 44px);
    letter-spacing: -0.01em;
    line-height: 1.14;
  }
}
@media (max-width: 410px) {
  .hero-title {
    font-size: 33px;
  }
}

/*
 * `.hero-sub` cũ: trắng 84% ở 16px. Trên chặng sáng của dải nền cũ ra khoảng
 * 3:1 — trượt. Với dải nền mới cộng 92% thì:
 *
 *     trên #005a6e  →  6,6:1
 *     trên #00738b  →  4,7:1
 *
 * Bề ngang 640px ở 16px là khoảng 78 ký tự một dòng; mắt bắt đầu lạc dòng từ
 * khoảng 75. 560px đưa về ~68 ký tự.
 */
.hero-sub {
  max-width: 560px;
  margin-top: 22px;
  color: rgba(255, 252, 253, 0.92);
  font-size: 17px;
  line-height: 1.7;
}
@media (max-width: 760px) {
  /* Dòng 1297 để 14px. Câu này là câu giải thích khách phải đọc để biết mình
     đang điền cái gì, và người đọc nó hay ở ngoài 30 tuổi, cầm điện thoại
     ngoài sáng. 16px là mức sàn, không phải mức đẹp. */
  .hero-sub {
    margin-top: 18px;
    font-size: 16px;
    line-height: 1.66;
  }
}

/*
 * Dòng mào đầu. Giới hạn trong `.hero` vì `.eyebrow` còn được dùng lại ở dải
 * "Chương trình ưu đãi" — đó là phần của agent khác, không đụng vào.
 * `.hero .eyebrow` (0,2,0) nên phải tự lo luôn khổ nhỏ, bản `(max-width:410px)`
 * ở dòng 1335 chỉ có (0,1,0) và không với tới đây nữa.
 */
.hero .eyebrow {
  gap: 11px;
  margin-bottom: 18px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.14em;
  line-height: 1.5;
}
@media (max-width: 410px) {
  .hero .eyebrow {
    font-size: 11px;
    letter-spacing: 0.1em;
  }
}
/* `flex:none` để vòng tròn không bị bóp méo khi nhãn bên cạnh dài ra — tiếng
   Khmer viết cùng ý này dài gần gấp đôi tiếng Việt.

   Bó trong `.hero` vì `.eyebrow-mark` cũng nằm ở dải "Chương trình ưu đãi"
   (`.programs .eyebrow-mark`, dòng 3620) — đó là phần của agent khác. */
.hero .eyebrow-mark {
  flex: none;
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  7. HERO — NÚT GỌI HÀNH ĐỘNG VÀ DẢI TIN CẬY
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Hero chỉ còn ĐÚNG MỘT nút, và nó mang lớp `.secondary` — nền trắng 8%, viền
 * trắng 30%. Trên nền tối đó là hình dạng của một nút phụ: mắt lướt qua nó để
 * tìm nút chính, không thấy, rồi thôi.
 *
 * Không đổi được lớp trong JSX, nhưng đổi được TRỌNG LƯỢNG của lớp đó. Nút
 * duy nhất thì phải nặng như nút chính: nền trắng đặc, chữ mận sâu (11,2:1),
 * bóng đủ để nó nổi lên khỏi dải xanh.
 *
 * Hai thứ CỐ Ý không có ở đây:
 *
 *   • `.hero-cta.primary` — `dang-ky.tsx` dòng 2174 dựng đúng một thẻ, và nó
 *     mang `class="hero-cta secondary"`. Không nơi nào trong repo viết
 *     `hero-cta primary`. Tô nó là tô cho một phần tử không tồn tại.
 *   • `.hero-actions` — nó bọc đúng MỘT nút, nên `gap` không có gì để giãn,
 *     còn `margin-top` thì dòng 298 đã để 32px.
 *
 * Chú ý: từ 760px trở xuống `styles.css` dòng 3379 ẩn hẳn `.hero-actions` —
 * mọi thứ ở đây chỉ có tác dụng trên máy tính.
 */
.hero-cta {
  /* `min-height` (55px), `border-radius` và `gap` của dòng 305 đã đúng sẵn —
     chép lại chúng với con số lệch một pixel là thêm việc phải bảo trì mà
     không đổi được gì trên màn hình. */
  padding: 14px 26px;
  font-size: 15px;
  font-weight: 700;
  transition:
    transform var(--vip-nhanh) var(--vip-vao),
    box-shadow var(--vip-vua) var(--vip-vao),
    background-color var(--vip-nhanh) var(--vip-vao),
    border-color var(--vip-nhanh) var(--vip-vao),
    color var(--vip-nhanh) var(--vip-vao);
}
.hero-cta.secondary {
  color: var(--vip-man-sau);
  border: 1px solid rgba(255, 255, 255, 0.92);
  background: var(--vip-the);
  box-shadow: 0 10px 24px rgba(0, 26, 34, 0.26);
  /* Nền đã đặc thì `backdrop-filter:blur(10px)` ở dòng 328 không đổi được gì,
     chỉ tốn thêm một lớp hợp thành. */
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.hero-cta.secondary:hover {
  border-color: var(--vip-the);
  background: var(--vip-hong-nhat);
}
.hero-cta:hover {
  transform: translateY(-2px);
  box-shadow: 0 18px 38px rgba(0, 26, 34, 0.34);
}

/*
 * Trên máy cảm ứng, Chrome Android giữ trạng thái `:hover` sau khi nhấc ngón
 * tay cho tới lần chạm tiếp theo ở chỗ khác. Nút bị nhấc lên 2px rồi TREO ở
 * đó trông y như lỗi hiển thị.
 */
@media (hover: none) {
  .hero-cta:hover {
    transform: none;
    box-shadow: 0 10px 24px rgba(0, 26, 34, 0.26);
  }
  .header-cta:hover {
    transform: none;
  }
}

/*
 * `vip.css` đặt `.hero :focus-visible{outline-color:#fff}` — đúng cho mọi thứ
 * trên nền xanh đậm, SAI đúng một chỗ: nút hero giờ nền trắng, vòng trắng trên
 * nền trắng là vô hình. `.hero .hero-cta:focus-visible` (0,3,0) cao hơn
 * `.hero :focus-visible` (0,2,0). Vòng đặt vào bên trong để nó luôn nằm trên
 * mặt trắng, không nửa trong nửa ngoài. Mận trên trắng: 5,6:1.
 */
.hero .hero-cta:focus-visible {
  outline: 2px solid var(--vip-man);
  outline-offset: -4px;
}

/*
 * Dải tin cậy. Cũ: 11px, trắng 74% — chữ nhỏ nhất trên trang lại đặt ở chỗ
 * tương phản thấp nhất. Mới 12px, và cỡ này giữ luôn ở khổ điện thoại (dòng
 * 1301 hạ xuống 10px, ở đó chỉ còn ĐÚNG MỘT chip vì dòng 3380 ẩn chip đầu —
 * càng không có lý do phải nhỏ).
 *
 * TRẮNG ĐẶC, KHÔNG PHA MỜ. Đây là chỗ dễ trượt nhất của cả hero, vì ba thứ
 * cộng dồn đúng tại một điểm: chip nằm ở đáy cột chữ, mà dải nền mới sáng
 * dần về góc DƯỚI PHẢI (116deg); quầng `circle at 96% 86%` phủ đúng lên đó;
 * và ở khổ điện thoại dòng 1900 còn lót cho chip một nền `rgba(255,255,255,
 * .06)`, tức là làm nền SÁNG THÊM ngay dưới chữ. Đo tại điểm xấu nhất trên
 * màn 375px:
 *
 *     trắng 90% → 4,2:1   ✗
 *     trắng đặc → 4,9:1   ✓
 *
 * Chữ nhỏ nhất thì phải đục nhất. Thứ bậc ở đây do CỠ CHỮ nói (12px cạnh
 * tiêu đề 64px), không cần mượn thêm độ mờ để nói lại.
 */
.trust-strip > span {
  gap: 9px;
  color: #ffffff;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
}
/* Đúng 700px, không phải 760px: dòng 1301 (hạ 10px) và dòng 1894 (lót nền,
   viền, đệm cho chip) đều nằm ở `max-width:700px`. Đè ở 760px thì trong
   khoảng 701–760 nó thêm đệm cho một đoạn chữ chưa có nền để mà đệm. */
@media (max-width: 700px) {
  .trust-strip > span {
    padding: 7px 12px;
    font-size: 12px;
  }
}
/*
 * Dấu tích đang là `rgba(0,142,170,.9)` — cùng họ màu với nền hero nên nó tan
 * vào nền, và trắng trên nó chỉ được 3,9:1. Mòng két đậm cho 7:1, cộng một
 * vành trắng mảnh để huy hiệu tách hẳn khỏi dải nền.
 */
.trust-check {
  flex: none;
  width: 20px;
  height: 20px;
  border: 1px solid rgba(255, 255, 255, 0.45);
  color: var(--vip-the);
  background: var(--vip-mongket-dam);
  font-size: 11px;
  font-style: normal;
  line-height: 1;
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  8. HERO — THẺ ẢNH BÁC SĨ
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Bản khai CUỐI của `.portrait-frame` là dòng 3317, không phải dòng 383: nó đã
 * thôi làm vòm bo 195px và trở thành một thẻ trắng `display:grid` hai hàng
 * (ảnh trên, thanh tên bác sĩ dưới). Đừng đọc dòng 383 rồi sửa theo.
 *
 * Hai chỗ chỉnh:
 *
 *   • Bỏ vành `0 0 0 8px rgba(255,255,255,.07)`. Đó là lớp trang trí thứ chín
 *     của hero, và nó chỉ là một quầng trắng mờ quanh một thẻ vốn đã có viền
 *     trắng — nói lại đúng thứ viền đã nói.
 *   • Độ nhoè bóng 90px → 60px. Bóng càng nhoè, vùng trình duyệt phải tính
 *     càng lớn; 90px quanh một thẻ 390×510 là hơn nửa triệu điểm ảnh phải vẽ
 *     lại mỗi lần thẻ đổi ảnh bác sĩ — mà nó đổi 4,2 giây một lần.
 *
 * Bo góc về `--vip-bo-5` (28px): thẻ này nằm cạnh dải chứng nhận bo 20px và
 * các bảng biểu mẫu bên dưới; 30px không thuộc thang nào nên hai đường cong
 * đặt cạnh nhau lệch nhau vài pixel — đủ để thấy là "sai" mà không chỉ ra
 * được sai ở đâu.
 */
.portrait-frame {
  border: 1px solid rgba(255, 255, 255, 0.66);
  border-radius: var(--vip-bo-5);
  box-shadow: 0 26px 60px rgba(0, 32, 42, 0.34);
}
/* Chồng ảnh bác sĩ kế tiếp nằm đè lên góc trên phải thẻ. Nền sâu hơn để vành
   trắng 3px quanh mỗi ảnh tròn có gì mà tách ra. */
.portrait-stack {
  border-color: rgba(255, 255, 255, 0.34);
  background: rgba(0, 45, 56, 0.52);
  box-shadow: 0 14px 30px rgba(0, 26, 34, 0.28);
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  9. THANH CHẠY NGANG
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Thanh này chạy chính ba cái tên đắt giá nhất của phòng khám — JCI
 * ENTERPRISE, RTAC, WATSON CARING SCIENCE — ở cỡ 9px, trắng 54%. Nhỏ và mờ
 * đến mức khách chỉ thấy "có chữ gì đó đang trôi". Nó được đánh dấu
 * `aria-hidden` nên trình đọc màn hình cũng bỏ qua: nếu không đọc được bằng
 * mắt thì nó không tồn tại với ai cả.
 *
 * 10px và trắng 78% vẫn nằm gọn trong dải cao 40px, và giờ đọc được.
 * Nền đục hơn để bỏ `backdrop-filter:blur(12px)` — một lớp làm mờ chạy suốt
 * bề ngang trang, đặt lên đúng thứ đang chuyển động liên tục.
 */
.hero-marquee {
  color: rgba(255, 252, 253, 0.78);
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(0, 26, 34, 0.34);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.hero-marquee span {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.16em;
}
/* `.hero-marquee i` (dấu ✦ ngăn cách) giữ nguyên 9px của dòng 560. Bản trước
   hạ nó xuống 8px — đúng một pixel, không ai thấy, và đi ngược lại chính
   luận điểm của cả tệp này là KHÔNG hạ cỡ chữ xuống nữa. */

/* ═══════════════════════════════════════════════════════════════════════════
 *  10. CHÂN TRANG
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * ── NỀN CŨ KHÔNG ĐỦ TỐI ĐỂ ĐẶT CHỮ LÊN ───────────────────────────────────
 *
 * Chân trang là nơi để địa chỉ và số điện thoại của ba cơ sở — thông tin khách
 * cần đọc khi đã quyết định đi khám. Cũ: `rgba(214,244,249,.72)` ở 11px trên
 * nền `#00768e`. Đo được 3,1:1 ở góc dưới phải, nơi quầng sáng làm nền nhạt
 * thêm. Chữ 11px cần 4,5:1.
 *
 * Có hai đường sửa: làm chữ sáng hơn, hoặc làm nền tối hơn. Chữ đã gần trắng
 * rồi nên chỉ còn đường thứ hai — mà nền tối hơn cũng đúng hơn về thẩm mỹ:
 * chân trang là chỗ để trang lắng xuống, không phải chỗ để nó sáng lên.
 *
 * Nền mới, chỗ nhạt nhất (`#00566a` cộng quầng xanh) cho trắng 6,7:1. Với chữ
 * `#d8f0f5` ở 12px thì được 5,6:1 — đạt, còn dư.
 *
 * KHÔNG đụng `padding`. `styles.css` hạ đệm chân trang ở khổ điện thoại (dòng
 * 1332 xuống 50/54, dòng 1911 xuống đáy 46) — mà tệp này nạp SAU, nên một
 * dòng `padding` viết ở ngoài media query sẽ đè sạch CẢ HAI và trả chân trang
 * về đệm khổ máy tính trên điện thoại. Đây là cái bẫy hay gặp nhất của một
 * lớp đè: bản đè không cần media query để thắng, nó thắng cả những media
 * query mà nó không định thắng.
 */
.site-footer {
  color: #e2f7fb;
  background:
    radial-gradient(circle at 14% 0, rgba(120, 235, 247, 0.14), transparent 26rem),
    radial-gradient(circle at 88% 100%, rgba(0, 190, 215, 0.14), transparent 28rem),
    linear-gradient(135deg, #00222b, #003d4b 52%, #00566a);
}

/*
 * Các dòng `.foot-accred` đều `margin:0`, nên ba địa chỉ cơ sở dính liền
 * thành một khối chữ không có chỗ nghỉ. `.foot-inner` là flex cột nên chỉ cần
 * `gap` — không phải thêm margin vào từng thẻ.
 */
.foot-inner {
  gap: 8px;
}
.foot-tag {
  margin: 0 0 6px;
  font-family: var(--sans);
  font-size: 22px;
  font-weight: 600;
  line-height: 1.4;
  /* Bóng `0 10px 30px rgba(0,30,38,.4)` là bóng TỐI trên nền TỐI: không tăng
     được tương phản, chỉ làm nét chữ nhoè ra. */
  text-shadow: none;
}
.foot-accred {
  max-width: 56ch;
  color: #d8f0f5; /* 5,6:1 ở chỗ nền nhạt nhất */
  font-size: 12px;
  line-height: 1.7;
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  11. SÁU NGÔN NGỮ
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * `dang-ky.tsx` dòng 187 ghi mã ngôn ngữ vào `document.documentElement.lang`,
 * nên `html[lang="km"]` chọn được. Độ chọn lọc (0,2,1) — cao hơn mọi quy tắc
 * cỡ chữ ở trên, kể cả `.hero .eyebrow`.
 *
 * ── TIẾNG KHMER ──────────────────────────────────────────────────────────
 *
 * Chữ Khmer xếp ba tầng quanh dòng cơ sở: dấu nguyên âm ở trên, phụ âm chân
 * (ជើង) móc xuống dưới. `line-height` hợp cho chữ Latin cắt cụt tầng dưới —
 * và nó cắt mất chữ, không phải cắt mất khoảng trắng.
 *
 * Tiếng Khmer cũng KHÔNG dùng dấu cách giữa các từ trong một cụm. Tiêu đề
 * "ការចុះឈ្មោះ – ការពិនិត្យមុខងារបន្តពូជ" là hai chuỗi liền. Trình duyệt nào
 * không có bộ ngắt dòng Khmer sẽ để nó tràn ra — mà `.hero` có
 * `overflow:hidden`, nên tràn ở đây nghĩa là MẤT CHỮ, im lặng, không dấu vết.
 * `overflow-wrap:break-word` đổi mất chữ thành ngắt xấu. Ngắt xấu còn đọc được.
 *
 * ── GIÃN CHỮ ─────────────────────────────────────────────────────────────
 *
 * `.eyebrow` giãn chữ 0.14em và `text-transform:uppercase`. Tiếng Khmer không
 * có chữ hoa nên `uppercase` vô nghĩa, còn giãn chữ thì TÁCH RỜI các thành
 * phần của một cụm chữ đáng lẽ dính liền — với người đọc Khmer nó giống như
 * đọc "t i ế n g   v i ệ t". Chữ Nhật, Hàn, Trung không vỡ như vậy nhưng giãn
 * 0.14em vẫn làm câu rời rạc.
 */
html[lang="km"] .hero-title {
  letter-spacing: 0;
  line-height: 1.45;
  overflow-wrap: break-word;
}
html[lang="km"] .hero-sub {
  line-height: 1.9;
  overflow-wrap: break-word;
}
html[lang="km"] .foot-accred {
  line-height: 1.95;
}
/* `.lang-menu li` KHÔNG có ở đây — nó đã nới `line-height` cho mọi ngôn ngữ ở
   mục 3. Danh sách bày cả sáu tên cùng lúc, nên nới theo `html[lang]` là bỏ
   sót đúng trường hợp thường gặp nhất: người đang đọc tiếng Việt mở danh sách
   ra để TÌM dòng tiếng Khmer. */
html[lang="km"] .eyebrow,
html[lang="ja"] .eyebrow,
html[lang="ko"] .eyebrow,
html[lang="zh"] .eyebrow {
  letter-spacing: 0.02em;
  text-transform: none;
}
/* ═══════════════════════════════════════════════════════════════════════════
 *  12. CHUYỂN ĐỘNG
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * ── HAI HOẠT ẢNH VÔ HẠN CÙNG LÚC ─────────────────────────────────────────
 *
 * `styles.css` dòng 1248–1251 cho `.portrait-stack` bập bênh lên xuống mãi
 * mãi (5,5 giây một nhịp) và `.hero-aura-one` trôi qua trôi lại mãi mãi (12
 * giây một nhịp), cộng thanh chạy ngang 28 giây. Ba thứ động vô hạn trong
 * cùng một khung hình, ở đúng phần trang mà khách dừng lại lâu nhất để đọc.
 *
 * Chuyển động vô hạn kéo mắt về phía nó — đó là toàn bộ công dụng của nó. Đặt
 * hai cái như vậy cạnh một tiêu đề thì tiêu đề luôn thua. Và đây là trang mà
 * việc cần làm là ĐỌC rồi ĐIỀN, không phải ngắm.
 *
 * Giữ lại hai hoạt ảnh MỘT LẦN (`hero-copy-in`, `portrait-in`) — chúng cho
 * cảm giác trang vừa mở ra rồi thôi, không đòi gì thêm. Giữ thanh chạy ngang
 * vì nó chở tên ba tổ chức chứng nhận, tức là nó có nội dung.
 *
 * Quy tắc phải nằm TRONG `@media (prefers-reduced-motion:no-preference)` vì
 * đó là nơi `styles.css` khai chúng — khai ở ngoài thì không đè được.
 */
@media (prefers-reduced-motion: no-preference) {
  .portrait-stack {
    animation: none;
  }
  .hero-aura-one {
    animation: none;
  }
}

/*
 * ── MÁY BẬT "GIẢM CHUYỂN ĐỘNG" ───────────────────────────────────────────
 *
 * `styles.css` dòng 1260 xử lý bằng `*{animation-duration:.001ms!important;
 * animation-iteration-count:1!important}`. Cách đó không TẮT hoạt ảnh, nó
 * TUA HẾT hoạt ảnh trong một phần nghìn giây — thanh chạy ngang nhảy phắt
 * sang khung hình cuối rồi đứng im ở đó.
 *
 * Với thanh chạy thì khung hình cuối là `translateX(-50%)`, mà nội dung được
 * lặp hai lần nên nhìn ra vẫn đúng. Đúng do MAY, không do thiết kế: sửa danh
 * sách trong JSX cho lẻ số lần lặp là dải chữ đứng lệch ngay, và không ai
 * hiểu vì sao.
 *
 * Nói thẳng ra thì không phải dựa vào may nữa. `animation-name:none` không bị
 * `!important` kia đụng tới (nó chỉ ép `animation-duration`), nên quy tắc này
 * thắng sạch.
 *
 * CHỈ HAI LỚP ĐƯỢC KỂ TÊN, và cả hai đều được khai ở NGOÀI media query.
 *
 * `.portrait-stack` (float), `.hero-aura-one` (aura-drift), `.hero-copy`
 * (hero-copy-in) và `.portrait-frame` (portrait-in) KHÔNG cần có mặt ở đây:
 * cả bốn chỉ được gán hoạt ảnh bên trong `@media (prefers-reduced-motion:
 * no-preference)` (dòng 1245–1251), nên khi máy bật "giảm chuyển động" thì
 * chúng vốn đã đứng yên. Viết `animation:none` cho một thứ không có hoạt ảnh
 * là mã không bao giờ chạy — và mã không bao giờ chạy thì cũng không bao giờ
 * sai lộ ra, nên nó ở lại mãi.
 */
@media (prefers-reduced-motion: reduce) {
  .hero-marquee div {
    animation: none;
    transform: none;
  }
  .lang-menu {
    animation: none;
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
 *  BIỂU MẪU — bảy khối, ô nhập, nhãn, lỗi, thanh tiến trình
 *  (gốc: vip-parts/2-bieu-mau.css)
 * ═══════════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════════
 *  BIỂU MẪU — BẢY KHỐI, Ô NHẬP, NHÃN, CÂU LỖI, THANH TIẾN TRÌNH
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Tệp này phụ trách phần khách thật sự PHẢI LÀM: bảy khối `.panel`, thanh
 * `.booking-rail` chỉ chỗ, các trường trong `.grid`/`.field`, và câu lỗi.
 *
 * Bốn việc, xếp theo thứ tự quan trọng:
 *
 *   1. Khách luôn biết mình đang ở khối nào và còn mấy khối. Biểu mẫu dài hơn
 *      4.400px; mất phương hướng ở giữa là lý do bỏ dở phổ biến nhất.
 *   2. Ô nhập mời gõ. Đây là chỗ khách bỏ công sức — nó phải sáng, viền rõ,
 *      chữ đủ to, không phải một hộp xám nằm chờ.
 *   3. Nhãn đọc được. Trước đây nhãn 12px và chú thích 11px; khách hiếm muộn
 *      phần lớn ngoài 30, nhiều người đọc ngoài nắng trên điện thoại.
 *   4. Câu lỗi nằm NGAY dưới ô sai, và có dấu hiệu hình chứ không chỉ màu đỏ.
 *
 * ── LƯU Ý CASCADE ─────────────────────────────────────────────────────────
 * Tệp này nạp SAU toàn bộ styles.css. Vì `@media` KHÔNG cộng thêm độ chọn
 * lọc, một quy tắc không-media ở đây vẫn THẮNG quy tắc cùng độ chọn lọc nằm
 * trong `@media` của styles.css — kể cả trên điện thoại. Nên chỗ nào
 * styles.css chỉ đổi giá trị Ở TRONG media (ví dụ `.grid{gap}` ở 700px), nếu
 * đè ở đây thì phải khai LẠI trong đúng media đó, không thì giá trị của máy
 * tính bàn tràn xuống điện thoại.
 */

/* ═══════════════════════════════════════════════════════════════════════════
 *  1. THANH TIẾN TRÌNH — ĐỔI TỪ THẺ TỐI SANG THẺ SÁNG
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * ĐÂY LÀ THAY ĐỔI LỚN NHẤT CỦA TỆP NÀY, và nó bắt đầu từ phép đo chứ không
 * phải từ sở thích.
 *
 * styles.css đắp bốn lượt "direction" lên `.rail-panel`, lượt cuối cho nó nền
 * chuyển sắc xanh mòng két đậm (#003d4a → #007f98) kèm hai vệt sáng radial ở
 * góc. Chữ trên nền đó đều là trắng pha độ mờ:
 *
 *   .rail-count      rgba(255,255,255,.56)  → 3,0:1   (chữ 11px, cần 4,5:1)
 *   .rail-steps li   rgba(255,255,255,.68)  → 3,7:1   (chữ 12px, cần 4,5:1)
 *   .rail-note p     rgba(255,255,255,.60)  → thấp hơn nữa, chữ 10px
 *
 * Cả ba đều rớt. Tệ hơn: vệt sáng `rgba(120,235,247,.25)` ở góc trên phải kéo
 * nền chỗ đó lên tới mức chữ TRẮNG ĐẶC cũng chỉ còn 2,9:1 — nghĩa là không có
 * độ mờ nào cứu được, phải đổi nền.
 *
 * Thẻ sáng gỡ cả ba cùng lúc, và còn ba cái lợi nữa:
 *
 *   • Hợp tinh thần "nền sáng, ấm". Một tấm xanh đậm chuyển sắc nhiều lớp là
 *     đúng thứ đang muốn tránh.
 *   • Bỏ được `backdrop-filter:blur(14px)` (styles.css dòng 574) và
 *     `filter:drop-shadow(...)` trên `.booking-rail` (dòng 3238). Hai thứ này
 *     bắt trình duyệt hợp thành lại từng khung hình cho một thẻ DÍNH — trên
 *     máy tầm thấp là giật khi cuộn, mà thẻ đã đục thì làm mờ nền phía sau
 *     chẳng để làm gì.
 *   • Thẻ sáng đặt được lên đầu biểu mẫu trên điện thoại mà không thành một
 *     mảng chắn (xem mục 8).
 *
 * Để thẻ trắng không tan vào các khối trắng bên cạnh: viền rõ hơn, cộng hai
 * dải nền nhạt ở đầu và chân thẻ làm khung.
 */

.booking-rail {
  /* Bóng đổ dạng filter là bóng phải VẼ LẠI mỗi khung hình cuộn. Bóng thường
     đặt trên .rail-panel cho cùng kết quả mà không tốn gì. */
  filter: none;
}

.rail-panel {
  border: 1px solid var(--vip-vien-dam);
  border-radius: var(--vip-bo-4);
  color: var(--vip-chu);
  background: var(--vip-the);
  box-shadow: var(--vip-noi-2);
  backdrop-filter: none;
}

/* Dải đầu thẻ hơi hồng để "Bước · 3/7" tách khỏi danh sách bên dưới — thẻ
   trắng trơn thì đầu thẻ và thân thẻ dính làm một khối không có nhịp. */
.rail-top {
  padding: 16px 18px 12px;
  border-bottom: 1px solid var(--vip-vien);
  background: var(--vip-hong-nhat);
}

.rail-kicker {
  color: var(--vip-man-sau);
  font-size: 12.5px;
  letter-spacing: 0.02em;
}

.rail-count {
  color: var(--vip-chu-mo);
  font-size: 12.5px;
}

/*
 * "3/7" là câu trả lời cho thứ khách tự hỏi nhiều nhất giữa chừng — "còn bao
 * lâu nữa". Cho nó cỡ chữ của một con số đáng đọc, đừng cỡ chữ chú thích.
 */
.rail-count b {
  color: var(--vip-man);
  font-size: 19px;
  font-weight: 800;
}

/*
 * Thanh 3px là một sợi tóc: nhìn lướt không thấy nó có chạy hay không. 6px
 * vẫn mảnh nhưng đọc được ở khoảng cách cầm điện thoại.
 *
 * Thanh này `aria-hidden`, nên nó KHÔNG được là nơi duy nhất nói tiến độ —
 * con số "3/7" ngay phía trên mới là nguồn thật. Đúng quy tắc "đừng nói một
 * trạng thái chỉ bằng màu".
 */
.rail-progress {
  height: 6px;
  margin: 12px 18px 10px;
  background: var(--vip-nen-chim);
}

.rail-progress span {
  background: var(--vip-man);
}

.rail-steps {
  padding: 8px 10px 12px;
}

/*
 * Viền trong suốt lúc nghỉ, KHÔNG phải `border:0`: khi một bước thành đang
 * xem hoặc đã xong thì chỉ đổi MÀU viền, không thêm viền — thêm viền là cả
 * danh sách nhích 2px.
 */
.rail-steps li {
  min-height: 52px;
  border: 1px solid transparent;
  border-radius: var(--vip-bo-2);
  color: var(--vip-chu);
}

.rail-steps li:hover {
  color: var(--vip-man-sau);
  background: var(--vip-nen-chim);
}

.rail-steps li.active {
  color: var(--vip-man-sau);
  border-color: var(--vip-hong);
  background: var(--vip-hong-nhat);
}

/*
 * 12px là cỡ chú thích, mà đây là mục lục của cả biểu mẫu.
 *
 * `overflow-wrap` vì cùng lý do như ở `.panel-title`: tiếng Khmer viết liền
 * không dấu cách, nên một tên bước Khmer là MỘT "từ" — không có chỗ xuống
 * dòng thì nó tràn khỏi cột giữa của chip.
 */
.rail-steps li > b {
  font-size: 13px;
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.rail-steps li > span {
  border-color: var(--vip-vien-dam);
  border-radius: var(--vip-bo-1);
  color: var(--vip-chu-mo);
  background: var(--vip-nen-chim);
  font-weight: 800;
}

/*
 * Ô số ĐẢO MÀU khi bước đang xem và khi đã xong. Đảo màu là đổi hình khối,
 * đọc được cả khi mắt không phân biệt được màu — khác hẳn việc chỉ tô chữ
 * sang một màu khác.
 */
.rail-steps li.active > span {
  color: var(--vip-the);
  border-color: var(--vip-man);
  background: var(--vip-man);
}

.rail-steps li.complete > span {
  color: var(--vip-the);
  border-color: var(--vip-mongket);
  background: var(--vip-mongket);
}

.rail-steps li > i {
  width: 20px;
  height: 20px;
  color: var(--vip-the);
  background: var(--vip-mongket);
  font-size: 11px;
}

.rail-note {
  padding: 14px 18px 16px;
  border-top: 1px solid var(--vip-vien);
  background: var(--vip-nen-chim);
}

.rail-note p {
  color: var(--vip-chu-mo);
  font-size: 11.5px;
  line-height: 1.6;
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  2. KHỐI .panel — MẶT THẺ VÀ TRẠNG THÁI
 * ═══════════════════════════════════════════════════════════════════════════ */

/*
 * `rgba(255,255,255,.97)` là trắng-gần-đục: trình duyệt vẫn phải pha nó với
 * nền, bảy lần, trong lúc cuộn. Trắng đặc cho đúng kết quả mắt nhìn thấy mà
 * không phải pha.
 */
.panel {
  border-color: var(--vip-vien);
  border-radius: var(--vip-bo-5);
  background: var(--vip-the);
  box-shadow: var(--vip-noi-2);
}

/*
 * Mảng radial ở góc trên phải trước rộng 220px, pha hồng với mòng két, và ĐỔI
 * TÔNG theo khối chẵn/lẻ. Cuộn qua bảy khối thì góc trên phải nhấp nháy
 * hồng–xanh–hồng–xanh, mắt bị kéo về phía một thứ không mang tin gì.
 *
 * Giữ mảng ấm lại (nó làm thẻ trắng bớt phẳng) nhưng nhỏ hơn, nhạt hơn, và
 * GIỐNG NHAU ở mọi khối.
 */
.panel::before,
.panel:nth-of-type(even)::before {
  width: 150px;
  height: 150px;
  background: radial-gradient(circle at 100% 0, rgba(var(--pink-rgb), 0.1), transparent 66%);
}

/*
 * Vạch trên mép thẻ đổi việc: trước là dải cầu vồng trang trí lặp lại bảy
 * lần, giờ là chỗ trả lời "tôi đang ở đâu". Lúc nghỉ nó là sợi chỉ mờ; khối
 * đang xem thì vạch chạy hết bề ngang và ăn màu mận đặc.
 */
.panel::after {
  height: 3px;
  background: rgba(var(--brand-rgb), 0.16);
}

/* Rê chuột không mang tin gì — điện thoại còn chẳng có. Hạ nó xuống gần như
   không đổi, để phần nhấn mạnh dồn hết cho `.is-current`. */
.panel:hover {
  border-color: var(--vip-vien-dam);
  box-shadow: var(--vip-noi-2);
}

/* Khối bắt buộc đã xong thì LÙI LẠI. Trước đây nó viền đậm và toả bóng mận,
   tức là khối đã xong hút mắt ngang khối đang phải làm. */
.panel-required.is-complete {
  border-color: var(--vip-vien);
  box-shadow: var(--vip-noi-1);
}

/*
 * Đặt SAU `.is-complete` là cố ý: một khối vừa xong vừa đang xem thì "đang
 * xem" phải thắng. Hai bộ chọn cùng độ chọn lọc, thứ tự quyết định.
 */
.panel.is-current {
  border-color: var(--vip-man);
  box-shadow: var(--vip-noi-3);
}

.panel.is-current::after {
  right: 0;
  left: 0;
  height: 4px;
  background: var(--vip-man);
}

/* Và "thiếu thông tin bắt buộc" thắng cả hai — nên nó đứng cuối. Bỏ quầng đỏ
   dày, giữ viền đỏ cộng một vòng mảnh; chữ trong `.panel-status.is-error` mới
   là thứ nói ra chuyện gì đang xảy ra. */
.panel-required.needs-attention {
  border-color: var(--danger);
  background: var(--vip-the);
  box-shadow: 0 0 0 3px rgba(185, 63, 74, 0.12), var(--vip-noi-2);
}

.panel-required.needs-attention::after {
  right: 0;
  left: 0;
  height: 4px;
  background: var(--danger);
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  3. ĐẦU KHỐI
 * ═══════════════════════════════════════════════════════════════════════════ */

.panel-head {
  border-bottom-color: var(--vip-vien);
}

/* Số thứ tự khối trước là gradient hồng sen → mận. Một con số hai chữ số
   không cần chuyển sắc; màu đặc đọc chắc hơn và bớt được một lớp vẽ. */
.panel-num {
  color: var(--vip-the);
  border-color: transparent;
  background: var(--vip-man);
  box-shadow: none;
  font-weight: 800;
}

.panel-ico {
  color: var(--vip-mongket-dam);
  border-color: rgba(var(--ivf-blue-rgb), 0.16);
  background: var(--vip-nen-chim);
}

/*
 * Không đụng `font-size`: styles.css đặt cỡ tiêu đề ở BA nơi, hai trong số đó
 * nằm trong `@media`. Đè ở đây là phải đè lại cả ba, mà cỡ hiện tại
 * (27px / 21px) vốn đã ổn.
 *
 * `overflow-wrap` mới là chỗ cần vá: tiếng Khmer viết liền, không có dấu cách
 * giữa từ, nên một tiêu đề Khmer là MỘT "từ" dài — trình duyệt không tìm được
 * chỗ xuống dòng và nó tràn ra khỏi cột.
 */
.panel-title {
  color: var(--vip-man-tham);
  line-height: 1.25;
  overflow-wrap: anywhere;
}

/*
 * Chip trạng thái trước là 9px, đậm 850, và `white-space:nowrap`.
 *
 * 9px là cỡ chữ chân trang, mà đây là câu duy nhất nói "khối này xong chưa".
 * `nowrap` thì chết với tiếng Khmer và tiếng Nhật: cùng một nhãn, tiếng Khmer
 * dài gần gấp đôi tiếng Việt — không xuống dòng được thì hoặc tràn ra ngoài,
 * hoặc bóp nát cột tiêu đề bên cạnh.
 */
.panel-status {
  min-height: 30px;
  padding: 6px 12px;
  border-radius: var(--vip-bo-4);
  font-size: 11px;
  font-weight: 750;
  line-height: 1.35;
  text-align: center;
  white-space: normal;
}

.panel-status.is-complete {
  color: var(--vip-the);
  border-color: var(--vip-man);
  background: var(--vip-man);
  box-shadow: none;
}

.panel-status.is-optional {
  color: var(--vip-chu-mo);
  border-color: var(--vip-vien-dam);
  background: var(--vip-nen-chim);
}

.panel-status.is-error {
  box-shadow: none;
}

/* Ghi chú trong khối ("vợ hoặc chồng", "chọn ngày trước"). Thêm vạch bên trái
   để nó đọc ra là một lời nhắc, không phải một ô nhập đang bị vô hiệu. */
.panel-note {
  padding: 12px 14px 12px 15px;
  border-left: 3px solid var(--vip-mongket);
  border-radius: var(--vip-bo-1);
  font-size: 13px;
  line-height: 1.6;
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  4. NHÃN VÀ GỢI Ý
 * ═══════════════════════════════════════════════════════════════════════════ */

/*
 * `label` là bộ chọn KHÔNG giới hạn phạm vi trong styles.css, nên ở đây cũng
 * giữ đúng phạm vi đó — nhưng chỉ đổi cỡ chữ, màu và cách xuống dòng. Không
 * đặt `display` hay `margin`: `.birth-year-field` trong hộp chọn năm sinh
 * cũng là một `<label>` và nó tự lo bố cục của mình.
 */
label {
  color: var(--vip-man-tham);
  font-size: 13.5px;
  font-weight: 700;
  line-height: 1.45;
  overflow-wrap: anywhere;
}

/*
 * "(không bắt buộc)" trước dùng `--quiet` (#a4979f) → 2,8:1 trên nền trắng.
 * Rớt xa mức 4,5:1, mà đây đúng là loại chữ khách cần đọc TRƯỚC khi quyết
 * định bỏ trống một ô.
 */
.opt {
  color: var(--vip-chu-mo);
  font-size: 12px;
  font-weight: 600;
}

.form-legend {
  margin-bottom: 16px;
  color: var(--vip-chu-mo);
  font-size: 13px;
  font-weight: 600;
}

/* 11px là cỡ chữ nhỏ nhất trang, mà `.hint` lại là chỗ nói "ghi cả số nhà và
   phường" — thứ ngăn khách nhập thiếu ngay từ đầu. */
.hint {
  color: var(--vip-chu-mo);
  font-size: 12.5px;
  line-height: 1.6;
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  5. Ô NHẬP
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * SỬA LỖI QUAN TRỌNG NHẤT Ở ĐÂY LÀ `font-size:16px`.
 *
 * Safari trên iOS tự PHÓNG TO cả trang khi tiêu điểm rơi vào ô nhập có cỡ chữ
 * dưới 16px, rồi không thu lại. styles.css để 15px, nên mỗi lần khách chạm
 * vào một ô là trang nhảy một nấc, cột chữ chạy khỏi màn hình, và khách phải
 * chụm tay thu nhỏ trước khi gõ. Biểu mẫu này hơn mười ô, tức là hơn mười lần.
 *
 * 16px cũng là cỡ đọc được ngoài nắng, nên đây là hai việc bằng một.
 */
input {
  min-height: 54px;
  padding: 14px 16px;
  border: 1.5px solid var(--vip-vien-dam);
  border-radius: var(--vip-bo-2);
  color: var(--vip-chu);
  background-color: var(--vip-the);
  font-size: 16px;
  line-height: 1.45;
}

/*
 * Chữ mờ trước là #b5a9b0 → 2,3:1. Trên điện thoại ngoài trời nó gần như
 * trắng. Dùng `--vip-chu-mo` (5,6:1): vẫn nhạt hơn hẳn chữ thật
 * (`--vip-chu`, 14,2:1) nên không ai nhầm gợi ý với giá trị đã nhập, mà đọc
 * được. `opacity:1` là để Firefox không làm mờ thêm một lần nữa.
 */
input::placeholder {
  color: var(--vip-chu-mo);
  opacity: 1;
}

input:hover {
  border-color: rgba(var(--brand-rgb), 0.45);
}

/*
 * Chỉ báo tiêu điểm THẬT ở đây là VIỀN đổi sang mận đặc: mận trên trắng là
 * 5,5:1, thừa mức 3:1 mà chỉ báo cần. Vòng mờ bên ngoài chỉ để mắt bắt được
 * chuyển động; một mình nó không đủ tương phản nên không được tính.
 *
 * `outline:none` ở đây là CỐ Ý và an toàn: viền cộng vòng đã thay đúng vai
 * trò của nó. Không có nó thì ô nhập đeo hai vòng lồng nhau — vòng tiêu điểm
 * chung ở vip.css cộng vòng này — và trông như lỗi hiển thị.
 */
input:focus {
  outline: none;
  border-color: var(--vip-man);
  background-color: var(--vip-the);
  box-shadow: 0 0 0 3px rgba(var(--brand-rgb), 0.2);
}

/*
 * Ô sai: viền đỏ ĐẶC cộng nền hồng rất nhạt. Nền nhạt để tìm ra ô sai khi
 * lướt nhanh qua một khối dài; viền mới là thứ chỉ đúng ô nào.
 *
 * Cả hai đều KHÔNG phải chỉ báo duy nhất — `.field-error` ngay bên dưới nói
 * ra bằng chữ.
 */
input:invalid.touched,
input.is-invalid {
  border-color: var(--danger);
  background-color: #fdf4f5;
  box-shadow: none;
}

/*
 * Ô SAI khi có tiêu điểm là ngoại lệ của `outline:none` ở trên, và nó là một
 * lỗ hổng thật chứ không phải chuyện thẩm mỹ.
 *
 * Ở ô bình thường, chỉ báo tiêu điểm là VIỀN đổi từ `--vip-vien-dam` sang mận
 * — chênh 3,6:1, đủ mức 3:1. Nhưng ô sai thì viền ĐÃ đỏ từ trước khi có tiêu
 * điểm, nên nó không đổi được nữa; thứ duy nhất còn lại là vòng mờ 18%, chỉ
 * chênh 1,3:1 với nền. Người đi bằng phím Tab qua một biểu mẫu đang có ô sai
 * sẽ không thấy mình đang đứng ở ô nào — mà đó đúng là lúc họ cần thấy nhất.
 *
 * Trả `outline` lại ở riêng trạng thái này, dùng đúng màu mận của vòng tiêu
 * điểm chung trong vip.css để hai thứ đọc ra là một hệ.
 */
input:invalid.touched:focus,
input.is-invalid:focus {
  outline: 2px solid var(--vip-man);
  outline-offset: 2px;
  border-color: var(--danger);
  box-shadow: 0 0 0 3px rgba(185, 63, 74, 0.18);
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  6. CÂU LỖI
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * `.field-error` là `<small role="alert">` nằm ngay sau ô trong `.field`
 * (flex cột), nên nó vốn đã đúng chỗ — dưới ô sai, không phải trên đầu khối.
 * Việc còn lại là làm nó đọc được và ĐỪNG chỉ dựa vào màu đỏ.
 *
 * Dấu chấm than vẽ bằng CSS thuần: vòng tròn là `border`, cái gạch và cái
 * chấm bên trong là hai mảng `linear-gradient` đặt đúng chỗ. Không emoji,
 * không phông biểu tượng, không thêm một yêu cầu mạng nào — khách 3G ở tỉnh
 * không phải chờ một tệp nữa mới biết mình gõ sai chỗ nào.
 */
.field-error,
.form-error {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  color: var(--danger);
  font-size: 13px;
  font-weight: 650;
  line-height: 1.55;
}

.field-error::before,
.form-error::before {
  flex: none;
  width: 17px;
  height: 17px;
  margin-top: 1px;
  border: 1.5px solid currentColor;
  border-radius: 50%;
  content: "";
  background-image: linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: center 3px, center 10px;
  background-size: 1.5px 5px, 1.5px 1.5px;
}

.form-error {
  padding: 14px 16px;
  border-color: rgba(185, 63, 74, 0.35);
  border-radius: var(--vip-bo-2);
  font-size: 13.5px;
  font-weight: 700;
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  7. LƯỚI TRƯỜNG
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Khe DỌC rộng hơn khe NGANG. Mắt đọc biểu mẫu theo hàng; khe dọc rộng hơn
 * thì "nhãn này thuộc ô nào" tự rõ mà không cần kẻ thêm khung.
 */
.grid {
  gap: 22px 20px;
}

.field,
.field-split > div {
  gap: 10px;
}

.field-split {
  gap: 20px;
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  8. ĐIỆN THOẠI
 * ═══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 920px) {
  /*
   * styles.css giấu dấu tích của bước đã xong ở khổ này (dòng 1286), để lại
   * mỗi ô số đổi màu — tức là trạng thái "đã xong" chỉ còn nói bằng MÀU. Trả
   * dấu tích về, và mở lại cột thứ ba của lưới cho nó có chỗ đứng.
   */
  .rail-steps li {
    grid-template-columns: 36px minmax(0, 1fr) 20px;
  }

  .rail-steps li > i {
    display: grid;
  }
}

@media (max-width: 760px) {
  /*
   * styles.css dòng 3379 giấu HẲN thanh tiến trình ở khổ này. Nghĩa là đúng
   * nhóm khách đông nhất — người mở đường dẫn từ tin nhắn Zalo — không có gì
   * cho biết biểu mẫu có bảy khối, đang ở khối nào, còn mấy khối.
   *
   * Trả nó lại. Nó KHÔNG dính (styles.css đã đặt `position:static` từ 920px),
   * nên nó nằm một lần ở đầu biểu mẫu như một mục lục rồi cuộn đi: đủ để đặt
   * kỳ vọng "bảy bước, bấm được để nhảy tới", mà không chiếm mất một phần ba
   * màn hình suốt buổi.
   *
   * Muốn lùi lại thì xoá đúng quy tắc này.
   */
  .booking-layout .booking-rail {
    display: block;
    margin-bottom: 4px;
  }
}

@media (max-width: 700px) {
  /* styles.css dòng 1312–1313 bóp phần đệm hai bên của thẻ xuống 15px ở khổ
     này. Quy tắc không-media ở mục 1 nuốt mất cả hai, nên khai lại đây —
     giữ nhịp dọc mới, trả lại bề ngang cho màn 360px. */
  .rail-top {
    padding: 14px 15px 10px;
  }

  .rail-progress {
    margin: 10px 15px 8px;
  }

  /*
   * Ở khổ này danh sách bước thành một dải cuộn ngang. styles.css khoá mỗi
   * chip ở đúng 174px — với tiếng Khmer, Nhật, Hàn thì tên bước dài hơn chỗ
   * đó và bị cắt. Cho chip nở theo chữ, chặn trên bằng `max-width` để chip kế
   * tiếp luôn ló ra một mẩu, nhờ đó khách biết còn cuộn được nữa.
   */
  .rail-steps {
    padding: 10px 12px 14px;
    scroll-padding-left: 12px;
    scroll-snap-type: x proximity;
  }

  .rail-steps li {
    flex: 0 0 auto;
    min-width: 170px;
    max-width: 74vw;
    border-color: var(--vip-vien-dam);
    background: var(--vip-nen);
    scroll-snap-align: start;
  }

  .rail-steps li.active {
    border-color: var(--vip-hong);
    background: var(--vip-hong-nhat);
  }

  /* Khai LẠI khe lưới trong đúng media của styles.css: quy tắc không-media ở
     mục 7 vốn thắng cả bên trong media này, nên nếu thiếu khối dưới đây thì
     khe 22px của máy tính bàn tràn xuống điện thoại. */
  .grid {
    gap: 18px;
  }

  .field-split {
    gap: 14px;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  9. GIẢM CHUYỂN ĐỘNG
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Tệp này không thêm `@keyframes` nào — mọi đổi trạng thái đều đi qua các
 * chuyển tiếp màu/bóng sẵn có của styles.css. Vẫn khai lại ở đây cho những
 * chuyển tiếp mà tệp này đụng tới, để không phải trông cậy vào quy tắc `*`
 * dùng `!important` ở styles.css dòng 1259 — quy tắc đó có thể bị gỡ bất cứ
 * lúc nào, còn khai báo này thì đứng độc lập.
 */
@media (prefers-reduced-motion: reduce) {
  .panel,
  .rail-steps li,
  .rail-steps li > span,
  .rail-progress span,
  input {
    transition: none;
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
 *  LỰA CHỌN — bác sĩ, lịch, khung giờ, nguồn biết tới
 *  (gốc: vip-parts/3-chon.css)
 * ═══════════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════════
 *  BỐN CHỖ KHÁCH RA QUYẾT ĐỊNH
 *  Nối vào cuối vip.css. Nạp sau styles.css nên thắng bằng thứ tự nguồn.
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Tệp này phụ trách bốn bề mặt mà khách phải CHỌN một thứ:
 *
 *   • Lưới bác sĩ            .doc-grid .doc-card .doc-photo …
 *   • Lịch chọn ngày khám    .exam-cal … .date-pick .birth-date-dialog
 *   • Hộp thoại chọn khung giờ                    .schedule-…
 *   • Hàng "biết tới qua đâu"                     .source-grid .source-opt
 *
 * ── MỘT NGUYÊN TẮC CHUNG CHO CẢ TỆP ───────────────────────────────────────
 *
 * Ở mọi bề mặt trên, ba trạng thái phải phân biệt được KHÔNG CẦN NHÌN MÀU:
 *
 *   đang chọn      → viền dày lên (viền + vòng inset) và có dấu tích
 *   chưa chọn      → viền mảnh, có vòng rỗng chờ được đánh dấu
 *   không chọn được→ viền ĐỨT NÉT và/hoặc gạch ngang chữ, kèm con trỏ cấm
 *
 * Lý do không phải "cho đúng WCAG". Khách của phòng khám phần lớn mở đường
 * dẫn từ tin nhắn Zalo, ngồi ngoài sáng, màn hình chỉnh sáng thấp cho đỡ hao
 * pin — trong hoàn cảnh đó chênh lệch màu giữa hồng nhạt và trắng gần như
 * biến mất, còn chênh lệch HÌNH thì không. Và đây là chỗ chọn ngày giờ đi
 * khám: chọn nhầm là mất một buổi đi lại.
 *
 * ── VÙNG CHẠM ─────────────────────────────────────────────────────────────
 *
 * Ô ngày, nút chuyển tháng, chip khung giờ, nút đóng hộp thoại: tất cả kéo
 * lên ≥44px. Chỗ nào nới ô con thì phải nới cả khung cha (lịch 330px chỉ cho
 * ra ô 40px), nên vài con số bề ngang ở đây là HỆ QUẢ của mức 44px, không
 * phải sở thích.
 */

/* ═══════════════════════════════════════════════════════════════════════════
 *  1. LƯỚI BÁC SĨ
 * ═══════════════════════════════════════════════════════════════════════════ */

.doc-grid {
  gap: 12px;
}

/*
 * Thẻ lùi lại một bước để ẢNH bước lên.
 *
 * Bản cũ cho thẻ nền #fffdfb, viền hồng khi rê chuột, bóng 30px và nhấc lên
 * 3px — tức là cái KHUNG là thứ động đậy, còn khuôn mặt bác sĩ thì đứng yên.
 * Nhưng khách quét mười một thẻ này bằng mặt người, không bằng khung. Nên
 * thẻ về trắng phẳng với bóng mảnh nhất, và toàn bộ phần "nổi" dồn cho ảnh.
 */
.doc-card {
  column-gap: 14px;
  row-gap: 5px;
  min-height: 122px;
  /* Chừa 46px bên phải cho vòng đánh dấu 26px + 12px lề + 8px thở. */
  padding: 14px 46px 14px 14px;
  border: 1.5px solid var(--vip-vien);
  border-radius: var(--vip-bo-4);
  background: var(--vip-the);
  box-shadow: var(--vip-noi-1);
  transition:
    border-color var(--vip-nhanh) var(--vip-vao),
    box-shadow var(--vip-nhanh) var(--vip-vao),
    transform var(--vip-nhanh) var(--vip-vao),
    background var(--vip-nhanh) var(--vip-vao);
}

.doc-card::before {
  height: 38%;
  background: linear-gradient(0deg, var(--vip-hong-nhat), transparent);
}

.doc-card:hover {
  border-color: var(--vip-hong);
  background: var(--vip-the);
  box-shadow: var(--vip-noi-2);
  transform: translateY(-2px);
}

/*
 * Thẻ đang chọn: viền 1.5px CỘNG một vòng inset 1px cùng màu — mắt đọc ra
 * một đường 2.5px. Đây là điểm khác biệt sống sót được khi màu tắt: dày mỏng
 * thì nhìn nghiêng, ngoài nắng, hay mù màu đều thấy.
 */
.doc-card.selected {
  border-color: var(--vip-man);
  background: var(--vip-the);
  box-shadow:
    inset 0 0 0 1px var(--vip-man),
    var(--vip-noi-2);
}

/*
 * Ảnh thật, khung trắng dày, vòng viền ngoài và bóng sâu hơn cả thẻ. Ở đây
 * bóng đậm hơn thẻ là CỐ Ý: hai lớp nổi ngược nhau làm ảnh như dán đè lên
 * thẻ chứ không phải in chìm vào nó.
 */
.doc-photo {
  border: 3px solid var(--vip-the);
  border-radius: var(--vip-bo-2);
  box-shadow:
    0 0 0 1px var(--vip-vien-dam),
    var(--vip-noi-2);
}

.doc-card.selected .doc-photo {
  box-shadow:
    0 0 0 2px var(--vip-man),
    var(--vip-noi-3);
}

/*
 * 12px và 10px là cỡ chữ của bảng điều khiển, không phải của một biểu mẫu y
 * tế mà người đọc thường trên 35 tuổi và đang đọc bằng điện thoại. Kéo lên
 * 13.5/11.5 và đổi màu chức danh sang --vip-chu-mo (6:1) thay cho --muted.
 */
.doc-name {
  color: var(--vip-man-sau);
  font-size: 13.5px;
  font-weight: 800;
  line-height: 1.4;
}

.doc-role {
  color: var(--vip-chu-mo);
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.45;
}

/*
 * Vòng đánh dấu hiện THƯỜNG TRỰC, chỉ đổi ruột.
 *
 * Bản cũ để `opacity:0` khi chưa chọn, nên mười một thẻ trống trơn và câu
 * "cái nào đang được chọn" chỉ trả lời được bằng sắc viền. Giờ mỗi thẻ mang
 * sẵn một vòng rỗng — đúng ngôn ngữ của nút chọn giấy tờ mà ai cũng biết
 * đọc: rỗng là chưa, có tích là rồi.
 *
 * Viền vòng rỗng dùng --vip-chu-nhat (3.15:1 trên trắng) chứ không dùng
 * --vip-vien-dam (1.4:1): chỉ báo trạng thái phải đạt 3:1, mà vòng này CHÍNH
 * LÀ chỉ báo.
 */
.doc-check {
  top: 12px;
  right: 12px;
  width: 26px;
  height: 26px;
  border: 2px solid var(--vip-chu-nhat);
  color: transparent;
  background: var(--vip-the);
  box-shadow: none;
  font-size: 14px;
  font-weight: 800;
  line-height: 1;
  opacity: 1;
  transform: none;
  transition:
    border-color var(--vip-nhanh) var(--vip-vao),
    background var(--vip-nhanh) var(--vip-vao),
    color var(--vip-nhanh) var(--vip-vao);
}

.doc-card.selected .doc-check {
  border-color: var(--vip-man-sau);
  color: var(--vip-the);
  background: var(--vip-man-dam);
  box-shadow: var(--vip-noi-1);
  opacity: 1;
  transform: none;
}

/* "Chưa có yêu cầu" không phải một bác sĩ. Nét đứt và nền kem nói điều đó
   trước khi khách kịp đọc chữ. */
.doc-card.none {
  border-style: dashed;
  background: var(--vip-nen);
}

/* ── Câu nhắc đầu phần chọn khung giờ ──────────────────────────────────────
 *
 * styles.css khai .doc-note hai lần, lần sau (khối "Final brand
 * consolidation") đổ nền `--teal-soft` — mà biến đó đã bị ánh xạ về HỒNG.
 * Kết quả là câu hướng dẫn mang đúng sắc hồng của thẻ trạng thái lỗi và của
 * dải nhấn thương hiệu. Đưa về nền kem trung tính: nó là lời chỉ đường, không
 * phải cảnh báo, cũng không phải quảng cáo.
 */
.doc-note {
  margin: 0 0 18px;
  padding: 14px 16px 14px 46px;
  border: 1px solid var(--vip-vien);
  border-radius: var(--vip-bo-3);
  color: var(--vip-chu-mo);
  background: var(--vip-nen-chim);
  font-size: 13px;
  line-height: 1.65;
}

.doc-note::before {
  top: 14px;
  left: 15px;
  width: 22px;
  height: 22px;
  border: 1.5px solid var(--vip-man);
  color: var(--vip-man);
  background: var(--vip-the);
  font-size: 12px;
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  2. HÀNG "BIẾT TỚI QUA ĐÂU"
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Ô này đã có sẵn chấm tròn kiểu nút chọn trong DOM, tức là đã có hình để
 * phân biệt trạng thái. Việc còn lại chỉ là làm chấm đó ĐỦ ĐẬM để thấy: viền
 * cũ dùng --line-strong, tương phản 1.6:1 với nền trắng — dưới xa mức 3:1 mà
 * một chỉ báo trạng thái phải đạt.
 */

.source-grid {
  gap: 12px;
}

.source-opt {
  min-height: 52px;
  padding: 13px 15px;
  border: 1.5px solid var(--vip-vien);
  border-radius: var(--vip-bo-3);
  color: var(--vip-chu);
  background: var(--vip-the);
  font-size: 13.5px;
  font-weight: 700;
  line-height: 1.45;
  transition:
    border-color var(--vip-nhanh) var(--vip-vao),
    background var(--vip-nhanh) var(--vip-vao),
    box-shadow var(--vip-nhanh) var(--vip-vao),
    transform var(--vip-nhanh) var(--vip-vao);
}

.source-opt:hover {
  border-color: var(--vip-hong);
  background: var(--vip-the);
  box-shadow: var(--vip-noi-1);
  transform: translateY(-1px);
}

.source-opt.selected {
  border-color: var(--vip-man);
  color: var(--vip-man-sau);
  background: var(--vip-the);
  box-shadow:
    inset 0 0 0 1px var(--vip-man),
    var(--vip-noi-1);
}

.source-opt .dot {
  width: 22px;
  height: 22px;
  border: 2px solid var(--vip-chu-nhat);
}

.source-opt.selected .dot {
  border-color: var(--vip-man);
}

.source-opt.selected .dot::after {
  background: var(--vip-man);
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  3. LỊCH CHỌN NGÀY KHÁM (chỉ hiện từ 701px trở lên)
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Bề ngang 364px KHÔNG phải con số làm đẹp — nó là phép chia ngược từ 44px:
 *
 *     (364 − 16×2 lề trong − 3×6 khe) ÷ 7 cột = 44.9px mỗi ô
 *
 * Với 330px cũ mỗi ô chỉ ra 40.6px, hụt vùng chạm. Nới lịch là an toàn: hàm
 * `ngam()` trong o-ngay.tsx đo `offsetWidth` lúc chạy rồi kẹp trong khung
 * nhìn, nên lịch không bao giờ trôi ra mép dù rộng thêm.
 */
.exam-cal {
  width: 364px;
  padding: 16px;
  border: 1px solid var(--vip-vien-dam);
  border-radius: var(--vip-bo-5);
  background: var(--vip-the);
  box-shadow: var(--vip-noi-4);
  /* styles.css cho lịch một hoạt ảnh không rào bằng prefers-reduced-motion.
     Tắt ở đây rồi bật lại trong khối no-preference bên dưới. */
  animation: none;
}

.exam-cal-head {
  grid-template-columns: 44px minmax(0, 1fr) 44px;
  gap: 8px;
  margin-bottom: 14px;
}

.exam-cal-head strong {
  color: var(--vip-man-sau);
  font-size: 16px;
  line-height: 1.4;
}

.exam-cal-nav {
  width: 44px;
  height: 44px;
  border: 1px solid var(--vip-vien-dam);
  border-radius: var(--vip-bo-2);
  color: var(--vip-man-sau);
  background: var(--vip-the);
  transition:
    border-color var(--vip-nhanh) var(--vip-vao),
    background var(--vip-nhanh) var(--vip-vao);
}

.exam-cal-nav:hover:not([aria-disabled="true"]) {
  border-color: var(--vip-man);
  background: var(--vip-hong-nhat);
}

/*
 * Nút hết đường đi: tô nhạt hẳn thay vì `opacity:.45`.
 *
 * Giảm độ đục làm mờ cả mũi tên SVG lẫn viền, nên nút trông như lỗi vẽ chứ
 * không như "đã hết tháng". Nền kem + chữ nhạt nói đúng nghĩa hơn, và vẫn
 * còn hình mũi tên để nhận ra đó là nút.
 */
.exam-cal-nav[aria-disabled="true"] {
  border-color: var(--vip-vien);
  color: var(--vip-chu-nhat);
  background: var(--vip-nen-chim);
  opacity: 1;
}

/*
 * Hàng tên thứ: Intl trả về chữ viết tắt của SÁU ngôn ngữ, trong đó Khmer
 * dựng dấu chồng cao hơn Latin. Bỏ chiều cao cố định, cho line-height 1.4.
 */
.exam-cal-week span {
  padding: 6px 0;
  color: var(--vip-chu-mo);
  font-size: 11px;
  line-height: 1.4;
}

/* Cột Chủ nhật: gạch ngang ngay trên TIÊU ĐỀ cột, không chỉ đổi màu. Khách
   thấy cả cột bị loại trước khi kịp bấm nhầm xuống một ô trong đó. */
.exam-cal-week span.is-closed {
  color: var(--vip-chu-mo);
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
}

.exam-cal-day {
  min-height: 44px;
  border-radius: var(--vip-bo-2);
  color: var(--vip-chu);
  font-size: 14px;
  transition:
    color var(--vip-nhanh) var(--vip-vao),
    border-color var(--vip-nhanh) var(--vip-vao),
    background var(--vip-nhanh) var(--vip-vao);
}

.exam-cal-day:hover:not(.is-blocked) {
  border-color: var(--vip-man);
  background: var(--vip-hong-nhat);
}

/*
 * Ngày của tháng bên cạnh vẫn BẤM ĐƯỢC, nên nó là chữ thật và phải đọc được.
 * --quiet (#a4979f) chỉ đạt 2.9:1. Lùi bằng độ đậm (600 so với 700) thay vì
 * bằng độ nhạt.
 */
.exam-cal-day.is-outside {
  color: var(--vip-chu-mo);
  font-weight: 600;
}

/* "Hôm nay" vẽ bằng vòng inset chứ không tăng border-width: đổi bề dày viền
   làm con số nhích một pixel, mà cả lưới đang dóng thẳng cột theo chữ số. */
.exam-cal-day.is-today:not(.is-selected) {
  color: var(--vip-mongket-dam);
  border-color: transparent;
  background: var(--vip-the);
  box-shadow: inset 0 0 0 2px var(--vip-mongket);
}

/*
 * Ngày không nhận khám — giữ đúng tinh thần cũ (kẻ chéo + con trỏ cấm) và
 * đẩy nó lên rõ hơn:
 *
 *   • sọc chéo dày gấp rưỡi, dùng nền kem chìm nên thấy được cả ngoài nắng
 *   • GẠCH NGANG con số cho MỌI lý do bị chặn, không riêng ngày nghỉ. Trước
 *     đây ngày đã qua và ngày quá xa chỉ nhạt đi, mà "nhạt" thì trùng với
 *     ngày của tháng bên cạnh — hai thứ khác hẳn nhau về hệ quả.
 *
 * Chữ ở mức 3.15:1 trên sọc trắng, 2.77:1 trên sọc kem. Ô này mang
 * aria-disabled="true" — thành phần giao diện đang tắt, WCAG 1.4.3 không đặt
 * ngưỡng cho nó. GẠCH NGANG mới là thứ mang nghĩa ở đây, còn lý do đầy đủ
 * hiện ở .exam-cal-note bên dưới với tương phản 6.1:1.
 */
.exam-cal-day.is-blocked {
  color: var(--vip-chu-nhat);
  background: repeating-linear-gradient(
    135deg,
    var(--vip-nen-chim),
    var(--vip-nen-chim) 5px,
    var(--vip-the) 5px,
    var(--vip-the) 10px
  );
  font-weight: 600;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
}

.exam-cal-day.is-blocked:hover {
  border-color: var(--vip-vien-dam);
}

/* Ngày đang chọn: khối đặc, trắng trên mận đậm (7.4:1). Đặc so với rỗng là
   khác biệt về HÌNH, đọc được cả khi in đen trắng. */
.exam-cal-day.is-selected {
  color: var(--vip-the);
  border-color: var(--vip-man-sau);
  background: var(--vip-man-dam);
  box-shadow: var(--vip-noi-2);
  font-weight: 800;
  text-decoration: none;
}

.exam-cal-note {
  margin: 12px 0 0;
  padding: 10px 12px;
  border: 1px solid var(--vip-vien);
  border-radius: var(--vip-bo-2);
  color: var(--vip-mongket-dam);
  background: var(--vip-nen-chim);
  font-size: 12.5px;
  line-height: 1.55;
}

/* Lời nhắc lỗi giữ nguyên màu --danger của kho; chỉ thêm viền cùng màu và
   chữ đậm để nó khác câu hướng dẫn bằng cả sắc lẫn nét. */
.exam-cal-note.is-warning {
  border-color: var(--danger);
  font-weight: 700;
}

.exam-cal-foot {
  gap: 10px;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--vip-vien);
}

.exam-cal-foot-btn {
  min-height: 44px;
  padding: 0 12px;
  border: 1px solid var(--vip-vien-dam);
  border-radius: var(--vip-bo-2);
  color: var(--vip-man-sau);
  background: var(--vip-the);
  font-size: 13px;
  line-height: 1.4;
  transition:
    border-color var(--vip-nhanh) var(--vip-vao),
    background var(--vip-nhanh) var(--vip-vao);
}

.exam-cal-foot-btn:hover:not([aria-disabled="true"]) {
  border-color: var(--vip-man);
  background: var(--vip-hong-nhat);
}

.exam-cal-foot-btn.is-quiet {
  color: var(--vip-chu-mo);
}

.exam-cal-foot-btn[aria-disabled="true"] {
  border-color: var(--vip-vien);
  color: var(--vip-chu-nhat);
  background: var(--vip-nen-chim);
  opacity: 1;
}

/*
 * Nút mở lịch nằm trong ô ngày. HAI thứ cố ý không khai ở đây:
 *
 *   • border-radius — nó phải ăn theo bo góc của <input>, mà ô nhập thuộc
 *     nhóm khác; khai cứng ở đây là hẹn trước một ngày lệch góc.
 *   • width — styles.css khoá `.date-pick > #examDate{padding-right:56px}`
 *     bằng một bộ chọn CÓ ID, thứ không bộ chọn lớp nào trong tệp này với
 *     tới được. Nới nút lên 56px thì chữ ngày dí sát vạch ngăn, không còn
 *     khe nào; 52px của styles.css chừa đúng 4px. Mà nút vốn cao bằng ô nhập
 *     (54px), nên 52×54 đã vượt vùng chạm 44px — nới thêm không được gì.
 */
.date-pick-cal {
  border-left: 1px solid var(--vip-vien-dam);
  color: var(--vip-mongket-dam);
  transition:
    color var(--vip-nhanh) var(--vip-vao),
    background var(--vip-nhanh) var(--vip-vao);
}

.date-pick-cal:hover {
  color: var(--vip-man);
  background: var(--vip-hong-nhat);
}

.date-pick-cal[aria-expanded="true"] {
  color: var(--vip-the);
  background: var(--vip-man);
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  4. DẢI MỞ LỊCH VÀ HỘP THOẠI CHỌN KHUNG GIỜ
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Dải mở lịch và đầu hộp thoại đang chạy một dải chuyển ba màu tím → hồng →
 * xanh mòng két. Ba sắc trong một nền là thứ làm trang trông như bản dựng
 * thử, và đúng thứ hướng dẫn thiết kế bảo tránh. Đổi về MỘT họ mận, đi từ
 * thẫm sang đậm, thêm một quầng hồng rất nhạt cho khỏi phẳng.
 */
.schedule-launch {
  gap: 18px;
  padding: 22px;
  border-radius: var(--vip-bo-5);
  background:
    radial-gradient(circle at 84% -40%, rgba(225, 127, 174, 0.3), transparent 16rem),
    linear-gradient(122deg, var(--vip-man-tham), var(--vip-man-sau) 58%, var(--vip-man-dam));
  box-shadow: var(--vip-noi-3);
}

/* Câu mô tả dưới tiêu đề: 11px ở mức 72% trắng là chữ trang trí, không phải
   chữ đọc được. Kéo lên 12px / 82% — 8:1 trên chỗ nhạt nhất của nền mận. */
.schedule-launch p {
  color: rgba(255, 255, 255, 0.82);
  font-size: 12px;
  line-height: 1.6;
}

.schedule-dialog {
  border-radius: var(--vip-bo-5);
  background: var(--vip-nen);
  box-shadow: var(--vip-noi-4);
}

/*
 * Rào hoạt ảnh mở hộp thoại; bật lại ở khối no-preference cuối tệp.
 *
 * Phải khai ở `[open]`, không phải ở `.schedule-dialog` trơn: styles.css
 * viết `.schedule-dialog[open]{animation:…}` — hai bậc. Một lớp trơn thua,
 * và cái rào sẽ im lặng không làm gì cả.
 */
.schedule-dialog[open] {
  animation: none;
}

/*
 * Bỏ `backdrop-filter: blur(12px) saturate(.85)`.
 *
 * Làm mờ TOÀN MÀN HÌNH là phép hợp ảnh chạy lại mỗi khung hình. Trên máy
 * Android tầm thấp — đúng nhóm máy mở đường dẫn từ Zalo — nó biến cú cuộn
 * trong hộp thoại thành giật cục, mà hộp thoại này là bảng bảy ngày cuộn
 * ngang. Nền che đã ở 72% đen, thừa sức tách lớp mà không cần làm mờ.
 */
.schedule-dialog::backdrop {
  backdrop-filter: none;
}

.schedule-dialog-head {
  /* Cột cuối nới 48px cho nút đóng đạt vùng chạm. */
  grid-template-columns: 56px minmax(0, 1fr) auto 48px;
  gap: 16px;
  padding: 20px 24px;
  background:
    radial-gradient(circle at 80% -80%, rgba(225, 127, 174, 0.28), transparent 19rem),
    linear-gradient(118deg, var(--vip-man-tham), var(--vip-man-sau) 62%, var(--vip-man-dam));
  box-shadow: var(--vip-noi-2);
}

.schedule-dialog-close {
  width: 48px;
  height: 48px;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: var(--vip-bo-2);
  background: rgba(255, 255, 255, 0.12);
  font-size: 26px;
  transition: background var(--vip-nhanh) var(--vip-vao);
}

/* Bỏ cú xoay 4 độ khi rê chuột. Một hộp thoại nhận thông tin khám chữa bệnh
   không cần nút đóng biết đùa. */
.schedule-dialog-close:hover {
  background: rgba(255, 255, 255, 0.22);
  transform: none;
}

.schedule-loading,
.schedule-unavailable {
  gap: 14px;
  color: var(--vip-chu-mo);
  font-size: 13.5px;
  line-height: 1.6;
}

.schedule-loading span {
  width: 26px;
  height: 26px;
  border-color: var(--vip-vien-dam);
  border-top-color: var(--vip-man);
}

.schedule-unavailable span {
  width: 36px;
  height: 36px;
  color: var(--vip-the);
  background: var(--vip-man);
}

.schedule-unavailable p {
  max-width: 46ch;
  margin: 0;
}

/* ── Bảng ma trận (từ 1101px trở lên) ─────────────────────────────────────
 *
 * Không đụng vào nền của thead: cột bác sĩ dính bên trái mang một sắc thẫm
 * riêng, đổi một trong hai là để lại một đường nối lệch màu giữa chúng.
 */
.schedule-matrix th,
.schedule-matrix td {
  border-right: 1px solid var(--vip-vien);
  border-bottom: 1px solid var(--vip-vien);
}

.schedule-matrix thead th {
  color: rgba(255, 255, 255, 0.88);
}

.schedule-matrix thead th > span {
  font-size: 11px;
}

.schedule-matrix thead th > strong {
  font-size: 13px;
}

/*
 * Huy hiệu "hôm nay" trên đầu cột. 7px là cỡ chữ không đọc được trên bất kỳ
 * màn hình nào, và `line-height` mặc định thì bó sát dấu chồng hai tầng.
 *
 * `text-transform:uppercase` cũng bỏ: nó là giả định "chữ Latin". Tiếng
 * Khmer không có khái niệm hoa/thường nên viết hoa là vô nghĩa, còn tiếng
 * Việt thì "HÔM NAY" toàn chữ hoa đọc chậm hơn "Hôm nay".
 */
.schedule-matrix thead th > em {
  margin-top: 4px;
  padding: 3px 8px;
  color: var(--vip-man-sau);
  background: var(--vip-the);
  font-size: 9.5px;
  line-height: 1.5;
  text-transform: none;
}

.schedule-matrix tbody tr:nth-child(even) td {
  background: var(--vip-nen);
}

.schedule-matrix tbody tr:hover td {
  background: var(--vip-hong-nhat);
}

/* ── Chip khung giờ ───────────────────────────────────────────────────────
 *
 * Ba trạng thái, ba HÌNH khác nhau:
 *
 *   còn khung, bấm được → viền liền, nền hồng nhạt
 *   đã chọn            → khối đặc mòng két CÓ DẤU TÍCH vẽ bằng CSS
 *   không trực         → trơ một gạch ngang, không viền không nền
 *
 * 44px là mức tối thiểu cho ngón tay; ô bảng cao 66px nên chip 44px vẫn
 * nằm gọn giữa ô.
 */
.schedule-slot {
  min-width: 44px;
  min-height: 44px;
  padding: 6px 10px;
  line-height: 1.4;
}

.schedule-slot.is-open {
  border: 1.5px solid var(--vip-hong);
  color: var(--vip-man-sau);
  background: var(--vip-hong-nhat);
  font-size: 12px;
  font-weight: 800;
  box-shadow: none;
}

/* Dấu "—" ở ô không trực là NGHĨA, không phải hoa văn: nó là câu trả lời cho
   "bác sĩ này hôm đó có không". Nên nó lấy --vip-chu-mo (6:1 trên ô trắng,
   5,8:1 trên hàng chẵn, 5,2:1 lúc rê chuột) chứ không lấy --vip-chu-nhat
   (3,15:1). Nó vẫn lặng hơn chip hồng đặc bên cạnh. */
.schedule-slot.is-off {
  color: var(--vip-chu-mo);
}

.schedule-slot-choice {
  border: 1.5px solid var(--vip-hong);
  transition:
    color var(--vip-nhanh) var(--vip-vao),
    background var(--vip-nhanh) var(--vip-vao),
    border-color var(--vip-nhanh) var(--vip-vao),
    box-shadow var(--vip-nhanh) var(--vip-vao);
}

.schedule-slot-choice:hover {
  color: var(--vip-mongket-dam);
  border-color: var(--vip-mongket);
  background: var(--vip-the);
  box-shadow: var(--vip-noi-1);
  transform: none;
}

.schedule-slot-choice.is-selected {
  gap: 7px;
  color: var(--vip-the);
  border-color: var(--vip-mongket-dam);
  background: var(--vip-mongket-dam);
  box-shadow: var(--vip-noi-2);
  font-weight: 800;
}

/*
 * Dấu tích vẽ bằng hai cạnh viền xoay 45 độ — không emoji, không phông biểu
 * tượng, không thêm một yêu cầu mạng nào. Chip là inline-flex nên dấu tích
 * vào làm một phần tử flex, đứng trước giờ và tự dóng giữa.
 *
 * Cái này mới là thứ nói "ĐÃ CHỌN" khi màu đi mất: khách xem trên máy chỉnh
 * sáng thấp hoặc in ra giấy đen trắng vẫn thấy dấu tích.
 */
.schedule-slot-choice.is-selected::before {
  flex: none;
  width: 6px;
  height: 11px;
  margin-top: -3px;
  border: solid var(--vip-the);
  border-width: 0 2px 2px 0;
  content: "";
  transform: rotate(45deg);
}

/* ── Thanh xác nhận dính đáy hộp thoại ────────────────────────────────────
 *
 * Bỏ `backdrop-filter: blur(16px)` vì đúng lý do như nền che, và vì thanh
 * này nằm ĐÈ LÊN CHỮ của bảng bên dưới — làm mờ sau lưng chữ là thứ hướng
 * dẫn thiết kế cấm thẳng. Nền chuyển sang đục hẳn.
 *
 * Cỡ chữ 8px/9px trong này là mức không ai đọc nổi, mà đây là dòng nhắc lại
 * "bạn vừa chọn bác sĩ nào, ngày nào, giờ nào" — câu quan trọng nhất của cả
 * hộp thoại. Kéo lên mức đọc được, kể cả nút xác nhận.
 */
.schedule-selection-bar {
  gap: 14px;
  padding: 14px 16px;
  border: 1.5px solid var(--vip-mongket);
  border-radius: var(--vip-bo-4);
  color: var(--vip-chu);
  background: var(--vip-the);
  box-shadow: var(--vip-noi-3);
  backdrop-filter: none;
}

.schedule-selection-bar small {
  color: var(--vip-mongket-dam);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  line-height: 1.5;
}

.schedule-selection-bar strong {
  font-size: 13px;
  line-height: 1.45;
}

.schedule-selection-bar p {
  color: var(--vip-chu-mo);
  font-size: 11px;
  line-height: 1.5;
}

.schedule-selection-bar button {
  min-height: 46px;
  padding: 10px 18px;
  border-radius: var(--vip-bo-2);
  font-size: 13px;
  line-height: 1.4;
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  5. BẢN THEO NGÀY — dưới 1101px
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * TOÀN BỘ khai báo của .schedule-day-tab và .schedule-shift-card trong
 * styles.css nằm trong @media (max-width:1100px). Đè chúng ở ngoài media
 * query thì bản đè đúng ở khổ desktop — nơi hai lớp này KHÔNG hề hiện — rồi
 * biến mất ở đúng khổ máy mà chúng phục vụ.
 */
@media (max-width: 1100px) {
  .schedule-day-tab {
    min-height: 62px;
    border-radius: var(--vip-bo-3);
    color: var(--vip-chu-mo);
    transition:
      color var(--vip-nhanh) var(--vip-vao),
      background var(--vip-nhanh) var(--vip-vao),
      box-shadow var(--vip-nhanh) var(--vip-vao),
      transform var(--vip-nhanh) var(--vip-vao);
  }

  .schedule-day-tab:hover {
    color: var(--vip-man-sau);
    background: var(--vip-the);
  }

  .schedule-day-tab[aria-selected="true"] {
    color: var(--vip-the);
    border-color: var(--vip-man-sau);
    background: var(--vip-man-dam);
    box-shadow:
      inset 0 0 0 1px rgba(255, 255, 255, 0.28),
      var(--vip-noi-2);
  }

  .schedule-day-tab > span {
    font-size: 10.5px;
  }

  .schedule-day-tab > strong {
    margin-top: 3px;
    font-size: 15px;
  }

  /*
   * Huy hiệu góc: bỏ `height:17px` cố định.
   *
   * Ô này chứa hoặc một con số, hoặc chữ "nghỉ" của sáu ngôn ngữ. Chiều cao
   * cứng thì bản tiếng Khmer bị xén mất chân dấu. max-width giữ nó không
   * tràn ra khỏi thẻ ngày khi chữ dài.
   */
  .schedule-day-tab > em {
    top: 6px;
    right: 6px;
    min-width: 20px;
    max-width: calc(100% - 14px);
    height: auto;
    min-height: 20px;
    padding: 1px 6px;
    color: var(--vip-man-sau);
    background: var(--vip-the);
    font-size: 9.5px;
    line-height: 1.4;
  }

  .schedule-day-tab > em.is-closed {
    min-width: 0;
    padding: 1px 7px;
    color: var(--vip-chu-mo);
    background: var(--vip-nen-chim);
  }

  /* Vạch "hôm nay" đổi sang mòng két: mận đã là màu của thẻ ĐANG CHỌN, để
     hai dấu hiệu khác nghĩa dùng chung một sắc là mời khách hiểu nhầm. */
  .schedule-day-tab.is-today::after {
    height: 3px;
    background: var(--vip-mongket);
  }

  /* Trên thẻ đang chọn (nền mận đậm) thì mòng két chìm mất, đổi sang trắng. */
  .schedule-day-tab[aria-selected="true"].is-today::after {
    background: var(--vip-the);
  }

  .schedule-shift-card {
    column-gap: 13px;
    min-height: 96px;
    padding: 13px;
    border: 1.5px solid var(--vip-vien);
    border-radius: var(--vip-bo-4);
    background: var(--vip-the);
    box-shadow: var(--vip-noi-1);
    transition:
      border-color var(--vip-nhanh) var(--vip-vao),
      box-shadow var(--vip-nhanh) var(--vip-vao),
      transform var(--vip-nhanh) var(--vip-vao);
  }

  .schedule-shift-card:hover {
    border-color: var(--vip-hong);
    box-shadow: var(--vip-noi-2);
    transform: translateY(-2px);
  }

  /*
   * Thẻ KHÔNG bấm được đang trông y hệt thẻ bấm được — cùng viền, cùng bóng,
   * cùng cú nhấc lên khi rê chuột — chỉ khác con trỏ, thứ mà điện thoại
   * không có. Nét đứt và nền kem nói ngay từ cái nhìn đầu: chỗ này chỉ để
   * xem.
   */
  .schedule-shift-card.is-static {
    border-style: dashed;
    border-color: var(--vip-vien-dam);
    background: var(--vip-nen-chim);
    box-shadow: none;
  }

  .schedule-shift-card.is-static:hover {
    border-color: var(--vip-vien-dam);
    box-shadow: none;
    transform: none;
  }

  /* Đang chọn: vòng inset 2px CỘNG thanh dọc 6px bên trái. Cả hai đều là bề
     dày, nên trạng thái này còn đọc được khi bỏ hết màu. */
  .schedule-shift-card.is-selected {
    border-color: var(--vip-mongket-dam);
    background: var(--vip-the);
    box-shadow:
      var(--vip-noi-2),
      inset 0 0 0 2px var(--vip-mongket-dam),
      inset 6px 0 0 var(--vip-mongket-dam);
  }

  /*
   * Bỏ cắt-đuôi-một-dòng cho tên và chức danh bác sĩ.
   *
   * `white-space:nowrap` + ellipsis được viết cho tên tiếng Việt. Cùng chức
   * danh đó, tiếng Khmer dài gần gấp đôi và bị cắt còn "Bác sĩ chuyên khoa…"
   * — khách mất đúng phần chữ giúp họ phân biệt hai bác sĩ. Thẻ cao thêm một
   * dòng rẻ hơn nhiều so với việc đó.
   */
  .schedule-shift-card strong {
    overflow: visible;
    font-size: 13px;
    line-height: 1.4;
    text-overflow: clip;
    white-space: normal;
  }

  .schedule-shift-card small {
    overflow: visible;
    color: var(--vip-chu-mo);
    font-size: 11px;
    line-height: 1.45;
    text-overflow: clip;
    white-space: normal;
  }

  /* 8px cho dòng "chọn khung giờ →" — dòng DUY NHẤT nói rằng thẻ này bấm
     được. Kéo lên 11px. */
  .schedule-shift-card .schedule-shift-action {
    margin-top: 7px;
    font-size: 11px;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  6. ĐIỆN THOẠI — dưới 701px
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Mốc kiểm: máy 375px. Ở khổ này hộp thoại chiếm trọn màn hình, hàng bảy
 * thẻ ngày nằm trên lưới 8 cột (mỗi thẻ ~79px), và không còn chuột nên mọi
 * thứ bấm được đều phải đạt 44px.
 */
@media (max-width: 700px) {
  /* Lý do bỏ làm mờ giống hệt nền che hộp thoại lịch trực: máy Android tầm
     thấp mở từ Zalo, mà tấm che này phủ kín màn hình. */
  .birth-date-dialog::backdrop {
    backdrop-filter: none;
  }

  .schedule-launch p {
    font-size: 11.5px;
  }

  /* Cột cuối 48px để nút đóng còn đủ 44px sau khi trừ viền. */
  .schedule-dialog-head {
    grid-template-columns: 44px minmax(0, 1fr) 48px;
    gap: 12px;
  }

  .schedule-dialog-close {
    width: 48px;
    height: 48px;
    border-radius: var(--vip-bo-2);
  }

  .schedule-day-tab {
    min-height: 60px;
    padding: 8px 4px;
  }

  .schedule-day-tab > span {
    font-size: 10px;
  }

  .schedule-day-tab > strong {
    font-size: 14px;
  }

  .schedule-day-tab > em {
    top: 5px;
    right: 5px;
    min-width: 19px;
    min-height: 19px;
    padding: 1px 5px;
    font-size: 9px;
  }

  .schedule-shift-card {
    min-height: 92px;
    padding: 12px;
    border-radius: var(--vip-bo-3);
  }

  .schedule-shift-card strong {
    font-size: 12.5px;
  }

  .schedule-selection-bar {
    gap: 11px;
    padding: 12px;
    border-radius: var(--vip-bo-3);
  }

  .schedule-selection-bar small {
    font-size: 10px;
  }

  .schedule-selection-bar strong {
    font-size: 12.5px;
  }

  .schedule-selection-bar button {
    min-height: 48px;
    font-size: 13px;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  7. MÁY HẸP — dưới 411px
 * ═══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 410px) {
  /*
   * styles.css thu lề phải thẻ bác sĩ còn 36px ở khổ này. Vòng đánh dấu bây
   * giờ rộng 26px, nên 36px làm chữ chui xuống dưới nó. 42px là mức vừa đủ:
   * 26 vòng + 10 lề + 6 thở.
   */
  .doc-card {
    padding: 12px 42px 12px 12px;
  }

  .doc-check {
    top: 10px;
    right: 10px;
  }

  .schedule-shift-card strong {
    font-size: 12px;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  8. MÀN CẢM ỨNG
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Trên máy không có chuột, `:hover` DÍNH LẠI sau cú chạm: khách bấm một thẻ
 * bác sĩ rồi cuộn đi, thẻ đó vẫn nhấc lên và đổi viền như đang được trỏ tới.
 * Hai thẻ cùng lúc trông như đang được chọn — ở đúng chỗ chỉ được chọn một.
 */
@media (hover: none) {
  .doc-card:hover,
  .source-opt:hover {
    box-shadow: var(--vip-noi-1);
    transform: none;
  }

  .doc-card:hover {
    border-color: var(--vip-vien);
  }

  .source-opt:hover {
    border-color: var(--vip-vien);
  }

  /* Thẻ đang chọn phải giữ nguyên diện mạo dù ngón tay vừa rời khỏi nó. */
  .doc-card.selected:hover {
    border-color: var(--vip-man);
    box-shadow:
      inset 0 0 0 1px var(--vip-man),
      var(--vip-noi-2);
  }

  .source-opt.selected:hover {
    border-color: var(--vip-man);
    box-shadow:
      inset 0 0 0 1px var(--vip-man),
      var(--vip-noi-1);
  }
}

@media (hover: none) and (max-width: 1100px) {
  .schedule-shift-card:hover {
    border-color: var(--vip-vien);
    box-shadow: var(--vip-noi-1);
    transform: none;
  }

  .schedule-shift-card.is-selected:hover {
    border-color: var(--vip-mongket-dam);
    box-shadow:
      var(--vip-noi-2),
      inset 0 0 0 2px var(--vip-mongket-dam),
      inset 6px 0 0 var(--vip-mongket-dam);
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  9. CHUYỂN ĐỘNG
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Cả tệp chỉ động đậy hai thuộc tính: transform và opacity. Không có chỗ nào
 * chạy width/height/top/left, vì hai nhóm đó bắt trình duyệt tính lại bố cục
 * mỗi khung hình — trên máy tầm thấp là giật thấy rõ.
 *
 * Hai hoạt ảnh dưới đây bật LẠI những gì phần trên đã tắt: styles.css khai
 * chúng ngoài mọi rào prefers-reduced-motion, nên cách duy nhất để tôn trọng
 * cài đặt của máy là tắt ở mặc định rồi mở trong no-preference.
 */
@media (prefers-reduced-motion: no-preference) {
  .exam-cal {
    animation: exam-cal-in var(--vip-nhanh) var(--vip-vao);
  }

  .schedule-dialog[open] {
    animation: schedule-dialog-in var(--vip-vua) var(--vip-vao);
  }
}

@media (prefers-reduced-motion: reduce) {
  .doc-card,
  .doc-check,
  .doc-photo,
  .source-opt,
  .source-opt .dot,
  .exam-cal,
  .exam-cal-nav,
  .exam-cal-day,
  .exam-cal-foot-btn,
  .date-pick-cal,
  .schedule-dialog,
  .schedule-dialog[open],
  .schedule-dialog-close,
  .schedule-slot-choice,
  .schedule-day-tab,
  .schedule-shift-card {
    transition: none;
    animation: none;
  }

  .doc-card:hover,
  .source-opt:hover,
  .schedule-shift-card:hover,
  .schedule-day-tab[aria-selected="true"] {
    transform: none;
  }

  /*
   * Vòng xoay báo đang tải: dừng quay thì một vòng khuyết ba phần tư trông
   * như lỗi vẽ. Đóng kín vòng lại để nó thành một dấu hiệu tĩnh đứng cạnh
   * câu "đang tải" — câu chữ mới là thứ nói nghĩa, vòng chỉ đi kèm.
   */
  .schedule-loading span {
    border-color: var(--vip-man);
    animation: none;
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
 *  GỬI — nút gửi, màn thành công, khối ưu đãi
 *  (gốc: vip-parts/4-gui.css)
 * ═══════════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════════
 *  4 — VÙNG GỬI VÀ MÀN THÀNH CÔNG
 *  Nối vào cuối vip.css. Nạp sau styles.css nên thắng bằng thứ tự nguồn.
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Tệp này lo hai thứ, theo đúng thứ tự khách gặp chúng:
 *
 *   1. Vùng gửi — hộp "còn thiếu gì" (.submit-gate) và nút gửi (.submit-btn).
 *      Đây là đích của cả trang. Khi đã điền đủ, nút phải là thứ nặng nhất
 *      trên màn; khi chưa đủ, hộp phía trên phải nói ĐANG THIẾU CÁI GÌ chứ
 *      không chỉ đổi màu.
 *   2. Màn thành công (.overlay) — ấn tượng cuối cùng khách mang về. Nhiều
 *      người vừa bấm gửi xong đang lo, nên màn này làm ẤM và YÊN TÂM, không
 *      ăn mừng. Trong đó có `.program-summary`: lớp mang tên "program" nhưng
 *      bản React dùng để in MÃ PHIẾU và khung giờ đã giữ được — thứ khách
 *      chụp màn hình mang đi.
 *
 * ── VÌ SAO Ở ĐÂY KHÔNG CÓ KHỐI "CHƯƠNG TRÌNH ƯU ĐÃI" ─────────────────────
 *
 * styles.css có hơn 1.300 dòng cho một dải khuyến mãi (.programs*,
 * .program-card, .program-offer) với gradient chạy, ánh sáng quét thẻ và một
 * hộp thoại viền vàng kim. Từng có một bản hạ tông cho cả khối đó ở đây; đã
 * bỏ đi, vì trong repo này KHÔNG có gì dựng ra chúng: `public/dang-ky/` chỉ
 * có styles.css và vip.css, không có trang tĩnh, không có
 * assets/js/programs.js, và src/app/dang-ky/*.tsx không in ra một lớp
 * `.program-*` nào ngoài `.program-summary` / `.program-summary-label`. Đè
 * lên những lớp đó là viết mã không bao giờ chạy.
 *
 * Cùng lý do với hai huy hiệu kính mờ trên hero (.clinic-badge,
 * .privacy-badge, và .glass-card chỉ dùng cho hai cái đó): React CÓ in chúng
 * ra, nhưng styles.css dòng 2073 tắt hẳn — `display:none!important` — nên
 * không bộ chọn nào ở đây với tới được.
 *
 * Ngày nào khối chương trình được dựng thật bằng React thì hạ tông nó cùng
 * lúc, dựa trên JSX có thật.
 */

/* ═══════════════════════════════════════════════════════════════════════════
 *  4.1 — HỘP "THÔNG TIN BẮT BUỘC"  (.submit-gate)
 * ═══════════════════════════════════════════════════════════════════════════ */

.submit-zone {
  /*
   * Tách hẳn khỏi phần cuối cùng của biểu mẫu. 23px cũ khiến vùng gửi trông
   * như phần thứ tám của biểu mẫu, trong khi nó là chỗ KẾT THÚC biểu mẫu.
   */
  margin-top: 30px;
}

.submit-gate {
  padding: 18px;
  border: 1px solid var(--vip-vien);
  border-radius: var(--vip-bo-4);
  /*
   * styles.css tô hộp này bằng gradient hồng. Nhưng đây là hộp báo "còn thiếu
   * gì" — nó phải đọc như một ghi chú bình tĩnh, không như một dải khuyến
   * mãi. Nền trắng phẳng trên nền kem của trang đã đủ tách bạch.
   */
  background: var(--vip-the);
  box-shadow: var(--vip-noi-1);
  transition: border-color var(--vip-vua) var(--vip-vao),
    box-shadow var(--vip-vua) var(--vip-vao);
}

/*
 * Trạng thái "đã đủ" KHÔNG được nói bằng riêng màu. Ô khoá bên trái đổi hình
 * (rỗng có gạch ngang → đặc có dấu tích) ở khối ngay dưới; ở đây chỉ thêm
 * viền mận cho khối đọc ra là "đã xong" khi liếc nhanh.
 */
.submit-gate.is-ready {
  border-color: var(--vip-man);
  background: var(--vip-the);
  box-shadow: var(--vip-noi-2);
}

.submit-gate-head {
  /*
   * flex-start chứ không phải center: tiếng Khmer và tiếng Nhật đẩy câu mô tả
   * xuống ba dòng, lúc đó ô khoá căn giữa sẽ trôi xuống giữa đoạn văn.
   */
  align-items: flex-start;
  gap: 12px;
}

.submit-gate-head strong {
  /*
   * 12px cho tiêu đề một khối là quá nhỏ. Khách của phòng khám phần lớn đọc
   * trên điện thoại, nhiều người lớn tuổi, và câu này là câu nói cho họ biết
   * vì sao nút gửi chưa dùng được.
   */
  color: var(--vip-chu);
  font-size: 15px;
  line-height: 1.4;
}

.submit-gate-head p {
  /* 10px màu #786b73 vừa nhỏ vừa nhạt. Đây là câu giải thích, không phải chú thích chân trang. */
  margin-top: 4px;
  color: var(--vip-chu-mo);
  font-size: 12.5px;
  line-height: 1.55;
}

/* ── Ô khoá: hình đổi theo trạng thái, không chỉ đổi màu ─────────────────
 *
 * DOM luôn in dấu "✓" vào ô này, kể cả khi biểu mẫu còn thiếu — tức là ở
 * trạng thái khoá, trang đang nói với khách một điều KHÔNG ĐÚNG. Đây là đợt
 * chỉ-CSS nên không sửa được DOM, nhưng sửa được cái khách nhìn thấy:
 *
 *   • chưa đủ → ô rỗng, viền xám, một gạch ngang ở giữa (dấu tích tô trong suốt)
 *   • đã đủ   → ô đặc màu mận, dấu tích trắng hiện ra
 *
 * Thêm nữa, dấu tích trắng trên nền xám #b9a8b2 cũ chỉ đạt 2,3:1 — đọc ngoài
 * nắng thì coi như không có gì ở đó.
 */
.submit-gate-lock {
  position: relative;
  flex: 0 0 40px;
  width: 40px;
  height: 40px;
  margin-top: 1px;
  /*
   * Viền phải là --vip-chu-nhat (3,5:1 trên trắng), KHÔNG phải --vip-vien-dam
   * (1,4:1). Ô này nằm trên nền trắng của chính hộp .submit-gate: viền 1,4:1
   * nghĩa là ở trạng thái khoá, khách chỉ thấy một gạch ngang lơ lửng giữa
   * không trung. Ô rỗng chỉ đọc ra là "ô rỗng" khi nhìn thấy được cái ô.
   */
  border: 2px solid var(--vip-chu-nhat);
  border-radius: var(--vip-bo-2);
  color: transparent;
  background: var(--vip-the);
  font-size: 17px;
  transition: background var(--vip-vua) var(--vip-vao),
    border-color var(--vip-vua) var(--vip-vao),
    color var(--vip-vua) var(--vip-vao);
}

.submit-gate-lock::before {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 14px;
  height: 2px;
  border-radius: 2px;
  content: "";
  background: var(--vip-chu-nhat);
  transform: translate(-50%, -50%);
}

.submit-gate.is-ready .submit-gate-lock {
  border-color: transparent;
  color: #ffffff;
  background: var(--vip-man);
  box-shadow: none;
}

.submit-gate.is-ready .submit-gate-lock::before {
  content: none;
}

/* ── Danh sách bốn mục bắt buộc ─────────────────────────────────────────── */

.submit-checklist {
  gap: 8px;
  margin-top: 15px;
}

.submit-checklist li {
  /*
   * 9px. Đây là danh sách nói cho khách biết họ còn thiếu phần nào của một
   * biểu mẫu bảy phần — không thể là cỡ chữ nhỏ nhất trên trang. 12,5px đọc
   * được trên điện thoại mà vẫn giữ được bốn chip trong hai hàng.
   */
  align-items: center;
  min-height: 38px;
  padding: 8px 12px;
  gap: 8px;
  border-color: var(--vip-vien);
  color: var(--vip-chu-mo);
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1.4;
  text-align: left;
}

.submit-checklist i {
  /*
   * Mặc định (chưa đụng tới mục nào) là một VÒNG RỖNG, không phải đĩa xám
   * đặc: vòng rỗng đọc ra là "chưa tích", đĩa đặc thì mơ hồ. Dấu tích bên
   * trong vẫn để trong suốt cho tới khi mục đó xong thật.
   *
   * Viền cũng phải là --vip-chu-nhat (3,5:1) chứ không phải --vip-vien-dam
   * (1,4:1 trên nền trắng của chip): đây là trạng thái MẶC ĐỊNH của cả bốn
   * mục lúc khách vừa mở trang, tức là cái người ta nhìn lâu nhất.
   */
  width: 18px;
  height: 18px;
  border: 1.5px solid var(--vip-chu-nhat);
  background: var(--vip-the);
  font-size: 10px;
  font-weight: 800;
}

.submit-checklist li.is-complete {
  color: var(--vip-man-dam);
  border-color: rgba(164, 70, 131, 0.28);
  background: var(--vip-hong-nhat);
}

.submit-checklist li.is-complete i {
  color: #ffffff;
  border-color: transparent;
  background: var(--vip-man);
}

/*
 * Mục còn thiếu là thông tin CÓ VIỆC PHẢI LÀM, nên nó được phép nặng hơn mục
 * đã xong. Chữ #8f2531 trên #fff1f2 đạt 7,9:1, và dấu "!" mà DOM in ra lo
 * phần "đừng nói một trạng thái chỉ bằng màu".
 */
.submit-checklist li.is-missing {
  color: #8f2531;
  border-color: #e0a3ab;
  background: #fff1f2;
  font-weight: 800;
}

.submit-checklist li.is-missing i {
  color: #ffffff;
  border-color: transparent;
  background: var(--danger);
}

@media (max-width: 700px) {
  /*
   * styles.css ép hai cột cứng ở khổ này. Nhãn tiếng Khmer dài gần gấp đôi
   * tiếng Việt, hai cột cứng trên máy 320px cắt nhãn thành bốn dòng. auto-fit
   * để máy hẹp tự rơi về một cột, máy 375px trở lên vẫn giữ hai cột cho gọn.
   */
  .submit-gate {
    padding: 15px;
  }
  .submit-checklist {
    grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  }
  .submit-checklist li {
    min-height: 40px;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  4.2 — NÚT GỬI  (.submit-btn)
 * ═══════════════════════════════════════════════════════════════════════════ */

.submit-btn {
  /*
   * styles.css kết thúc ở gradient `--brand → --rgb-purple (#bd2f8d) → --teal`.
   * `--rgb-purple` là hồng cánh sen chói, còn `--teal` đến khối `:root` cuối
   * cùng đã mang giá trị TÍM — nên nút chạy tím → hồng neon → tím. Đó đúng là
   * cái gradient tím-hồng mà bản nâng cấp này phải tránh.
   *
   * Thay bằng ba bậc trong CÙNG họ mận của logo. Vẫn có vệt sáng-tối cho nút
   * có khối, nhưng không đổi tông giữa chừng. Bậc sáng nhất (#a44683) với chữ
   * trắng đạt 5,5:1.
   */
  min-height: 62px;
  border-radius: var(--vip-bo-4);
  background: linear-gradient(
    100deg,
    var(--vip-man) 0%,
    var(--vip-man-dam) 62%,
    var(--vip-man-sau) 100%
  );
  /*
   * Bóng đậm hơn mọi thẻ khác trên trang (thẻ dùng --vip-noi-1/2) là CỐ Ý:
   * đây là đích của cả trang, mắt phải rơi vào đây khi cuộn tới.
   */
  box-shadow: 0 10px 22px rgba(93, 40, 74, 0.18), 0 24px 48px rgba(93, 40, 74, 0.22);
  font-size: 16px;
  font-weight: 800;
  letter-spacing: 0.005em;
  line-height: 1.35;
  transition: transform var(--vip-vua) var(--vip-vao),
    box-shadow var(--vip-vua) var(--vip-vao);
}

/*
 * Bỏ vệt sáng quét ngang lúc rê chuột. Nó là thủ pháp của trang bán hàng, và
 * ở đây nó quét qua đúng cái nút mà người ta bấm để giao đi thông tin y tế
 * riêng tư của mình. Nút đã nhấc lên và bóng nở ra khi rê — thế là đủ.
 */
.submit-btn::before {
  content: none;
}

.submit-btn:hover {
  box-shadow: 0 14px 28px rgba(93, 40, 74, 0.22), 0 30px 60px rgba(93, 40, 74, 0.26);
  transform: translateY(-2px);
}

.submit-btn:active {
  box-shadow: 0 6px 14px rgba(93, 40, 74, 0.2);
  transform: translateY(0);
}

/*
 * `:disabled` ở trang này CHỈ bật trong lúc đang gửi — biểu mẫu thiếu thông
 * tin thì nút vẫn bấm được (và trả lỗi ngay tại chỗ thiếu). Nên trạng thái
 * này phải đọc ra là "đang xử lý", không phải "hỏng":
 *
 *   • con trỏ `progress` thay cho `not-allowed` — nói đúng chuyện đang xảy ra.
 *   • styles.css khoá nền xám bằng `!important` nên không đổi nền được. Nhưng
 *     bóng ĐỔ VÀO TRONG được vẽ ĐÈ LÊN nền, và `box-shadow:none` của nó thì
 *     không có `!important`. Một lớp phủ mận mờ đổ vào trong kéo chữ trắng từ
 *     2,7:1 (rớt) lên 4,8:1 (đạt) mà không phải chạm vào `!important` kia.
 *   • bỏ `opacity:.72`: mờ cả nút thì con quay và nhãn mờ theo, mà đó đúng là
 *     hai thứ khách cần đọc được ở giây phút này.
 */
.submit-btn:disabled {
  cursor: progress;
  color: #ffffff;
  box-shadow: inset 0 0 0 999px rgba(59, 25, 45, 0.34);
  opacity: 1;
  transform: none;
}

/* Mũi tên là SVG trong DOM, chỉ nhích theo trục X — transform, không đụng bố cục. */
.btn-arrow {
  flex: none;
  transition: transform var(--vip-nhanh) var(--vip-vao);
}

/*
 * KHÔNG khai `display` cho `.btn-spinner`.
 *
 * DOM đặt thuộc tính `hidden` lên nó khi không gửi, và thứ ẩn nó đi là quy
 * tắc mặc định của trình duyệt `[hidden]{display:none}` — quy tắc yếu nhất
 * trong bảng. Chỉ cần một dòng `display:…` ở đây là con quay quay suốt ngày
 * ngay cạnh nhãn "Gửi đăng ký".
 */
.btn-spinner {
  width: 20px;
  height: 20px;
  border-color: rgba(255, 255, 255, 0.42);
  border-top-color: #ffffff;
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  4.3 — MÀN THÀNH CÔNG  (.overlay)
 * ═══════════════════════════════════════════════════════════════════════════ */

.overlay {
  /*
   * `place-items:center` của styles.css căn giữa thẻ trong một khung
   * `position:fixed;inset:0` KHÔNG cuộn được. Thẻ cao hơn màn hình — chuyện
   * xảy ra ngay khi có mã phiếu, có khung giờ, lại thêm tiếng Khmer — thì nó
   * tràn đều hai đầu và PHẦN ĐẦU BỊ CẮT, tức là khách mất luôn dòng tiêu đề
   * và có khi cả mã phiếu, không cuộn lên lấy lại được.
   *
   * Hai dòng `align-items` dưới đây là một cặp dự phòng cố ý: trình duyệt cũ
   * bỏ qua dòng có `safe` và giữ `start` (thẻ dính mép trên, cuộn được);
   * trình duyệt mới hiểu `safe center` thì căn giữa lại như cũ và tự bỏ căn
   * giữa khi không đủ chỗ. Không bản nào cắt mất đầu thẻ.
   */
  align-items: start;
  justify-items: center;
  align-items: safe center;
  overflow-y: auto;
  overscroll-behavior: contain;
  /*
   * Nền đậm hơn (.74) vì `backdrop-filter` không chạy ở một số webview cũ —
   * nơi rất nhiều khách của phòng khám mở trang này. Không có làm mờ thì
   * riêng lớp phủ phải đủ tối để biểu mẫu phía sau im hẳn đi.
   */
  background: rgba(24, 44, 50, 0.74);
  backdrop-filter: blur(7px);
}

.overlay-card {
  border: 1px solid var(--vip-vien);
  border-radius: var(--vip-bo-5);
  /*
   * Ấm chứ không mát. Bản cũ pha xanh (#f1fcfd) — màu của phần mềm, của báo
   * cáo. Người vừa gửi xong hồ sơ hiếm muộn nên gặp một mặt giấy ấm.
   */
  background: linear-gradient(180deg, var(--vip-the) 0%, var(--vip-the) 60%, #fdf9fb 100%);
  box-shadow: var(--vip-noi-4);
}

/*
 * Vệt trang trí góc trên trái: styles.css tô nó xanh #cceff4. Đổi sang hồng
 * nhạt để nó đi cùng mặt giấy ấm ở trên. Vệt góc dưới phải (::after) giữ
 * nguyên màu cũ — hai góc một ấm một mát là đúng cặp màu của logo, và đổi nó
 * sang một sắc xanh khác chỉ là đổi cho khác.
 */
.overlay-card::before {
  background: var(--vip-hong-nhat);
}

.overlay-card h2 {
  /*
   * 28px cố định tràn dòng ở tiếng Khmer trên máy 320px. clamp cho nó co lại;
   * `text-wrap:balance` chia dòng cho cân thay vì bỏ một chữ lẻ xuống dòng cuối.
   */
  margin-bottom: 10px;
  color: var(--vip-man-sau);
  font-size: clamp(23px, 6.4vw, 29px);
  line-height: 1.25;
  text-wrap: balance;
}

.overlay-card p {
  /* Đây là câu bệnh viện dặn khách việc tiếp theo. 13px là quá nhỏ cho một lời dặn. */
  margin-bottom: 22px;
  color: var(--vip-chu-mo);
  font-size: 15px;
  line-height: 1.65;
}

/*
 * Nút duy nhất của màn này. Giữ nền đặc (nó là lối ra duy nhất) nhưng đổi từ
 * gradient xanh sang một sắc mòng két phẳng — đúng màu chữ IVF trong logo, và
 * chữ trắng trên nó đạt 7,0:1.
 */
.overlay-card .submit-btn.ghost {
  border: 0;
  color: #ffffff;
  background: var(--vip-mongket-dam);
  box-shadow: 0 8px 20px rgba(3, 98, 120, 0.22);
}

.overlay-card .submit-btn.ghost:hover {
  background: var(--vip-mongket);
  box-shadow: 0 12px 26px rgba(3, 98, 120, 0.26);
}

@media (max-width: 410px) {
  /*
   * 24px lề phủ + 30px lề thẻ = còn 212px cho chữ trên máy 320px. Tiếng Khmer
   * không sống nổi trong 212px.
   */
  .overlay {
    padding: 14px;
  }
  .overlay-card {
    padding: 30px 20px 24px;
    border-radius: var(--vip-bo-4);
  }
}

/*
 * Hoạt ảnh vào của thẻ. Bản cũ dùng đường cong vọt lố (cubic-bezier …1.14) —
 * một cú nảy ăn mừng. Nhiều người bấm gửi xong đang lo, nên đổi sang một nhịp
 * dâng lên rồi dừng. Chỉ transform và opacity.
 */
@media (prefers-reduced-motion: no-preference) {
  .overlay {
    animation: vip-phu-hien var(--vip-vua) var(--vip-vao) both;
  }
  .overlay-card {
    animation: vip-the-thanh-cong var(--vip-cham) var(--vip-vao) both;
  }
}

@keyframes vip-phu-hien {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes vip-the-thanh-cong {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  4.4 — KHỐI TÓM TẮT TRONG MÀN THÀNH CÔNG  (.program-summary)
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * Lớp này mang tên "program" vì bản tĩnh dùng nó để liệt kê ưu đãi đã chọn.
 * Bản React dùng lại nó cho việc khác hẳn và quan trọng hơn nhiều: in MÃ PHIẾU
 * và khung giờ đã giữ được. Đây là thứ khách chụp màn hình mang đi.
 */

.program-summary {
  /*
   * `.overlay-card` căn giữa toàn bộ chữ. Nhưng `.program-summary li` lại
   * thụt trái 20px và treo dấu "✓" ở left:0 — thành ra dấu tích dính mép trái
   * còn chữ trôi ra giữa, không dòng nào thẳng hàng với dòng nào. Danh sách
   * thì phải căn trái.
   */
  margin-top: 18px;
  padding: 14px 16px;
  border: 1px solid var(--vip-vien);
  border-radius: var(--vip-bo-3);
  background: var(--vip-nen-chim);
  text-align: left;
}

.program-summary .program-summary-label {
  /*
   * Ô này giữ hai loại nội dung rất khác nhau: chữ "Mã phiếu", hoặc CẢ MỘT CÂU
   * giải thích vì sao chưa có giờ hẹn. 12px đủ cho cái đầu, không đủ cho cái sau.
   */
  display: block;
  margin-bottom: 6px;
  color: var(--vip-man-sau);
  font-size: 13.5px;
  font-weight: 800;
  line-height: 1.5;
}

.program-summary li {
  padding-left: 20px;
  color: var(--vip-chu);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.55;
}

.program-summary li::before {
  color: var(--vip-mongket-dam);
}

/* ═══════════════════════════════════════════════════════════════════════════
 *  4.5 — GIẢM CHUYỂN ĐỘNG
 * ═══════════════════════════════════════════════════════════════════════════
 *
 * styles.css đã có một khối `*{animation-duration:.001ms!important; …}` cho
 * chế độ này, và vì nó dùng `!important` nên nó vẫn thắng mọi thứ ở đây. Khối
 * dưới là bản khai lại tường minh: nó rẻ, và nó ghi lại rằng những chuyển
 * tiếp mới thêm ở tệp này đã được cân nhắc cho chế độ giảm chuyển động chứ
 * không phải bị bỏ sót.
 */
@media (prefers-reduced-motion: reduce) {
  .overlay,
  .overlay-card {
    animation: none;
    opacity: 1;
    transform: none;
  }
  .submit-gate,
  .submit-gate-lock,
  .submit-btn,
  .btn-arrow {
    transition: none;
  }
}
