/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   KHUNG TRANG TRÍ VIEWER
   Chỉ có hiệu lực khi <html> được gắn class .tt-bat (do js/trangTri.js gắn). Phòng nào không cấu hình
   khung thì file này không đụng tới một dòng nào của giao diện cũ.

   ⚠⚠ CỐT LÕI CỦA KIẾN TRÚC — ĐỪNG SỬA NGƯỢC (đã đo bằng trình duyệt thật 21/09/2026):
   1. `body` trở thành Ô NỘI DUNG: position:fixed + transform. `transform` biến body thành khối chứa
      của MỌI phần tử position:fixed bên trong nó ⇒ 14 chỗ `document.body.appendChild(...)` trong
      app.js (modal, toast, QR, panel…) TỰ ĐỘNG nằm gọn trong khung mà KHÔNG phải sửa app.js 453KB.
      Đo được: overlay [240,90,945,675] khớp hộp body [240,90,960,675] (lệch 15px = thanh cuộn).
   2. Các lớp trang trí gắn vào <html> (anh em với body), nên KHÔNG bị transform của body kéo theo và
      vẫn bám theo màn hình. Đo được: phủ đủ 1600×900.
   3. Mọi lớp trang trí đều pointer-events:none ⇒ chạm/cuộn xuyên thẳng xuống nội dung. Đo bằng
      elementFromPoint: trả về nội dung, không phải lớp khung.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

html.tt-bat {
  overflow: hidden;
  height: 100%;
  background: var(--tt-mau, #0f172a);
}

/* ⚠⚠ BODY CHỈ LÀM KHUNG CHỨA VÀ CẮT — TUYỆT ĐỐI KHÔNG ĐỂ NÓ CUỘN.
   Bản đầu tôi cho body vừa là khối chứa vừa là vùng cuộn. Sai nặng: `position:fixed` nằm trong phần tử
   có `transform` thì bám theo phần tử đó, nên hễ body cuộn là chúng CUỘN THEO. Đo được: cuộn 400px thì
   thanh bên `#sidebar` từ top 59 tụt xuống −341, tức trôi hẳn khỏi khung — đúng lỗi người dùng báo.
   ⇒ Tách hai vai: body giữ `transform` (khối chứa) + `overflow:hidden` (cắt sạch, không cho gì lọt ra),
   còn việc cuộn giao cho `#tt-cuon` bên trong. Vì khối chứa của các phần tử fixed vẫn là BODY — thứ
   không cuộn — nên thanh bên, tiêu đề, modal đều đứng yên đúng chỗ. */
html.tt-bat body {
  position: fixed;
  left: var(--tt-l, 0px);
  top: var(--tt-t, 0px);
  width: var(--tt-w, 100vw);
  height: var(--tt-h, 100vh);
  margin: 0;
  overflow: hidden;                      /* ★ không thứ gì của trang được lọt ra ngoài khung */
  transform: translateZ(0);              /* ★ điểm 1 ở đầu file — đừng bỏ */
  z-index: 1;
  border-radius: var(--tt-bo, 0px);
}

/* Lớp cuộn: bọc toàn bộ nội dung sẵn có của trang. KHÔNG được đặt transform/filter/will-change ở đây,
   nếu không nó lại thành khối chứa của các phần tử fixed và lỗi trượt quay về y như cũ. */
html.tt-bat #tt-cuon {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;          /* cuộn hết rồi thì thôi, đừng kéo luôn trang phía sau */
}
/* app.js khoá cuộn lúc mở hộp thoại bằng `body.style.overflow='hidden'` (9 chỗ) và class vg-modal-open.
   Body giờ không cuộn nữa nên hai thứ đó thành vô nghĩa — phải bắc cầu sang đúng lớp đang cuộn. */
html.tt-bat body.vg-modal-open #tt-cuon,
html.tt-bat body.vg-sidebar-open #tt-cuon { overflow: hidden; }

/* 4 chỗ duy nhất trong CSS viewer dùng 100vh. Trong khung thì màn hình không còn là mốc nữa,
   để nguyên sẽ luôn thừa một khoảng trắng cuộn được.

   ⚠⚠ `body` PHẢI là `min-height: 0`, KHÔNG được để `100%`. Đo được lỗi này trên trình duyệt thật:
   body đang `position: fixed` nên `100%` quy chiếu về MÀN HÌNH chứ không phải hộp nội dung —
   nó đè mất `height: var(--tt-h)` và ô nội dung cao đúng bằng màn hình (đo: 900px thay vì 726px),
   tức nội dung tràn khỏi ô trống của khung. `.app`/`.main` thì nằm trong body nên `100%` mới đúng. */
