body {
    -webkit-font-smoothing: antialiased;
}

/* Nền xám-xanh nhạt (giống bản V1 — slate-100) thay vì trắng tinh, để card/nội dung trắng nổi bật hẳn lên trên nền
   thay vì chìm cùng màu. Muốn quay lại nền trắng tinh cũ: background-color: #ffffff. Muốn quay lại nền hồng gradient:
   background-color: #fff0f3; background-image: radial-gradient(900px 420px at 5% -10%, #fdd9e7 0%, transparent 60%),
   radial-gradient(760px 400px at 98% 0%, #ece0fb 0%, transparent 62%), radial-gradient(700px 500px at 50% 108%, #fcdce9 0%, transparent 60%); */
.page-bg {
    background-color: #f1f5f9;
}

.no-bar::-webkit-scrollbar {
    display: none;
}

.no-bar {
    -ms-overflow-style: none;
    scrollbar-width: none;
}

.card-img {
    transition: transform .55s cubic-bezier(.2,.7,.3,1);
}

.group:hover .card-img {
    transform: scale(1.06);
}

::-webkit-scrollbar {
    width: 8px;
    height: 8px;
}

::-webkit-scrollbar-thumb {
    background: #fd9bb2;
    border-radius: 8px;
}

@media (prefers-reduced-motion: reduce) {
    * {
        animation-duration: .001ms !important;
        transition-duration: .001ms !important;
    }
}

/* Router có <FocusOnNavigate Selector="h1" /> tự đưa focus vào h1 sau mỗi lần chuyển trang để hỗ trợ
   đọc màn hình — giữ hành vi này cho accessibility, chỉ ẩn khung viền focus mặc định của trình duyệt
   vẽ lên tiêu đề (h1 không phải phần tử tương tác nên không cần hiện outline như nút/link/input). */
h1:focus {
    outline: none;
}

/* Icon sóng âm biểu thị có giọng giới thiệu — cùng thiết kế với obs-overlay.html (donate voice),
   dùng lại cho Player: badge tĩnh ở thẻ danh sách, animate khi đang phát ở trang chi tiết. */
.voice-wave {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 12px;
}

.voice-wave span {
    display: block;
    width: 2.5px;
    border-radius: 2px;
    background: currentColor;
}

.voice-wave.is-playing span {
    animation: voice-wave-anim .8s ease-in-out infinite alternate;
}

.voice-wave span:nth-child(1) { height: 4px; animation-delay: 0s; }
.voice-wave span:nth-child(2) { height: 9px; animation-delay: .15s; }
.voice-wave span:nth-child(3) { height: 6px; animation-delay: .3s; }
.voice-wave span:nth-child(4) { height: 10px; animation-delay: .1s; }
.voice-wave span:nth-child(5) { height: 5px; animation-delay: .25s; }

/* Nút sóng âm trên thẻ hàng mobile — thu sóng cho vừa ô, không tràn viền ảnh */
button.row-voice {
    overflow: hidden;
}
button.row-voice .voice-wave {
    height: 9px;
    gap: 1.5px;
}
button.row-voice .voice-wave span {
    width: 2px;
}
button.row-voice .voice-wave span:nth-child(1) { height: 3px; }
button.row-voice .voice-wave span:nth-child(2) { height: 7px; }
button.row-voice .voice-wave span:nth-child(3) { height: 5px; }
button.row-voice .voice-wave span:nth-child(4) { height: 8px; }
button.row-voice .voice-wave span:nth-child(5) { height: 4px; }

/* Nút nghe voice + badge OnCam trên thẻ Player — đúng vị trí/kích thước bản V1, màu đỏ rose V1 */
button.voice-player {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: auto;
    height: 28px;
    min-width: 40px;
    padding: 0 8px;
    border-radius: 9999px;
    background: rgba(255, 255, 255, .92);
    color: #d80c3c;
    box-shadow: 0 1px 4px rgba(0, 0, 0, .18);
}

html.dark button.voice-player {
    background: rgba(15, 23, 42, .88);
    color: #f86285;
}

.cam-badge {
    width: 28px;
    height: 28px;
    border-radius: 9999px;
    display: grid;
    place-items: center;
    background: rgba(255, 255, 255, .92);
    color: #d80c3c;
    font-size: 11px;
    box-shadow: 0 1px 4px rgba(0, 0, 0, .18);
}

html.dark .cam-badge {
    background: rgba(15, 23, 42, .88);
    color: #f86285;
}

