/* ===========================================================================
   VIẾT BÀI THẲNG LÊN ĐỀ - BỘ ÁO DÙNG CHUNG
   ===========================================================================
   Tách khỏi assets/css/pages/practice.css ngày 30/08/2026, khi bộ máy viết bài
   được dùng ở CHỖ THỨ HAI: chế độ Làm Bài của trang Xem Đề (paper-viewer.html),
   nơi tờ đề do chính VPath dựng ra thành ảnh từng trang.

   Vì sao tách thành file riêng thay vì chép sang: hai bản chép sẽ lệch nhau ở
   lần sửa thứ nhất, mà thứ lệch ở đây là VỊ TRÍ CHỮ trên trang đề. Toàn bộ khối
   này chỉ mô tả lớp phủ viết bài, không dính gì tới bố cục riêng của trang nào,
   nên nó vốn đã thuộc về một file dùng chung.

   Trang nào nạp file này thì cũng phải nạp assets/js/pages/luyen-de-viet-bai.abae7bcb.js,
   và ngược lại. Đọc khối chú thích đầu file JS đó trước khi sửa gì ở đây: mọi
   kích thước bên dưới đều tính bằng calc(var(--vb-rong) * n), trong đó --vb-rong
   là BỀ NGANG ĐANG HIỂN THỊ của ảnh, do ResizeObserver cập nhật. Nhờ vậy chữ co
   giãn cùng ảnh khi xoay iPad hay kéo ranh giới khung, mà không phải vẽ lại một
   node nào.
   =========================================================================== */

/* KHUNG BỌC MỘT TẤM ẢNH ĐỀ. Bộ máy viết bài tìm đúng class này để dựng lớp phủ,
   nên trang nào muốn viết được thì phải bọc mỗi tấm ảnh trong một .khung-anh-de.
   position: lớp phủ neo vào đúng tấm ảnh của nó.
   overflow: ô chữ kéo lố ra ngoài mép ảnh bị cắt gọn thay vì tràn sang tấm kế. */
.khung-anh-de {
    position: relative;
    border-radius: var(--ao-r-nho);
    overflow: hidden;
}

.vb-lop {
    position: absolute;
    inset: 0;
    z-index: 2;
}

/* Con trỏ MŨI TÊN THƯỜNG trên ảnh đề (13/09/2026, công cụ Chọn kiểu Canva). Bản trước để con trỏ chữ khắp
   ảnh vì "bấm vào đâu cũng viết được": bấm chỗ trống là đẻ ra ô chữ. Chủ dự án bỏ hẳn cách đó ("cho để chế
   độ là con chỏ chuột thông thường đi"), nên con trỏ chữ chỉ còn trong ô gõ, còn rê lên mực là mũi tên dời. */
.dang-viet-bai .khung-anh-de { cursor: default; }

/* ---- Ô gõ trên một dòng kẻ ---- */
.vb-dong {
    position: absolute;
    display: flex;
    align-items: flex-end;
}

