/* ══════════════════════════════════════════════════════════════════════
   DRAFT DOCTOR — WRITING LIVE SESSION · comment rail (writing/live-session.js)
   Hợp đồng: docs/DESIGN_LIVE_WRITING_SESSION.md §5.5/§6 — panel bên lề,
   KHÔNG BAO GIỜ can thiệp <textarea> của mode đang chạy.
   ══════════════════════════════════════════════════════════════════════ */

/* ── Rail — panel nổi GÓC DƯỚI-PHẢI, THU GỌN mặc định ────────────────────
   QA-FIX 26/7 (owner báo, có ảnh): bản cũ đặt `top:72px; right:12px` nên trên
   desktop nó nằm ĐÚNG chỗ cột phải của Studio/Quick — tức che đề bài và ảnh
   biểu đồ, thứ học sinh phải đọc suốt lúc viết. Không có chỗ trống nào để
   nhồi một panel 280px: `main` của builder rộng 1140px và được canh giữa, lề
   mỗi bên chỉ ~60px ⇒ mọi panel fixed đều che một cái gì. Nên đổi hợp đồng
   hiển thị: MẶC ĐỊNH THU GỌN (chỉ 1 thanh tiêu đề + số nhận xét), bung ra khi
   học sinh bấm hoặc khi có nhận xét mới tới. Góc dưới-phải vì đó là chỗ ít
   nội dung nhất, và thu gọn thì cao ~40px nên gần như không che gì.

   MÀU: `--dd-card` / `--dd-border` KHÔNG TỒN TẠI ở bất cứ đâu trong repo (đã
   grep cả repo) — nên rail luôn dùng fallback TỐI #12172a trong khi `color:
   inherit` lấy chữ ĐEN của theme sáng ⇒ đen trên đen, không đọc được (đúng
   lỗi owner báo). Biến thật của app là bộ trong theme.css: --surf/--border/
   --text/--shadow, tự đổi theo light/dark. Luôn khai báo bg VÀ color thành
   cặp, không bao giờ để `inherit` với một bg cứng. ─────────────────────── */
/* ── 31/7 (owner) — RAIL → NÚT TRÒN (FAB) ────────────────────────────────
   Panel thu gọn cũ vẫn cao ~92px và rộng 300px ở đáy-phải, tức luôn có một
   khối đặc nằm đè lên vùng mà mọi mode đặt nút hành động (nút "Sang bước … →"
   của Studio, nút nộp/kiểm tra của Quick). Cách chữa cũ (chừa padding cho
   `main`) chỉ đúng với `main`; bất cứ nút nào neo kiểu khác vẫn bị che.
   Nay: ở trạng thái nghỉ chỉ còn 1–2 NÚT TRÒN 52px ở góc, còn danh sách nhận
   xét là popover chỉ tồn tại khi bấm. `.dd-live-rail` từ chỗ LÀ cái panel trở
   thành khung định vị TRONG SUỐT — không nền/viền/bóng, và
   `pointer-events:none` để khoảng trống quanh nút không nuốt click của trang
   phía dưới (các nút con bật lại `auto`). ─────────────────────────────── */
