/**
 * Giao dien trang tro ly ao — Chatbot AI LDLD TP.HCM
 *
 * Tach ra tu chat.tpl ngay 31/07/2026. Truoc do toan bo CSS nam thang trong the
 * <style> cua template: moi lan sua giao dien la phai sua file .tpl, va trinh duyet
 * khong cache duoc phan nay nen tai lai toan bo o moi luot xem trang.
 *
 * Trang nap file nay kem ?v=<thoi diem sua file> nen sau moi lan cap nhat, trinh
 * duyet tu lay ban moi — khong can bao nguoi dung xoa cache.
 *
 * @added    2026-07-31 by Tinh — P9.25 tach CSS khoi template
 * @modified 2026-08-01 by Tinh — P9.32 nhan vat len dau, duoi bong bong lat len,
 *           go .rail-voice/.switch/.field va ca hang toc do doc
 * @modified 2026-08-22 by Tinh — P9.36 mobile: bo the noi + nut mo, khoi tro ly co thanh vong tron
 */

:root {
    --bg:        #eef2f7;
    --surface:   #ffffff;
    --surface-2: #f7fafd;
    --line:      #e3eaf2;
    --ink:       #0f2740;
    --ink-soft:  #405a73;
    --muted:     #7b8ca0;
    --brand:     #004b8d;
    --brand-2:   #1d6fb8;
    --brand-ink: #ffffff;
    --ok:        #1b7f4b;
    --danger:    #c62828;
    --radius:    14px;
    --radius-sm: 9px;
    --shadow:    0 1px 2px rgba(15,39,64,.05), 0 8px 24px rgba(15,39,64,.06);
    --mono:      ui-monospace, SFMono-Regular, 'Cascadia Mono', Consolas, monospace;
}

* { box-sizing: border-box; }
html, body { height: 100%; }

/* Bàn phím phải thấy mình đang ở đâu. Trước đây không nút nào có viền focus nên
   người dùng Tab qua trang là mất dấu hoàn toàn. */
:focus-visible { outline: 2px solid var(--brand-2); outline-offset: 2px; border-radius: 4px; }

/* Trang có 4 hiệu ứng lặp vô hạn (chấm trạng thái, con trỏ gõ, vòng quay, micro).
   Ai bật "giảm chuyển động" trong hệ điều hành thì tắt hết. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
    }
}
body {
    margin: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: 'Segoe UI', system-ui, -apple-system, Tahoma, sans-serif;
    font-size: 14px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}
button { font-family: inherit; }

/* ---------------------------------------------------------------- */
/* Shell: thanh trái | hội thoại | trợ lý ảo                         */
/* ---------------------------------------------------------------- */
/*
 * Cài đặt giọng đọc nằm trong thanh trái. Cột phải chỉ còn trợ lý ảo và nội dung
 * bắt đầu ngay từ góc trên bên phải.
 */
.app {
    display: grid;
    grid-template-columns: 232px minmax(0, 1fr) 324px;
    grid-template-rows: minmax(0, 1fr);
    height: 100vh;
    overflow: hidden;
}
.rail        { grid-area: 1 / 1 / 2 / 2; }
.main        { grid-area: 1 / 2 / 2 / 3; }
.stage-block { grid-area: 1 / 3 / 2 / 4; }