.vb-go {
    width: 100%;
    outline: none;
    background: transparent;
    /* Chữ viết bài dùng Plus Jakarta Sans như toàn trang, KHÔNG dùng font viết
       tay: đây là bài làm để đọc lại và đối chiếu Mark Scheme, không phải một
       món trang trí. */
    font-family: "Plus Jakarta Sans", system-ui, sans-serif;
    line-height: 1.15;
    caret-color: var(--navy-600, #234C7C);
    -webkit-user-modify: read-write-plaintext-only;
}

/* nowrap + overflow:hidden là ĐIỀU KIỆN để thuật toán tràn dòng chạy được:
   canhTran() so scrollWidth với clientWidth để biết chữ đã dài quá vạch chưa.
   Cho phép xuống dòng ở đây là scrollWidth không bao giờ vượt clientWidth, và
   chữ sẽ tự xuống dòng NGAY TRONG một ô, đè lên vạch kế tiếp. */
.vb-dong .vb-go {
    white-space: nowrap;
    overflow: hidden;
}

/* Vệt sáng rất nhạt khi rê chuột qua một dòng đã có chữ: đủ để biết ô nào sẽ
   nhận con trỏ, không đủ để che dòng kẻ chấm bên dưới.

   Đáy ô nay trùng đúng vạch kẻ (xem taoODong trong luyen-de-viet-bai.js), nên
   vệt này dừng ngay TRÊN vạch chứ không phủ qua nó. Bản đầu để ô thò xuống dưới
   vạch và chủ dự án nhìn ra ngay khi xem thử: vệt nền che mất chính cái vạch mà
   chữ phải nằm trên. */
.vb-dong:hover .vb-go,
.vb-dong .vb-go:focus {
    background: rgba(35, 76, 124, .05);
    border-radius: 2px 2px 0 0;
}

/* ---- Dải dòng đang bôi đen (chọn nhiều dòng, 10/09/2026) ----
   Mỗi dòng là một ô gõ riêng nên trình duyệt không tự bôi xuyên dòng được; lớp JS
   tự giữ dải và gắn .vb-dong--chon. Nền đậm hơn hẳn vệt rê chuột ở trên để không
   nhầm "đang chọn" với "đang rê qua". Cũng dừng TRÊN vạch như vệt rê, cùng lý do. */
.vb-dong--chon .vb-go,
.vb-dong--chon:hover .vb-go {
    background: rgba(35, 76, 124, .18);
    border-radius: 2px 2px 0 0;
}
/* Trong lúc kéo chọn dòng: chặn trình duyệt bôi tiếp chữ trong ô bắt đầu kéo, kẻo
   vệt bôi xanh của nó đè lên nền dải. Gỡ ngay khi thả chuột. */
.vb-lop--keo-chon,
.vb-lop--keo-chon .vb-go {
    -webkit-user-select: none;
    user-select: none;
}

/* ---- Ô chữ thả tự do (kiểu Canva) ---- */
/* Viền đứt LUÔN THẤY MỜ MỜ, không đợi rê chuột mới hiện.
   Bản đầu để viền trong suốt cho gọn mắt, nhưng gọn quá thành ra không ai biết ô
   chữ tồn tại: chủ dự án thử xong nói "khó dùng quá". Một nét đứt rất nhạt là đủ
   để thấy ô ở đâu mà không làm rối bài làm. */
.vb-o-tu-do {
    position: absolute;
    border: 1px dashed rgba(35, 76, 124, .22);
    border-radius: 3px;
}
.vb-o-tu-do:hover,
.vb-o-tu-do:focus-within {
    border-color: rgba(35, 76, 124, .35);
    background: rgba(255, 255, 255, .55);
}

.vb-go--tu-do {
    white-space: pre-wrap;
    word-break: break-word;
    min-height: 1em;
    padding: 2px 3px;
}

/* HAI TAY NẮM XANH ĐÃ BỎ PHẦN MÀU (12/09/2026).
   Trước đây ô chữ có ba nút: ô vuông xanh (kéo đi), thanh dọc xanh (đổi bề ngang), chấm đỏ (xoá) —
   tất cả là khối màu đặc nằm NGOÀI mép ô. Một câu điền bảng có cả chục ô chữ, thành ra chục khối
   xanh với chấm đỏ rải khắp đề, đè lên cả chữ in lẫn chữ bài làm. Chủ dự án chụp lại và nói nhìn
   thừa thãi. Nay:
     - ô vuông kéo đi: BỎ HẲN, dời ô bằng cách kéo thẳng vào thân ô (keoThanO trong luyen-de-viet-bai.js);
     - thanh đổi bề ngang: giữ NGUYÊN tính năng nhưng không tô màu nữa, chỉ là một dải trong suốt sát
       mép phải ô, con trỏ đổi thành mũi tên ngang khi rê vào;
     - nút xoá: vẫn đỏ và vẫn thấy, vì nó là thao tác mất dữ liệu, phải nhìn ra ngay là nút gì. */
.vb-keo, .vb-xoa {
    position: absolute;
    border-radius: 2px;
    transition: opacity .15s;
    touch-action: none;   /* kéo bằng ngón tay, không để trình duyệt cuộn trang */
}
/* Dải kéo bề ngang: không tô gì, nhưng vẫn nhận được cú kéo. Nằm vắt qua mép phải (5px trong, 3px
   ngoài) để vừa với tay mà không ăn vào chữ. opacity KHÔNG dùng ở đây: dải trong suốt sẵn, mà
   opacity: 0 thì trên Safari có lúc thôi nhận pointer. */
.vb-keo {
    right: -3px; top: 0;
    width: 8px; height: 100%;
    background: transparent;
    cursor: ew-resize;
}
/* Ô chữ nhận cú kéo ở thân để dời đi: báo bằng con trỏ, không bằng một khối màu. Lúc đang gõ thì
   trả lại con trỏ chữ, vì kéo trong ô đang gõ là bôi đen. */
.vb-o-tu-do { cursor: move; }
.vb-o-tu-do:focus-within { cursor: auto; }
.vb-go--tu-do:focus { cursor: text; }
/* Nút xoá ô chữ. Đỏ ngay từ đầu chứ không đợi rê vào mới đổi màu: nó là thao tác
   mất dữ liệu, phải nhìn ra ngay là nút gì. Lấy lại được bằng Ctrl+Z nên không
   cần hộp xác nhận. */
.vb-xoa {
    right: -9px;
    top: -9px;
    width: 18px;
    height: 18px;
    opacity: 0;
    border-radius: 50%;
    /* #B91C1C là đúng mã đỏ đang dùng cho bút "tự chấm bài" trong bảng MAU của
       luyen-de-viet-bai.js. Viết thẳng mã chứ không qua biến CSS: theme.css không
       khai biến đỏ nào, và var() trỏ vào biến không tồn tại thì rơi về giá trị
       dự phòng một cách im lặng, đọc code lại tưởng có biến. */
    background: #B91C1C;
    color: #fff;
    font-size: 13px;
    font-weight: 800;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}
.vb-xoa:hover { background: #7F1D1D; }

.vb-o-tu-do:hover .vb-xoa,
.vb-o-tu-do:focus-within .vb-xoa { opacity: .9; }

@media (hover: none) {
    /* CHỈ Ô ĐANG SOẠN MỚI HIỆN TAY NẮM (12/09/2026).
       Bản trước cho cả ba tay nắm hiện THƯỜNG TRỰC trên máy không có chuột, lý do ghi ở khối trên:
       iPad không có trạng thái rê để mà chờ. Nhưng một câu điền bảng có cả chục ô chữ, và mỗi ô đẻ ra
       ba nút nằm NGOÀI mép ô (top / left / right âm), nên màn hình thành một đám vuông xanh với chấm
       đỏ rải khắp đề, che mất chữ của chính bài làm lẫn chữ in của đề. Chụp lại được trên iPad với 6 ô:
       18 nút cùng hiện. Chạm vào ô là ô nhận focus, nên :focus-within đủ để lấy tay nắm ra khi cần mà
       không phải nhìn chúng suốt. Vùng chạm vẫn nới to như cũ. */
    .vb-xoa { opacity: 0; }
    .vb-o-tu-do:focus-within .vb-xoa { opacity: .9; }
    /* Ngón tay to hơn con trỏ chuột: nới vùng chạm mà không nới phần nhìn thấy. */
    .vb-keo { width: 16px; right: -6px; }
    .vb-xoa { width: 24px; height: 24px; right: -12px; top: -12px; font-size: 15px; }
}

/* ---- Thanh công cụ viết bài ---- */
/* Bậc z-index 30: DƯỚI header dính (40), TRÊN nội dung. Bậc này đã ghi vào
   bảng thang z-index trong DESIGN_SYSTEM.md, đừng chế số mới ở đây. */
.thanh-viet-bai {
    position: sticky;
    top: 8.5rem;              /* dưới header 5rem + thanh công cụ câu */
    z-index: 30;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
    margin-bottom: .75rem;
    padding: .5rem .625rem;
    background: #fff;
    border: 1px solid var(--stone-200, #E7E5E4);
    border-radius: var(--ao-r-nho);
    box-shadow: 0 4px 14px rgba(27, 58, 92, .08);
}

.thanh-viet-bai__nhom {
    display: flex;
    align-items: center;
    gap: .25rem;
}
.thanh-viet-bai__vach,
.thanh-viet-bai__ngat {
    width: 1px;
    align-self: stretch;
    background: var(--stone-200, #E7E5E4);
    margin: 0 .125rem;
}
/* HAI HÀNG CỐ ĐỊNH ở thanh bám trên màn rộng (13/09/2026): hàng 1 công cụ + định dạng chữ, hàng 2 hoàn tác +
   trạng thái lưu. Trước đó hàng nút vừa khít (dư 48px ở chế độ Chọn): cầm bút là nhóm độ dày nét hiện ra, nhóm
   hoàn tác bị đẩy xuống ghép vào dòng chữ gợi ý, thanh cao 74px -> 90px và CẢ TRANG NHẢY 16px mỗi lần đổi công cụ.
   Thêm nút Hình và Đường thì hàng nào cũng tràn. Ngắt chủ động thì thanh cao đứng yên ở mọi chế độ.
   Thanh nằm ngang cả bề rộng (trang Kho Đề, --hang) và thanh bám đáy điện thoại vẫn đủ chỗ / tự xuống hàng theo
   kiểu riêng, nên ở đó chỗ ngắt chỉ là một vạch ngăn thường. */
@media (min-width: 768px) {
    .thanh-viet-bai:not(.thanh-viet-bai--hang):not(.thanh-viet-bai--cot) > .thanh-viet-bai__ngat {
        flex-basis: 100%;
        width: auto;
        height: 0;
        margin: 0;
        background: none;
    }
}
/* Nhóm độ dày nét lúc không cầm bút / hình / đường: ẩn nhưng GIỮ CHỖ, để số hàng của thanh không đổi theo công cụ.
   visibility (không phải display) cũng gỡ nó khỏi thứ tự Tab và khỏi cây trợ năng. */
.thanh-viet-bai__giu-cho {
    visibility: hidden;
}

/* Ô trạng thái lưu ở cuối thanh công cụ Kho Đề: bề ngang CỐ ĐỊNH, một dòng, chữ dài thì "…".
   Chữ trong ô đổi sau mỗi lượt tự lưu; để ô co giãn theo chữ là thanh đổi số hàng và cả tờ đề
   giật theo (30/09/2026). 7rem vừa "Đang lưu..." / "Đã lưu" ở cỡ text-2xs. */
.thanh-viet-bai__trang-thai {
    flex: 0 0 7rem;
    width: 7rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-align: right;
}

/* ---- Ô CỠ CHỮ TÍNH BẰNG PIXEL (05/09/2026) ----
   Thay ba nút A nhỏ / A vừa / A lớn. Chủ dự án chốt giữa một buổi dạy: cỡ chữ phải là một con số
   px gõ được như trong Word, vì ba nấc cũ tính theo khoảng cách vạch kẻ của từng lớp nên cùng một
   nấc lại ra hai cỡ khác hẳn giữa tờ giấy và ảnh đề.

   Giấu mũi tên tăng giảm của trình duyệt: chúng bé tí, khác nhau ở mỗi trình duyệt, và đã có hai
   nút cộng trừ cỡ ngón tay hai bên. Vẫn để type="number" để bàn phím điện thoại bật bàn số. */
.vb-co {
    display: inline-flex;
    align-items: baseline;
    gap: 2px;
    padding: 0 6px;
    border: 1px solid var(--stone-300, #D6D3D1);
    border-radius: 2px;
    background: #fff;
}
.vb-co__o {
    width: 2.6ch;
    border: 0;
    outline: none;
    background: transparent;
    font: inherit;
    font-size: 13px;
    font-weight: 700;
    text-align: right;
    color: var(--navy-900, #0D1F33);
    -moz-appearance: textfield;
    appearance: textfield;
}
.vb-co__o::-webkit-outer-spin-button,
.vb-co__o::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.vb-co__o:focus-visible { outline: 2px solid var(--gold-500, #C9A227); outline-offset: 2px; }
.vb-co__dv {
    font-size: 10px;
    font-weight: 700;
    color: var(--stone-500, #78716C);
}

.vb-nut {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .35rem;
    min-width: 2rem;
    height: 2rem;
    padding: 0 .5rem;
    font-size: .75rem;
    font-weight: 800;
    color: var(--stone-600, #57534E);
    background: var(--stone-100, #F5F5F4);
    border-radius: var(--ao-r-nho);
    transition: background-color .15s, color .15s;
}
.vb-nut:hover:not(:disabled) { background: var(--stone-200, #E7E5E4); }
.vb-nut:disabled { opacity: .4; cursor: not-allowed; }
.vb-nut[aria-pressed="true"] { background: var(--navy-600, #234C7C); color: #fff; }

/* ---- NÚT TÁCH ĐÔI MÀU CHỮ / TÔ SÁNG, KIỂU WORD (11/09/2026) ----
   Thay bốn chấm màu cũ. Thân nút áp màu "dùng gần nhất" (vạch màu dưới biểu tượng), mũi tên mở
   bảng màu. Hai nửa là hai <button> thật, dính liền nhau thành một khối. */
.vb-tach {
    display: inline-flex;
    align-items: stretch;
}
.vb-tach .vb-tach__than {
    border-radius: var(--ao-r-nho) 0 0 var(--ao-r-nho);
    min-width: 2rem;
    padding: 0 .4rem;
}
/* Mũi tên rộng 24px: đúng mức tối thiểu vùng chạm của WCAG 2.2 (2.5.8). */
.vb-tach .vb-tach__mui {
    border-radius: 0 var(--ao-r-nho) var(--ao-r-nho) 0;
    min-width: 1.5rem;
    padding: 0 .25rem;
    border-left: 1px solid var(--stone-200, #E7E5E4);
    font-size: .65rem;
}
.vb-tach .vb-tach__mui[aria-expanded="true"] { background: var(--stone-200, #E7E5E4); }
/* Biểu tượng + vạch màu bên dưới, như chữ A đỏ gạch của Word. */
.vb-bieu-mau {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    line-height: 1;
}
.vb-bieu-mau__vach {
    width: 1rem;
    height: 4px;
    border-radius: 1px;
    /* Viền tối .45 để vạch trắng / vàng vẫn thấy rõ trên nền xám nhạt của nút (tương phản đồ hoạ
       tối thiểu 3:1, WCAG 1.4.11). */
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .45);
}
@media (pointer: coarse) {
    .vb-tach .vb-tach__mui { min-width: 2rem; }
}

/* ---- BỐN CHẤM MÀU MỰC LÚC CẦM BÚT ----
   Chỉ hiện khi đang ở chế độ bút (như nhóm độ dày nét): đổi qua lại giữa mực xanh đen để viết và
   mực đỏ để tự chấm là thao tác hay làm nhất lúc cầm bút, phải còn là MỘT cú bấm. Chính nó là mẫu
   màu nên không mang chữ; viền đậm lên khi đang được chọn thay vì đổi nền. */
.vb-mau {
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    border: 2px solid transparent;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12);
    transition: border-color var(--ao-nhanh, 150ms);
}
.vb-mau[aria-pressed="true"] { border-color: var(--navy-900, #0D1F33); }

/* ---- DẢI NHIỀU DÒNG TÔ ĐÚNG TỪNG KÝ TỰ (11/09/2026) ----
   Dòng đầu / cuối của dải chỉ dính một phần: tô đúng phần chữ đó bằng CSS Custom Highlight API
   (veToChuDai trong luyen-de-viet-bai.js). Cùng màu với nền dòng nằm trọn trong dải (.vb-dong--chon)
   để cả dải đọc ra là một khối. */
::highlight(vb-dai) { background-color: rgba(35, 76, 124, .22); }

/* ---- BẢNG MÀU KIỂU PAINT / WORD (11/09/2026) ----
   Dựng bởi moBangMau trong luyen-de-viet-bai.js, gắn thẳng vào body. z-index 65: nổi trên cửa sổ
   nổi tờ insert của trang Ôn Tập (.khung-noi, 60), dưới toast (70). Đã ghi vào bảng thang z-index
   của DESIGN_SYSTEM.md. Dải cầu vồng của ô phổ màu và dải sáng tối là CHÍNH công cụ chọn màu,
   không phải trang trí, nên không phạm luật bỏ gradient của hệ thiết kế. */
.vb-bang-mau {
    position: fixed;
    z-index: 65;
    box-sizing: border-box;
    width: min(19rem, calc(100vw - 1rem));
    padding: .75rem;
    overflow-y: auto;
    overscroll-behavior: contain;
    background: #fff;
    border: 1px solid var(--stone-200, #E7E5E4);
    border-radius: var(--ao-r-nho, 14px);
    box-shadow: var(--ao-bong-cao, 0 8px 16px rgba(13, 31, 51, .07), 0 24px 48px rgba(13, 31, 51, .13));
    font-family: "Plus Jakarta Sans", system-ui, sans-serif;
    color: var(--stone-700, #44403C);
    transition: opacity var(--ao-vua, 220ms) var(--ao-ease-vao, ease), transform var(--ao-vua, 220ms) var(--ao-ease-vao, ease);
}
.vb-bang-mau[hidden] { display: none; }
@starting-style {
    .vb-bang-mau { opacity: 0; transform: translateY(4px); }
}
/* Điện thoại: một tấm ngang ngay trên thanh công cụ bám đáy, rộng gần hết màn hình. */
.vb-bang-mau--tam { width: min(24rem, calc(100vw - 1rem)); }
/* Vòng focus mặc định (navy-500) chìm mất trên các ô màu xanh đậm: đẩy nó ra ngoài ô một chút. */
.vb-bang-mau :focus-visible { outline-offset: 2px; }
.vb-bang-mau__dau {
    display: flex;
    align-items: center;
    gap: .25rem;
    margin-bottom: .25rem;
}
.vb-bang-mau__ten {
    flex: 1;
    font-size: .8125rem;
    font-weight: 800;
    color: var(--navy-900, #0D1F33);
}
.vb-bang-mau__dong,
.vb-bang-mau__lui {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 999px;
    color: var(--stone-600, #57534E);
    transition: background-color var(--ao-nhanh, 150ms);
}
.vb-bang-mau__dong:hover,
.vb-bang-mau__lui:hover { background: var(--stone-100, #F5F5F4); }
.vb-bang-mau__nhan {
    margin: .55rem 0 .3rem;
    font-size: .6875rem;
    font-weight: 700;
    color: var(--stone-600, #57534E);
}
.vb-bang-mau__khong,
.vb-bang-mau__tu {
    display: flex;
    align-items: center;
    gap: .5rem;
    width: 100%;
    margin-top: .25rem;
    padding: .45rem .6rem;
    border-radius: 6px;
    background: var(--stone-100, #F5F5F4);
    font-size: .75rem;
    font-weight: 700;
    color: var(--stone-700, #44403C);
    transition: background-color var(--ao-nhanh, 150ms);
}
.vb-bang-mau__tu { margin-top: .6rem; }
.vb-bang-mau__khong:hover,
.vb-bang-mau__tu:hover { background: var(--stone-200, #E7E5E4); }
/* Mười ô một hàng, tự co theo bề ngang bảng (~24px trên bảng 19rem, đúng mức tối thiểu vùng chạm
   của WCAG 2.2 mục 2.5.8; trên tấm điện thoại rộng hơn nên ô to hơn). */
.vb-bang-mau__luoi {
    display: grid;
    grid-template-columns: repeat(10, minmax(0, 1fr));
    gap: .25rem;
}
.vb-o-mau {
    width: 100%;
    aspect-ratio: 1;
    border-radius: 4px;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .14);
    cursor: pointer;
    transition: transform var(--ao-nhanh, 150ms);
}
/* Ô đang dùng đánh dấu bằng khung TRONG (viền navy + vòng trắng), không dùng outline: outline để
   dành riêng cho vòng focus bàn phím (navy-500 !important của theme.css). Hai thứ cùng là outline
   thì ô vừa được chọn vừa có focus trông y như chỉ được chọn, người dùng bàn phím mất dấu. Vòng
   trắng giữ khung thấy được trên ô tối, viền navy giữ nó thấy được trên ô sáng (vàng, xanh ngọc). */
.vb-o-mau[aria-pressed="true"] {
    box-shadow: inset 0 0 0 2px var(--navy-900, #0D1F33), inset 0 0 0 4px #fff;
}
@media (hover: hover) and (pointer: fine) {
    .vb-o-mau:hover { transform: scale(1.12); }
}

/* Màn TỰ CHỌN: ô cầu vồng + thanh sáng tối, đúng bố cục "Edit colors" của Paint. */
.vb-tu-chon {
    display: flex;
    gap: .6rem;
    margin-top: .25rem;
}
/* Ngang là sắc màu (đỏ, vàng, lục, lam, tím, về đỏ); dọc là độ tươi: trên cùng tươi nhất, xuống
   dưới nhạt dần về xám, như Paint. Tức HSL với độ sáng 50%. */
.vb-pho {
    position: relative;
    flex: 1;
    height: 9rem;
    border-radius: 6px;
    cursor: crosshair;
    touch-action: none;
    background:
        linear-gradient(to bottom, rgba(128, 128, 128, 0), #808080),
        linear-gradient(to right, #f00 0%, #ff0 16.667%, #0f0 33.333%, #0ff 50%, #00f 66.667%, #f0f 83.333%, #f00 100%);
}
.vb-pho__diem {
    position: absolute;
    width: 14px;
    height: 14px;
    margin: -7px 0 0 -7px;
    border: 2px solid #fff;
    border-radius: 50%;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, .55);
    pointer-events: none;
}
/* Thanh sáng tối: trên trắng, giữa là màu đang chọn (--vb-mau-giua do veBang đặt), dưới đen. */
.vb-sang {
    position: relative;
    flex: 0 0 1rem;
    height: 9rem;
    border-radius: 6px;
    cursor: pointer;
    touch-action: none;
    background: linear-gradient(to bottom, #fff, var(--vb-mau-giua, #808080), #000);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .14);
}
/* Nới vùng chạm của thanh hẹp lên ~28px mà không nới phần nhìn thấy. */
.vb-sang::before {
    content: "";
    position: absolute;
    inset: 0 -6px;
}
.vb-sang__diem {
    position: absolute;
    left: 50%;
    width: 22px;
    height: 8px;
    margin: -4px 0 0 -11px;
    border-radius: 3px;
    background: #fff;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, .55);
    pointer-events: none;
}
.vb-so-sanh {
    display: flex;
    align-items: center;
    gap: .35rem;
    margin-top: .6rem;
    font-size: .6875rem;
    font-weight: 700;
    color: var(--stone-600, #57534E);
}
.vb-so-sanh__moi,
.vb-so-sanh__cu {
    flex: 1;
    height: 1.5rem;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .14);
}
.vb-so-sanh__moi { border-radius: 6px 0 0 6px; }
.vb-so-sanh__cu { border-radius: 0 6px 6px 0; }

.vb-bang-mau__hex {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin-top: .75rem;
}
.vb-bang-mau__xem {
    flex-shrink: 0;
    width: 2rem;
    height: 2rem;
    border-radius: 6px;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .14);
}
.vb-bang-mau__o-hex {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    flex: 1;
    min-width: 0;
    height: 2rem;
    padding: 0 .5rem;
    border: 1px solid var(--stone-300, #D6D3D1);
    border-radius: 6px;
    background: #fff;
    font-size: .8125rem;
    font-weight: 700;
    color: var(--stone-500, #78716C);
}
.vb-bang-mau__o-hex:focus-within { outline: 2px solid var(--navy-500, #2C4A6E); outline-offset: 1px; }
/* Mã sai: viền đỏ + dòng báo lỗi đỏ bên dưới (trạng thái lỗi của ô nhập theo hệ thiết kế). */
.vb-bang-mau__o-hex--loi { border-color: #B91C1C; }
.vb-bang-mau__o-hex input {
    width: 100%;
    min-width: 0;
    border: 0;
    outline: none;
    background: transparent;
    font: inherit;
    color: var(--navy-900, #0D1F33);
    text-transform: uppercase;
    letter-spacing: .04em;
    font-variant-numeric: tabular-nums;
}
/* Safari iOS phóng to cả trang khi chạm vào ô nhập chữ nhỏ hơn 16px. */
@media (pointer: coarse) {
    .vb-bang-mau__o-hex input { font-size: 16px; }
}
.vb-bang-mau__ap {
    height: 2rem;
    padding: 0 .75rem;
    border-radius: 6px;
    background: var(--navy-900, #0D1F33);
    color: #fff;
    font-size: .75rem;
    font-weight: 800;
    transition: background-color var(--ao-nhanh, 150ms);
}
.vb-bang-mau__ap:hover { background: var(--navy-700, #16324F); }
.vb-bang-mau__loi {
    margin-top: .35rem;
    font-size: .75rem;
    font-weight: 600;
    color: #B91C1C;
}
.vb-bang-mau__loi:empty { display: none; }

/* Trên điện thoại và iPad cầm dọc, thanh công cụ bám ĐÁY màn hình: tay cầm bút
   ở dưới, với lên đỉnh màn hình là bỏ chỗ đang viết. */
@media (max-width: 767px) {
    .thanh-viet-bai {
        position: fixed;
        top: auto;
        left: .5rem;
        right: .5rem;
        bottom: .5rem;
        margin: 0;
        justify-content: center;
        box-shadow: 0 -4px 18px rgba(27, 58, 92, .14);
    }
    /* Chừa chỗ cho thanh cố định, không thì nó che mất dòng cuối của câu. Theo bề cao đo được của
       thanh (--vb-thanh-cao, máy viết bài ghi), vì thanh xuống hàng và cao thêm khi cầm bút.
       Cộng thêm dải bản nháp khi có (--vb-nhap-cao): trên điện thoại dải nằm TRÊN thanh, nên hai thứ
       cộng lại mới là phần đáy màn hình bị che. */
    .dang-viet-bai { padding-bottom: calc(var(--vb-thanh-cao, 3.5rem) + var(--vb-nhap-cao, 0px) + 1rem); }
}

/* ---- Tờ giấy kẻ dòng đặt dưới đề ----
   VÌ SAO PHẢI CÓ (số đo, không phải phỏng đoán): bộ cắt của dự án cắt SÁT phần đề
   bài, phần giấy trắng có kẻ dòng bên dưới phần lớn bị bỏ lại. Đo 30 ảnh ngẫu
   nhiên mỗi môn ngày 29/08/2026: 9709 chỉ 9/30 ảnh còn dòng kẻ và tổng cộng 11
   dòng, chiều cao trung vị 177px, tức gần như không còn chỗ nào để viết. Nếu chỉ
   dựa vào dòng kẻ in sẵn thì tính năng này vô dụng với đúng môn đông câu nhất.
   Tờ giấy này là chỗ viết thật; dòng kẻ in sẵn trong ảnh là phần thêm khi ảnh có. */
.vb-giay {
    margin-top: .75rem;
    background: #fff;
    border: 1px solid var(--stone-200, #E7E5E4);
    border-radius: var(--ao-r-nho);
    overflow: hidden;
}

.vb-giay__nhan {
    padding: .375rem .75rem;
    font-size: .625rem;
    font-weight: 800;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--stone-500, #78716C);
    background: var(--stone-50, #FAFAF9);
    border-bottom: 1px solid var(--stone-200, #E7E5E4);
}

/* Lớp gõ của tờ giấy KHÔNG absolute như lớp phủ trên ảnh: nó không nằm chồng lên
   thứ gì, nó tự chiếm chỗ trong dòng chảy của trang và tự cao lên khi giấy dài
   ra. Chiều cao do JS đặt bằng calc(var(--vb-rong) * n). */
.vb-lop--giay {
    position: relative;
    inset: auto;
}

/* Vạch kẻ vẽ bằng DOM chứ không bằng repeating-linear-gradient, vì ô gõ đặt theo
   cùng một công thức toạ độ; hai công thức song song là kiểu gì cũng có ngày lệch
   nhau nửa pixel rồi chữ nằm chông chênh trên vạch. */
.vb-vach-giay {
    position: absolute;
    left: calc(var(--vb-rong) * .04);
    right: calc(var(--vb-rong) * .03);
    height: 0;
    border-bottom: 1px dotted var(--stone-300, #D6D3D1);
    pointer-events: none;
}

/* ---- Bút vẽ (29/08/2026) ---- */
/* Canvas nét bút phủ kín lớp, KHÔNG nhận sự kiện: pointer bắt trên chính lớp
   (gaButChoLop trong luyen-de-viet-bai.js) và gác theo chế độ, nên ở chế độ Chữ
   canvas không cản một cú bấm nào vào dòng kẻ hay ô chữ. */
.vb-but {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
}

/* Đang cầm bút hoặc tẩy. touch-action: none là điều kiện để vẽ bằng MỘT ngón
   trên iPad — không tắt thì trình duyệt giành ngón tay để cuộn trang và nét đứt
   quãng; cuộn trong lúc vẽ thì dùng hai ngón. Chỉ áp khi chế độ vẽ đang bật,
   chế độ Chữ giữ nguyên cuộn một ngón như mọi trang web. */
.vb-lop--ve {
    touch-action: none;
    cursor: crosshair;
}
/* Ở chế độ vẽ, chữ bên dưới không bắt chuột nữa: nét vẽ đi NGANG QUA một dòng
   chữ phải liền mạch, không bị ô chữ nuốt mất sự kiện giữa chừng. */
.vb-lop--ve .vb-go,
.vb-lop--ve .vb-tay,
.vb-lop--ve .vb-keo,
.vb-lop--ve .vb-xoa {
    pointer-events: none;
}

/* ---- Công cụ Chọn kiểu Canva (13/09/2026) ----
   Dựng bởi veKhungChon trong luyen-de-viet-bai.js. Toạ độ tính theo --vb-rong như ô chữ tự do. z-index ở đây
   là trong lòng lớp phủ (.vb-lop tự lập ngữ cảnh xếp chồng ở bậc 2), không phải bậc của trang. */
.vb-lop--tren-muc { cursor: move; }
/* Công cụ Ô chữ: bấm vào đâu cũng đặt ô, kể cả lên một dòng đã có chữ, nên ô gõ tạm không bắt chuột. Không
   tắt cuộn một ngón như lớp vẽ: đặt ô là một cú chạm (click), không phải một nét kéo. */
.vb-lop--dat-o { cursor: crosshair; }
.vb-lop--dat-o .vb-go,
.vb-lop--dat-o .vb-tay,
.vb-lop--dat-o .vb-keo,
.vb-lop--dat-o .vb-xoa { pointer-events: none; }

.vb-khung-chon {
    position: absolute;
    z-index: 5;
    box-sizing: border-box;
    border: 1.5px solid var(--navy-600, #234C7C);
    border-radius: 2px;
    /* Viền trắng mảnh bên ngoài: khung vẫn thấy rõ khi nằm đè lên chữ in đen của đề. */
    box-shadow: 0 0 0 1px rgba(255, 255, 255, .9);
    cursor: move;
    /* Ngón tay kéo nét ĐÃ chọn: trong khung thì trình duyệt không được giành ngón tay để cuộn trang, không
       thì pointercancel bắn giữa chừng và nét không nhúc nhích. Ngoài khung vẫn cuộn một ngón như thường. */
    touch-action: none;
}
.vb-khung-chon[hidden] { display: none; }
/* TẤM ẢNH ĐANG CÓ KHUNG CHỌN (14/09/2026). Ôn Tập cắt đề thành từng dải, có dải chỉ cao 41px: khung chọn, hai góc trên
   và thanh nhỏ Nhân đôi / Xoá thò ra ngoài dải, bị overflow: hidden của .khung-anh-de cắt mất, và lớp của dải kế bên
   (cùng z-index 2, đứng sau trong DOM) đè lên. Lúc đó cho đúng tấm này tràn THEO CHIỀU DỌC và nổi lên bậc 3.
   - Chỉ tràn dọc: chiều ngang vẫn cắt (clip, không lập khung cuộn), vì khung sát mép phải tờ đề mà tràn ngang thì khung
     cuộn .khung-viet-cuon mọc thêm một đoạn cuộn ngang. Trình duyệt chưa có clip thì bỏ dòng đó, tràn cả hai chiều.
   - Bậc 3 so với bậc 2 của các dải khác trong cùng khối ảnh câu, vẫn dưới thanh công cụ viết bài (30). Khối bọc các
     dải KHÔNG được lập ngữ cảnh xếp lớp riêng, không thì phần khung thò xuống tờ giấy (.vb-lop--giay, bậc 2, đứng
     ngoài khối) bị tờ giấy giành cú bấm: xem .khoi-anh-cau trong practice.css (hiệu ứng hiện dần phải là backwards).
   - :has thay cho class vì .khung-anh-de nằm trong template Vue (Vue giữ quyền class của nó). Trình duyệt chưa có :has
     thì chỉ mất phần tràn, giữ nguyên hành vi cũ.
   - Dòng gõ, ô chữ tự do, vùng khoanh nằm trong .vb-lop__chu và lớp đó VẪN cắt tràn lúc này, nên ô chữ kéo lố đáy ảnh
     không lòi sang dải bên dưới. Chỉ khung chọn (con trực tiếp của .vb-lop) được thò ra.
   Chỗ đặt thanh nhỏ theo phần nhìn thấy: datChoThanhChon trong luyen-de-viet-bai.js. */
.vb-lop--dang-chon { z-index: 3; }
.khung-anh-de:has(> .vb-lop--dang-chon) {
    overflow: visible;
    overflow-x: clip;
}
/* Hết cắt tràn dọc thì góc bo của tấm ảnh là của chính ảnh (ảnh trang Kho Đề không mang class bo góc). */
.khung-anh-de:has(> .vb-lop--dang-chon) > img { border-radius: inherit; }

/* Lớp chữ: dựng bởi lopChu trong luyen-de-viet-bai.js. Phủ đúng hộp lớp, không bắt chuột (con của nó thì bắt, và sự
   kiện vẫn nổi bọt lên .vb-lop). Chỉ cắt tràn khi tấm ảnh đang tràn; lúc thường .khung-anh-de cắt như trước, còn tờ giấy
   (có chế độ tự cuộn) không bao giờ bị lớp này cắt. clip sau hidden: hidden là dự phòng, clip không lập khung cuộn nên
   con trỏ gõ sát đáy không cuộn ngầm lớp này. */
.vb-lop__chu {
    position: absolute;
    inset: 0;
    pointer-events: none;
}
/* :where cho độ ưu tiên bằng 0: luật riêng của từng thứ (.vb-khoanh không bắt chuột, .vb-lop--ve .vb-go...) vẫn thắng. */
:where(.vb-lop__chu) > * { pointer-events: auto; }
.khung-anh-de > .vb-lop--dang-chon > .vb-lop__chu {
    overflow: hidden;
    overflow: clip;
}
.vb-thanh-chon {
    position: absolute;
    left: 50%;
    bottom: calc(100% + 8px);
    transform: translateX(-50%);
    display: flex;
    gap: 2px;
    padding: 3px;
    background: #fff;
    border: 1px solid var(--stone-200, #E7E5E4);
    border-radius: var(--ao-r-nho, 14px);
    box-shadow: var(--ao-bong-cao, 0 8px 16px rgba(13, 31, 51, .07), 0 24px 48px rgba(13, 31, 51, .13));
    cursor: default;
    white-space: nowrap;
    /* Nổi trên bốn góc co giãn (cùng nằm trong khung chọn, đứng sau thanh trong DOM): lúc khe hẹp thanh được đặt đè
       lên khung, góc mà nằm trên nút thì cú bấm Xoá thành cú kéo co giãn. */
    z-index: 1;
}
/* Phía trên khung không đủ chỗ nhìn thấy (sát đầu khung cuộn, ngay dưới thanh công cụ dính): thanh nhỏ xuống dưới. */
.vb-khung-chon--thanh-duoi .vb-thanh-chon { bottom: auto; top: calc(100% + 8px); }
/* Khe hẹp, cả trên lẫn dưới đều không đủ chỗ: JS đặt top bằng px ngay chỗ tâm hai nút bấm được (choThanhTrongKhe). */
.vb-khung-chon--thanh-kep .vb-thanh-chon { bottom: auto; }
.vb-thanh-chon__nut {
    width: 2rem;
    height: 2rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: calc(var(--ao-r-nho, 14px) - 4px);
    color: var(--navy-800, #152E4D);
    background: transparent;
    transition: background-color .15s;
}
.vb-thanh-chon__nut:hover { background: var(--stone-100, #F5F5F4); }
.vb-thanh-chon__nut:focus-visible { outline: 2px solid var(--navy-600, #234C7C); outline-offset: 1px; }

/* Bốn góc co giãn. Phần nhìn thấy nhỏ (11px) cho khỏi che nét, vùng bấm nới ra 29px bằng ::before để ngón tay
   vẫn trúng. Góc trên trái / dưới phải kéo chéo xuôi, hai góc kia chéo ngược. */
.vb-khung-chon__goc {
    position: absolute;
    width: 11px;
    height: 11px;
    box-sizing: border-box;
    background: #fff;
    border: 1.5px solid var(--navy-600, #234C7C);
    border-radius: 2px;
}
.vb-khung-chon__goc::before { content: ""; position: absolute; inset: -9px; }
.vb-khung-chon__goc--tl { left: -6px; top: -6px; cursor: nwse-resize; }
.vb-khung-chon__goc--br { right: -6px; bottom: -6px; cursor: nwse-resize; }
.vb-khung-chon__goc--tr { right: -6px; top: -6px; cursor: nesw-resize; }
.vb-khung-chon__goc--bl { left: -6px; bottom: -6px; cursor: nesw-resize; }
/* Góc sát mép phần nhìn thấy (khung cuộn, thanh dính, mép màn hình) thì thụt vào trong khung cho khỏi mất nửa ô. */
.vb-khung-chon--sat-tren .vb-khung-chon__goc--tl,
.vb-khung-chon--sat-tren .vb-khung-chon__goc--tr { top: 0; }
.vb-khung-chon--sat-duoi .vb-khung-chon__goc--bl,
.vb-khung-chon--sat-duoi .vb-khung-chon__goc--br { bottom: 0; }
.vb-khung-chon--sat-trai .vb-khung-chon__goc--tl,
.vb-khung-chon--sat-trai .vb-khung-chon__goc--bl { left: 0; }
.vb-khung-chon--sat-phai .vb-khung-chon__goc--tr,
.vb-khung-chon--sat-phai .vb-khung-chon__goc--br { right: 0; }

/* Bảng chọn hình / kiểu đường: đi chung khung .vb-bang-mau (dungManHinh trong luyen-de-viet-bai.js). */
.vb-bang-hinh {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: .375rem;
}
.vb-o-hinh {
    aspect-ratio: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: .5rem;
    border-radius: calc(var(--ao-r-nho, 14px) - 4px);
    background: var(--stone-50, #FAFAF9);
    border: 1px solid transparent;
    color: var(--navy-800, #152E4D);
    transition: background-color .15s, border-color .15s;
}
.vb-o-hinh:hover { background: var(--stone-100, #F5F5F4); }
.vb-o-hinh[aria-pressed="true"] { border-color: var(--navy-600, #234C7C); background: #fff; }
.vb-o-hinh:focus-visible { outline: 2px solid var(--navy-600, #234C7C); outline-offset: 1px; }
.vb-o-hinh svg { width: 100%; height: 100%; overflow: visible; }
.vb-o-hinh polyline {
    fill: none;
    stroke: currentColor;
    stroke-width: 520;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.vb-bang-hinh__ghi {
    margin: .625rem 0 0;
    font-size: .6875rem;
    line-height: 1.45;
    color: var(--stone-500, #78716C);
}

/* Khung khoanh vùng lúc kéo chuột từ chỗ trống. */
.vb-khoanh {
    position: absolute;
    z-index: 5;
    pointer-events: none;
    border: 1px solid var(--navy-600, #234C7C);
    background: rgba(35, 76, 124, .08);
}

/* Ba nút độ dày trên thanh công cụ: chính chấm tròn là mẫu độ dày. */
.vb-net {
    width: 2rem;
    height: 2rem;
    border-radius: var(--ao-r-nho);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--stone-100, #F5F5F4);
    transition: background-color .15s;
}
.vb-net:hover { background: var(--stone-200, #E7E5E4); }
.vb-net[aria-pressed="true"] { background: var(--navy-600, #234C7C); }
.vb-net span {
    border-radius: 50%;
    background: var(--stone-600, #57534E);
}
.vb-net[aria-pressed="true"] span { background: #fff; }
.vb-net--manh span { width: 4px; height: 4px; }
.vb-net--vua span { width: 7px; height: 7px; }
.vb-net--dam span { width: 11px; height: 11px; }

/* ---- Khung cuộn cố định khi đang Viết Bài (29/08/2026) ----
   Câu 9618 dài ba màn hình cộng tờ giấy làm bài dài vô hạn: cuộn cả trang thì
   thanh công cụ viết trôi mất và cảm giác "đang làm bài trên một tờ đề" vỡ vụn.
   Khung này cao vừa phần màn hình còn lại dưới header + hai thanh công cụ, cuộn
   bên trong, mọi thứ quanh nó đứng yên.
   100dvh chứ không phải 100vh: trên iPad thanh địa chỉ Safari thò thụt làm 100vh
   sai cả trăm pixel, dvh mới là chiều cao nhìn thấy thật. */
.khung-viet-cuon {
    max-height: calc(100dvh - 16.5rem);
    overflow-y: auto;
    /* Cuộn NGANG nữa, không chỉ dọc: phóng tờ đề quá bề ngang khung thì phải với tới được mép
       phải, nếu không phần đề bên phải bị cắt và không có cách nào xem. Ở cỡ 100% tờ giấy vẫn
       vừa khung nên thanh cuộn ngang không hiện, hành vi cũ giữ nguyên. */
    overflow-x: auto;
    overscroll-behavior: contain;
    padding-right: .25rem;
}
@supports not (height: 100dvh) {
    .khung-viet-cuon { max-height: calc(100vh - 16.5rem); }
}
/* Điện thoại: thanh công cụ viết bám ĐÁY màn hình (fixed, xem .thanh-viet-bai),
   nên phần trừ gồm cả nó lẫn header. */
@media (max-width: 767px) {
    .khung-viet-cuon { max-height: calc(100dvh - 15rem); }
}

/* ---- Ba chỗ ở của tờ Giấy Làm Bài (29/08/2026) ----
   'trong' (mặc định): nằm dưới ảnh đề như cũ, không class nào thêm.
   'noi':  cửa sổ nổi kéo quanh màn hình, thanh nhãn là tay cầm.
   'chia': ghim vào nửa phải màn hình như tờ insert, đề bên trái.
   Trạng thái nằm trong máy chữ (trangThai.cheDoGiay) nên sống qua mọi lần Vue
   vẽ lại; ba nút chuyển nằm ngay trên thanh nhãn của tờ giấy. */
.vb-giay__nhan {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
}
.vb-giay__ten { min-width: 0; }
.vb-giay__nut-cum { display: flex; align-items: center; gap: .25rem; flex-shrink: 0; }
.vb-giay__nut {
    width: 1.5rem;
    height: 1.5rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--ao-r-nho);
    color: var(--stone-500, #78716C);
    font-size: .7rem;
    transition: background-color .15s, color .15s;
}
.vb-giay__nut:hover { background: var(--stone-200, #E7E5E4); color: var(--navy-800, #1B3A5C); }
/* Nút × chỉ có nghĩa khi đang là cửa sổ nổi. */
.vb-giay__nut--dong { display: none; }
.vb-giay--noi .vb-giay__nut--dong { display: inline-flex; }
.vb-giay--noi .vb-giay__nut--noi,
.vb-giay--chia .vb-giay__nut--chia { background: var(--navy-600, #234C7C); color: #fff; }

/* Cửa sổ nổi. z-index 30: cùng bậc thanh công cụ viết trong bảng DESIGN_SYSTEM,
   dưới header dính (40) nên không bao giờ che thanh điều hướng chính. left/top
   do máy chữ đặt bằng inline style lúc kéo. */
.vb-giay--noi {
    position: fixed;
    z-index: 30;
    width: min(560px, 92vw);
    max-height: 72dvh;
    margin-top: 0;
    display: flex;
    flex-direction: column;
    box-shadow: 0 18px 48px rgba(27, 58, 92, .28);
}
.vb-giay--noi .vb-giay__nhan { cursor: move; touch-action: none; user-select: none; }
.vb-giay--noi .vb-lop--giay { overflow-y: auto; flex: 1 1 auto; }

/* Chia đôi màn hình: tờ giấy ghim nửa phải, đề thu về nửa trái. */
.vb-giay--chia {
    position: fixed;
    z-index: 30;
    top: 9.5rem;
    right: .75rem;
    bottom: .75rem;
    width: 42vw;
    margin-top: 0;
    display: flex;
    flex-direction: column;
    box-shadow: 0 10px 30px rgba(27, 58, 92, .16);
}
.vb-giay--chia .vb-lop--giay { overflow-y: auto; flex: 1 1 auto; }
/* Khung câu hỏi nhường chỗ: class do máy chữ bật/tắt cùng nhịp với chế độ. */
.khung-chia-giay { margin-right: calc(42vw + .5rem); }

/* Điện thoại không đủ chỗ chia đôi: chế độ chia rơi về dạng nổi toàn cỡ ở nửa
   dưới màn hình, vẫn kéo lên đọc đề phía trên được. */
@media (max-width: 767px) {
    .vb-giay--chia {
        top: auto;
        left: .5rem;
        right: .5rem;
        bottom: 5rem;   /* chừa thanh công cụ viết đang bám đáy */
        height: 44dvh;
        width: auto;
    }
    .khung-chia-giay { margin-right: 0; }
}


/* ===========================================================================
   BIẾN THỂ CHO TRANG XEM ĐỀ (chế độ Làm Bài, 30/08/2026)
   ===========================================================================
   Hai con số của bản gốc đều đo theo bố cục trang Luyện Đề: thanh công cụ dính
   dưới header 5rem cộng thanh công cụ câu, còn cột cuộn thì trừ chiều cao màn
   hình. Trang Xem Đề không có cả hai thứ đó: nó chia màn hình thành khung cố
   định sẵn bằng flex, nên ở đây thanh nằm thành một hàng riêng và cột trang chỉ
   việc lấp đầy khung cha.
   =========================================================================== */

/* Thanh công cụ thành MỘT HÀNG dưới header, không dính, không bo góc, chỉ còn
   viền đáy để tách khỏi khung xem. */
.thanh-viet-bai--hang {
    position: static;
    top: auto;
    margin-bottom: 0;
    border-width: 0 0 1px 0;
    border-radius: 0;
    box-shadow: none;
}

/* Cột trang nằm trong khung đã có chiều cao sẵn: lấp đầy khung cha thay vì tự
   tính theo chiều cao màn hình. */
.khung-viet-cuon--trong-khung {
    max-height: 100%;
    height: 100%;
    padding: .75rem .5rem;
}
/* Chừa 1.25rem ở đáy khung cuộn (14/09/2026) cho góc co giãn (thò 6px) và vùng bấm nới của nó (thêm 9px) khi chọn một nét
   sát đáy dải ảnh CUỐI. Thiếu chỗ này thì chúng thành phần tràn cuộn được: khung cuộn mọc thêm một đoạn mỗi lần chọn,
   và máy có thanh cuộn chiếm chỗ (Windows) còn hiện thanh cuộn làm cả cột đề co lại rồi bung ra khi bỏ chọn. Khung chọn
   thì đã kẹp trong ảnh (veKhungChon). Dùng một khối đệm ::after thay vì padding-bottom: padding-bottom của phần tử này
   đã có ba luật khác giành nhau (.dang-viet-bai chừa chỗ cho thanh công cụ bám đáy điện thoại, .viet-tren-de.dang-viet-bai
   ở Kho Đề, dạng viết gọn của --trong-khung), đè vào là mất chỗ chừa cho thanh đáy. */
.khung-viet-cuon::after {
    content: "";
    display: block;
    height: 1.25rem;
}

/* Trang đề rộng gần bằng cả khung, nên chừa hai bên một chút cho ô chữ thả tự do
   ở sát mép vẫn kéo được, và giữ chúng nằm giữa khi khung rộng hơn trang. */
.viet-tren-de .khung-anh-de {
    /* BỀ NGANG TỜ GIẤY = khổ chuẩn nhân với cỡ phóng người dùng chọn (--vb-phong, mặc định 1).
       Hệ số .75 là MỐC 100% MỚI (lệnh chủ dự án 31/08): mốc cũ min(100%, 1240px) bị chê quá to,
       nên 100% bây giờ bằng ba phần tư mốc cũ. Muốn đổi lại cỡ mặc định thì sửa đúng số này,
       đừng sửa 1240px — con số đó là khổ giấy trần, không phải cỡ hiển thị.
       Phóng quá bề ngang khung thì tràn ra, và .khung-viet-cuon cho cuộn ngang.
       ĐỔI BỀ NGANG chứ KHÔNG transform: scale() — lớp viết lưu toạ độ theo tỉ lệ trên bề ngang
       (luyen-de-viet-bai.js) và có ResizeObserver vẽ lại, nên bài làm cũ giữ nguyên vị trí. */
    width: calc(min(100%, 1240px) * .75 * var(--vb-phong, 1));
    margin-left: auto;
    margin-right: auto;
    box-shadow: 0 1px 6px rgba(27, 58, 92, .10);
}

/* Điện thoại: thanh công cụ của trang Luyện Đề bám đáy màn hình, nhưng ở trang
   Xem Đề nó là một hàng trong dòng chảy nên phải huỷ luật đó, không thì nó nhảy
   xuống che mất cột phải. */
@media (max-width: 767px) {
    .thanh-viet-bai--hang {
        position: static;
        left: auto;
        right: auto;
        bottom: auto;
    }
    /* Luật chừa chỗ cho thanh bám đáy không còn đúng ở đây: thanh đã nằm thành
       một hàng riêng, chừa thêm 4,5rem chỉ tổ để lại một dải trống cuối cột.
       NHƯNG dải bản nháp thì VẪN bám đáy màn hình ở trang này, nên phần chừa cho nó phải giữ lại:
       luật này đè lên luật chung ở trên (cùng số media query, chọn lọc hơn), bỏ --vb-nhap-cao ra
       là dải che mất cuối cột phải, đúng chỗ em đang viết. */
    .viet-tren-de.dang-viet-bai { padding-bottom: calc(var(--vb-nhap-cao, 0px) + .75rem); }
}

/* ---- THÔNG BÁO BẢN NHÁP (11/09/2026) ----
   Bản bài làm ở máy này đã bị thay bằng bản mới hơn trên máy chủ (một tab / máy khác vừa lưu). Máy viết
   bài tự dựng dải này (hienNhap trong luyen-de-viet-bai.js) nên bốn trang dùng máy không sửa gì. Cố định
   ở đáy màn hình; trên điện thoại nằm TRÊN thanh công cụ bám đáy (--vb-thanh-cao). Cùng bậc z-index 65
   với bảng màu viết bài (bảng z-index trong DESIGN_SYSTEM.md). Vạch vàng bên trái là dấu "cần em chọn",
   không phải dấu lỗi: không có gì bị mất. */
.vb-nhap {
    position: fixed;
    left: 50%;
    bottom: 1.25rem;
    z-index: 65;
    box-sizing: border-box;
    width: min(38rem, calc(100vw - 1.5rem));
    transform: translateX(-50%);
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: .75rem;
    row-gap: .625rem;
    align-items: start;
    padding: .875rem 1rem;
    background: #fff;
    border: 1px solid var(--stone-200, #E7E5E4);
    border-left: 4px solid var(--gold-500, #C08A2E);
    border-radius: var(--ao-r-nho, 14px);
    box-shadow: var(--ao-bong-cao, 0 8px 16px rgba(13, 31, 51, .07), 0 24px 48px rgba(13, 31, 51, .13));
    font-family: "Plus Jakarta Sans", system-ui, sans-serif;
    color: var(--navy-900, #0D1F33);
}
.vb-nhap[hidden] { display: none; }
/* Dải bám đáy màn hình nên nó CHE phần cuối trang: chừa đúng bề cao đo được (--vb-nhap-cao, máy viết
   bài ghi, đã cộng sẵn khoảng cách trên dưới). Không có dải thì biến bị gỡ hẳn và chỗ chừa về 0, chứ
   không để lại một vệt trắng dưới chân câu. Trên điện thoại phần chừa nằm trong khối cộng với
   --vb-thanh-cao ở media query phía trên, nên luật này chỉ dành cho màn rộng. */
@media (min-width: 768px) {
    .dang-viet-bai { padding-bottom: var(--vb-nhap-cao, 0px); }
}
.vb-nhap__bieu {
    grid-row: 1 / span 2;
    margin-top: .2rem;
    color: var(--gold-600, #A6741F);
}
.vb-nhap__chu {
    margin: 0;
    font-size: .875rem;
    line-height: 1.5;
}
.vb-nhap__nut {
    grid-column: 2;
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
}
.vb-nhap__chinh,
.vb-nhap__phu {
    min-height: 2.25rem;
    padding: .4rem .9rem;
    border-radius: 999px;
    font: inherit;
    font-size: .8125rem;
    font-weight: 700;
    cursor: pointer;
    transition: background-color var(--ao-nhanh, 150ms), border-color var(--ao-nhanh, 150ms);
}
.vb-nhap__chinh {
    border: 1px solid var(--navy-900, #0D1F33);
    background: var(--navy-900, #0D1F33);
    color: #fff;
}
.vb-nhap__chinh:hover { background: var(--navy-700, #1B3A5C); border-color: var(--navy-700, #1B3A5C); }
.vb-nhap__phu {
    border: 1px solid var(--stone-300, #D6D3D1);
    background: #fff;
    color: var(--navy-900, #0D1F33);
}
.vb-nhap__phu:hover { background: var(--stone-100, #F5F5F4); }
@media (max-width: 767px) {
    .vb-nhap { bottom: calc(var(--vb-thanh-cao, 0px) + 1rem); }
}

/* ===========================================================================
   CỘT CÔNG CỤ VIẾT BÀI Ở TRANG ÔN TẬP (15/09/2026)
   ===========================================================================
   Chủ dự án: "đẩy cái thanh mục bút các thứ sang bên tay phải thành một cái cột đi cho tăng diện tích nhìn
   câu hỏi". Thanh ngang hai hàng cũ dính ở top 8.5rem ăn 98px chiều cao màn hình (162px ở bề ngang 1024px), và
   khi thanh công cụ câu xuống hai hàng thì nó dính ĐÈ lên hàng thứ hai, che mất chính nút Viết Bài. Nay từ 768px:
     - thẻ xem câu (.the-xem-cau--viet) cao tối đa vừa màn hình dưới header và chia dọc: thanh công cụ câu ở trên,
       hàng viết bài lấy phần còn lại. Flex tự trừ bề cao thanh công cụ câu dù nó một hay hai hàng, thay cho con
       số calc(100dvh - 16.5rem) cũ chỉ đúng khi mọi thanh đều một hàng (đo ở 1440x900 khung thò khỏi đáy màn
       hình 54px, ở 1024x768 là 118px);
     - hàng viết bài (.vung-viet-bai--cot) = [khung cuộn câu hỏi | cột công cụ]. Cột đứng TRƯỚC trong DOM (Tab đi
       qua công cụ trước) nên xếp sang phải bằng order;
     - cột là lưới ba ô: nút đơn chiếm một ô, nút tách đôi (thân + mũi tên mở bảng) chiếm trọn một hàng.
   Dưới 768px thanh vẫn nằm ngang bám đáy màn hình; chỉ phần thẻ cao vừa màn hình là dùng chung (điện thoại cũng
   dính đúng lỗi khung thò khỏi đáy: thanh công cụ câu ở đó xuống bốn hàng). Chỉ Ôn Tập mang các lớp này; Bài
   tập, Bài test và Kho Đề giữ thanh của chúng. */
/* Bản chữ ngắn / biểu tượng chỉ dành cho cột dọc. Viết thêm .vb-nut để thắng display của lớp fa-solid. */
.vb-chi-cot,
.vb-nut .vb-chi-cot { display: none; }

.the-xem-cau--viet {
    display: flex;
    flex-direction: column;
    /* 5rem header dính + 0.75rem thở phía trên (đúng chỗ datLaiDiemDoc và cuonKhungXemVeDau đưa thẻ về) +
       0.75rem thở dưới đáy. */
    max-height: calc(100dvh - 6.5rem);
}
.the-xem-cau--viet > .thanh-cong-cu-cau { flex: none; }
/* Hàng viết bài kéo hai bên cao bằng nhau (stretch): khung cuộn co theo phần còn lại của màn hình, cột công cụ
   cuộn riêng khi màn hình quá thấp. KHÔNG dùng max-height: 100% cho cột: thẻ chỉ có max-height chứ không có
   height, nên phần trăm không quy ra được số nào và cột thò khỏi đáy thẻ. */
.the-xem-cau--viet > .vung-viet-bai {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    align-items: stretch;
}
.the-xem-cau--viet .vung-viet-bai__noi-dung {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
.the-xem-cau--viet .khung-viet-cuon {
    flex: 0 1 auto;
    min-height: 0;
    max-height: none;
}
@media (max-width: 767px) {
    /* Thanh công cụ viết bám đáy màn hình (fixed, bề cao --vb-thanh-cao, cách đáy .5rem): trừ luôn phần nó che. */
    .the-xem-cau--viet { max-height: calc(100dvh - 7rem - var(--vb-thanh-cao, 3.5rem)); }
}
@media (min-width: 768px) {
    .vung-viet-bai--cot {
        display: flex;
        align-items: flex-start;
        gap: .75rem;
    }
    .the-xem-cau--viet > .vung-viet-bai--cot { align-items: stretch; }
    .vung-viet-bai--cot > .vung-viet-bai__noi-dung {
        order: 1;
        flex: 1 1 auto;
        min-width: 0;
    }

    .thanh-viet-bai--cot {
        --vb-o: 1.625rem;     /* một ô lưới = bề ngang một nút đơn */
        --vb-khe: .125rem;
        order: 2;
        flex: none;
        flex-direction: column;
        flex-wrap: nowrap;
        align-items: center;
        gap: .375rem;
        margin: 0;
        padding: .375rem .3125rem;
        /* Thanh ray bên phải chứ không phải một hộp nổi: cột kéo cao bằng khung câu hỏi, nên một hộp có viền và bóng
           sẽ thành một ô trắng dài trống trơn dưới mấy nút. Nền trong suốt (thẻ bên dưới vốn trắng), chỉ một vạch
           dọc ngăn với câu hỏi. */
        background: transparent;
        border: 0;
        border-left: 1px solid var(--stone-200, #E7E5E4);
        border-radius: 0;
        box-shadow: none;
        /* Chia đôi với tờ insert thì khung câu hỏi không tự cuộn mà cả trang cuộn, và thanh công cụ câu cũng thôi
           ghim (.thanh-cong-cu-cau--khong-ghim): cột bám ngay dưới header. Ở thẻ đang viết thường cột kéo cao
           bằng hàng nên không còn chỗ để dính, hai dòng này vô hại. */
        top: 5.75rem;
        max-height: calc(100dvh - 6.5rem);
        overflow-y: auto;
        overscroll-behavior: contain;
    }
    .the-xem-cau--viet .thanh-viet-bai--cot {
        max-height: none;
        min-height: 0;
    }
    .thanh-viet-bai--cot > * { order: 3; }
    .thanh-viet-bai--cot > .thanh-viet-bai__nhom--cong-cu { order: 1; }
    /* Độ dày nét lên ngay dưới nhóm công cụ, gần cây bút đang cầm. Vẫn giữ chỗ lúc ẩn (.thanh-viet-bai__giu-cho)
       nên đổi công cụ không làm các nút phía dưới trượt đi. */
    .thanh-viet-bai--cot > .thanh-viet-bai__vach--net,
    .thanh-viet-bai--cot > .thanh-viet-bai__nhom--net { order: 2; }
    .thanh-viet-bai--cot > .thanh-viet-bai__trang-thai { order: 4; }

    .thanh-viet-bai--cot > .thanh-viet-bai__nhom {
        display: grid;
        grid-template-columns: repeat(3, var(--vb-o));
        gap: var(--vb-khe);
    }
    .thanh-viet-bai--cot .vb-nut {
        min-width: 0;
        width: 100%;
        padding: 0;
    }
    .thanh-viet-bai--cot .vb-tach {
        grid-column: 1 / -1;
        display: flex;
    }
    .thanh-viet-bai--cot .vb-tach .vb-tach__than { flex: 1 1 auto; width: auto; }
    .thanh-viet-bai--cot .vb-tach .vb-tach__mui { flex: 0 0 var(--vb-o); width: auto; min-width: 0; }
    .thanh-viet-bai--cot .vb-net { width: 100%; height: var(--vb-o); }
    /* Ô cỡ chữ gọn trong một ô: bỏ chữ "px" (nhãn trợ năng của ô đã nói "tính bằng pixel"). */
    .thanh-viet-bai--cot .vb-co {
        display: flex;
        align-items: center;
        justify-content: center;
        min-width: 0;
        height: 2rem;
        padding: 0;
    }
    .thanh-viet-bai--cot .vb-co__o { width: 100%; text-align: center; }
    .thanh-viet-bai--cot .vb-co__dv { display: none; }

    /* Vạch ngăn nhóm thành vạch NGANG. .thanh-viet-bai__ngat (chỗ ngắt hàng của thanh ngang) cũng là một vạch. */
    .thanh-viet-bai--cot > .thanh-viet-bai__vach,
    .thanh-viet-bai--cot > .thanh-viet-bai__ngat {
        flex: none;
        align-self: stretch;
        width: auto;
        height: 1px;
        margin: 0 .125rem;
        background: var(--stone-200, #E7E5E4);
    }

    .thanh-viet-bai--cot > .thanh-viet-bai__trang-thai {
        margin: 0;
        max-width: calc(3 * var(--vb-o) + 2 * var(--vb-khe));
        font-size: .625rem;
        line-height: 1.35;
        text-align: center;
        overflow-wrap: anywhere;
    }
    .thanh-viet-bai--cot .vb-chi-hang { display: none; }
    .thanh-viet-bai--cot .vb-chi-cot { display: inline; }
    .thanh-viet-bai--cot .vb-nut .vb-chi-cot { display: inline-block; }

    /* Tờ giấy chế độ CHIA ĐÔI ghim mép phải MÀN HÌNH, tức nằm đè lên cột công cụ. Đẩy nó sang trái cột bằng
       --ot-cot-phai (khoảng cách từ mép phải màn hình tới mép trái cột, practice.page.js đo), và cho đỉnh nó ngang
       đỉnh khung cuộn lúc thẻ đã neo dưới header (--ot-thanh-cau-cao là bề cao thanh công cụ câu, một hay hai hàng).
       VẪN GIỮ position: fixed của bản gốc: máy viết bài tính vùng nhìn thấy của thanh Nhân đôi / Xoá theo tổ tiên
       TRONG DOM, mà tờ giấy nằm trong khung cuộn; đổi sang absolute (bám khung nội dung) thì nó nghĩ tờ giấy nằm
       ngoài vùng khung cuộn và giấu luôn thanh đó — đã thử và bắt được bằng bộ bấm thử tờ giấy chia đôi.
       Bề ngang tờ giấy 42vw giữ nguyên, và .khung-chia-giay đã chừa 42vw + .5rem nên khung câu hỏi vẫn không chui
       xuống dưới tờ giấy (mép phải khung = mép trái cột - 12px). */
    .vung-viet-bai--cot .vb-giay--chia {
        /* 5rem header + 0.75rem thở (chỗ thẻ neo tới) + thanh công cụ câu + 1rem = đúng đỉnh khung cuộn; đáy 1.75rem
           = 0.75rem thở dưới thẻ + 1rem padding đáy thẻ. Bề ngang: chia đôi phần còn lại của hàng, không phải 42vw
           của bản gốc — 42vw tính theo cả màn hình nên ở đây nó nuốt gần hết chỗ, khung câu hỏi còn 120px. */
        top: calc(5.75rem + var(--ot-thanh-cau-cao, 6.25rem) + 1rem);
        bottom: 1.75rem;
        left: var(--ot-giay-trai, auto);
        right: var(--ot-cot-phai, .75rem);
        width: auto;
    }
    .vung-viet-bai--cot .khung-chia-giay { margin-right: var(--ot-giay-rong, calc(42vw + .5rem)); }
}
@media (min-width: 768px) and (pointer: coarse) {
    /* Ngón tay: ô 32px như nút của thanh ngang. */
    .thanh-viet-bai--cot { --vb-o: 2rem; --vb-khe: .25rem; }
}
@supports not (height: 100dvh) {
    .the-xem-cau--viet { max-height: calc(100vh - 6.5rem); }
    @media (max-width: 767px) {
        .the-xem-cau--viet { max-height: calc(100vh - 7rem - var(--vb-thanh-cao, 3.5rem)); }
    }
    @media (min-width: 768px) {
        .thanh-viet-bai--cot { max-height: calc(100vh - 6.5rem); }
    }
}