.dd-live-rail {
  position: fixed;
  bottom: 14px;
  right: 14px;
  display: flex; flex-direction: column; align-items: flex-end; gap: 10px;
  z-index: 400;
  font-size: .82rem;
  color: var(--text, #16181d);
  pointer-events: none;
}
.dd-live-rail > * { pointer-events: auto; }

/* Cột nút tròn — phần DUY NHẤT luôn hiện. live-session.js đo chính khối này
   (measureRailSpace) để chừa chỗ ở cuối trang. */
.dd-live-fabs { display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }

.dd-live-fab {
  position: relative;
  width: 52px; height: 52px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  border: 1px solid var(--border, rgba(0,0,0,.14));
  background: var(--surf, #fff);
  color: var(--text, #16181d);
  box-shadow: var(--shadow, 0 12px 32px rgba(0,0,0,.22));
  font: inherit; font-size: 1.35rem; line-height: 1;
  cursor: pointer;
  transition: transform .15s ease, box-shadow .15s ease, filter .15s ease;
}
.dd-live-fab:hover { transform: translateY(-2px); }
.dd-live-fab:focus-visible { outline: 3px solid var(--accent, #2563eb); outline-offset: 2px; }
.dd-live-fab-ic { pointer-events: none; }

/* Chấm đỏ + số nhận xét CHƯA XEM. Khi đã xem hết, badge chuyển sang trung
   tính và chỉ còn là bộ đếm — mất hẳn badge thì học sinh không còn tín hiệu
   nào cho biết thầy/cô ĐÃ nhận xét (lý do bộ đếm ra đời, QA-FIX 26/7). */
.dd-live-rail-count {
  position: absolute; top: -3px; right: -3px;
  min-width: 20px; height: 20px; padding: 0 5px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px;
  background: var(--surf2, #e5e7eb); color: var(--text, #16181d);
  border: 2px solid var(--surf, #fff);
  font-size: .68rem; font-weight: 800; line-height: 1;
}
.dd-live-fab.has-unseen .dd-live-rail-count {
  background: #e11d48; color: #fff;
  animation: ddLiveDot 1.6s ease-in-out infinite;
}
@keyframes ddLiveDot {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.18); }
}

/* Nhận xét mới tới: nút SÁNG LÊN + RUNG. Rung chỉ ~3 nhịp rồi thôi (rung mãi
   thì phiền và che mất việc học), còn quầng sáng + chấm đỏ CÒN LẠI cho tới
   khi học sinh mở panel — đó mới là thứ chống bỏ lỡ. */
.dd-live-fab.is-alert { animation: ddLiveShake .5s ease-in-out 3; }
.dd-live-fab.has-unseen {
  box-shadow: 0 0 0 4px rgba(225,29,72,.22), 0 12px 32px rgba(0,0,0,.22);
  border-color: rgba(225,29,72,.55);
}
@keyframes ddLiveShake {
  0%, 100% { transform: translateX(0) rotate(0); }
  20%      { transform: translateX(-3px) rotate(-6deg); }
  40%      { transform: translateX(3px)  rotate(6deg); }
  60%      { transform: translateX(-2px) rotate(-4deg); }
  80%      { transform: translateX(2px)  rotate(4deg); }
}
/* Người tắt hiệu ứng chuyển động vẫn phải nhận được tín hiệu — giữ chấm đỏ và
   quầng sáng, chỉ bỏ phần nhúc nhích. */
@media (prefers-reduced-motion: reduce) {
  .dd-live-fab.is-alert { animation: none; }
  .dd-live-fab.has-unseen .dd-live-rail-count { animation: none; }
}

/* Popover danh sách — chỉ tồn tại khi mở, nên không che gì lúc nghỉ. */
.dd-live-panel {
  display: none;
  width: 300px; max-width: calc(100vw - 28px);
  flex-direction: column;
  background: var(--surf, #fff);
  color: var(--text, #16181d);
  border: 1px solid var(--border, rgba(0,0,0,.14));
  border-radius: 14px;
  box-shadow: var(--shadow, 0 12px 32px rgba(0,0,0,.22));
  overflow: hidden;
}
.dd-live-rail.is-open .dd-live-panel { display: flex; }
.dd-live-panel-head {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px;
  font-weight: 700;
  border-bottom: 1px solid var(--border, rgba(0,0,0,.12));
}
.dd-live-panel-close {
  margin-left: auto; flex: none;
  background: transparent; border: 0; color: inherit;
  font: inherit; font-size: .9rem; cursor: pointer; opacity: .6;
  padding: 2px 4px; border-radius: 6px;
}
.dd-live-panel-close:hover { opacity: 1; background: var(--surf2, rgba(0,0,0,.05)); }

.dd-live-rail-list {
  display: flex;
  padding: 8px; flex-direction: column; gap: 8px;
  max-height: min(46vh, 420px); overflow-y: auto;
}
.dd-live-rail-empty { padding: 12px 8px; opacity: .6; text-align: center; }

.dd-live-item {
  border: 1px solid var(--border, rgba(0,0,0,.12));
  border-radius: 10px;
  padding: 8px 10px;
  cursor: pointer;
  transition: background .15s ease, transform .15s ease;
}
.dd-live-item:hover { background: var(--surf2, rgba(0,0,0,.05)); }
.dd-live-item.is-drifted { cursor: default; opacity: .65; }
.dd-live-item.is-new { animation: ddLiveItemIn .5s ease; }
@keyframes ddLiveItemIn {
  from { transform: translateX(12px); opacity: 0; background: rgba(255,196,0,.18); }
  to   { transform: translateX(0); opacity: 1; }
}

.dd-live-item-top { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; }
.dd-live-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.dd-live-dot-info  { background: #4aa3ff; }
.dd-live-dot-minor { background: #f5c518; }
.dd-live-dot-major { background: #ff5a5a; }
.dd-live-crit {
  font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  opacity: .75;
}
.dd-live-time { margin-left: auto; font-size: .7rem; opacity: .55; }

.dd-live-quote {
  font-style: italic;
  opacity: .85;
  margin-bottom: 4px;
  overflow-wrap: break-word;
}
.dd-live-drift { font-style: normal; opacity: .6; }
.dd-live-comment { overflow-wrap: break-word; }

/* ── Toast — new-comment bell (top-center, transient) ─────────────────── */
.dd-live-toast {
  position: fixed;
  top: 16px; left: 50%;
  transform: translate(-50%, -12px);
  background: var(--surf, #fff);
  border: 1px solid var(--border, rgba(0,0,0,.14));
  color: var(--text, #16181d);
  padding: 10px 18px;
  border-radius: 999px;
  box-shadow: 0 10px 28px rgba(0,0,0,.4);
  z-index: 500;
  opacity: 0;
  transition: opacity .3s ease, transform .3s ease;
  pointer-events: none;
  font-size: .85rem;
  font-weight: 600;
}
.dd-live-toast.show { opacity: 1; transform: translate(-50%, 0); }

/* ── Closed-session banner (§6 — không khoá viết theo comment, chỉ theo
   effective_open; banner chỉ xuất hiện khi phiên THẬT SỰ đã đóng) ──────── */
.dd-live-closed-banner {
  position: fixed;
  bottom: 16px; left: 50%;
  transform: translateX(-50%);
  background: #3a1f1f;
  color: #ffd6d6;
  border: 1px solid rgba(255,90,90,.4);
  padding: 10px 18px;
  border-radius: 12px;
  z-index: 500;
  font-weight: 600;
  font-size: .85rem;
  box-shadow: 0 10px 28px rgba(0,0,0,.4);
}

/* ── Màn nhỏ: nút tròn giữ nguyên kích thước (52px là ngưỡng chạm thoải mái),
   chỉ popover kéo rộng gần hết bề ngang và thấp hơn để không đè ô viết.
   KHÔNG kéo `.dd-live-rail` full-width như bản panel cũ: khung giờ trong suốt,
   kéo rộng chỉ khiến nó phủ vô hình lên đáy màn hình. ─────────────────────── */
@media (max-width: 860px) {
  .dd-live-rail { bottom: 10px; right: 10px; }
  .dd-live-panel { width: calc(100vw - 20px); }
  .dd-live-rail-list { max-height: 38vh; }
}

/* ── QA-FIX 26/7 — TEST ROOM: `.dd-tr-room` là overlay `position:fixed`
   `z-index:9998` mount thẳng vào <body> (testroom.js:571), cùng cha xếp lớp
   với rail (z 400) ⇒ trong phiên Test Room live, TOÀN BỘ lớp nhận xét trực
   tiếp (rail + toast + banner đóng phiên) nằm SAU phòng thi, học sinh không
   bao giờ thấy nhận xét của giáo viên. Không nâng z-index vô điều kiện: các
   mode khác còn `.dd-fb-ws` (9999) và lightbox ảnh (10000) phải ở trên rail.
   Nên nâng CÓ PHẠM VI bằng class body do buildRail()/removeRail() bật-tắt,
   chỉ khi mode === 'testroom'. Lightbox (10000) vẫn thắng rail (9999).

   M10 (Lỗi 1, owner báo 27/7) — z-index cao hơn thôi thì rail vẫn ĐÈ đúng lên
   `.dd-tr-foot` (tab Part + nút ←/→/✓ nộp bài) vì cả hai đều neo `bottom`.
   `--dd-tr-foot-h` do live-session.js đo lúc chạy (setupTestRoomFootWatch,
   KHÔNG hard-code — chiều cao footer đổi theo tab Part có wrap hay không) và
   ghi lên <body>; chỉ đọc trong phạm vi `body.dd-live-in-room` nên
   Quick/Studio (`bottom:14px` gốc ở rule `.dd-live-rail` phía trên) không
   suy suyển. Fallback 56px khi biến chưa kịp đo (lần đầu, trước lượt đo lại
   — lượt đó dùng setTimeout chứ không rAF, lý do ở live-session.js). ──── */
body.dd-live-in-room .dd-live-rail {
  z-index: 9999;
  bottom: calc(var(--dd-tr-foot-h, 56px) + 10px);
}
body.dd-live-in-room .dd-live-toast,
body.dd-live-in-room .dd-live-closed-banner { z-index: 10001; }

/* ── Lỗi owner báo 31/7 — QUICK/STUDIO: rail che nút chuyển bước ─────────
   Rail nổi (fixed, đáy-phải) cao ~95px kể cả lúc thu gọn, còn nút "Sang bước
   … →" của Studio nằm trong `.dd-nav` — footer THEO LUỒNG ở cuối thân bước,
   căn phải (studio.js navFooter) — và `main` chỉ chừa `padding-bottom:64px`
   (index.css:14). Cuộn tới cuối trang là nút nằm gọn dưới rail.

   Chừa thêm đúng chiều cao phần LUÔN HIỆN (cột nút tròn) + 26px thở. 26 chứ
   không phải 14 (bằng `bottom` của rail): đo trong harness ở 1280×800, mức
   18px vẫn còn giao nhau 188px² (đáy nút 696 vs đỉnh rail 694) vì chiều cao
   trang cuối cùng còn phụ thuộc margin/làm tròn của nội dung bước. Số đo do
   live-session.js ghi lên <body> lúc chạy (measureRailSpace) chứ không
   hard-code: rail cao khác nhau tuỳ có nút "📤 Nộp bài" hay không và tuỳ màn
   ≤860px (rail kéo full chiều ngang). Fallback 96px khi biến chưa kịp đo.

   Phạm vi `body.dd-live-has-rail` — CHỈ bật trong phiên live quick/studio, gỡ
   ở removeRail() — nên trang Viết ngoài phiên live không đổi một pixel nào,
   và Test Room (overlay có vùng cuộn riêng) đi đường --dd-tr-foot-h ở trên. */
body.dd-live-has-rail main {
  padding-bottom: calc(var(--dd-live-rail-h, 96px) + 26px);
}

/* ── M7 — multi-essay switcher (homework.js#mountEssaySwitcher). Floating
   bar, top-center, mirrors .dd-live-toast's placement/shadow language but
   stays put (no auto-hide — the student needs it for the whole session). ── */
.dd-hw-essay-switch {
  position: fixed;
  top: 16px; left: 50%;
  transform: translateX(-50%);
  display: flex; gap: 6px; flex-wrap: wrap; justify-content: center;
  background: var(--surf, #fff);
  color: var(--text, #16181d);
  border: 1px solid var(--border, rgba(0,0,0,.14));
  border-radius: 999px;
  padding: 6px;
  box-shadow: var(--shadow, 0 10px 28px rgba(0,0,0,.22));
  z-index: 480; /* dưới toast (500), trên rail (400) */
}
.dd-hw-essay-chip {
  border: 1px solid transparent;
  background: transparent;
  color: inherit;
  opacity: .75;
  border-radius: 999px;
  padding: 6px 14px;
  font-size: .8rem;
  font-weight: 600;
  cursor: pointer;
}
.dd-hw-essay-chip:hover:not(:disabled) { opacity: 1; background: rgba(255,255,255,.06); }
.dd-hw-essay-chip.is-on {
  opacity: 1;
  background: rgba(90,140,255,.18);
  border-color: rgba(90,140,255,.5);
  cursor: default;
}
.dd-hw-essay-chip.is-done { opacity: .9; }
.dd-hw-essay-chip:disabled { cursor: default; }

@media (max-width: 860px) {
  .dd-hw-essay-switch { top: auto; bottom: 56px; left: 8px; right: 8px; transform: none; }
}

/* ── M8b — Studio rail: grouped by step (work item 1) ──────────────────── */
.dd-live-group + .dd-live-group { margin-top: 4px; }
.dd-live-group-head {
  font-size: .7rem; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
  opacity: .6; padding: 6px 4px 2px;
}
.dd-live-step-chip {
  font-size: .68rem; font-weight: 700; opacity: .8;
  background: var(--surf2, rgba(0,0,0,.06)); border-radius: 999px; padding: 1px 8px;
}
.dd-live-jump {
  display: block; margin-top: 6px;
  background: transparent; border: 1px solid var(--border, rgba(0,0,0,.2));
  color: inherit; border-radius: 8px; padding: 5px 10px;
  font-size: .75rem; font-weight: 600; cursor: pointer; text-align: left;
}
.dd-live-jump:hover { background: var(--surf2, rgba(0,0,0,.06)); }
.dd-live-item.is-deleted { cursor: default; opacity: .6; }

/* Fragment badge (M8b work item 4) — pinned as a CHILD of the [data-frag-id]
   node itself so it dies automatically when studio.js's next full render
   wipes #ddStudio (see live-session.js onStudioRender comment for why no
   separate cleanup pass is needed). */
.dd-live-frag-badge {
  position: absolute; top: -8px; right: -8px;
  background: #f5c518; color: #1a1400;
  font-size: .68rem; font-weight: 700; line-height: 1;
  border-radius: 999px; padding: 3px 6px;
  box-shadow: 0 2px 6px rgba(0,0,0,.35);
  pointer-events: none; z-index: 5;
}

/* Stepper notification dot — same survive-render reasoning as the badge above. */
.dd-live-step-dot {
  position: absolute; top: -3px; right: -3px;
  width: 9px; height: 9px; border-radius: 50%;
  background: #ff5a5a; border: 1px solid var(--surf, #fff);
  pointer-events: none; z-index: 5;
}

/* ── M9b — "nháy viền" định vị sau khi học sinh bấm 1 thẻ nhận xét để nhảy
   tới đúng chỗ (Studio: div bao mảnh cấu trúc; Quick/Test Room: chính ô viết
   <textarea>). 1 class dùng chung cho cả 2 vì cùng là "khoanh viền tạm thời
   ~1.5s" — box-shadow không cần position:relative và tự theo border-radius
   sẵn có của node, không phải khai riêng. Selection trong ô viết đã là
   highlight rồi; viền nháy chỉ để mắt bắt được MÌNH VỪA NHẢY TỚI ĐÂU, không
   phải để tô đậm nội dung — nên không đụng background/color (không có cặp
   nào cần khai, khỏi phạm luật "inherit cạnh bg cứng"). */
@keyframes ddLiveJumpFlash {
  0%, 50%, 100% { box-shadow: none; }
  25%, 75% { box-shadow: 0 0 0 3px var(--accent); }
}
.dd-live-jump-flash { animation: ddLiveJumpFlash 1.5s ease-in-out; }

/* ── M9 — Quick-mode gutter marker (work item 6) ────────────────────────
   .dd-live-gutter-wrap replaces the essay <textarea> in the flow with a
   flex row [gutter | textarea]; align-items:stretch (flex default) makes
   the gutter match the textarea's rendered height automatically. */
.dd-live-gutter-wrap { display: flex; align-items: stretch; gap: 4px; }
.dd-live-gutter { position: relative; width: 14px; flex: none; overflow: hidden; }
.dd-live-gutter-mark {
  position: absolute; left: 2px; width: 9px; height: 9px;
  border-radius: 50%; border: 0; padding: 0; cursor: pointer;
  background: #f5c518; box-shadow: 0 1px 3px rgba(0,0,0,.3);
}
.dd-live-gutter-mark:hover { background: #ffd766; }

/* Nút nộp bài trong rail (QA-FIX 26/7) — đường nộp DUY NHẤT cho quick/studio
   trong phiên live, để học sinh không phải tiêu 1 lượt AI "Kiểm tra" mới có
   nút nộp. Test Room dùng nút ✓ của phòng thi, không render nút này.
   31/7: cũng thành nút tròn, nằm TRÊN nút nhận xét. KHÔNG nhét nó vào trong
   popover: đường nộp duy nhất mà phải mở panel mới thấy thì lại là đúng cái
   bẫy "phải bấm thêm một bước mới nộp được" mà QA-FIX 26/7 vừa gỡ. */
.dd-live-rail .dd-live-submit {
  background: var(--accent, #2563eb);
  color: #fff;
  border-color: transparent;
}
.dd-live-rail .dd-live-submit:hover:not(:disabled) { filter: brightness(1.08); }
.dd-live-rail .dd-live-submit:disabled { opacity: .6; cursor: default; transform: none; }

/* Nhãn chữ cạnh nút tròn: nút chỉ có icon thì học sinh phải đoán. Nhãn hiện
   khi hover/focus trên máy có chuột; trên cảm ứng thì `title` + aria-label là
   đường duy nhất, nên cả hai luôn được đặt trong buildRail(). */
.dd-live-fab-label {
  position: absolute; right: calc(100% + 8px); top: 50%;
  transform: translateY(-50%);
  white-space: nowrap;
  background: var(--surf, #fff); color: var(--text, #16181d);
  border: 1px solid var(--border, rgba(0,0,0,.14));
  box-shadow: var(--shadow, 0 12px 32px rgba(0,0,0,.22));
  border-radius: 8px; padding: 5px 9px;
  font-size: .76rem; font-weight: 600;
  opacity: 0; pointer-events: none;
  transition: opacity .15s ease;
}
.dd-live-fab:hover .dd-live-fab-label,
.dd-live-fab:focus-visible .dd-live-fab-label { opacity: 1; }