/* ---- Left rail ---- */
.rail {
    background: var(--surface);
    border-right: 1px solid var(--line);
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow-y: auto;
}
.rail-brand {
    display: flex; align-items: center; gap: 10px;
    padding: 18px 16px 14px;
}
.rail-brand img {
    width: 32px; height: 32px; border-radius: 8px; object-fit: contain;
    background: var(--surface-2);
}
.rail-brand b { font-size: 14px; line-height: 1.25; letter-spacing: -.01em; }
.rail-nav { padding: 4px 10px; display: flex; flex-direction: column; gap: 2px; }
.rail-item {
    display: flex; align-items: center; gap: 10px;
    width: 100%; text-align: left;
    padding: 9px 10px; border: 0; border-radius: var(--radius-sm);
    background: transparent; color: var(--ink-soft);
    font-size: 13.5px; cursor: pointer;
}
.rail-item:hover { background: var(--surface-2); color: var(--ink); }
.rail-item.is-active { background: #e8f1fb; color: var(--brand); font-weight: 600; }
.rail-item svg { width: 17px; height: 17px; flex: none; stroke-width: 1.7; }
.rail-sep { margin: 12px 16px 6px; }
.session-search-wrap {
    position: relative; margin: 3px 10px 5px;
}
.session-search-wrap svg {
    position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
    width: 14px; height: 14px; color: var(--muted); stroke-width: 1.8;
    pointer-events: none;
}
.session-search-wrap input {
    width: 100%; height: 34px; padding: 6px 10px 6px 31px;
    border: 1px solid var(--line); border-radius: var(--radius-sm);
    background: var(--surface-2); color: var(--ink); font-size: 12.5px;
    outline: none;
}
.session-search-wrap input::placeholder { color: var(--muted); }
.session-search-wrap input:focus {
    border-color: var(--brand-2); background: var(--surface);
    box-shadow: 0 0 0 2px rgba(30,117,193,.10);
}
.rail-session-list {
    flex: 1 1 auto; min-height: 44px; overflow-y: auto;
    padding: 2px 10px 10px;
    scrollbar-width: thin; scrollbar-color: #c7d5e4 transparent;
}
.session-group-label {
    padding: 8px 9px 4px; color: var(--ink); font-size: 11.5px;
    line-height: 1.3; font-weight: 650;
}
.session-group-label[data-session-group="recent"] { margin-top: 5px; }
.session-row {
    position: relative; display: block; width: 100%;
    border-radius: var(--radius-sm); overflow: visible;
}
.session-item {
    display: flex; align-items: flex-start; gap: 8px;
    min-width: 0; width: 100%; padding: 8px 38px 8px 9px;
    border: 0; border-radius: var(--radius-sm);
    background: transparent; color: var(--ink-soft); text-align: left; cursor: pointer;
}
.session-row.is-pinned .session-item { padding-right: 62px; }
.session-row:hover .session-item,
.session-row.has-open-menu .session-item { background: var(--surface-2); color: var(--ink); }
.session-item.is-active { background: #e8f1fb; color: var(--brand); }
.session-row:hover .session-item.is-active,
.session-row.has-open-menu .session-item.is-active { background: #e8f1fb; color: var(--brand); }
.session-item svg {
    flex: none; width: 15px; height: 15px; margin-top: 2px; stroke-width: 1.7;
}
.session-copy { min-width: 0; flex: 1; }
.session-title {
    display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: 12.5px; line-height: 1.35; font-weight: 550;
}
.session-meta {
    display: block; margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    color: var(--muted); font-size: 10.5px; line-height: 1.3;
}
.session-item.is-active .session-title { font-weight: 650; }
.session-pin-indicator {
    position: absolute; right: 31px; top: 50%; transform: translateY(-50%);
    display: grid; place-items: center; width: 28px; height: 28px;
    color: var(--muted); pointer-events: none;
}
.session-pin-indicator svg { width: 13px; height: 13px; stroke-width: 1.8; }
.session-more {
    position: absolute; right: 3px; top: 50%; transform: translateY(-50%);
    display: grid; place-items: center; width: 28px; height: 28px;
    padding: 0; border: 0; border-radius: 7px; background: transparent;
    color: var(--muted); cursor: pointer; opacity: 0;
    transition: opacity .15s ease, color .15s ease, background-color .15s ease;
}
.session-more svg { width: 16px; height: 16px; }
.session-row:hover .session-more,
.session-row.has-open-menu .session-more,
.session-more:focus-visible { opacity: 1; }
.session-more:hover,
.session-more:focus-visible,
.session-row.has-open-menu .session-more {
    color: var(--ink); background: #e8eef5; outline: none;
}
@media (hover: none) { .session-more { opacity: .72; } }
.session-actions-menu {
    position: fixed; z-index: 70; width: 174px; padding: 5px;
    border: 1px solid #dbe3ec; border-radius: 10px;
    background: var(--surface); color: var(--ink);
    box-shadow: 0 12px 32px rgba(15,39,64,.18), 0 2px 8px rgba(15,39,64,.10);
}
.session-actions-menu[hidden] { display: none !important; }
.session-menu-item {
    display: flex; align-items: center; gap: 10px; width: 100%;
    padding: 8px 9px; border: 0; border-radius: 7px;
    background: transparent; color: var(--ink); text-align: left;
    font-size: 13px; cursor: pointer;
}
.session-menu-item svg {
    flex: none; width: 17px; height: 17px; stroke-width: 1.7;
}
.session-menu-item:hover,
.session-menu-item:focus-visible { background: var(--surface-2); outline: none; }
.session-menu-item.is-danger { color: #b42318; }
.session-menu-item.is-danger:hover,
.session-menu-item.is-danger:focus-visible { background: #fff0ee; }
.session-menu-item:disabled { color: #aeb8c3; cursor: not-allowed; background: transparent; }
.session-menu-item.is-loading svg { animation: session-menu-pulse .7s ease-in-out infinite alternate; }
.session-menu-separator { height: 1px; margin: 4px 5px; background: var(--line); }
@keyframes session-menu-pulse { to { opacity: .25; } }
.session-list-empty { padding: 8px 10px; color: var(--muted); font-size: 11.5px; }
.session-search-empty {
    padding: 10px; color: var(--muted); font-size: 11.5px; text-align: center;
}
.rail-foot { margin-top: auto; padding: 10px; border-top: 1px solid var(--line); }
.rail-who {
    padding: 8px 10px; border-radius: var(--radius-sm);
    background: var(--surface-2); margin-bottom: 8px;
}
.rail-who .who-name { font-weight: 600; font-size: 13px; }
.rail-who .who-meta { font-size: 12px; color: var(--muted); word-break: break-word; }

.label {
    font-family: var(--mono);
    font-size: 11.5px; letter-spacing: .06em;
    color: var(--muted); text-transform: lowercase;
}

/* ---- Main column ---- */
.main { position: relative; display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.topbar {
    display: flex; align-items: center; gap: 12px;
    padding: 12px 20px;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
}
.topbar .t-title { font-weight: 650; letter-spacing: -.01em; }
.topbar .t-desc {
    font-size: 12.5px; color: var(--muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 52ch;
}
.topbar .t-actions { margin-left: auto; display: flex; gap: 8px; }
.btn {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 7px 13px; border-radius: 9px;
    border: 1px solid var(--line); background: var(--surface);
    color: var(--ink-soft); font-size: 13px; cursor: pointer;
}
.btn:hover { background: var(--surface-2); color: var(--ink); }
.btn svg { width: 15px; height: 15px; stroke-width: 1.8; }
.btn-primary {
    background: linear-gradient(135deg, var(--brand-2), var(--brand));
    border-color: transparent; color: var(--brand-ink); font-weight: 600;
}
.btn-primary:hover {
    background: linear-gradient(135deg, var(--brand-2), var(--brand));
    filter: brightness(1.07); color: var(--brand-ink);
}
.btn-primary[disabled] { opacity: .6; cursor: not-allowed; filter: none; }
.btn-ghost { border-color: transparent; background: transparent; }
.btn-icon { padding: 7px; }
.rail-toggle { display: none; }

/* ---- Avatar stage (cột phải) ---- */
/* Đệm dưới 14px vì hàng nút nay nằm DƯỚI nhân vật — để 0 thì nút dính sát mép dưới
   cửa sổ, bấm hụt và nhìn như bị cắt.

   KHOẢNG HỞ GIỮA CÁC PHẦN DÙNG `gap`, KHÔNG dùng margin của từng khối (P9.32b).
   Trước đó mỗi khối tự khai một kiểu nên đo ra 10 / 0 / 12 / 26 / 10px — năm khoảng
   hở khác nhau trong cùng một cột, mắt đọc thành "xếp đại". Nay một nhịp 12px cho
   tất cả; tổng chiều cao gần như không đổi (58px -> 60px) nên bố cục không xê dịch. */
/* P16.1 — dòng danh tính khi đoàn viên vào từ mini-app CDS. Một dòng mảnh, nền nhạt,
   KHÔNG phải cảnh báo: nó chỉ nói cho người dùng biết hệ thống đang hiểu họ là ai.
   Chữ dài (tên + tên CĐCS + số đã che) thì cắt bằng ellipsis chứ không xuống dòng —
   đây là thanh cố định trên đầu, cao gấp đôi là đẩy cả khung chat xuống. */
.asker-bar {
    /* Ẩn ở đây chứ không bằng style="" trong template (P9.25): mọi thứ trang trí đã
       gom về file này, và có phép kiểm canh không cho style="" mọc lại. */
    display: none;
    flex: none;
    padding: 7px 16px;
    border-bottom: 1px solid var(--line);
    background: #f2f7fc;
    color: var(--ink-soft);
    font-size: 12.5px;
    line-height: 1.35;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Chấm báo đang đọc trên vòng tròn trợ lý. Trên desktop KHÔNG hiện: ở đó đã có viên
   thuốc trạng thái ghi hẳn thành chữ, thêm một chấm nữa là nói hai lần cùng một thứ. */
.stage-live { display: none; }

.stage-block {
    background: var(--surface);
    border-left: 1px solid var(--line);
    padding: 14px 16px;
    min-width: 0; min-height: 0;
    display: flex; flex-direction: column; gap: 12px;
    overflow-y: auto;
}
.stage-block > * { flex-shrink: 0; }
.stage-block > .label { display: block; }

/* Không thẻ, không viền, không nền chuyển màu — CỐ Ý.
   Đã đo: nền clip là #ffffff TUYỆT ĐỐI (8 khung, 40.000 điểm ở hai góc trên,
   điểm tối nhất 255, lệch 0,00%), mà panel cũng là #ffffff (--surface) — nên
   để trùng nhau thì không còn mối ghép nào để lộ. Ở layout ngang cũ phải dựng
   nêm trắng vì nhân vật nằm trên thẻ có màu; ở đây không cần. */
.stage-card {
    display: flex; flex-direction: column; align-items: center;
    position: relative;
}
/* Vệt mờ dần ở chân nhân vật: thân chạy hết bề ngang hàng đáy clip (đo được
   600/600 điểm) nên để nguyên là một nhát cắt phẳng ngang ngực. Làm mờ về
   #ffffff cho thân tan vào nền cột.

   LỊCH SỬ: P9.21 tôi đã gỡ vệt này vì tưởng nó là chỗ hở anh Tinh phàn nàn —
   hiểu nhầm, anh muốn giữ. Trả lại nguyên trạng.

   An toàn vì cả hai đầu đều là trắng đặc: nền clip đo được #ffffff tuyệt đối
   (8 khung, 40.000 điểm ở hai góc trên, lệch 0,00%) và nền panel là --surface
   cũng #ffffff. */
/* Chiều cao tính theo PHẦN TRĂM chứ không phải px cố định — đây là chỗ đã sinh ra
   "viền bên phải" anh Tinh thấy.

   Đo trên clip: vai phải nhân vật chạm mép phải từ dòng 558/668 = 84% chiều cao
   trở xuống, vai trái từ 92%. Chỗ chạm đó bị cắt thành một VẠCH DỌC ở mép. Vệt mờ
   cũ cao 38px cố định nên khi nhân vật to lên (nay tới 300px) nó chỉ phủ 13% dưới
   cùng, để hở phần vạch dọc từ 84% tới 87% — nhìn thành cái viền.

   26% luôn phủ trọn vùng bị cắt (16% dưới cùng) ở mọi cỡ nhân vật. */
.stage-card::after {
    content: '';
    position: absolute; left: 0; right: 0; bottom: 0;
    height: 26%; min-height: 34px;
    background: linear-gradient(180deg, rgba(255,255,255,0), #ffffff 88%);
    pointer-events: none;
}
/* Khung dọc, không bo góc, không viền. Tỉ lệ 204x227 khớp tỉ lệ clip (600x668)
   để không cắt cụt hai bên vai. Nền TRẮNG cho khớp nền clip.

   ĐÃ THỬ VÀ BỎ: mix-blend-mode:multiply để xoá nền trắng của clip cho lộ hoạ tiết
   thẻ. Trên thực tế nhân vật ra ĐEN THUI — trình duyệt đưa <video> ra layer riêng
   nên phép nhân chạy với nền trong suốt (= đen) chứ không phải với nền thẻ. Muốn
   nhân vật nổi trên hoạ tiết thì phải có clip WebM/VP9 CÓ ALPHA, không có đường
   tắt bằng CSS. */
.avatar-holder {
    position: relative;
    width: 204px; height: 227px; flex: none;
    background: #ffffff;
    overflow: hidden;
}
.avatar-holder canvas, .avatar-holder svg { display: block; width: 100%; height: 100%; }

/* Khắc phục lỗi viền đen của thẻ video trên Chromium do width/height tính ra số lẻ lẻ.
   Phóng to video ra 2px và lùi lại 1px để viền đen nếu có sẽ bị giấu ngoài overflow:hidden */
.ldld-video, .ldld-video-rest {
    width: calc(100% + 2px) !important;
    height: calc(100% + 2px) !important;
    margin-top: -1px !important;
    margin-left: -1px !important;
}
/* Khoá một dòng: chữ trạng thái đổi liên tục ("Sẵn sàng trả lời" ->
   "Đang tạo giọng đọc…" -> "Nhấn 🔊 Nghe để bật tiếng"). Câu nào dài quá mà
   xuống dòng là viên thuốc cao gấp đôi và đẩy cả khối — lại giật. */
/* Căn GIỮA cho thẳng trục với nhân vật (nhân vật do .stage-card căn giữa). Trước
   đây viên thuốc dính mép trái dưới một nhân vật căn giữa — lệch trục thấy rõ. */
.stage-state {
    display: inline-flex; align-items: center; gap: 7px;
    align-self: center;
    max-width: 100%;
    font-size: 12.5px; color: var(--ink-soft);
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-radius: 999px; padding: 4px 11px;
    white-space: nowrap;
}
.stage-state span { overflow: hidden; text-overflow: ellipsis; }
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--muted); flex: none; }
.dot.on   { background: var(--ok);   animation: blip 1.1s ease-in-out infinite; }
.dot.busy { background: #d98324; animation: blip 1.1s ease-in-out infinite; }
@keyframes blip { 50% { opacity: .25; } }

/* Lời đang đọc, dạng BONG BÓNG THOẠI có đuôi chỉ LÊN nhân vật (nhân vật đã lên
   đầu khối từ P9.32, nên đuôi mọc ở mép TRÊN).
   Màu nền dùng --brand-2 (#1d6fb8) chứ không lấy đúng màu #267bf9 của ảnh mẫu:
   chữ trắng trên #267bf9 chỉ đạt 3,97:1, dưới ngưỡng 4,5:1 của WCAG AA cho chữ
   thường; #1d6fb8 vẫn xanh rõ mà đạt 5,23:1. */
/* Dải màu chéo thay cho một mảng xanh phẳng. Cả hai đầu dải đều phải đọc được
   chữ trắng: #1e75c1 = 4,81:1 và #0a4a80 = 9,11:1, đều qua ngưỡng AA 4,5:1.
   Đã thử #3183cf cho tươi hơn nhưng chỉ được 3,98:1 nên bỏ. */
.caption {
    position: relative;
    background: linear-gradient(150deg, #1e75c1 0%, #17639f 48%, #0a4a80 100%);
    /* Bo đều bốn góc: cái đuôi nay mọc ở GIỮA mép trên (xem .caption::after) nên
       không còn góc nào phải bạt phẳng cho đuôi mọc ra. */
    border-radius: 16px;
    padding: 13px 15px 20px;
    /* Không đổ bóng — anh Tinh bỏ. Vệt sáng ::before bên dưới vẫn giữ, nó nằm
       TRONG bong bóng nên không tạo quầng ra ngoài. */
}
/* Vệt sáng góc trên–trái cho bong bóng có khối, thay vì phẳng lì.
   Nằm dưới chữ vì pseudo-element ::before vẽ trước các nút con. */
.caption::before {
    content: '';
    position: absolute; top: 0; right: 0; bottom: 0; left: 0;
    border-radius: inherit;
    background: radial-gradient(120% 80% at 12% -10%,
                rgba(255,255,255,.20), rgba(255,255,255,0) 60%);
    pointer-events: none;
}
/* Đuôi bong bóng chĩa LÊN nhân vật, mọc ở CHÍNH GIỮA mép trên — nhân vật được
   .stage-card căn giữa nên đuôi phải chỉ đúng vào trục của nó. Để lệch trái 21px như
   trước là đuôi chỉ vào khoảng không bên cạnh nhân vật.

   Màu lấy đầu SÁNG của dải (#1e75c1) vì mép trên là chỗ dải bắt đầu — lấy màu giữa
   hay đầu tối là thấy rõ đuôi khác màu thân.
   KHÔNG đặt overflow lên .caption, nếu không đuôi bị cắt mất. */
.caption::after {
    content: '';
    position: absolute; top: -9px; left: 50%; margin-left: -9px;
    width: 0; height: 0;
    border-left: 9px solid transparent;
    border-right: 9px solid transparent;
    border-bottom: 10px solid #1e75c1;
}
/* Lớp cuộn: câu trả lời dài hơn khung thì TRƯỢT THEO lời đọc chứ không bị cắt.
   Trước đây dùng -webkit-line-clamp:3 nên mọi chữ từ dòng 4 trở đi không bao
   giờ hiện ra, dù máy vẫn đang đọc tới đó.

   CHIỀU CAO CỐ ĐỊNH, không phải max-height: khối này bị ghim xuống đáy cột,
   nên nếu khung phình ra theo độ dài câu trả lời thì mỗi lần chữ xuống dòng
   là cả nhân vật lẫn hai khối bên trên bị xê dịch — nhìn thành giật. Cao cứng
   6 dòng (6 × 21,6px) thì bố cục đứng yên tuyệt đối từ lúc im lặng tới lúc
   đọc xong. Giá phải trả: lúc chữ ngắn thì dưới bong bóng có khoảng trống. */
.caption-body {
    position: relative;          /* mốc offsetTop cho con trỏ .here */
    font-size: 13.5px; line-height: 1.6;
    color: rgba(255,255,255,.66);
    height: 130px; overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: rgba(255,255,255,.45) transparent;
}
.caption-body::-webkit-scrollbar { width: 5px; }
.caption-body::-webkit-scrollbar-thumb {
    background: rgba(255,255,255,.45); border-radius: 3px;
}
/* Phần đã đọc rõ hẳn, phần chưa đọc mờ đi — chữ trắng đặc trên #1d6fb8 đạt
   5,23:1, phần mờ .66 còn 2,7:1 nên chỉ dùng cho chữ CHƯA đọc tới. */
.caption .said { color: #ffffff; font-weight: 600; }
.caption .rest { color: rgba(255,255,255,.66); }
/* Con trỏ vị trí đang đọc: rộng 0 nhưng cao bằng một dòng, để đo được offsetTop
   của đúng dòng đang đọc mà không chèn thêm khoảng trắng nào vào câu. */
.caption .here {
    display: inline-block; width: 0; height: 1em; vertical-align: -.15em;
}
.caption.is-idle .caption-body {
    color: rgba(255,255,255,.82); font-style: italic;
}
/* Thanh tiến độ đọc ở đáy bong bóng. Dùng đúng con số paintCaption() đã có
   (charIndex / độ dài câu trả lời) nên không phát sinh trạng thái mới, mà
   người nghe biết được còn bao nhiêu nữa. Định vị tuyệt đối nên không cộng
   thêm chiều cao — bố cục vẫn đứng yên. */
.caption-prog {
    position: absolute; left: 15px; right: 15px; bottom: 9px;
    height: 3px; border-radius: 3px;
    background: rgba(255,255,255,.20);
    overflow: hidden;
}
.caption-prog i {
    display: block; height: 100%; width: 0;
    border-radius: 3px;
    background: rgba(255,255,255,.9);
    transition: width .18s linear;
}
/* Lúc im lặng thì chưa đọc gì để mà báo tiến độ. */
.caption.is-idle .caption-prog { opacity: 0; }
.stage-tools { display: flex; gap: 8px; flex-wrap: wrap; }
.stage-tools .btn { flex: 1; justify-content: center; }
/* Tốc độ đọc, chuyển từ thanh trái về cuối khối trợ lý (P9.32). Có khung riêng để
   tách khỏi hai nút ngay trên: một bên là thao tác, một bên là thiết lập.

   MỘT HÀNG chứ không phải nhãn trên / thanh dưới như hồi ở thanh trái: cột này đã
   chật chiều cao (đo được ở test quét 480–1200px), hai hàng tốn thêm ~30px. */
/* Hàng tốc độ đọc (.stage-voice) đã gỡ hẳn ở P9.32c: gần như không ai đụng tới thanh
   trượt, mà nó chiếm một hàng ở cuối một cột vốn đã chật chiều cao. Tốc độ nay lấy
   thẳng từ thiết lập của admin (`tts_base_rate`). */

/* ---- Conversation ---- */
.conversation {
    flex: 1; min-height: 0; overflow-y: auto;
    padding: 16px 20px 8px;
    scroll-behavior: smooth;
}
.chat-jump-bottom {
    position: absolute; left: 50%; bottom: 118px; z-index: 8;
    display: grid; place-items: center; width: 38px; height: 38px;
    padding: 0; border: 1px solid #cbd7e3; border-radius: 50%;
    background: var(--surface); color: var(--ink-soft); cursor: pointer;
    box-shadow: 0 4px 14px rgba(15,39,64,.18);
    transform: translateX(-50%);
    transition: color .15s ease, border-color .15s ease, background-color .15s ease,
                box-shadow .15s ease;
}
.chat-jump-bottom[hidden] { display: none !important; }
.chat-jump-bottom svg { width: 19px; height: 19px; stroke-width: 1.8; }
.chat-jump-bottom:hover,
.chat-jump-bottom:focus-visible {
    color: var(--brand); border-color: var(--brand-2); background: #f5f9fd;
    box-shadow: 0 5px 18px rgba(15,39,64,.23);
}
.greeting-card {
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--radius); padding: 16px; box-shadow: var(--shadow);
    margin-bottom: 14px;
}
.greeting-card p { margin: 0 0 12px; color: var(--ink-soft); }
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.chip {
    background: var(--surface); border: 1px solid #cfe0f2; color: var(--brand);
    border-radius: 999px; padding: 6px 14px; font-size: 13px; cursor: pointer;
}
.chip:hover { background: #e8f1fb; }
.greeting-inline-suggestions {
    margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line);
}

.msg { margin-bottom: 14px; display: flex; flex-direction: column; }
.msg.user { align-items: flex-end; }
.bubble {
    max-width: 78%; padding: 12px 15px;
    border-radius: var(--radius); font-size: 14px; line-height: 1.6;
}
.bubble.user {
    background: linear-gradient(135deg, var(--brand-2), var(--brand));
    color: #fff; border-bottom-right-radius: 5px;
}
.bubble.bot {
    background: var(--surface); border: 1px solid var(--line);
    color: var(--ink); border-bottom-left-radius: 5px; box-shadow: var(--shadow);
}
.bubble.bot strong { color: var(--brand); font-weight: 650; }
.bubble.bot p { margin: 0 0 8px; }
.bubble.bot p:last-child { margin-bottom: 0; }
.bubble.bot ol, .bubble.bot ul { margin: 6px 0 10px 20px; padding: 0; }
.bubble.bot ol { list-style: decimal; }
.bubble.bot ul { list-style: disc; }
.bubble.bot ul ul, .bubble.bot ol ul { list-style: circle; margin: 4px 0 4px 18px; }
.bubble.bot li { margin: 3px 0; }
.bubble.bot code {
    background: var(--surface-2); padding: 1px 5px; border-radius: 4px;
    font-family: var(--mono); font-size: 12.5px;
}
.bubble.bot a { color: var(--brand); text-decoration: underline; }
.bubble.bot .bot-heading {
    font-weight: 650; color: var(--brand); font-size: 15px;
    margin: 12px 0 6px; padding-bottom: 5px; border-bottom: 1px solid var(--line);
}
.bubble.bot .bot-basis {
    margin-top: 10px; padding: 10px 12px;
    background: #eaf6ee; border-left: 3px solid #3d9d63;
    border-radius: var(--radius-sm); font-size: 13px; color: #14532d;
}
.bubble.bot .bot-basis strong { color: #14532d; }
.bubble.bot .bot-sources {
    margin-top: 10px; padding: 10px 12px;
    background: var(--surface-2); border-left: 3px solid var(--brand-2);
    border-radius: var(--radius-sm); font-size: 12.5px; color: var(--ink-soft);
}
.bubble.bot .bot-sources strong { color: var(--brand); }
.bubble.bot .bot-sources ul { margin: 6px 0 0 18px; list-style: square; }
.bubble.bot .bot-sources:not(.is-expanded) .bot-source-extra { display: none; }
.source-toggle {
    margin-top: 8px; padding: 3px 0;
    border: 0; background: transparent; color: var(--brand);
    font: inherit; font-weight: 600; cursor: pointer;
}
.source-toggle:hover { text-decoration: underline; }
.source-toggle:focus-visible { outline: 2px solid var(--brand-2); outline-offset: 2px; }

/* ---- Hàng nút dưới mỗi câu trả lời ----
   Trước đây cả ba nút đều nền trong suốt viền xám, nhìn như chữ trơn nên không ai
   biết là bấm được. Nay mỗi nút mang màu của việc nó làm: nghe = xanh thương hiệu,
   hữu ích = xanh lá, chưa tốt = đỏ. Màu chỉ hiện rõ khi rê chuột / đã chọn, lúc
   thường vẫn nhạt để không lấn át nội dung câu trả lời. */
.msg-tools { display: flex; align-items: center; gap: 7px; margin-top: 9px; flex-wrap: wrap; }
.tool-btn {
    display: inline-flex; align-items: center; gap: 5px;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: 999px; padding: 4px 12px;
    font-size: 12.5px; line-height: 1.5; cursor: pointer; color: var(--ink-soft);
    transition: background .15s ease, border-color .15s ease, color .15s ease, box-shadow .15s ease;
}
.tool-btn:hover { border-color: #cfe0f2; box-shadow: 0 1px 3px rgba(15,39,64,.08); }
.tool-btn:focus-visible { outline: 2px solid var(--brand-2); outline-offset: 2px; }

.tool-speak:hover      { background: #eaf3fc; border-color: var(--brand-2); color: var(--brand); }
.fb-up:hover           { background: #e9f6ee; border-color: #3d9d63; color: #14532d; }
.fb-down:hover         { background: #fdecec; border-color: #d05252; color: #7f1d1d; }

.tool-btn.active-up    { background: #e3f4e9; border-color: #3d9d63; color: #14532d; font-weight: 600; }
.tool-btn.active-down  { background: #fbe6e6; border-color: #d05252; color: #7f1d1d; font-weight: 600; }
.tool-btn.is-playing {
    background: #e3eefb; border-color: var(--brand-2); color: var(--brand); font-weight: 600;
}
.fb-done {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 12.5px; color: var(--ok); font-weight: 600;
}
.fb-modal {
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--radius-sm); padding: 11px; margin-top: 7px;
    font-size: 13px; max-width: 78%;
}
.fb-modal label { display: block; margin: 4px 0; cursor: pointer; }
.fb-modal textarea {
    width: 100%; margin-top: 7px; padding: 7px;
    border: 1px solid var(--line); border-radius: 7px;
    font-size: 13px; font-family: inherit; resize: vertical; min-height: 42px;
}

.stream-cursor {
    display: inline-block; width: 3px; height: 1em;
    background: var(--brand); margin-left: 2px; vertical-align: text-bottom;
    animation: blink-cursor .8s step-end infinite;
}
.stream-new { animation: stream-reveal .12s ease-out both; }
@keyframes stream-reveal {
    from { opacity: .35; }
    to   { opacity: 1; }
}
@keyframes blink-cursor { 0%,100% { opacity: 1; } 50% { opacity: 0; } }
.spinner {
    width: 14px; height: 14px; border-radius: 50%;
    border: 2px solid rgba(0,75,141,.25); border-top-color: var(--brand);
    animation: spin .8s linear infinite; display: inline-block;
}
.btn-primary .spinner { border-color: rgba(255,255,255,.4); border-top-color: #fff; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- Composer ---- */
.composer {
    padding: 12px 20px;
    background: var(--surface);
    border-top: 1px solid var(--line);
    display: flex; gap: 10px; align-items: center;
}
.composer input {
    flex: 1; padding: 12px 16px;
    border: 1px solid var(--line); border-radius: 11px;
    font-size: 14.5px; font-family: inherit; outline: none; background: var(--surface-2);
}
.composer input:focus { border-color: var(--brand-2); background: var(--surface); }
/* ---- Hỏi bằng giọng nói ---- */
.mic-btn { flex: none; }
.mic-btn.is-rec {
    background: #fdecec; border-color: #f0b4b4; color: var(--danger);
    animation: micpulse 1.2s ease-in-out infinite;
}
@keyframes micpulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(198,40,40,.28); }
    50%      { box-shadow: 0 0 0 8px rgba(198,40,40,0); }
}
.mic-note {
    padding: 0 20px 8px; font-size: 12.5px; color: var(--muted);
    background: var(--surface); display: none;
}
.mic-note.is-on { display: block; }
.mic-note.is-err { color: var(--danger); }
.disclaimer {
    padding: 9px 20px; text-align: center;
    font-size: 12.5px; color: var(--muted);
    background: var(--surface); border-top: 1px solid var(--line);
}

/* ---- Cài đặt giọng đọc: KHÔNG CÒN GÌ ----
   P9.32 dọn sạch cả khối. `.field` (nhãn trên / điều khiển dưới), `.switch` (công tắc
   gạt), `.field select` (ô chọn giọng) rồi `.stage-voice` (hàng tốc độ) lần lượt bị gỡ
   theo từng thứ biến mất khỏi giao diện. Người dùng nay không chỉnh gì về giọng đọc:
   bật/tắt bằng nút trên thanh đầu, còn tốc độ do admin đặt bằng `tts_base_rate`. */
.hint { font-size: 12px; color: var(--muted); margin-top: 8px; line-height: 1.5; }
.badge {
    display: inline-block; padding: 2px 9px; border-radius: 999px;
    font-size: 11.5px; font-weight: 600;
    background: #e8f1fb; color: var(--brand);
}
.badge.warn { background: #fdf0dc; color: #8a5008; }

/* ---- Overlay ---- */
.overlay {
    position: fixed; inset: 0; z-index: 50;
    background: rgba(9,26,43,.55);
    display: flex; align-items: center; justify-content: center; padding: 20px;
}
.overlay .card {
    width: 100%; max-width: 500px; background: var(--surface);
    border-radius: var(--radius); padding: 22px;
    box-shadow: 0 20px 60px rgba(0,0,0,.28);
}
.overlay h3 { margin: 0 0 6px; color: var(--brand); font-size: 18px; }
.overlay p { margin: 0 0 16px; color: var(--muted); font-size: 13.5px; }
.form-row { display: flex; gap: 10px; margin-bottom: 11px; }
.form-row .col { flex: 1; min-width: 0; }
.form-row label { display: block; font-size: 12.5px; margin-bottom: 5px; color: var(--ink-soft); }
.form-row input {
    width: 100%; padding: 10px 12px;
    border: 1px solid var(--line); border-radius: 9px;
    font-size: 14px; font-family: inherit; outline: none;
}
.form-row input:focus { border-color: var(--brand-2); }
.overlay .actions { display: flex; justify-content: flex-end; gap: 9px; margin-top: 14px; }
.error { color: var(--danger); font-size: 13px; margin-top: 9px; }

/* ---- Bảng chọn giọng đọc (P9.33) ----
   Danh sách CÓ THỂ CUỘN chứ không giãn theo số giọng: mười ba dòng cộng thanh tốc
   độ và hàng nút là quá chiều cao khung xem của laptop 1366x768, mà nút "Dùng giọng
   này" nằm dưới cùng — tràn ra ngoài là chọn xong không lưu được. */
.overlay .card-voice { max-width: 460px; }
.voice-list {
    max-height: min(46vh, 340px); overflow-y: auto;
    border: 1px solid var(--line); border-radius: var(--radius-sm);
    background: var(--surface-2); padding: 5px;
}
.voice-loading { padding: 16px; text-align: center; color: var(--muted); font-size: 13px; }
.voice-item {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 9px; border-radius: var(--radius-sm);
    cursor: pointer; user-select: none;
}
.voice-item:hover { background: #e8f1fb; }
.voice-item.is-picked { background: #e8f1fb; }
.voice-item .v-dot {
    flex: none; width: 15px; height: 15px; border-radius: 50%;
    border: 2px solid var(--line); background: var(--surface);
}
.voice-item.is-picked .v-dot { border-color: var(--brand); box-shadow: inset 0 0 0 3px var(--brand); }
.voice-item .v-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.voice-item .v-main b { font-size: 13.5px; color: var(--ink); font-weight: 600; }
.voice-item .v-main i { font-style: normal; font-size: 12px; color: var(--muted); }
.voice-item .v-play {
    flex: none; width: 30px; height: 30px; padding: 0;
    display: flex; align-items: center; justify-content: center;
    border: 1px solid var(--line); border-radius: 50%;
    background: var(--surface); color: var(--ink-soft); cursor: pointer;
}
.voice-item .v-play:hover { background: var(--brand); border-color: var(--brand); color: var(--brand-ink); }
.voice-item .v-play svg { width: 13px; height: 13px; stroke-width: 1.8; }
/* Giọng đang phát: viền chạy quanh nút để mắt bắt được ngay dòng nào đang kêu,
   kể cả khi danh sách đã cuộn đi vài dòng. */
.voice-item.is-playing .v-play {
    background: var(--brand); border-color: var(--brand); color: var(--brand-ink);
    animation: voicePulse 1.1s ease-in-out infinite;
}
@keyframes voicePulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(29,111,184,.45); }
    50%      { box-shadow: 0 0 0 5px rgba(29,111,184,0); }
}
.voice-warn {
    margin-bottom: 10px; padding: 8px 10px; border-radius: var(--radius-sm);
    background: #fff6e5; border: 1px solid #f0d9a8;
    color: #8a5a00; font-size: 12.5px;
}
.voice-speed { margin-top: 13px; }
.voice-speed label { display: block; font-size: 12.5px; color: var(--ink-soft); margin-bottom: 5px; }
.voice-speed label b { color: var(--brand); font-family: var(--mono); }
.voice-speed input[type=range] { width: 100%; accent-color: var(--brand); }
.voice-speed-note { display: block; font-size: 11.5px; color: var(--muted); margin-top: 3px; }

@media (prefers-reduced-motion: reduce) {
    .voice-item.is-playing .v-play { animation: none; }
}

/* ĐẶT TRƯỚC MỌI @media LÀ CỐ Ý: các mốc bên dưới ghi đè hai biến này, mà chúng
   cùng độ ưu tiên (.stage-block) nên cái nào viết SAU thì thắng. Để khối này
   xuống dưới là mọi override cho tablet/điện thoại thành vô tác dụng — đã dính
   đúng lỗi đó một lần, test bắt được. */
/* ---- Responsive theo CHIỀU CAO cửa sổ ----
   Vấn đề của cột phải không phải bề ngang mà là chiều cao: nó xếp dọc nhãn +
   chip trạng thái + bong bóng + nhân vật + nút, cộng lại ~814px. Laptop
   1366x768 chỉ còn ~600px khung xem nên nhân vật bị đẩy khỏi tầm nhìn.

   ĐÃ THỬ VÀ BỎ: chia 4 mốc @media (max-height) với cặp width/height cứng.
   Sai vì mốc media query là chiều cao KHUNG XEM chứ không phải chiều cao màn
   hình — màn 1600x900 chỉ còn ~760px khung xem nên rơi vào mốc thấp hơn hẳn
   dự tính, và ở dải (700,800] vẫn tràn 9px. Chia mốc cứng thì mỗi dải phải
   tính riêng cho trường hợp chật nhất, rất dễ sót.

   Nay co giãn LIÊN TỤC theo vh. Bề ngang suy ra từ CÙNG một biến nên tỉ lệ
   clip 600x668 (0,89820) luôn đúng tuyệt đối, không cần aspect-ratio. */
/* Nhân vật co giãn theo chiều cao khung xem. Trần 280px vì bề ngang suy ra là
   280 x 0,8982 = 251px, vẫn lọt trong lòng cột 292px. */
.stage-block {
    --ava-h: clamp(150px, 30vh, 280px);
    --cap-h: clamp(40px, 10vh, 130px);
}
.avatar-holder {
    height: var(--ava-h);
    width: calc(var(--ava-h) * 0.8982);
}
.caption-body { height: var(--cap-h); }

/* ---- Responsive ---- */
/* ---------------------------------------------------------------- */
/* Máy tính bảng trở xuống: trợ lý ảo co thành VÒNG TRÒN nhân vật ở góc trái */
/* ---------------------------------------------------------------- */
/*
 * LỖI ĐÃ VÁ Ở ĐÂY: trước đây mốc này chỉ đổi .app về 2 cột, nhưng .stage-block
 * vẫn giữ grid-area trỏ vào CỘT 3 — cột đó không còn tồn tại nên trình duyệt đẻ
 * ra một cột ngầm và bóp méo cột giữa. Đó chính là lỗi sidebar trên tablet.
 * Nay .stage-block chuyển sang position:fixed nên ra hẳn khỏi luồng lưới,
 * không còn tham chiếu cột nào nữa.
 *
 * ĐÃ THỬ VÀ BỎ (P9.36): nút tròn (.stage-fab) mở ra thẻ nổi 324px, và câu chào
 * tự bung thẻ đó ra. Anh Tinh chê: vừa vào trang đã có một tấm thẻ che mất khung
 * chat, xấu. Nay khối trợ lý ảo CO THẲNG thành vòng tròn nhân vật ở đúng chỗ cũ
 * của cái nút — luôn hiện, clip chạy và mấp máy miệng ngay tại đó, không bấm,
 * không đóng/mở. Chữ trạng thái + lời đọc + nút Đọc/Dừng chỉ còn trên desktop;
 * trên mobile công tắc "Tự động đọc" nằm ở cột trái (ngăn kéo) là đủ.
 */
/* Dieu kien do JS quyet dinh (lop html.is-compact): khung nhin <=1180px HOAC trang
   dang nam trong IFRAME.

   Vi sao khong con la @media: trong iframe, the <meta name="viewport"> BI BO QUA —
   khung nhin bang be ngang CSS ma trang cha cap cho iframe. Mini-app CDS cap cho
   iframe mot be ngang rong, nen @media (max-width: 1180px) khong bao gio khop va
   trang dung ra bo cuc desktop 3 cot: doan vien mo tab Tro ly so thay ca mot BANG
   tro ly ben phai thay vi vong tron nho goc trai. Da dung lai dung tinh huong do
   bang iframe 1280px roi chup anh — ra dung nhu vay.

   JS dat lop nay trong <head>, truoc luot ve dau tien, nen khong co canh nhay.
   Trang nay von khong chay duoc neu tat JS, nen khong mat gi khi bo @media. */
    html.is-compact .app { grid-template-columns: 232px minmax(0, 1fr); }

    /* --- Vòng tròn trợ lý ảo ---
       Nằm bên TRÁI và lùi ra khỏi khung chat: 232px là bề ngang cột trái, cộng 16px
       đệm. Để bên phải thì nó đè lên nút Gửi và mép phải của bong bóng trả lời.

       bottom 126px = đo khối đáy rồi cộng đệm: ô nhập 43,4 + đệm/viền composer 25
       = 68,4px, cộng dòng disclaimer 37,8px -> 106,2px. Trước để 84px nên nó nằm
       lọt trong thanh chat.

       58px = ĐÚNG BẰNG cái nút cũ. Tôi để 96px trước (lý do: ở 58px cái miệng chỉ còn
       ~8px, mấp máy khó thấy) nhưng anh Tinh xem xong bảo to quá, chốt về cỡ cũ.
       Đổi cỡ chỉ cần sửa một con số này — khung nhân vật bên dưới tính theo %. */
    html.is-compact .stage-block {
        --ava-d: 58px;
        position: fixed; left: 248px; right: auto; bottom: 126px; z-index: 41;
        width: var(--ava-d); height: var(--ava-d);
        min-height: 0; max-height: none;
        padding: 0; gap: 0;
        border: 2px solid var(--surface); border-radius: 50%;
        background: var(--surface);
        box-shadow: 0 4px 16px rgba(15,39,64,.28);
        pointer-events: none;   /* chỉ để nhìn — không bấm, không có gì để mở */
        /* KHÔNG cắt ở đây mà cắt ở .stage-card: chấm báo đang đọc mọc ra mép vòng
           tròn, để overflow:hidden ở khối ngoài là xén mất một góc của nó. */
        overflow: visible;
    }
    /* Chấm báo đang đọc — bản dựng lại của .fab-dot cũ, cùng cỡ, cùng chỗ (mép dưới
       phải), để anh Tinh vẫn liếc một cái là biết trợ lý đang đọc hay đang chờ. */
    html.is-compact .stage-live {
        display: block;
        position: absolute; right: 1px; bottom: 1px;
        width: 13px; height: 13px; border-radius: 50%;
        background: var(--muted); border: 2px solid var(--surface);
    }
    html.is-compact .stage-live.on   { background: var(--ok);   animation: blip 1.1s ease-in-out infinite; }
    html.is-compact .stage-live.busy { background: #d98324; animation: blip 1.1s ease-in-out infinite; }
    /* Chỉ chừa lại nhân vật. Các khối kia vẫn nằm trong DOM (JS ghi trạng thái và
       lời đọc vào chúng liên tục) nên KHÔNG gỡ khỏi template — chỉ giấu đi. */
    html.is-compact .stage-block > .label,
    html.is-compact .stage-block > .stage-state,
    html.is-compact .stage-block > .caption,
    html.is-compact .stage-block > .stage-tools { display: none; }

    /* Nhân vật bị cắt tròn Ở ĐÂY (không phải ở .stage-block) — xem ghi chú overflow
       bên trên. Lùi vào trong viền 2px của khối ngoài nên không lộ mối ghép. */
    html.is-compact .stage-card {
        position: absolute; top: 0; left: 0; right: 0; bottom: 0;
        border-radius: 50%; overflow: hidden;
    }
    html.is-compact .stage-card::after { display: none; }   /* vệt mờ chân nhân vật: vòng tròn đã cắt rồi */

    /* Phóng clip lên 145% vòng tròn rồi kéo lên 6% để KHUÔN MẶT nằm giữa vòng,
       không phải nguyên khung hình thu nhỏ (thu nguyên khung thì đầu chỉ còn nửa
       trên vòng, nửa dưới toàn áo).
       Ba cặp số 145/-6, 165/-11, 190/-16 đã dựng thử ra ảnh rồi soi: 165 trở lên
       bắt đầu cắt tóc hai bên, 145 vẫn còn cổ áo nên ra dáng người, không thành
       cái mặt bị khoét.
       130,2% = 145% x 0,8982 — GIỮ ĐÚNG tỉ lệ clip 600x668, lệch là méo mặt.
       avatar3d.js tự tính lại khung theo tỉ lệ khung chứa ở mỗi lần resize nên đổi
       cỡ ở đây không cần đụng vào JS. */
    html.is-compact .avatar-holder {
        position: absolute; left: 50%; top: -6%;
        width: 130.2%; height: 145%;
        transform: translateX(-50%);
    }
/* --- het khoi may tinh bang tro xuong --- */
/* ---------------------------------------------------------------- */
/* Điện thoại                                                        */
/* ---------------------------------------------------------------- */
/*
 * Điện thoại dùng CHUNG vòng tròn của mốc 1180px — không viết riêng một kiểu bố
 * cục nữa, chỉ dời vị trí cho khớp mép trái và thanh chat của điện thoại.
 *
 * ĐÃ THỬ VÀ BỎ: thanh ngang cố định trên cùng, nhân vật 64px. Nó luôn nhìn thấy
 * nhưng chiếm mất 83px của màn hình vốn đã hẹp, mà nhân vật nhỏ tới mức không còn
 * ra hình người.
 */
/* Dieu kien do JS quyet dinh (lop html.is-phone): khung nhin <=860px HOAC trang
   dang nam trong iframe. Trong iframe the <meta viewport> BI BO QUA — khung nhin la
   be ngang CSS ma trang cha cap cho iframe, mini-app CDS cap rong nen @media khong
   bao gio khop va trang dung ra bo cuc desktop. Xem chu thich o html.is-compact. */
    html.is-phone .app { grid-template-columns: minmax(0, 1fr); }
    html.is-phone .rail {
        position: fixed; left: 0; top: 0; bottom: 0; width: 232px; z-index: 45;
        transform: translateX(-100%); transition: transform .22s ease;
        box-shadow: 8px 0 30px rgba(15,39,64,.12);
    }
    html.is-phone .rail.is-open { transform: translateX(0); }
    html.is-phone .rail-toggle { display: inline-flex; }
    html.is-phone .topbar .t-desc { display: none; }
    html.is-phone .bubble { max-width: 92%; }
    html.is-phone .conversation { padding: 12px; }
    html.is-phone .composer { padding: 10px 12px; }
    /* Từ đây cột trái là ngăn kéo nên không còn 232px phải né — vòng tròn về sát
       mép trái. Điện thoại composer đệm 10px thay vì 12px nên khối đáy còn 102,2px. */
    html.is-phone .stage-block { left: 12px; right: auto; bottom: 120px; }
/* --- het khoi dien thoai --- */


@media (max-height: 620px) {
    .stage-block > .label { display: none; }
}
.scrim {
    position: fixed; inset: 0; background: rgba(9,26,43,.35);
    z-index: 38; display: none;
}
.scrim.is-on { display: block; }

/* ---------------------------------------------------------------- */
/* Các rule kéo từ thuộc tính style="" trong template về đây (P9.25)  */
/* ---------------------------------------------------------------- */

/* Khối tiêu đề ở topbar: min-width:0 để chữ dài bị cắt bằng ellipsis thay vì
   đẩy giãn cả hàng — thiếu nó là flex item không chịu co. */
.topbar .t-main { min-width: 0; }

/* Khung dựng nhân vật lấp đầy .avatar-holder; kích thước thật do
   .avatar-holder quyết định (co giãn theo vh). */
#avatarStage { width: 100%; height: 100%; }

/* Chữ xác nhận đánh giá: bản "chưa tốt" dùng màu cảnh báo. Trước đây gán màu
   thẳng bằng style="" ở hai chỗ khác nhau trong JS nên dễ lệch nhau. */
.fb-done.is-bad { color: var(--danger); }

/* Hộp chọn lý do khi bấm "Chưa tốt". */
.fb-modal-title { margin-bottom: 6px; font-weight: 600; }
.fb-modal-actions { display: flex; gap: 6px; margin-top: 6px; }