@keyframes voice-wave-anim {
    from { transform: scaleY(1); }
    to { transform: scaleY(1.8); }
}

/* Vòng lan tỏa (halo) phía sau 2 nút nổi ChatDock (Chat thế giới / Tin nhắn) — 2 vòng lệch nhịp nhau để
   ra hiệu ứng sóng lan liên tục, chỉ chạy CSS thuần, không cần JS. Màu lấy theo currentColor (class
   text-* đặt trên chính <span class="fab-ring">) nên dùng lại được cho nhiều nút khác nhau. */
.fab-ring {
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: 9999px;
    pointer-events: none;
}

.fab-ring::before,
.fab-ring::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 9999px;
    background: currentColor;
    opacity: .45;
    animation: fab-ring-pulse 2.4s cubic-bezier(0, 0, .3, 1) infinite;
}

.fab-ring::after {
    animation-delay: 1.2s;
}

@keyframes fab-ring-pulse {
    0% { transform: scale(1); opacity: .45; }
    100% { transform: scale(1.9); opacity: 0; }
}

/* Blazor Router tự focus <h1> mỗi lần chuyển trang (FocusOnNavigate, đúng chuẩn a11y cho trình đọc màn
   hình) — trình duyệt mặc định vẽ viền outline đen quanh phần tử được focus bằng JS giống hệt focus bàn
   phím, gây khó chịu về mặt thị giác dù người dùng không hề bấm Tab. Ẩn outline này đi, không ảnh hưởng
   focus bàn phím thật vì h1 vốn không nằm trong luồng Tab tự nhiên. */
h1:focus {
    outline: none;
}

/* Ô nhập liệu (input/textarea/select) toàn site luôn nền trắng — không dùng hồng nhạt. Chọn theo thẻ nên phủ được cả component chung
   (TableSearchBar, SingleSelect...) mà không phải sửa từng class bg-blush-* rải rác; dấu :not() loại các ô không phải ô gõ chữ (và nâng độ ưu tiên của textarea/select lên trên class bg-blush-* của Tailwind). */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="color"]):not([type="button"]):not([type="submit"]),
textarea:not([hidden]),
select:not([hidden]) {
    background-color: #ffffff;
}

/* Logo trong khung điện thoại của banner tải app: nhấp nhô nhẹ + toả sáng hồng để gây chú ý mà không rối mắt. */
@keyframes tbcg-logo-float {
    0%, 100% { transform: translateY(0) scale(1); filter: drop-shadow(0 0 0 rgba(216, 12, 60, 0)); }
    50% { transform: translateY(-4px) scale(1.08); filter: drop-shadow(0 6px 10px rgba(216, 12, 60, .38)); }
}

.logo-float {
    animation: tbcg-logo-float 2.8s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
    .logo-float {
        animation: none !important;
    }
}

/* Chiều cao thanh menu tab (cả padding safe-area). Thanh Đặt đơn/Donate dùng đúng biến này, không cộng safe-area lần nữa — nếu cộng sẽ hở một khe so với menu. */
:root {
    --tabbar-h: calc(51px + env(safe-area-inset-bottom, 0px));
}

/* Hiệu ứng mở modal dùng chung (AppModal, ConfirmHost) — nền mờ dần, hộp thoại phóng to nhẹ + trượt lên, tạo cảm giác
   nổi bật hơn so với việc bật ra tức thì như trước. */
@keyframes tbcg-modal-backdrop-in {
    from { opacity: 0; }
    to { opacity: 1; }
}

.modal-backdrop-in {
    animation: tbcg-modal-backdrop-in .18s ease-out;
}

@keyframes tbcg-modal-pop-in {
    0% { opacity: 0; transform: scale(.94) translateY(10px); }
    100% { opacity: 1; transform: scale(1) translateY(0); }
}

.modal-pop-in {
    animation: tbcg-modal-pop-in .24s cubic-bezier(.2, .8, .3, 1);
}

/* Nền khung chat kiểu "doodle" giống app mobile (ChatWallpaper.js): gradient pastel rất nhạt + ô icon game lặp
   liền mạch. Ô ảnh vẽ sẵn ở 2x (1184px) nên background-size 592px để nét trên màn retina; độ đậm icon đã nằm sẵn
   trong ảnh. Nền đứng yên khi cuộn danh sách tin — bong bóng tin vẫn nền đặc nên chữ không bị lẫn. */
