/* ══════════════════════════════════════════════════════════════════════════════════════════════
   VỎ TRANG BÀI TẬP TRÊN WEB — NGUỒN TOKEN DUY NHẤT của cả site (§41.7)
   ──────────────────────────────────────────────────────────────────────────────────────────────
   Nạp ở MỌI trang: index.html (học viên) · gv.html (bảng theo dõi + tài khoản).
   gv.css nạp SAU file này và chỉ thêm phần riêng của bảng theo dõi.

   ⚠ MỘT BỘ TOKEN DUY NHẤT — đừng khai màu/gradient mới ở file khác.
     Theme bám app (renderer/css/landing.css + buttons.css §8): xanh #1A6FBF, Segoe UI,
     nút "glossy" (gradient dọc + gờ sáng + nhấc 1px khi hover), bo 6px, cao 28px.
     Tên token tiếng Anh (--blue/--t1/--border) là bản chính; các tên tiếng Việt cũ
     (--xanh/--xam/--vien…) giữ làm BÍ DANH để mã cũ không vỡ — đừng xoá.

   ⚠ BÀI HỌC §32.24 (đã sai 3 lần với riêng layout ô chữ): slide app là khung CỨNG 960×540 +
     transform:scale. Trên điện thoại dọc, thu cho vừa bề ngang thì chữ nhỏ không đọc nổi, và mọi
     mẹo chia lại lưới đều hỏng vì chiều cao đã được tính sẵn cho màn hình lớn.
     CÁCH ĐÚNG DUY NHẤT: ở màn hẹp thì BỎ HẲN khung cố định + BỎ transform, trả .sl về
     height:auto/width:100%, cho cả trang cuộn dọc như trang web bình thường.
   ⚠ baigiang.css (chép từ app) định nghĩa .sl và mọi layout — file này chỉ bọc NGOÀI và ghi đè
     phần khung. KHÔNG sửa baigiang.css bằng tay: nó là bản chép từ app.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── màu ──────────────────────────────────────────────────────────────────────────────── */
  --blue: #1A6FBF;
  --blue-hover: #155EA3;
  --blue-dark: #0D47A1;
  --blue-light: #EBF4FF;
  --bg: #F4F7FB;
  --white: #fff;
  --border: #DDE4EE;
  --vien: #d8dde3;
  --t1: #1A2332;
  --t2: #4A5568;
  --t3: #7A8799;
  --label: #374151;
  --luc: #2e7d32;
  --cam: #ef6c00;
  --do: #d32f2f;
  --r: 6px;
  --font: 'Segoe UI', 'Helvetica Neue', Roboto, Arial, sans-serif;

  /* ── gradient nút (glossy §8) ─────────────────────────────────────────────────────────── */
  --grad-btn: linear-gradient(180deg, #3E8FD8 0%, #1A6FBF 55%, #1660AB 100%);
  --grad-btn-h: linear-gradient(180deg, #4C9CE4 0%, #1C77C9 55%, #12569A 100%);
  --grad-soft: linear-gradient(180deg, #FFFFFF 0%, #F1F5FA 100%);
  --grad-soft-h: linear-gradient(180deg, #FFFFFF 0%, #E8EFF7 100%);

  /* ── BÍ DANH cho mã cũ — đừng xoá ─────────────────────────────────────────────────────── */
  --xanh: var(--blue);
  --xanh-dam: var(--blue-dark);
  --xam: var(--bg);
}

* { box-sizing: border-box; }

/* ⚠⚠ PHẢI GHI ĐÈ `html,body` CỦA baigiang.css — NGUYÊN NHÂN LỖI KHÔNG CUỘN ĐƯỢC (2026-09-01).
   baigiang.css dòng 19 khai `html,body{height:100vh;overflow:hidden}` vì đó là CSS của app
   ELECTRON — app chạy toàn màn hình trong cửa sổ cố định nên cố tình khoá cuộn trang. Ta chép
   nguyên file đó sang web (để slide hiển thị y hệt trong app) nên thừa hưởng luôn cái khoá:
   nội dung cao 2125px bị nhốt trong khung 502px, không cuộn được, KHÔNG có dấu hiệu gì.
   Trên máy tính màn rộng thì nội dung vừa màn hình nên không lộ ra — chỉ điện thoại mới thấy.
   ⚠ trang.css PHẢI nạp SAU baigiang.css trong <head> thì rule này mới thắng. */
html, body {
  margin: 0; padding: 0;
  font-family: var(--font);
  background: var(--bg); color: var(--t1);
  height: auto;        /* ghi đè height:100vh */
  min-height: 100%;
  overflow: visible;   /* ghi đè overflow:hidden — để trang cuộn tự nhiên */
}
/* Chặn tràn ngang bằng `clip` (KHÔNG tạo vùng cuộn riêng như `hidden`, nên không khoá cuộn dọc) */
body { overflow-x: clip; }
/* Chặn "vuốt xuống để tải lại" của trình duyệt điện thoại (Chrome Android, Safari iOS 16+):
   vuốt quá đà ở đầu trang là tải lại cả trang, mất màn làm bài/kết quả. Cuộn thường không đổi. */
html, body { overscroll-behavior-y: none; }

a { color: var(--blue); text-decoration: none; }
a:hover { color: var(--blue-hover); text-decoration: underline; }
:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }

.an { display: none !important; }
.spacer { flex: 1; }

/* ── Màn hình dạng hộp giữa (vào bài / đã nộp / đăng nhập) ─────────────────────────────────── */
.man { min-height: 100vh; min-height: 100dvh; display: flex; align-items: center; justify-content: center; padding: 10px; }
.hop {
  background: var(--white); border: 1px solid var(--vien); border-radius: 10px;
  padding: 16px; width: 100%; max-width: 380px; text-align: center;
  box-shadow: 0 1px 3px rgba(26, 51, 80, .06);
}
.hop h1 { font-size: 20px; margin: 6px 0; color: var(--blue-dark); }
.phu { font-size: 13px; color: var(--t2); margin: 4px 0 10px; }
.kicker {
  display: block; font-size: 11px; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--t3);
}
/* Dòng chân hộp — vd link "Dành cho giảng viên" ở trang học viên */
.chan-hop { margin-top: 14px; padding-top: 10px; border-top: 1px solid var(--border); font-size: 12px; color: var(--t3); }

/* ── Ô nhập ───────────────────────────────────────────────────────────────────────────────── */
.nhan { display: block; text-align: left; font-size: 13px; font-weight: 600; color: var(--label); margin: 8px 0 4px; }
.goiy { font-weight: 400; color: #8a939c; }
/* ⚠⚠ CỠ CHỮ Ô NHẬP PHẢI ≥ 16px — KHÔNG BAO GIỜ hạ xuống 15px cho "gọn" (sửa 2026-09-10).
   iOS Safari TỰ PHÓNG TO cả trang khi người dùng chạm vào ô nhập có cỡ chữ < 16px, và KHÔNG tự
   thu lại. Trang phóng rồi thì iOS neo mọi phần tử `position:fixed` theo khung GỐC chứ không
   theo khung đang nhìn ⇒ nút ‹ › ☰ và Nộp bài TRÔI RA NGOÀI MÀN HÌNH (toạ độ âm), chạm không
   tới ⇒ người dùng không chuyển được slide, không làm được bài. Đo trên máy thật: zoom 1.07,
   btTruoc ở x=−4, btNop ở x=−262. Android/máy tính KHÔNG có cơ chế tự phóng này nên không dính. */
.o {
  width: 100%; height: 40px; padding: 0 10px;
  font-family: var(--font); font-size: 16px; color: var(--t1);
  background: var(--white); border: 1px solid var(--vien); border-radius: var(--r); outline: none;
  transition: border-color .15s, box-shadow .15s;
}
.o::placeholder { color: #A8B2BF; }
.o:focus { border-color: var(--blue); box-shadow: 0 0 0 3px rgba(26, 111, 191, .12); }
.o-ma { font-size: 28px; text-align: center; letter-spacing: 8px; font-weight: 700; height: 56px; }
select.o {
  height: 28px; font-size: 13px; padding: 0 26px 0 8px; cursor: pointer; appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%237A8799' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 8px center;
  width: auto; min-width: 120px;
}
.loi { color: var(--do); font-size: 13px; min-height: 18px; margin-top: 6px; }

/* ── Nút — bề mặt "glossy" đồng bộ app (§8) ───────────────────────────────────────────────── */
.bt {
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  height: 28px; padding: 0 12px; border-radius: var(--r);
  font-family: var(--font); font-size: 13px; font-weight: 600;
  cursor: pointer; white-space: nowrap;
  border: 1px solid #CFD8E6; background: var(--grad-soft); color: var(--t2);
  box-shadow: inset 0 1px 0 #fff, 0 1px 2px rgba(26, 51, 80, .10);
  transition: background .15s, border-color .15s, box-shadow .15s, color .15s, transform .12s;
}
.bt:hover:not(:disabled) { background: var(--grad-soft-h); border-color: #AAB4C4; color: var(--blue); transform: translateY(-1px); }
.bt:active:not(:disabled) { transform: translateY(0); box-shadow: inset 0 2px 4px rgba(26, 51, 80, .18); }
.bt:disabled { opacity: .45; cursor: not-allowed; }

.bt-chinh {
  color: #fff; border-color: #1560A6; background: var(--grad-btn);
  text-shadow: 0 1px 1px rgba(0, 0, 0, .18);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .42), 0 1px 2px rgba(26, 51, 80, .18);
}
.bt-chinh:hover:not(:disabled) {
  background: var(--grad-btn-h); border-color: #12569A; color: #fff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .55), 0 3px 9px rgba(26, 111, 191, .34);
}
.bt-nop {
  color: #fff; border-color: #256b28;
  background: linear-gradient(180deg, #4CA050 0%, #2e7d32 55%, #276B2A 100%);
  text-shadow: 0 1px 1px rgba(0, 0, 0, .18);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .38), 0 1px 2px rgba(26, 51, 80, .18);
}
.bt-nop:hover:not(:disabled) {
  color: #fff; border-color: #1f5c22;
  background: linear-gradient(180deg, #58B15C 0%, #338838 55%, #22601F 100%);
}
.bt-do { border-color: #f5c2c0; color: var(--do); background: linear-gradient(180deg, #FFFFFF 0%, #FDF1F0 100%); }
.bt-do:hover:not(:disabled) { color: var(--do); border-color: #e59d9a; background: linear-gradient(180deg, #FFFFFF 0%, #FBE3E1 100%); }

.bt-nho { height: 26px; padding: 0 8px; font-size: 12px; }
.bt-lon { height: 46px; padding: 0 24px; font-size: 15px; }
.bt-rong { width: 100%; }        /* nút CTA trải hết bề ngang hộp */
.bt-phu { min-width: 44px; }     /* nút ‹ › ở màn làm bài */

/* ── Màn làm bài ──────────────────────────────────────────────────────────────────────────── */
/* ══ MÀN LÀM BÀI — THANH TRÊN + VÙNG SLIDE (2026-10-02) ═══════════════════════════════════
   Thanh trên: ☰ · ‹ · Nộp bài · › (+ hạn giờ bên phải). Menu mục lục = NGĂN KÉO ở mọi cỡ màn,
   ☰ bị JS ẩn khi bài chỉ có 1 slide. */
#manBai { display: flex; flex-direction: column; align-items: stretch; padding: 0; height: 100vh; height: 100dvh; }

.thanh-tren {
  flex: 0 0 auto; display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 6px;
  padding: 6px 10px; background: var(--white); border-bottom: 1px solid var(--vien);
}
/* Lưới 3 cột [trống | cụm nút | hạn giờ] — 2 cột bên chia đều ⇒ cụm nút nằm ĐÚNG GIỮA thanh,
   kể cả khi có hạn giờ. (Bản trước để hạn giờ trong luồng flex ⇒ cụm nút lệch trái trên điện thoại.) */
.tt-cum { display: flex; align-items: center; gap: 6px; }
.thanh-tren .gio { justify-self: end; margin: 0; }
/* ☰ và Nộp bài cao bằng nút ‹ › (giữ đúng kích thước cũ của ‹ ›) */
.bt-menu { width: 40px; height: 56px; padding: 0; font-size: 18px; }
.thanh-tren .bt-nop { height: 56px; min-width: 110px; padding: 0 16px; font-size: 14px; }

/* ── Menu mục lục (ngăn kéo) ───────────────────────────────────────────────────────────── */
.menu {
  position: fixed; left: 0; top: 0; bottom: 0; z-index: 40; width: 260px; max-width: 82vw;
  display: flex; flex-direction: column; min-width: 0;
  background: var(--white); border-right: 1px solid var(--vien);
  transform: translateX(-100%); transition: transform .18s ease;
  box-shadow: 2px 0 12px rgba(26, 51, 80, .18);
}
.menu.mo { transform: none; }
.menu-nen { position: fixed; inset: 0; z-index: 35; background: rgba(26,51,80,.42); }
.menu-nen:not(.mo) { display: none; }
.menu-dau { flex: 0 0 auto; padding: 10px; border-bottom: 1px solid var(--vien); }
.menu-ten { font-size: 14px; font-weight: 700; color: var(--blue-dark); line-height: 1.3; }
.menu-phu { font-size: 12px; color: var(--t3); margin-top: 2px; }

/* Mục lục slide — thay dải chấm tiến độ cũ, và bấm được để nhảy thẳng tới slide */
.ds-slide { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 6px; }
.sl-muc {
  display: flex; align-items: center; gap: 6px; width: 100%;
  padding: 6px 8px; margin-bottom: 2px; border: 0; border-radius: var(--r);
  background: none; font-family: var(--font); font-size: 13px; color: var(--t2);
  text-align: left; cursor: pointer; line-height: 1.3;
}
.sl-muc:hover { background: var(--blue-light); color: var(--blue); }
.sl-muc.nay { background: var(--blue); color: #fff; font-weight: 600; }
.sl-muc-so { flex: 0 0 20px; font-variant-numeric: tabular-nums; opacity: .75; }
.sl-muc-ten { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Dấu tình trạng: ✓ = làm xong · ○ = còn dở · (trống) = slide không có bài tập */
.sl-muc-tt { flex: 0 0 auto; font-size: 12px; }
.sl-muc-tt.xong { color: var(--luc); }
.sl-muc.nay .sl-muc-tt.xong { color: #bdf0bf; }
.sl-muc-tt.dang { color: var(--t3); }

.gio { display: block; font-size: 15px; font-weight: 700; color: var(--blue-dark); font-variant-numeric: tabular-nums; white-space: nowrap; }
.gio:empty { display: none; }          /* phiên không đặt hạn giờ ⇒ không chừa chỗ trống */
.gio.gap { color: var(--do); }

/* ── Vùng slide ────────────────────────────────────────────────────────────────────────── */
.san {
  flex: 1 1 auto; min-width: 0; min-height: 0; position: relative;
  display: flex; align-items: center; justify-content: center; overflow: hidden; padding: 10px;
}
/* ⚠ HAI LỚP: `.khung-ty-le` mang kích thước SAU khi scale (do JS đặt), `.lop-slide` giữ nguyên
   960×540 rồi bị scale từ GÓC TRÁI-TRÊN. `transform` không đổi hộp bố cục — chỉ scale mà không
   sửa kích thước khung ngoài thì khung 960×540 vẫn đòi chỗ và đẻ thanh cuộn dù nhìn đã vừa. */
.khung-ty-le { flex: 0 0 auto; }
.lop-slide { width: 960px; height: 540px; transform-origin: 0 0; }

/* Nút chuyển slide ‹ › trên thanh trên — giữ kích thước cũ (34×56 máy tính · 44×44 điện thoại) */
.bt-canh { flex: 0 0 auto; width: 34px; min-width: 34px; height: 56px; padding: 0; font-size: 20px; }
.bt-canh:disabled { opacity: .2; }

/* Kết quả */
.diem { font-size: 40px; font-weight: 700; color: var(--blue-dark); margin: 6px 0; }
.qs { display: flex; gap: 3px; flex-wrap: wrap; justify-content: center; margin-bottom: 8px; }
.qs i { width: 14px; height: 14px; border-radius: 3px; display: block; }
.qs i.d { background: var(--luc); }
.qs i.s { background: var(--do); }

/* Băng thông báo — đè mép trên, đồng bộ mirror-host (§32.4) */
.banner {
  position: fixed; top: 0; left: 50%; transform: translateX(-50%);
  background: var(--blue); color: #fff; font-weight: 500; font-size: 14px;
  padding: 10px 18px; border-radius: 0 0 8px 8px; z-index: 9900; max-width: 92vw; text-align: center;
}
.banner--nhac { background: var(--cam); }
.banner--ok { background: var(--luc); }

/* ══ MÁY TÍNH / TABLET NGANG: giữ khung 960×540 của app, thu cho vừa ══════════════════════ */
@media (min-width: 701px) {
  /* ⚠ KHÔNG scale ở đây — việc thu nhỏ do `.lop-slide` lo (JS `vuaKhung()` đặt cả kích thước
     khung ngoài lẫn transform). Trước đây rule này scale theo `--ty-le`, một biến KHÔNG có gì
     đặt ⇒ slide luôn đúng cỡ gốc 960×540, màn nào cũng vậy. */
  .san .sl { width: 960px; height: 540px; flex: 0 0 auto; }
}

/* ══ ĐIỆN THOẠI DỌC: BỎ khung cứng, cho trang cuộn dọc (§41.7 — bài học §32.24) ═══════════ */
@media (max-width: 700px) {
  /* CẢ TRANG cuộn dọc như trang web thường; thanh trên/dưới DÍNH mép để nút Nộp bài luôn thấy.
     KHÔNG cuộn bên trong .san — cách đó làm vùng cuộn lồng nhau, rất khó dùng trên cảm ứng. */
  #manBai { display: block; min-height: 100vh; min-height: 100dvh; height: auto; }
  .san { display: block; overflow: visible; padding: 0; }
  /* Khung tỉ lệ + lớp scale chỉ có nghĩa ở màn rộng — màn hẹp trả về luồng thường */
  .khung-ty-le, .lop-slide {
    width: auto !important; height: auto !important; transform: none !important;
  }

  /* Thanh trên DÍNH mép trên khi cả trang cuộn dọc ⇒ ‹ › và Nộp bài luôn với tới được.
     Dùng `sticky` (không `fixed`) — iOS phóng trang (§41.20) thì phần tử fixed trôi khỏi màn hình. */
  .thanh-tren { position: sticky; top: 0; z-index: 30; padding: 6px 8px; }
  .thanh-tren .gio { font-size: 13px; }
  .bt-canh { width: 44px; min-width: 44px; height: 44px; }
  .bt-menu, .thanh-tren .bt-nop { height: 44px; }

  .san .sl {
    width: 100% !important; height: auto !important; min-height: 0 !important;
    max-width: 100%; transform: none !important;   /* ⚠ BỎ scale — nếu không chữ nhỏ không đọc nổi */
    border-radius: 0; box-shadow: none; display: block;
  }

  /* ⚠⚠ MẤU CHỐT — PHẢI GỠ `flex:1`, KHÔNG CHỈ `height:auto`.
     baigiang.css khai `.sl .mcql{flex:1;min-height:0;overflow-y:auto}` = "chiếm phần DƯ của khung
     cao 540px". Bỏ chiều cao cố định đi thì phần dư thành 0 ⇒ vùng câu hỏi CO VỀ 0, các câu biến
     mất và không cuộn được (đã gặp trên điện thoại 2026-09-01). `height:auto` KHÔNG cứu được vì
     flex-basis:0 vẫn thắng. Phải đặt `flex:0 0 auto` để vùng cao đúng bằng nội dung. */
  .san .sl .mcql,
  .san .sl .questions-panel,
  .san .sl .passage-panel,
  .san .sl .qp-rs3,
  .san .sl .sl-body,
  .san .sl .sl-col {
    flex: 0 0 auto !important;
    height: auto !important;
    min-height: 0 !important;
    max-height: none !important;
    overflow: visible !important;
    display: block !important;
  }

  /* Header slide khai `flex:0 0 15%; height:10%` — tính theo khung 540px, vô nghĩa khi cao tự do */
  .san .sl .sl-head { flex: 0 0 auto !important; height: auto !important; }

  /* 4 lựa chọn xếp 4 cột ngang (opts-c4) thì trên màn hẹp phải xuống thành 1 cột */
  .san .sl .options-container { display: block !important; }
  .san .sl .option-item { width: auto !important; margin-bottom: 6px; }

  /* Bảng / lưới rộng: nhốt cuộn ngang vào RIÊNG nó, không cho tràn cả trang.
     ⚠ min-width:0 là mấu chốt — thiếu nó flex item không co xuống dưới bề rộng nội dung. */
  .san .sl table, .san .sl .cw-left { display: block; min-width: 0; max-width: 100%; overflow-x: auto; }
  .sl-muc { padding: 9px 8px; font-size: 14px; }   /* mục lục cao hơn cho ngón tay */

  /* Ô nhập cao hơn cho ngón tay */
  .o { height: 44px; }

  /* ⚠ Ô nhập BÊN TRONG bài tập (điền từ, ô chữ, kéo-thả) cũng phải ≥16px — cùng lý do tự phóng
     ở trên. Chữ to hơn thiết kế gốc một chút, nhưng đổi lại người học không bị mất sạch nút
     điều hướng giữa chừng. CHỈ áp trên màn hẹp; máy tính giữ nguyên cỡ chữ của bài giảng. */
  .san .sl input, .san .sl select, .san .sl textarea { font-size: 16px !important; }
  .o-ma { font-size: 26px; letter-spacing: 7px; height: 52px; }
  .bt-lon { height: 48px; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   MỞ RỘNG SANG MỌI DẠNG BÀI TẬP (2026-09-08) — §41
   ══════════════════════════════════════════════════════════════════════════════════════════════ */

/* Mỗi slide giữ khung DOM RIÊNG (xem đầu trang.js): chuyển slide = ẩn/hiện, không vẽ lại, nên bài
   đang làm dở — nhất là vị trí chip kéo-thả và chữ trong lưới ô chữ — không mất.

   ⚠⚠ PHẢI LÀ `block`, TUYỆT ĐỐI KHÔNG `display:contents` (sửa 2026-09-10 sau khi người dùng báo).
   Bản 08/09 dùng `display:contents` cho lớp bọc này. Trên Chrome (Windows, Android) chạy đúng,
   nhưng trên **iPhone/Safari** thì bấm ‹ › không đổi slide và không chọn được đáp án — WebKit
   có bug đã biết: đổi qua lại giữa `display:contents` và `display:none` KHÔNG dựng lại render
   tree đúng, nên slide mới không bao giờ hiện ra dù DOM đã đổi class chuẩn.
   Triệu chứng đánh lừa: nhìn như "nút hỏng", thực ra nút chạy đúng còn màn hình đứng im.
   `block` cho hình y hệt (`.sl` tự khai kích thước; mọi rule đều viết `.san .sl` dạng hậu duệ
   nên không phụ thuộc lớp bọc) mà không đụng vào vùng bug của WebKit.
   QUY TẮC: trang web này phục vụ cả iPhone ⇒ KHÔNG dùng `display:contents` ở bất kỳ đâu. */
.san .khung { display: block; }
.san .khung.an { display: none !important; }

/* ── CÔNG CỤ CHỈ DÀNH CHO GIẢNG VIÊN — ẩn trên máy học viên ────────────────────────────────
   Ô chữ có hàng nút 💡 Gợi ý / 📋 Danh sách từ ở mép dưới panel phải (§32.23). Máy học viên qua
   mirror LAN đã ẩn bằng CSS trong STUDENT_PAGE; trang web phải làm y hệt, nếu không học viên tự
   hé lộ được đáp án. (Chữ trong bảng "Danh sách từ" thì ChamDiem.bocHtml đã xoá khỏi HTML rồi —
   ẩn bằng CSS KHÔNG đủ, mở DevTools là đọc được.) */
.san .cw-bar { display: none !important; }

/* ══ iOS: BỎ `:hover` TRÊN THIẾT BỊ CẢM ỨNG ═══════════════════════════════════════════════
   ⚠⚠ NGUYÊN NHÂN "chạm vào đáp án mà không chọn được" trên iPhone (2026-09-10).
   iOS Safari coi phần tử CÓ style `:hover` là "hoverable": cú chạm ĐẦU TIÊN chỉ được hiểu là
   "đưa chuột tới" — nó áp `:hover` (người dùng thấy ô đổi màu) và **KHÔNG phát ra `click`**.
   Không có click ⇒ radio không tick ⇒ `onclick="rmcqPick(this)"` không bao giờ chạy. Đo trên máy
   thật khớp đúng: chạm tới `label.option-item`, nhưng `rmcqPick: 0 lần` và `radio đã tick: 0`.
   Windows/Android Chrome KHÔNG có luật này nên không dính; Playwright mô phỏng chạm nhưng không
   mô phỏng luật hover-rồi-mới-click nên KHÔNG tái hiện được (mất nhiều vòng vì tin vào nó).
   `@media (hover: none)` = thiết bị không có chuột thật ⇒ gỡ hẳn rule hover ở đó.
   QUY TẮC: phần tử BẤM ĐƯỢC trên trang web phục vụ điện thoại KHÔNG được đổi hình bằng `:hover`
   mà không bọc trong `@media (hover: hover)`. */
@media (hover: none) {
  .san .sl .option-item:hover,
  .san .sl .spk-opt:hover,
  .san .sl .ws-word:hover,
  .san .sl .cw-clue:hover,
  .san .sl .wc-opt:hover { background: #fff; }
  /* Giữ nguyên màu của các trạng thái thật — hover không được đè lên chúng */
  .san .sl .option-item.selected:hover  { background: #e3f2fd; }
  .san .sl .option-item.correct:hover   { background: #d4edda; }
  .san .sl .option-item.incorrect:hover { background: #f8d7da; }
}

/* ── KÉO-THẢ BẰNG NGÓN TAY ─────────────────────────────────────────────────────────────────
   Engine kéo của app dùng Pointer Events. Trên cảm ứng, trình duyệt mặc định hiểu thao tác kéo
   là CUỘN TRANG và nuốt luôn pointermove ⇒ không kéo được chip.
   ⚠ Chỉ đặt `touch-action:none` cho CHÍNH thẻ kéo được và ô thả — KHÔNG đặt cho cả vùng bài tập:
     làm thế là chặn luôn việc cuộn trang khi ngón tay đặt vào giữa bài, mà bài dài thì học viên
     không cuộn xuống được nữa. */
.san .ww-chip, .san .ro-card, .san .mt-card,
.san .ww-drop, .san .kp7-drop, .san .gf-drop, .san .pm-box, .san .ro-drop, .san .mt-drop {
  touch-action: none;
}

/* ── ĐIỆN THOẠI DỌC: bỏ nốt các vùng cuộn tính theo khung 540px của những layout mới ────────
   Cùng lý do đã ghi ở khối @media phía trên: baigiang.css khai `flex:1;min-height:0;overflow:auto`
   = "chiếm phần DƯ của khung cao 540px". Bỏ chiều cao cố định thì phần dư = 0 ⇒ vùng co về 0 và
   nội dung BIẾN MẤT. Thêm layout mới có vùng cuộn → PHẢI bổ sung selector vào đây. */
@media (max-width: 700px) {
  .san .sl .spk-list,
  .san .sl .cloze-panel, .san .sl .cloze-content, .san .sl .qp-rs4,
  .san .sl .kp7-wrap, .san .sl .kp7-passage, .san .sl .kp7-content,
  .san .sl .ws-wrap, .san .sl .ws-box,
  .san .sl .wc-body,
  .san .sl .gf-wrap, .san .sl .gf-cols, .san .sl .gf-col,
  .san .sl .ro-wrap, .san .sl .ro-cols, .san .sl .ro-list,
  .san .sl .mt-wrap, .san .sl .mt-rows,
  .san .sl .cw-side, .san .sl .cw-sidescroll {
    flex: 0 0 auto !important;
    height: auto !important;
    min-height: 0 !important;
    max-height: none !important;
    overflow: visible !important;
  }

  /* Bố cục 2 cột (đoạn văn | bảng từ · nguồn | ô thả · lưới | gợi ý) xếp chồng cho vừa màn hẹp */
  .san .sl .kp7-2col, .san .sl .ro-cols, .san .sl .cw-wrap, .san .sl .qp-rs3, .san .sl .qp-rs4 {
    display: block !important;
  }
  .san .sl .gf-cols { display: block !important; }

  /* Sắp xếp thứ tự: card cao gần kín màn hình ⇒ touch-action:none trên card làm KHÔNG CUỘN được
     tới các ô thả bên dưới. Điện thoại cho cuộn dọc trên card; xếp bằng cách BẤM card
     (vào ô trống đầu tiên / bấm lại để trả về) — wireReorder lo phần bấm. */
  .san .sl .ro-card, .san .sl .ro-drop { touch-action: pan-y; }
  /* Kéo = GIỮ NGÓN ~0,3s rồi kéo (wireReorder) — chặn bôi đen chữ / menu chép khi giữ ngón */
  .san .sl .ro-card { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
  /* Giữ ngón đủ lâu ⇒ viền ĐỎ báo đã kéo được (cả thẻ gốc lẫn bản nổi theo ngón tay) */
  .san .sl .ro-card.ro-held, .ro-ghost.ro-held { border-color: #E53935 !important; box-shadow: 0 0 0 2px #E53935 !important; }

  /* ⚠ KHUNG BÀI TẬP KÉO BỀ RỘNG (§32.41, `.bw-wrap`) mang `width:<px>` + `margin-left:<px>` INLINE
     tính cho khung 960px ⇒ trên điện thoại vẫn đòi đúng bề rộng đó, chữ không xuống dòng và cả
     trang phải cuộn ngang (người dùng báo 2026-09-30, ket-reading-part7). Màn hẹp trả về bề rộng
     màn hình để chữ tự chảy. */
  .san .sl .bw-wrap {
    width: auto !important; margin-left: 0 !important; margin-right: 0 !important;
    max-width: 100% !important; min-width: 0 !important;
  }
  .san .sl .kp7-content, .san .sl .cloze-content, .san .sl .gf-wrap, .san .sl .wc-body {
    overflow-wrap: anywhere;
  }

  /* ⚠ pic-match + word-web neo ô thả theo TOẠ ĐỘ % của khung ảnh — không xếp lại được cho màn
     hẹp. Giữ nguyên tỉ lệ và cho cuộn ngang trong chính khung đó (mấu chốt là min-width:0). */
  .san .sl .pm-canvas, .san .sl .ww-webs { min-width: 0; max-width: 100%; overflow-x: auto; }
}

/* ══ THANH PHÁT AUDIO CỦA BÀI NGHE (§41.29) ═══════════════════════════════════════════════
   Nằm TRONG `.san`, DƯỚI slide. `.san` vì thế phải xếp dọc (2 nút ‹ › nay ở thanh trên). Ẩn bằng class `.an` khi slide không có audio.
   ⚠ Ở NGOÀI `#khungTyLe` (không bị transform:scale) nên chữ/nút giữ đúng cỡ ở mọi tỉ lệ. */
.san { flex-direction: column; gap: 8px; }
.au-bar {
  flex: 0 0 auto; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  justify-content: center; max-width: 100%;
  padding: 6px 10px; border: 1px solid var(--vien, #d8dde3); border-radius: 10px;
  background: #f4f7fa;
}
.au-bar.an { display: none; }
.au-bar audio { height: 34px; max-width: 100%; }
.au-nhom { display: flex; gap: 4px; flex-wrap: wrap; }
.au-nut {
  min-width: 30px; height: 28px; padding: 0 8px; cursor: pointer;
  border: 1px solid var(--vien, #d8dde3); border-radius: 6px; background: #fff;
  font: inherit; font-size: 13px; font-weight: 600; color: var(--chu, #1a3350);
}
.au-nut:hover { background: #e9eef4; }
.au-nut.on { background: var(--xanh, #1976d2); border-color: var(--xanh, #1976d2); color: #fff; }

/* ══ Ô GÕ của Viết lại câu / Đặt câu (spk-writing-part8/9 — §41.30) ════════════════════════
   Ô này CHỈ có trên web: app không có ô nhập cho học viên (§34.4), `bocHtml` chèn vào đúng chỗ
   khối đáp án gợi ý vừa bị cắt bỏ. */
.san .sl .sw8-in-wrap, .san .sl .sw9-in-wrap { margin-top: 4px; }
.san .sl .sw-in {
  width: 100%; box-sizing: border-box; padding: 5px 8px;
  border: 1px solid #b9c4d0; border-radius: 6px; background: #fff;
  font: inherit; font-size: calc(15px * var(--bgz, 1)); color: #1a3350;
}
.san .sl .sw-in:focus { outline: none; border-color: var(--xanh, #1976d2); box-shadow: 0 0 0 2px rgba(25,118,210,.15); }
.san .sl .sw-in.sw-ok { border-color: #2e7d32; background: #e8f5e9; }
.san .sl .sw-in.sw-bad { border-color: #c62828; background: #ffebee; }
.san .sl .sw-goi { margin-top: 3px; font-size: calc(14px * var(--bgz, 1)); color: #2e7d32; font-weight: 600; }

/* ⚠ Ô NHẬP < 16px làm iOS TỰ PHÓNG cả trang, và trang đã phóng thì mọi `position:fixed`
   (2 nút ‹ ›, nút Nộp bài) TRÔI RA NGOÀI MÀN HÌNH — xem §41.20. */
@media (max-width: 820px) {
  .san .sl .sw-in { font-size: 16px; }
}

/* ══ SỬA HIỂN THỊ ĐIỆN THOẠI DỌC (2026-09-30 — rà bằng tools/kiem-tra-web-dien-thoai.js) ══════ */
@media (max-width: 700px) {

  /* ② ẢNH MINH HỌA TRÁI/PHẢI (§32.17): khung ảnh mang width px INLINE tính cho slide 960px, lại thêm
     padding-left/right INLINE (§32.17.1) ⇒ trên màn hẹp ảnh nuốt hết bề ngang và ĐẨY CÂU HỎI RA
     NGOÀI MÉP TRÁI. Xếp chồng: ảnh Trái → ở TRÊN nội dung, ảnh Phải → ở DƯỚI (theo thứ tự đọc). */
  .san .sl .illus-wrap {
    display: flex !important; flex: 0 0 auto !important; min-height: 0 !important;
    padding-left: 0 !important; padding-right: 0 !important; gap: 8px;
  }
  .san .sl .illus-wrap.pos-left, .san .sl .illus-wrap.pos-top { flex-direction: column !important; }
  .san .sl .illus-wrap.pos-right, .san .sl .illus-wrap.pos-bottom { flex-direction: column-reverse !important; }
  .san .sl .illus-wrap > * { min-width: 0 !important; max-width: 100% !important; }
  .san .sl .illus-wrap > .gfi-box {
    flex: 0 0 auto !important; width: auto !important; height: auto !important;
    max-height: none !important; align-self: center !important; margin: 0 auto !important;
  }
  .san .sl .illus-wrap .gfi-strip {
    height: auto !important; width: 100% !important; flex-direction: row !important;
    flex-wrap: wrap !important; justify-content: center; overflow: visible !important;
  }
  .san .sl .illus-wrap .gfi-box img {
    width: auto !important; height: auto !important; max-width: 100% !important;
    max-height: 55vh !important; margin: 0 auto;
  }

  /* ③ GHÉP TỪ VỚI ẢNH: khung ảnh `.pm-canvas{flex:1;min-height:0}` = "phần dư của khung 540px" ⇒
     bỏ chiều cao cố định là CO VỀ 0 — học viên chỉ thấy bảng từ, không thấy ảnh, không có ô thả.
     Ô thả neo theo TOẠ ĐỘ % của khung ⇒ khung PHẢI giữ ĐÚNG tỉ lệ như trên máy tính (đo ở 1280px:
     có header 940×366 · bảng từ trái/phải 732×446 · ẩn header 940×429 · ẩn header + trái/phải
     732×509), chỉ thu nhỏ theo bề ngang. Bảng từ Trái/Trên nằm trên ảnh, Phải/Dưới nằm dưới ảnh. */
  .san .sl .pm-wrap, .san .sl .pm-wrap.pm-bank-side {
    display: flex !important; flex-direction: column !important; flex: 0 0 auto !important; min-height: 0 !important;
  }
  .san .sl .pm-wrap .ww-bank {
    flex: 0 0 auto !important; max-height: none !important; align-self: stretch !important;
    flex-direction: row !important; flex-wrap: wrap !important;
  }
  .san .sl .pm-canvas { flex: 0 0 auto !important; width: 100% !important; min-height: 0 !important; aspect-ratio: 940 / 366; }
  .san .sl .pm-bank-side .pm-canvas { aspect-ratio: 732 / 446; }
  .san .sl:not(.has-head) .pm-canvas { aspect-ratio: 940 / 429; }
  .san .sl:not(.has-head) .pm-bank-side .pm-canvas { aspect-ratio: 732 / 509; }
  /* Khoảng hở giữa các ảnh là 6px CỐ ĐỊNH, không co theo khung ⇒ khung thu còn ~40% thì 6px thành
     "to" tương đối, hàng ảnh vừa khít trên máy tính bị đẩy xuống dòng và ảnh bị cắt. Thu theo tỉ lệ. */
  .san .sl .pm-grid { --pm-gap: 2px; }   /* baigiang.css tính chiều cao + bề ngang ảnh theo biến này */

  /* ④ GHÉP TỪ VỚI ẢNH — Ô THẢ GẮN ẢNH (slide mới, §32.15): ô nằm TRONG khung từng ảnh nên KHÔNG cần
     giữ tỉ lệ khung máy tính ⇒ XẾP LẠI cho điện thoại: 2 ảnh/hàng (3 nếu màn ≥ 520px), ảnh to theo bề
     ngang, ô thả nằm NGAY DƯỚI ảnh (không đè lên ảnh, chữ dài tự xuống dòng) ⇒ hết cảnh 6 ảnh bé tí
     trên một hàng, chip chồng lên nhau. Trang cuộn dọc như thường, KHÔNG cuộn ngang.
     Bảng từ DÍNH trên đầu (dưới thanh nút) để kéo được tới ảnh ở hàng dưới.
     ⚠ Slide CŨ có ô tự do (`.pm-box` không `.pm-anch`) và chế độ "1 ảnh" (`.pm-one`) VẪN neo toạ độ %
       ⇒ giữ nguyên quy tắc ③ ở trên, không đụng. */
  .san .sl .pm-wrap:not(.pm-one):not(.pm-car):not(:has(.pm-box:not(.pm-anch))) .pm-canvas {
    aspect-ratio: auto !important; height: auto !important; overflow: visible !important; border: 0;
  }
  .san .sl .pm-wrap:not(.pm-one):not(.pm-car):not(:has(.pm-box:not(.pm-anch))) .pm-grid {
    position: static !important; inset: auto; transform: none !important; overflow: visible;
    flex-wrap: wrap !important; align-content: flex-start; align-items: flex-start; gap: 10px 8px; --pm-gap: 8px;
  }
  .san .sl .pm-wrap:not(.pm-one):not(.pm-car):not(:has(.pm-box:not(.pm-anch))) .pm-grid > .pm-cell {
    flex: 0 0 calc((100% - 8px) / 2) !important; max-width: calc((100% - 8px) / 2) !important; height: auto !important;
    flex-direction: column; align-items: center;
  }
  .san .sl .pm-wrap:not(.pm-one):not(.pm-car):not(:has(.pm-box:not(.pm-anch))) .pm-grid > .pm-cell > img {
    width: 100% !important; height: auto !important; max-height: 40vh; object-fit: contain;
  }
  .san .sl .pm-wrap:not(.pm-one):not(.pm-car):not(:has(.pm-box:not(.pm-anch))) .pm-slots {
    position: static !important; transform: none !important; max-width: 100%; width: 100%; margin-top: 4px;
  }
  .san .sl .pm-wrap:not(.pm-one):not(.pm-car):not(:has(.pm-box:not(.pm-anch))) .pm-box { width: 100%; min-width: 0; min-height: 34px; }
  .san .sl .pm-wrap .ww-chip { white-space: normal; max-width: 100%; text-align: center; }
  .san .sl .pm-wrap:not(.pm-one):not(.pm-car):not(:has(.pm-box:not(.pm-anch))) .ww-bank {
    position: sticky !important; top: var(--tt-h, 58px); z-index: 5;
  }
  /* ⑤ BĂNG CHUYỀN (S.pmCar — GV bật rồi mới đẩy): giữ băng chuyền như máy tính, khung ảnh cao hơn
     (4:3) để ảnh giữa đủ to trên màn dọc; bảng từ dính trên đầu như ④. Ô thả vẫn nằm trong ảnh. */
  .san .sl .pm-wrap.pm-car .pm-canvas { aspect-ratio: 4 / 3 !important; overflow: hidden !important; }   /* đè overflow-x:auto chung của .pm-canvas */
  .san .sl .pm-wrap.pm-car .ww-bank { position: sticky !important; top: var(--tt-h, 58px); z-index: 35; }
}
@media (min-width: 520px) and (max-width: 700px) {
  .san .sl .pm-wrap:not(.pm-one):not(.pm-car):not(:has(.pm-box:not(.pm-anch))) .pm-grid > .pm-cell {
    flex-basis: calc((100% - 16px) / 3) !important; max-width: calc((100% - 16px) / 3) !important;
  }
}

/* ══ CHIA ĐỘNG TỪ (verb-form) — Ô GÕ do `bocHtml` chèn vào chỗ trống, CHỈ có trên web ═══════════
   `.sw-in` mặc định rộng 100% (ô viết cả câu của sw8/9) ⇒ ở đây phải thu về ô NỘI DÒNG. */
.san .sl .vf-in { display: inline-block; width: 8.5em; max-width: 100%; margin: 0 3px; padding: 2px 6px; vertical-align: baseline; }
.san .sl .vf-goi { display: inline; margin: 0 4px 0 2px; font-size: calc(14px * var(--bgz, 1)); }

@media (max-width: 700px) {
  /* Vùng cuộn tính theo khung 540px của các layout mới nạp CSS (xem khối "bỏ nốt các vùng cuộn") */
  .san .sl .vf-wrap, .san .sl .vf-body,
  .san .sl .sw8-body, .san .sl .sw9-body,
  .san .sl .mcql.sl1-wrap, .san .sl .sl1-item, .san .sl .sl1-main {
    flex: 0 0 auto !important; height: auto !important; min-height: 0 !important;
    max-height: none !important; overflow: visible !important;
  }
  .san .sl .vf-slot { white-space: normal; }

  /* ④ NGHE VÀ CHỌN: ảnh đáp án mang bề ngang THẬT của ảnh (min-width:auto của flex item) nên
     tràn khỏi màn hình. Dạng 3 ảnh giữ LƯỚI 3 CỘT như đề in (rule chung `.options-container{display:
     block}` phía trên xếp chồng chúng thành 3 ảnh khổng lồ); dạng 1 ảnh + A/B/C thu ảnh vừa bề ngang. */
  .san .sl .options-container.sl1-imgs { display: grid !important; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 6px; }
  .san .sl .sl1-imgs .option-item.sl1-opt { min-width: 0 !important; margin-bottom: 0; padding: 4px; }
  .san .sl .sl1-img { min-width: 0; max-width: 100% !important; width: 100% !important; height: auto !important; }
  .san .sl .sl1-main .sl1-img { width: auto !important; max-height: 55vh; }
  .san .sl .explanation-section.sl1-ts { flex: 0 0 auto !important; height: auto !important; }
  .san .sl .explanation-section.sl1-ts:not(.show) { display: none !important; }

  /* ⑤ NỐI CỘT: thẻ cao CỐ ĐỊNH `--mt-h` (40px) ⇒ chữ dài xuống 2–3 dòng trên màn hẹp là bị cắt.
     Cho thẻ cao theo chữ (tối thiểu vẫn 40px). `auto` trong max-height là giá trị không hợp lệ
     ⇒ trình duyệt rơi về `none` — đúng cái cần. */
  .san .sl .mt-wrap { --mt-h: auto; }
  .san .sl .mt-row { min-height: 40px; }
  .san .sl .mt-body { padding-top: 6px; padding-bottom: 6px; }

  /* ⑥ SƠ ĐỒ MẠNG TỪ: 2–3 sơ đồ ngang cho khung 960px ⇒ trên màn hẹp mỗi sơ đồ MỘT HÀNG. Ô thả neo %
     trong TỪNG sơ đồ nên xếp lại cả sơ đồ không làm lệch ô nào. */
  .san .sl .ww-webs { display: grid !important; grid-template-columns: minmax(0, 1fr) !important;
    gap: 30px 0 !important; overflow: visible !important; padding: 20px 4px; }
  .san .sl .ww-webs .ww-web { grid-column: auto !important; max-width: min(300px, calc(100% - 56px)) !important; }
  /* ↑ ô thả 4 góc nhô ra ngoài khung sơ đồ 26px mỗi bên (.c-tl/.c-tr…) ⇒ chừa 56px kẻo màn 360px lòi mép phải */

  /* ⑦ KHỐI TỰ DO (§32.40): trên máy tính nổi TUYỆT ĐỐI theo % của slide 960×540 — màn hẹp slide
     cao tự do nên % mất nghĩa, khối đè lên câu hỏi. Trả về luồng thường, xếp SAU nội dung bài. */
  .san .sl .tb-over, .san .sl .tb-layer { position: static !important; inset: auto !important; }
  .san .sl .tb-over .tb-box, .san .sl .tb-layer .tb-box {
    position: static !important; width: auto !important; height: auto !important;
    max-width: 100%; margin-top: 8px;
  }
  .san .sl .tb-box img { max-width: 100%; height: auto; }

  /* ⑧ Ô CHỮ: khung lưới bị giới hạn cao theo khung 540px (lưới cao 436, khung 430) ⇒ đáy lưới
     bị cắt vài px. Trả chiều cao về theo nội dung; cuộn ngang (lưới rộng) vẫn giữ như cũ. */
  .san .sl .cw-left { height: auto !important; max-height: none !important; overflow-y: hidden !important; padding-bottom: 2px; }
  .san .sl .cw-left .cw-grid { margin: 0 auto; }
}

/* ══ CHIP TỪ / Ô THẢ KHÔNG ĐƯỢC TRÀN MÉP MÀN HÌNH (2026-10-08 — người dùng báo ở dạng điền từ kéo thả) ══
   `.ww-chip` của app là `white-space:nowrap` (thiết kế cho khung 960px) ⇒ cụm từ dài, màn 360px hay cỡ chữ
   phóng (`--bgz` > 1) là chip — trong bảng từ lẫn sau khi thả vào chỗ trống — lòi ra ngoài mép phải.
   Bảng từ dạng LƯỚI 5 CỘT (`.ws-box`: ket-reading-part7, word-select) trên màn hẹp còn ép chip thành
   cột chữ dọc 3–4 ký tự ⇒ chuyển sang hàng tự xuống dòng như `.ww-bank`. */
@media (max-width: 700px) {
  .san .sl .ww-chip, .san .sl .ws-word, .san .sl .ro-card, .san .sl .mt-card, .san .sl .sw9-chip {
    white-space: normal !important; max-width: 100%; min-width: 0; overflow-wrap: anywhere;
  }
  .san .sl .ww-chip { text-align: center; }
  .san .sl .ww-drop, .san .sl .kp7-drop, .san .sl .gf-drop { max-width: 100%; }
  .san .sl .kp7-drop:not(:empty), .san .sl .gf-drop:not(:empty) { min-width: 0; }
  .san .sl .ws-box {
    display: flex !important; flex-wrap: wrap; justify-content: center; align-items: center;
    gap: 6px; grid-template-columns: none;
  }
  .san .sl .ws-box > * { margin: 0 !important; }
}

/* ══ BẢNG TỪ GHIM TRÊN ĐẦU khi cuộn — dạng điền từ KÉO THẢ (2026-10-08, người dùng yêu cầu) ═════════
   Điện thoại cuộn CẢ TRANG ⇒ đọc xuống chỗ trống phía dưới là bảng từ trôi mất, không còn gì để kéo.
   Ghim bảng từ ngay dưới thanh nút (`--tt-h` do `vuaKhung` đo) — phần chữ bên dưới vẫn cuộn bình thường.
   Bảng từ dài thì tự cuộn trong 35vh để không che hết màn hình.
   ⚠ sticky chỉ chạy khi KHÔNG tổ tiên nào có overflow ≠ visible và CHA của bảng từ bao trọn phần chữ
     (đúng với .gf-wrap / .ww-wrap / .kp7-wrap). Bảng từ cột phải của kp7 (`.kp7-2col`) nằm SAU đoạn văn
     trong DOM ⇒ đảo thứ tự hiển thị cho bảng lên trên. */
@media (max-width: 700px) {
  .san .sl .gf-wrap > .ww-bank,
  .san .sl .ww-wrap:not(.pm-wrap) > .ww-bank,
  .san .sl .kp7-wrap > .kp7-bank {
    position: sticky !important; top: var(--tt-h, 58px); z-index: 6;
    max-height: 35vh !important; overflow-y: auto !important;
    box-shadow: 0 3px 6px rgba(20, 40, 80, .12);
  }
  .san .sl .kp7-wrap.kp7-2col { display: flex !important; flex-direction: column-reverse !important; gap: 8px; }
  .san .sl .kp7-wrap.kp7-2col > .kp7-bank { width: auto !important; max-width: 100%; }
  /* Bảng từ cột phải (mỗi từ/câu một hàng rộng hết cột) khi đã lên đầu thì chảy thành hàng như bảng thường,
     kẻo 6–8 hàng full-width chiếm gần hết màn hình. Câu dài vẫn tự xuống dòng trong chip. */
  .san .sl .kp7-bank.kp7-side { display: flex !important; flex-wrap: wrap; justify-content: center; gap: 6px; }
  .san .sl .kp7-bank.kp7-side .ww-chip { display: inline-flex !important; width: auto !important; margin: 0 !important; }
  .san .sl .kp7-bank .kp7-bankw { display: none; }
}

/* ── Nối cặp bằng đường — kiểu "Rải tự do" (§32.51): điện thoại đưa ô về THẲNG HÀNG ──────────────
   --nl-flat:1 báo cho nlRedraw (engine.js) dùng mép CỘT làm đầu đường thay cho data-x của ô. */
@media (max-width: 700px) {
  .san .sl .nl-scatter { --nl-flat: 1; }
  .san .sl .nl-scatter .nl-l, .san .sl .nl-scatter .nl-r { width: 100% !important; margin: 0 !important; }
}

/* Hội thoại sơ đồ (§32.54) trên điện thoại: bỏ khung kéo-thả tuyệt đối + zoom, cụm chảy theo bề rộng màn hình */
@media (max-width:700px){
  .san .sl .rp-area{position:static;margin-top:6px}
  .san .sl .rp-box{position:static;width:100% !important;height:auto !important}
  .san .sl .rp-box .rp-in{height:auto;display:block}
  .san .sl .rp-arrow{width:100%;height:auto}
}
