/* =============================================================================
 * bulbal-messages.css — Phase 03: khung tin nhắn (bong bóng chat) — theme Bulbal.
 * Nạp SAU css/base.css + bulbal-tokens.css. CHỈ overlay trình bày, KHÔNG thêm/
 * xoá/đổi thứ tự phần tử DOM. Mọi màu PHẢI qua var(--bb-*) khai báo ở
 * bulbal-tokens.css (Phase 01) — cấm hardcode hex/rgba, cấm !important.
 *
 * Vùng sở hữu độc quyền: #messages-panel, #scroller.chat-box và toàn bộ bên
 * trong (li.left/right/single/first/last/middle/meta/flash, .bubble, .bubble.tip,
 * .bubble.date, .content-meta, .message-content, .timestamp, .timestamp-padding,
 * .author, li.left > .avatar-box, .menuTrigger trong bubble), #go-to-latest.
 * KHÔNG đụng #messages-container (nền chấm, thuộc Phase 01) và KHÔNG đụng
 * #topic-caption-panel (header khung chat, thuộc Phase 01 — dù prompt điều phối
 * có nhắc tới, file phase-03 gốc không liệt kê selector này trong "File
 * Ownership" nên bỏ qua để tránh đè lên P01, xem report).
 *
 * BA CẢNH BÁO BẮT BUỘC NHỚ (đã có người vấp trước đây):
 *   1) KHÔNG đặt display:flex lên .content-meta — base dùng
 *      span.timestamp{float:right} + clearfix .message-content:after{clear:both}
 *      để "giờ nằm cuối dòng" kiểu Telegram. Flex-hoá sẽ huỷ float, giờ rớt
 *      xuống dòng riêng, xấu hơn nguyên bản.
 *   2) KHÔNG thêm ::after{content:"done_all"} — dấu đã nhận là phần tử THẬT do
 *      ReceivedMarker render sẵn bên trong span.timestamp (i.material-icons).
 *      Thêm nữa sẽ hiện 2 dấu.
 *   3) Class ẩn của #go-to-latest là ".hidden" (base: .action-button.hidden),
 *      KHÔNG phải ".is-hidden" như bản mockup ghi nhầm.
 * ============================================================================= */

/* ── 1. #messages-panel — vùng cuộn, neo tin mới nhất xuống đáy ──────────────
 *
 * 🔴 LỖI ĐÃ SỬA 260730 — KHÔNG BAO GIỜ đặt `justify-content: flex-end` ở đây.
 * Bản đầu (đợt 1) dùng flex-end để neo tin mới xuống đáy ⇒ KHUNG CHAT KHÔNG CUỘN
 * ĐƯỢC, cả desktop lẫn mobile. Đây là bẫy kinh điển của flexbox: phần nội dung
 * tràn về phía ĐẦU trục (lên trên) KHÔNG được tính vào scrollHeight và không thể
 * cuộn tới. Số đo thật lúc lỗi (cửa sổ cao 320px): nội dung #scroller = 360px
 * nhưng panel báo clientHeight = scrollHeight = 181px, scrollTop luôn = 0, đỉnh
 * hội thoại nằm ngoài khung và mất hẳn.
 *
 * Cách neo đáy ĐÚNG: để panel cuộn bình thường, đẩy con xuống bằng
 * `margin-top: auto` trên #scroller (xem mục 2) — ít tin thì dồn xuống đáy,
 * nhiều tin thì cuộn được đầy đủ. */
#messages-panel {
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  /* Khai báo TƯỜNG MINH giá trị mặc định (thay vì chỉ xoá dòng flex-end cũ):
   * vừa là biển báo "đừng đổi", vừa để bản CSS này khi tiêm chồng lên bản cũ
   * lúc QA vẫn huỷ được flex-end — xoá một khai báo không tự huỷ khai báo cũ. */
  justify-content: flex-start;
  padding: 18px 0 8px;
}

/* ── 2. #scroller.chat-box — cột giữa trang, khoảng cách trong cụm nhỏ ─────── */
#scroller.chat-box {
  list-style: none;
  /* margin-top:auto = neo cụm tin xuống ĐÁY khi hội thoại ít tin, nhưng KHÔNG
   * chặn cuộn khi nhiều tin (khác hẳn justify-content:flex-end ở panel — xem
   * ghi chú lỗi mục 1). trái/phải auto giữ nguyên việc căn giữa cột. */
  margin: auto auto 0;
  padding: 0 24px;
  max-width: var(--bb-chat-max);
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