html.tt-bat body { min-height: 0 !important; }
html.tt-bat #tt-cuon > .app,
html.tt-bat .app,
html.tt-bat .main { min-height: 100% !important; }
html.tt-bat .sidebar { height: 100% !important; }

/* ⚠ Mấy chỗ dùng 100vw/100vh: trong khung, `body` mới là khối chứa của các phần tử position:fixed,
   nhưng `vw/vh` thì VẪN quy chiếu về màn hình. Để nguyên là chúng lệch ra ngoài ô nội dung.
   Đo được trên trình duyệt thật: `#viewerCredit` (left: calc(100vw + …)/2) lòi sang phải, đẻ ra
   thanh cuộn ngang 8px trong khung. Các luật gốc đều có !important nên ở đây phải !important theo. */
html.tt-bat .viewer-credit { max-width: calc(100% - 20px) !important; }
@media (min-width: 1200px) {
  html.tt-bat .viewer-credit { left: calc((100% + var(--sidebar-width, 280px)) / 2) !important; }
  html.tt-bat .main.expanded .viewer-credit { left: calc((100% + var(--sidebar-collapsed, 84px)) / 2) !important; }
}
/* ── ẢNH PHÓNG TO (lightbox) ──────────────────────────────────────────────────────────────────
   ⚠⚠ BẢN VÁ TRƯỚC CỦA TÔI SAI VÀ LÀM TỆ HƠN: đặt `max-height: calc(100% - 120px)` thẳng lên
      `.lightbox-img`. Nhưng `%` của chiều cao chỉ có nghĩa khi THẺ CHA có chiều cao XÁC ĐỊNH, mà
      `.lightbox-content` lại cao theo nội dung (`height:auto`) ⇒ luật ấy tính ra `none`, đồng thời
      `!important` đã đè mất `max-height:90vh` gốc ⇒ ảnh KHÔNG CÒN GIỚI HẠN CHIỀU CAO, phóng quá cỡ
      rồi tràn khỏi cả thẻ bọc (ô đếm "1 / 1" nằm giữa ảnh, đáy ảnh bị cắt cụt).
   ⇒ Cách đúng: cho THẺ BỌC một khổ xác định tính theo `%` của `.lightbox` (thẻ này `position:fixed`
      + inset 0 nên bám đúng khung, chiều cao xác định), rồi ảnh mới `max-width/height:100%`.
   Chừa lề: hai bên ≥ 70px cho nút chuyển ảnh (`left/right: -70px`), dưới ≥ 40px cho ô đếm
   (`bottom: -40px`). Dưới 640px thì nút chuyển đã nằm bên trong nên chỉ cần lề mỏng. */