.chat-wallpaper {
    background-color: #fbf3ff;
    background-image: url('/assets/chat-doodle.png?v=1'), linear-gradient(135deg, #fff5f7, #fbf3ff, #f2f5ff);
    background-size: 592px 592px, 100% 100%;
    background-repeat: repeat, no-repeat;
}

html.dark .chat-wallpaper {
    background-color: #111827;
    background-image: url('/assets/chat-doodle-dark.png?v=1'), linear-gradient(135deg, #0f172a, #161a2e, #111827);
}

/* Dark Mode — 3 chỗ không định nghĩa được bằng class dark: của Tailwind vì đều nằm trong file CSS thuần này
   (page-bg là 1 class riêng, scrollbar là pseudo-element, input là rule ép bằng tên thẻ có độ ưu tiên cao hơn
   mọi class Tailwind — xem rule "Ô nhập liệu" phía trên). Toàn bộ màu còn lại của site dùng class dark: trực tiếp
   trong .razor, xem 0.docs/TinhNang_DarkMode.md. */
html.dark .page-bg {
    background-color: #0f172a;
}

html.dark ::-webkit-scrollbar-thumb {
    background: #475569;
}

/* Đè lại đúng rule "Ô nhập liệu" ở trên khi Dark Mode bật — cùng kiểu selector (tên thẻ + :not()) để độ ưu tiên
   cao hơn class dark:bg-* của Tailwind. Chữ + placeholder phải đủ sáng: trình duyệt (Safari) hay giữ
   -webkit-text-fill-color / opacity mặc định làm ô tìm bị mờ. */
html.dark {
    color-scheme: dark;
}

html.dark input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="color"]):not([type="button"]):not([type="submit"]),
html.dark textarea:not([hidden]),
html.dark select:not([hidden]) {
    background-color: #1e293b;
    color: #f8fafc;
    -webkit-text-fill-color: #f8fafc;
    caret-color: #f86285;
}

html.dark input::placeholder,
html.dark textarea::placeholder {
    color: #94a3b8;
    -webkit-text-fill-color: #94a3b8;
    opacity: 1;
}

/* Ô tìm nằm trong khung (Players/Streamers): giữ trong suốt, không bị đè thành khối slate mờ hơn khung. */
html.dark input.bg-transparent {
    background-color: transparent;
}

/* Đồng hồ cát của bộ đếm "Phiên đang diễn ra" (OrderCountdownChip thẻ lớn): tự lật 180° mỗi vòng + vòng lan toả
   phía sau, để người dùng thấy ngay thời gian ĐANG chạy thật chứ không phải con số tĩnh. Không phải icon "đang tải"
   nên không vi phạm quy ước cấm spinner ở trạng thái tải dữ liệu. */
@keyframes tbcg-hourglass-flip {
    0%, 45% { transform: rotate(0deg); }
    55%, 100% { transform: rotate(180deg); }
}

.tbcg-hourglass {
    animation: tbcg-hourglass-flip 2.4s ease-in-out infinite;
}

@keyframes tbcg-countdown-ring {
    0% { transform: scale(1); opacity: .35; }
    100% { transform: scale(1.35); opacity: 0; }
}

.tbcg-countdown-ring {
    background: currentColor;
    animation: tbcg-countdown-ring 2.4s cubic-bezier(0, 0, .3, 1) infinite;
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    .tbcg-hourglass,
    .tbcg-countdown-ring {
        animation: none !important;
    }
}

/* Con trỏ giả của ô nhập mã xác thực (OtpCodeInput) — con trỏ thật bị ẩn vì chữ thật nằm sát mép trái input phủ
   toàn dải, không khớp vị trí từng ô. Nhấp nháy đúng nhịp mặc định của trình duyệt (~1s). */
@keyframes tbcg-otp-caret {
    0%, 49% { opacity: 1; }
    50%, 100% { opacity: 0; }
}

.otp-caret {
    animation: tbcg-otp-caret 1s step-end infinite;
}

@media (prefers-reduced-motion: reduce) {
    .otp-caret {
        animation: none !important;
    }
}


/* Đồng hồ cát "Thanh toán tự động": lật nửa vòng rồi dừng một nhịp, lặp lại — báo hệ thống đang chờ webhook ngân hàng */
@keyframes tbcg-hourglass-flip {
    0% { transform: rotate(0deg); }
    30%, 50% { transform: rotate(180deg); }
    80%, 100% { transform: rotate(360deg); }
}

.hourglass-flip {
    display: inline-block;
    animation: tbcg-hourglass-flip 2.4s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
    .hourglass-flip {
        animation: none !important;
    }
}