/* ── 3. Canh trái/phải/giữa + khoảng cách cụm ──────────────────────────────── */
#scroller > li.left,
#scroller > li.right {
  max-width: 74%;
}
#scroller > li.left {
  align-self: flex-start;
}
#scroller > li.right {
  align-self: flex-end;
}
#scroller > li.meta {
  align-self: center;
}
#scroller > li.first {
  margin-top: 12px;
}

/* ── 4. Vô hiệu đuôi nhọn của .bubble.tip ──────────────────────────────────
 * base vẽ tam giác bằng .left/.right .bubble.tip::before (clip-path). Mockup
 * bỏ đuôi, dùng bo góc vát ở mục 6 thay thế. Selector có #scroller (id) nên
 * specificity cao hơn ".left .bubble.tip::before" (3 class) của base — thắng
 * mà không cần !important. */
#scroller .bubble.tip::before {
  content: none;
}

/* ── 5. .bubble — khung chung 2 phía ───────────────────────────────────────── */
#scroller .bubble {
  padding: 8px 13px 7px;
  border-radius: var(--bb-r-bub);
  font-size: var(--bb-fs-base);
  line-height: 1.5;
  word-break: break-word;
  transition: transform var(--bb-dur) var(--bb-ease), box-shadow var(--bb-dur) var(--bb-ease);
}
#scroller > li:hover .bubble {
  transform: translateY(-1px);
}

/* Base lồng .message-content bên trong .bubble > .content-meta và tự thêm
 * padding ngang riêng (0.75rem) — nếu giữ nguyên sẽ cộng dồn với padding của
 * .bubble ở trên (padding đôi). Dồn toàn bộ padding về .bubble, .message-content
 * chỉ còn co giãn theo nội dung. */
#scroller .message-content {
  padding: 0;
}

/* ── 6. Màu 2 phía ──────────────────────────────────────────────────────────── */
#scroller > li.left .bubble {
  background: var(--bb-bub-in);
  color: var(--bb-txt-1);
  border: 1px solid var(--bb-bub-in-line);
  box-shadow: var(--bb-sh-1);
}
#scroller > li.right .bubble {
  background: var(--bb-bub-out);
  color: var(--bb-txt-on-brand);
  box-shadow: var(--bb-sh-3);
}

/* Bo góc theo cụm: chỉ tin CUỐI mỗi cụm mới vát nhẹ về phía người gửi.
 * (li.single cũng dính class .tip nhưng KHÔNG vát — giữ bo tròn đều 4 góc.) */
#scroller > li.last.left .bubble {
  border-bottom-left-radius: var(--bb-r-bub-tail);
}
#scroller > li.last.right .bubble {
  border-bottom-right-radius: var(--bb-r-bub-tail);
}

/* ── 7. .timestamp — GIỮ float:right của base, chỉ chỉnh màu/cỡ/khoảng cách ── */
#scroller .timestamp {
  font-size: var(--bb-fs-meta);
  margin-left: 10px;
  white-space: nowrap;
}
#scroller > li.left .timestamp {
  color: var(--bb-txt-3);
}
#scroller > li.right .timestamp {
  /* bulbal (P05, QA 260729): bản gốc để opacity:0.9 ("trắng ~90% đủ đọc") — ĐO LẠI bằng
   * script scratch/scripts/wcag-contrast.mjs cho thấy KHÔNG đủ: opacity trộn chữ trắng với
   * chính nền gradient ngay dưới nó trước khi so màu, tại điểm sáng nhất (--bb-bub-out stop
   * 1) ra ~4.21:1 (sáng) / ~4.49:1 (tối) — cả 2 TRƯỢT AA 4.5:1 cho chữ 11.5px (không phải
   * "chữ lớn" nên không được hưởng ngưỡng 3:1). Bỏ opacity, giữ trắng đặc — khớp lại đúng số
   * đã kiểm chứng cho bong bóng (4.81:1 sáng / 5.17:1 tối, xem report P03 + phase-05). */
  color: var(--bb-txt-on-brand);
}
#scroller .timestamp i.material-icons {
  vertical-align: -2px;
  margin-left: 2px;
}

/* Dấu "đã đọc" (done_all) của base bị ép màu bằng .blue{color:...!important},
 * và "gửi lỗi" (warning) bằng .danger-color{...!important} — file này bị cấm
 * dùng !important nên KHÔNG override được thuộc tính color. Dùng filter (một
 * bước render riêng, không đụng color) để kéo icon sáng hơn, đọc được trên nền
 * gradient xanh. Xem report để biết tỉ lệ tương phản gốc rất thấp (~1.3:1). */