html.tt-bat .lightbox-content {
  width: calc(100% - 152px) !important;
  height: calc(100% - 100px) !important;
  max-width: none !important;
  max-height: none !important;
}
html.tt-bat .lightbox-img {
  max-width: 100% !important;
  max-height: 100% !important;
  width: auto !important;
  height: auto !important;
  object-fit: contain !important;
}
@media (max-width: 640px) {
  html.tt-bat .lightbox-content {
    width: calc(100% - 20px) !important;
    height: calc(100% - 96px) !important;
  }
}
@media (max-width: 767px) {
  html.tt-bat .kl-modal-box { max-width: calc(100% - 16px) !important; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   ĐƯA MỌI THỨ DÙNG vh/vw VỀ ĐÚNG KHUNG THU HẸP

   ⚠ Đây là nguồn lỗi tinh vi nhất của cả tính năng. Trong khung, `body` là khối chứa của các phần tử
     `position:fixed`, nên `%` của chúng quy về ĐÚNG khung. Nhưng `vh/vw` thì LUÔN quy về MÀN HÌNH,
     bất kể khung to nhỏ ra sao. Hậu quả người dùng thấy:
       · ảnh phóng to (lightbox) trần 94vw×88vh → to hơn cả khung → bị cắt cụt;
       · bot thông tin nhanh đặt `top:17vh` → rơi sai chỗ so với khung;
       · các hộp thoại `width:min(96vw,940px)` → tràn ra ngoài rồi bị cắt.
     ⇒ Đổi hết sang `%`, vì `%` mới bám theo khung. Các luật gốc phần lớn có !important nên ở đây
     buộc phải !important theo.
   ⚠ Thêm luật vh/vw mới vào CSS viewer thì nhớ bổ sung vào khối này, không thì lại tràn.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* Bot trợ lý + khối lập phương + bảng thông tin của bot */
/* ⚠ CỐ Ý KHÔNG !important ở ba luật này. Robot kéo-thả được: JS đặt left/top thẳng vào thuộc
   tính style. Nếu ở đây !important thì `top` của CSS đè mất `top` do kéo ⇒ kéo dọc xong robot lại
   bật về chỗ cũ. Chỉ cần độ ưu tiên (html.tt-bat + class) là đã thắng luật gốc rồi, và style trực
   tiếp vẫn thắng cả hai — đúng thứ tự mong muốn. */
html.tt-bat .vg-3d-gyro { right: clamp(8px, 2.2%, 44px); top: 17%; }
html.tt-bat .vg-3d-cube { bottom: 8%; }
html.tt-bat .vg-gyro-info { right: calc(clamp(8px, 2.2%, 44px) + 162px); top: 15%; }

/* Ảnh phóng to và các hộp thoại — phải nằm gọn trong khung, không được cắt cụt */
html.tt-bat .kl-modal-box { max-height: 92% !important; }
html.tt-bat .qra-box { max-width: 94% !important; max-height: 88% !important; }
html.tt-bat .vg-follow-box { max-width: 94% !important; max-height: 80% !important; }
html.tt-bat #announcementModal .modal-box { max-width: min(94%, 680px) !important; }
html.tt-bat .note-modal-box { max-height: 85% !important; }
html.tt-bat .pic-modal-box { max-height: 88% !important; }
html.tt-bat .avatar-zoom-container { max-width: 80% !important; }
html.tt-bat .lhs-modal { width: min(96%, 940px) !important; max-height: 90% !important; }
html.tt-bat .nfx-card { width: min(96%, 880px) !important; max-height: 90% !important; }
@media (max-width: 480px) {
  html.tt-bat .flxlb-box { max-height: 94% !important; }
}
@media (max-width: 767px) {
  html.tt-bat .nfx-card { max-height: 94% !important; }
}
/* Thanh bên ở khổ hẹp: 85vw là 85% MÀN HÌNH, trong khung hẹp thì nó chiếm gần hết chỗ */
html.tt-bat .sidebar { max-width: 85% !important; }


/* ───────────────────────────── Các lớp trang trí (con của <html>) ───────────────────────────── */
.tt-lop {
  position: fixed;
  pointer-events: none;                  /* ★ điểm 3 — yêu cầu tuyệt đối của người dùng */
  -webkit-user-select: none;
  user-select: none;
}

/* Nền quanh khung. 4 kiểu, xem chú thích trong js/trangTri.js:
   ambient (nhoè ảnh khung) · anh (ảnh riêng) · noidung (hoà làm một) · color/none (màu trơn). */
#tt-nen {
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background: var(--tt-mau, #0f172a);
}
#tt-nen i,
#tt-nen u {
  position: absolute;
  /* Nhoè mạnh thì mép ảnh bị loang trong suốt, nên phải nới ra ngoài khung nhìn rồi phóng nhẹ.
     Độ nhoè = 0 thì JS đặt --tt-noi:0 / --tt-phong:1 để ảnh nền giữ đúng nét và đúng khuôn hình. */
  inset: var(--tt-noi, -14%);
  display: block;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  filter: blur(var(--tt-mo, 64px)) saturate(var(--tt-bh, 1.8)) brightness(var(--tt-sang, 0.68));
  transform: scale(var(--tt-phong, 1.2));
  opacity: 0.95;
}

/* ★ Chế độ "hoà làm một": nền phải trải ĐÚNG KHỔ MÀN HÌNH và tuyệt đối KHÔNG nhoè, không phóng to —
   chỉ thế thì mảng nền ngoài khung mới nối liền với mảng nền trong ô, mắt không thấy ranh giới. */
html.tt-nennd #tt-nen i,
html.tt-nennd #tt-nen u {
  inset: 0;
  filter: none;
  transform: none;
  background-attachment: scroll;
  /* ★ Cuộn tới đâu màu đổi tới đó. CSS không chuyển mượt được `background-image`, nên JS dùng HAI lớp
     đổi vai: vẽ màu mới lên lớp đang ẩn rồi cho nó rõ dần, lớp kia mờ dần. Đổi màu êm, không giật. */
  transition: opacity .55s ease;
}
/* … và bản nền nằm TRONG ô nội dung phải tắt đi, nếu không sẽ có hai dải gradient khác khổ
   chồng nhau, lộ vệt ngay tại mép khung. `.content`/`.app` vốn đã trong suốt nên nội dung vẫn
   nhìn thấy nền chung phía sau.

   ⚠⚠ TẮT BẰNG `opacity`, TUYỆT ĐỐI KHÔNG BẰNG `background-image: none`.
   Đã dính lỗi này: JS phải ĐỌC LẠI nền của trang vài nhịp (trang áp chủ đề sáng/tối và ảnh nền riêng
   của filter link sau khi tải xong). Nếu tắt bằng `background-image: none` thì từ lần đọc thứ hai trở
   đi nó đọc đúng cái mình vừa tắt, thấy "none", rồi chép cái rỗng đó ra lớp nền ngoài ⇒ mất sạch nền.
   Đặt `opacity: 0` thì `getComputedStyle` vẫn trả về gradient thật, mà mắt vẫn không thấy bản trong ô. */