#scroller > li.right .timestamp i.material-icons.blue,
#scroller > li.right .timestamp i.material-icons.danger-color {
  filter: brightness(1.9) saturate(0.5);
}

/* ── 8. Nhãn ngày — pill dính đỉnh khi cuộn ────────────────────────────────── */
#scroller > li.meta {
  position: sticky;
  top: 4px;
  z-index: 3;
  margin: 6px 0 12px;
}
#scroller > li.meta .bubble.date {
  padding: 5px 14px;
  border-radius: var(--bb-r-pill);
  background: var(--bb-chip);
  color: var(--bb-chip-txt);
  border: 1px solid var(--bb-line);
  box-shadow: var(--bb-sh-1);
  font-size: var(--bb-fs-meta);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
/* Chữ nhãn ngày hiện đang là tiếng Anh ("today") do i18n chưa truyền locale
 * (xem Unresolved trong phase-03 — không phải việc CSS sửa được). Vẫn giữ
 * ::first-letter viết hoa phòng khi P05 đổi sang chuỗi có chữ thường ở đầu. */
#scroller > li.meta .bubble.date::first-letter {
  text-transform: uppercase;
}

/* ── 9. Chat nhóm: avatar-box + .author trong li.left ─────────────────────── */
#scroller > li.left > .avatar-box {
  width: 30px;
  height: 30px;
  min-width: 30px;
  min-height: 30px;
  margin-right: 8px;
  margin-bottom: 0;
  align-self: flex-end;
}
/* bulbal (260730): đưa .author lên TRÊN .bubble kiểu Zalo/Telegram bằng
 * flex `order` — KHÔNG đổi thứ tự DOM (JSX vẫn render .bubble trước .author,
 * xem chat-message.jsx). Div bọc ngoài (`li.left > div:last-child`, con thứ 2
 * của li — sau .avatar-box) vốn là block thường; ép flex-column rồi cho
 * .author order:-1 để nó vẽ trước .bubble mà không cần sửa JSX. Chỉ cần
 * li.left vì .author không bao giờ render ở li.right (tin của mình). */
#scroller > li.left > div:last-child {
  display: flex;
  flex-direction: column;
  /* flex-start (thay vì stretch mặc định) để .bubble/.author giữ đúng cỡ theo
   * nội dung như bản block cũ (shrink-to-fit), tránh stretch kéo giãn bubble
   * theo chiều ngang ngoài ý muốn — căn trái khớp mép trái bubble. */
  align-items: flex-start;
}
#scroller .author {
  order: -1;
  padding: 0 0 3px 4px;
  font-size: 12px;
  color: var(--bb-txt-3);
}

/* ── 10. .menuTrigger trong bubble — ẨN HẲN ──────────────────────────────────
 * Nút expand_more absolute top-right đè chữ + timestamp (đặc biệt tin ngắn /
 * mobile: base ép opacity:0.3 nên luôn thấy). Không render từ JSX nữa; rule
 * CSS dự phòng nếu cache/build cũ còn DOM. Không đụng .contact-box / pinned. */
#scroller .menuTrigger {
  display: none;
}

/* ── 11. Đính kèm — không tràn bong bóng ───────────────────────────────────── */
#scroller .message-content img,
#scroller .message-content video {
  max-width: 100%;
  height: auto;
  border-radius: 14px;
  display: block;
}

/* ── 11b. Chữ đặc biệt TRONG bong bóng: link, @nhắc tên, trích dẫn trả lời ──
 *
 * Đo thật trên hội thoại LIVE (nền bong bóng gửi đi ≈ #265CDF, điểm giữa
 * gradient --bb-bub-out). Cả ba đều TRƯỢT AA trước khi vá:
 *   a (link)              #3B82F6 → 1.55:1   (gần như tàng hình)
 *   .reply-quote          #0F172A → 3.13:1
 *   .mention.dk-fg-14     #C32E9E → 1.14:1
 *
 * Gốc rễ của .mention: base.css khai báo `--clr-dk-fg-N: var(--clr-dk-bg-N)`
 * — Tinode DÙNG CHUNG bảng 16 màu cho nền avatar chữ cái VÀ màu chữ @nhắc tên.
 * Bảng --bb-tile-* đợt 3 được tính để làm NỀN cho chữ trắng, nên khi bị dùng
 * làm MÀU CHỮ trên nền xanh thì hỏng. Xử lý hai tầng:
 *   • tokens: tách riêng --clr-*-fg-* sáng hơn cho chế độ tối (bulbal-tokens.css);
 *   • ở đây: trong bong bóng GỬI ĐI thì mọi thứ về chữ trắng (5.71:1).
 * Link ở bong bóng NHẬN cũng phải đổi: #3B82F6 trên nền trắng chỉ 3.68:1. */
#scroller > li.right .message-content a,
#scroller > li.right .message-content .reply-quote {
  color: var(--bb-txt-on-brand);
}
/* NGOẠI LỆ DUY NHẤT của luật "cấm !important" trong file này: base.css dòng
 * ~2969-3000 khai báo cả 32 lớp `.lt-fg-N`/`.dk-fg-N` kèm `!important`, nên
 * specificity bao nhiêu cũng thua. Đo chứng minh: không có !important thì
 * @nhắc tên trong bong bóng xanh vẫn 1.14:1 (sáng) / 3.66:1 (tối). */
#scroller > li.right .message-content .mention {
  color: var(--bb-txt-on-brand) !important;
  font-weight: 600;
}
#scroller > li.right .message-content .reply-quote {
  border-left-color: var(--bb-txt-on-brand);
}
#scroller > li.left .message-content a {
  color: var(--bb-link-in);
}
#scroller .message-content a {
  text-decoration: underline;
}

/* ── 12. #go-to-latest — nút tròn về tin mới nhất ──────────────────────────── */
#go-to-latest {
  width: 44px;
  height: 44px;
  border: 1px solid var(--bb-line);
  border-radius: 50%;
  background: var(--bb-chip);
  color: var(--bb-chip-txt);
  box-shadow: var(--bb-sh-2);
  transition: transform var(--bb-dur) var(--bb-ease), color var(--bb-dur) var(--bb-ease);
}
#go-to-latest:hover {
  transform: translateY(-2px);
  color: var(--bb-brand-600);
}
/* base đã có .action-button.hidden thu 1px + opacity:0 để ẩn hẳn — bổ sung
 * pointer-events để chắc chắn không bắt click khi đang thu nhỏ. */
#go-to-latest.hidden {
  pointer-events: none;
}

/* ── 13. Mobile ≤640px (đúng breakpoint của base, không tự chế) ───────────── */
@media (max-width: 640px) {
  #scroller > li.left,
  #scroller > li.right {
    max-width: 82%;
  }
  #scroller.chat-box {
    padding: 0 12px;
  }
  /* base.css ép .menuTrigger { opacity: 0.3 } vì không có hover — chặn hẳn. */
  #scroller .menuTrigger {
    display: none;
    opacity: 0;
    pointer-events: none;
  }
}

/* ── 14. Tôn trọng prefers-reduced-motion — CHỈ trong vùng sở hữu ─────────── */
@media (prefers-reduced-motion: reduce) {
  #scroller .bubble {
    transition: none;
  }
  #go-to-latest {
    transition: none;
  }
  .agent-typing-dots i {
    animation: none;
    opacity: 0.6;
  }
}

/* ── 15. Agent / peer typing loading row (plain bubble, no markdown) ─────── */
#scroller > li.agent-typing-row {
  display: flex;
  justify-content: flex-start;
  max-width: 78%;
  margin: 4px 0 10px;
  list-style: none;
  clear: both;
  float: left;
  width: auto;
}
.agent-typing-bubble {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-radius: 16px 16px 16px 4px;
  background: var(--bb-bubble-peer-bg, var(--clr-bubble-right-bg, #fafafa));
  color: var(--bb-text-secondary, var(--clr-text-secondary, #757575));
  font-size: 0.92em;
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.06);
}
.agent-typing-label {
  line-height: 1.3;
}
.agent-typing-dots {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 12px;
}
.agent-typing-dots i {
  display: block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--bb-primary, var(--clr-primary-accent, #2094f3));
  opacity: 0.35;
  animation: agent-typing-bounce 1.2s infinite ease-in-out;
}
.agent-typing-dots i:nth-child(2) {
  animation-delay: 0.15s;
}
.agent-typing-dots i:nth-child(3) {
  animation-delay: 0.3s;
}
@keyframes agent-typing-bounce {
  0%,
  80%,
  100% {
    opacity: 0.3;
    transform: translateY(0);
  }
  40% {
    opacity: 1;
    transform: translateY(-3px);
  }
}