html.tt-nennd body::before,
html.tt-nennd body::after { opacity: 0 !important; }

/* Máy yếu: hạ độ nhoè (blur lớn rất nặng trên GPU di động cũ). Chế độ "hoà làm một" không nhoè nên
   không dính luật này. */
@media (max-width: 480px) {
  html:not(.tt-nennd) #tt-nen i,
  html:not(.tt-nennd) #tt-nen u { filter: blur(calc(var(--tt-mo, 64px) * 0.62)) saturate(1.6) brightness(0.7); }
}

/* Lớp ảnh trang trí. Mỗi bộ có thể có NHIỀU ảnh, mỗi ảnh đặt vị trí/kích thước riêng cho từng loại
   thiết bị — JS tính ra px rồi gán thẳng, nên ở đây chỉ cần định vị tuyệt đối. */
/* ★ LỚP NẰM SAU LƯNG TRANG.
   Ảnh đặt TRƯỚC dòng mốc "Nội dung trang" vẽ ở đây — sau nền toả sáng nhưng trước mặt trang.
   Nhờ vậy ảnh nền lớn không còn che kín mặt trang như trước. */
#tt-sau { inset: 0; z-index: 0; }
#tt-sau img { position: absolute; display: block; transform-origin: center center; }

/* Chế độ đè thẳng: trang nằm trong luồng bình thường, muốn lớp chui ra sau nó thì phải âm z-index.
   body::before của trang ở z-index -2, nên -1 đúng là khe giữa nền trang và nội dung trang. */
html.tt-delen #tt-sau { z-index: -1; }

/* Có lớp nằm sau lưng ⇒ tắt nền riêng của trang, nếu không nó che kín lớp phía sau.
   ⚠ Tắt bằng opacity chứ KHÔNG phải background-image:none — lý do xem phần nền "hoà làm một". */
html.tt-losau body::before,
html.tt-losau body::after { opacity: 0 !important; }

#tt-khung { inset: 0; z-index: 2147483000; }
#tt-khung img {
  position: absolute;
  display: block;
  transform-origin: center center;
  /* Ảnh luôn được JS đặt đúng khổ theo tỉ lệ gốc nên không cần object-fit, và không bao giờ méo. */
}

/* ── Chế độ ĐÈ THẲNG LÊN TRANG ──────────────────────────────────────────────────────────────────
   Trang giữ nguyên khổ, không bọc lại, không thu nhỏ, không đụng gì tới bố cục — chỉ thêm lớp ảnh
   phủ lên trên. Đây là chế độ an toàn nhất vì không sửa cấu trúc DOM của trang. */
html.tt-delen #tt-nen { display: none; }

#tt-hat { inset: 0; z-index: 2147483001; }
#tt-hat canvas { display: block; width: 100%; height: 100%; }

/* Người dùng bật "giảm chuyển động" thì tắt hẳn hạt rơi — JS cũng không chạy vòng lặp. */
@media (prefers-reduced-motion: reduce) {
  #tt-hat { display: none; }
  #tt-nen i { filter: blur(48px) saturate(1.4) brightness(0.7); }
}

/* ── Ba hộp thoại còn sót (quét bằng máy mới thấy: duyệt mọi luật CSS có vw/vh rồi đối chiếu với
      danh sách đã đè) ──────────────────────────────────────────────────────────────────────────
   `%` ở đây tính được vì thẻ cha `.modal`/`.events-modal` đều `position:fixed; inset:0` nên có
   chiều cao XÁC ĐỊNH. Đừng bê cách này sang thẻ cha cao theo nội dung — đó đúng là chỗ đã sai với
   ảnh phóng to. */
html.tt-bat .modal-box { max-height: 90% !important; }
html.tt-bat .events-modal-box { max-height: 88% !important; }
html.tt-bat .event-detail-box { max-height: 90% !important; }
@media (max-width: 768px) {
  html.tt-bat .modal-box { max-height: 85% !important; }
  html.tt-bat .events-modal-box,
  html.tt-bat .event-detail-box { max-height: 95% !important; }
}
@media (max-width: 767px) {
  html.tt-bat .modal-box,
  html.tt-bat .events-modal-box { max-width: calc(100% - 16px) !important; max-height: 92% !important; }
}
@media (max-width: 480px) {
  html.tt-bat .events-modal-box,
  html.tt-bat .event-detail-box { max-height: 98% !important; }
}
