/* Trang chủ: ảnh nền toàn màn hình, các thẻ kính mờ xếp giữa trang, mở đầu bằng một chuỗi animation CSS.
   Mọi chuyển động đều dùng transform và opacity (card đồ họa xử lý, không phải vẽ lại) và tắt hẳn khi người dùng bật "giảm chuyển động". */

body {
  background: transparent; /* để phông nền (nằm sau) hiện ra; màu nền dự phòng đặt ở thẻ html */
}

/* ===== Phông nền ===== */

.backdrop {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  background: var(--bg);
}

/* Ảnh nền trôi rất chậm, như máy quay đang lia nhẹ */
.bg {
  position: absolute;
  inset: 0;
  background: url("/assets/default-bg.webp") center / cover no-repeat;
  animation: drift 42s ease-in-out infinite alternate;
}

@keyframes drift {
  from {
    transform: scale(1.05) translate3d(0, 0, 0);
  }
  to {
    transform: scale(1.14) translate3d(-2%, -1.5%, 0);
  }
}

/* Lớp phủ tối dần về mép để thẻ nổi lên, kèm lớp chấm nhỏ cho nền có kết cấu */
.veil {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at center, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0.62) 100%),
    radial-gradient(rgba(0, 0, 0, 0.38) 1px, transparent 1.3px) 0 0 / 3px 3px;
}

/* ===== Không khí ở phông nền =====
   Nhiều lớp chiều sâu xếp trên lớp phủ tối, tất cả do app.js (makeAtmosphere) tạo theo công thức cố định:
   quầng sáng trôi chậm, sao chớp, ba lớp đốm bay lên (xa: nhỏ, chậm, mờ; giữa: tàn lửa; gần: đốm sáng mờ như đèn thành phố lệch nét),
   thỉnh thoảng một vệt sao băng, và cả bầu không khí nghiêng nhẹ theo con trỏ chuột.
   Màu --s1..--s4 được app.js đo từ chính ảnh nền; chưa đo xong thì dùng bảng màu của trang. */
.sparks {
  --s1: var(--c3);
  --s2: var(--c2);
  --s3: var(--c1);
  --s4: #fff;
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

/* Một quầng sáng lớn trôi chậm hai màu, tạo cảm giác ánh đèn neon lan trong không khí (một phần tử duy nhất cho nhẹ) */
.aurora {
  position: absolute;
  top: -20vmax;
  left: -18vmax;
  width: 76vmax;
  height: 76vmax;
  background:
    radial-gradient(closest-side at 28% 32%, var(--s1), transparent 72%),
    radial-gradient(closest-side at 72% 68%, var(--s3), transparent 72%);
  opacity: 0.15;
  animation: aurora 44s ease-in-out infinite alternate;
}

@keyframes aurora {
  to {
    transform: translate3d(48vw, 30vh, 0) scale(1.12);
  }
}

/* Sao: các cụm nhỏ, mỗi cụm là một phần tử một điểm ảnh có vài bóng đổ (mỗi bóng một ngôi sao), chớp riêng theo nhịp riêng.
   Chia cụm để mỗi lớp chớp chỉ chiếm một mảng nhỏ của màn hình, trình duyệt đỡ phải trộn cả màn hình mỗi khung hình. */
.stars {
  position: absolute;
  top: var(--y);
  left: var(--x);
  width: 1px;
  height: 1px;
  animation: twinkle var(--t) ease-in-out var(--d) infinite alternate;
}

@keyframes twinkle {
  from {
    opacity: 0.2;
  }
  to {
    opacity: 1;
  }
}

/* Ba lớp đốm bay lên. Mỗi lớp trôi lệch nhẹ theo chuột với độ khác nhau (--mx, --my từ -1 đến 1) nên có chiều sâu thị sai */
.layer {
  position: absolute;
  inset: 0;
  transition: transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.layer.far {
  transform: translate3d(calc(var(--mx, 0) * -5px), calc(var(--my, 0) * -3px), 0);
}

.layer.mid {
  transform: translate3d(calc(var(--mx, 0) * -13px), calc(var(--my, 0) * -8px), 0);
}

.layer.near {
  transform: translate3d(calc(var(--mx, 0) * -28px), calc(var(--my, 0) * -17px), 0);
}

/* Mỗi đốm có hai chuyển động chạy cùng lúc: bay lên (transform) và đung đưa ngang (translate), nên đường bay uốn lượn.
   app.js đặt vị trí, cỡ, tốc độ qua các biến --x --s --t --d --w --o --c --sw --st */
.layer i {
  position: absolute;
  bottom: -90px;
  left: var(--x);
  width: var(--s);
  height: var(--s);
  border-radius: 50%;
  background: var(--c);
  box-shadow: 0 0 calc(var(--s) * 4) var(--c), 0 0 calc(var(--s) * 1.5) var(--c);
  opacity: 0;
  animation:
    spark var(--t) linear var(--d) infinite,
    sway var(--st) ease-in-out var(--d) infinite alternate;
}

/* Lớp gần: đốm lớn mềm như đèn đường lệch nét, không có viền */
.layer.near i {
  background: radial-gradient(circle, color-mix(in srgb, var(--c) 62%, transparent), color-mix(in srgb, var(--c) 20%, transparent) 55%, transparent 72%);
  box-shadow: none;
}

@keyframes spark {
  0% {
    transform: translate3d(0, 0, 0) scale(0.6);
    opacity: 0;
  }
  10% {
    opacity: var(--o);
  }
  32% {
    opacity: calc(var(--o) * 0.5);
  }
  55% {
    opacity: var(--o);
  }
  76% {
    opacity: calc(var(--o) * 0.6);
  }
  90% {
    opacity: var(--o);
  }
  100% {
    transform: translate3d(var(--w), -118vh, 0) scale(1.1);
    opacity: 0;
  }
}

@keyframes sway {
  from {
    translate: calc(var(--sw) * -1) 0;
  }
  to {
    translate: var(--sw) 0;
  }
}

/* Sao băng: mỗi vệt chỉ hiện ở 12% đầu của một chu kỳ dài, rồi vắng lặng cho tới lần sau */
.meteor {
  position: absolute;
  top: var(--y);
  left: var(--x);
  width: var(--l);
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--c) 75%, transparent) 70%, #fff);
  box-shadow: 0 0 10px color-mix(in srgb, var(--c) 70%, transparent);
  opacity: 0;
  transform: rotate(28deg);
  animation: meteor var(--t) linear var(--d) infinite;
}

@keyframes meteor {
  0% {
    opacity: 0;
    transform: translate3d(0, 0, 0) rotate(28deg);
  }
  1.5% {
    opacity: 1;
  }
  11% {
    opacity: 0;
    transform: translate3d(42vw, 22.3vw, 0) rotate(28deg);
  }
  100% {
    opacity: 0;
    transform: translate3d(42vw, 22.3vw, 0) rotate(28deg);
  }
}

/* Chưa đọc xong nội dung admin đã lưu thì ẩn nền và thẻ để không bị nhảy.
   Lần đầu vào trang (chưa có bộ nhớ đệm, hàm Vercel khởi động nguội) việc đọc nội dung có thể mất vài giây, nên KHÔNG được tự hiện sớm:
   hiện sớm là lộ trang tĩnh chưa có dữ liệu ngay trước màn chờ "bấm để vào...". app.js luôn kết thúc trạng thái này (đọc xong, hoặc quá
   LOAD_TIMEOUT_MS trong loadSite thì dùng nội dung mặc định). Khoảng chờ dưới đây chỉ là chốt chặn cho trường hợp script không chạy được
   hẳn (lỗi tải module), phải dài hơn LOAD_TIMEOUT_MS. */
html[data-config="loading"] .backdrop,
html[data-config="loading"] .stage,
html[data-config="loading"] .volbox,
html[data-config="loading"] .bar {
  opacity: 0;
  animation: reveal 0s 15s forwards;
}

@keyframes reveal {
  to {
    opacity: 1;
  }
}

/* ===== Màn chờ "bấm để vào..." =====
   Giống guns.lol: ảnh nền mờ và tối, chữ nhấp nhẹ ở giữa; mọi thứ khác ẩn cho tới khi vào. Cú bấm đầu tiên là thao tác của người dùng nên
   trình duyệt cho phép nhạc phát có tiếng. Lúc vào, data-config chuyển sang "ready" và chuỗi mở đầu bên dưới bắt đầu; nền "lấy nét"
   từ đúng trạng thái mờ này (data-gate="used": lớp ảnh nền chạy keyframe unblur, còn .backdrop không chạy focus-in nên không chớp tắt). */
/* Chỉ làm mờ lớp ảnh nền (không phải cả .backdrop): phóng to 1,2 lần để mép ảnh mờ nằm ngoài màn hình (làm mờ cả khối thì mép bị tối), và đốm bay phía trên vẫn rõ nét */
html[data-config="gate"] .bg {
  filter: blur(20px) brightness(0.45);
  transform: scale(1.2);
  animation: none;
}

html[data-config="gate"] :is(.stage, .volbox, .bar) {
  opacity: 0;
  pointer-events: none;
}

.gate {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text);
  font-size: clamp(1.25rem, 3.2vw, 1.75rem);
  font-weight: 700;
  letter-spacing: 0.01em;
}

.gate span {
  padding: 8px 18px;
  text-shadow:
    0 0 18px color-mix(in srgb, var(--c3) 55%, transparent),
    0 0 44px color-mix(in srgb, var(--c1) 35%, transparent);
  animation: gate-pulse 2.4s ease-in-out infinite;
}

.gate:focus-visible {
  outline: none;
}

.gate:focus-visible span {
  outline: 2px solid var(--c3);
  outline-offset: 6px;
  border-radius: 12px;
}

@keyframes gate-pulse {
  0%,
  100% {
    opacity: 0.62;
    transform: scale(1);
  }
  50% {
    opacity: 1;
    transform: scale(1.05);
  }
}

@keyframes unblur {
  from {
    filter: blur(20px) brightness(0.45);
    transform: scale(1.2);
  }
}

html[data-config="ready"][data-gate="used"] .backdrop {
  animation: none;
}

html[data-config="ready"][data-gate="used"] .bg {
  animation:
    drift 42s ease-in-out infinite alternate,
    unblur 1.9s cubic-bezier(0.2, 0.7, 0.1, 1) backwards;
}

/* ===== Chuỗi mở đầu =====
   Chạy một lần khi app.js đặt data-config="ready" (nội dung đã sẵn sàng). Thứ tự và độ trễ, tính từ lúc đó:
   0s     nền "lấy nét" từ mờ sang rõ
   0.25s  các thẻ nổi lên lần lượt, hơi nghiêng 3D
   0.5s   vòng sáng quanh ảnh đại diện xoay vào
   0.9s   từng chữ của tên rơi xuống
   1.3s   một vệt sáng quét qua mỗi thẻ
   1.45s  lời giới thiệu hiện ra
   1.6s   các icon nền tảng bật lên
   1.2s   thanh nhạc trượt lên từ chân trang; nhóm âm lượng ở góc trên bên trái bật lên
   1.5s   các ô logo game bật lên
   Các keyframe chỉ có khung "from", nên trạng thái cuối chính là kiểu thường của phần tử: nếu animation bị tắt thì nội dung vẫn hiện đủ. */

html[data-config="ready"] .backdrop {
  animation: focus-in 1.9s cubic-bezier(0.2, 0.7, 0.1, 1) backwards;
}

@keyframes focus-in {
  from {
    opacity: 0;
    filter: blur(20px) brightness(0.45);
    transform: scale(1.08);
  }
}

/* ===== Bố cục ===== */

/* Một cột duy nhất rộng bằng thẻ rộng nhất (thẻ Game tôi chơi, co theo nội dung, tối đa 640 px hoặc bề rộng màn hình):
   thẻ hồ sơ và thẻ game luôn cùng một bề rộng. */
.stage {
  display: grid;
  grid-template-columns: fit-content(min(640px, 100%));
  justify-content: center;
  align-content: center;
  gap: 14px;
  min-height: 100svh;
  padding: 56px 16px 48px;
  perspective: 1400px;
}

.card {
  position: relative;
  border: 1px solid var(--line);
  border-radius: 28px;
  background: var(--panel);
  -webkit-backdrop-filter: blur(22px) saturate(1.3);
  backdrop-filter: blur(22px) saturate(1.3);
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.55);
}

html[data-config="ready"] .card {
  animation: rise 0.95s cubic-bezier(0.2, 0.7, 0.1, 1) backwards;
  animation-delay: calc(var(--i, 0) * 150ms + 250ms);
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(28px) rotateX(10deg) scale(0.96);
  }
}

/* Vệt sáng quét chéo qua mặt kính, một lần cho mỗi thẻ */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(105deg, transparent 38%, rgba(255, 255, 255, 0.16) 50%, transparent 62%) no-repeat;
  background-position: 130% 0;
  background-size: 260% 100%;
  opacity: 0;
  pointer-events: none;
}

html[data-config="ready"] .card::after {
  animation: sheen 1.5s ease-out backwards;
  animation-delay: calc(var(--i, 0) * 220ms + 1.3s);
}

@keyframes sheen {
  from {
    opacity: 1;
    background-position: 130% 0;
  }
  to {
    opacity: 1;
    background-position: -45% 0;
  }
}

/* ===== Hồ sơ ===== */

.profile {
  min-width: min(100%, 340px); /* thẻ game chỉ có vài logo thì thẻ hồ sơ vẫn đủ rộng cho tên và icon */
  isolation: isolate;
  display: grid;
  justify-items: center;
  gap: 6px;
  padding: 40px 32px 32px;
  text-align: center;
}

/* Vầng sáng chạy theo nhịp nhạc: một lớp sáng nằm sau ảnh đại diện và tên, chỉ đổi độ trong suốt (--beat từ 0 đến 1).
   Đổi độ trong suốt do card đồ họa lo, không phải vẽ lại; trước đây đổi độ rộng bóng đổ của chữ làm tụt khung hình khi nhạc phát. */
.profile::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  z-index: -1;
  width: min(100%, 560px);
  height: 320px;
  background:
    radial-gradient(closest-side at 30% 55%, color-mix(in srgb, var(--c1) 55%, transparent), transparent),
    radial-gradient(closest-side at 70% 55%, color-mix(in srgb, var(--c3) 45%, transparent), transparent),
    radial-gradient(closest-side, color-mix(in srgb, var(--c2) 60%, transparent), transparent);
  opacity: var(--beat, 0);
  pointer-events: none;
  transform: translateX(-50%);
  will-change: opacity;
}

/* Ảnh đại diện nằm trong một vòng sáng quay liên tục quanh nó */
.avatar-ring {
  position: relative;
  display: grid;
  place-items: center;
  width: 142px;
  aspect-ratio: 1;
}

.avatar-ring::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(transparent 0%, var(--c1) 12%, var(--c2) 38%, var(--c3) 62%, transparent 82%);
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 2px));
  animation: orbit 6s linear infinite;
}

@keyframes orbit {
  to {
    transform: rotate(360deg);
  }
}

html[data-config="ready"] .avatar-ring {
  animation: ring-in 1s cubic-bezier(0.2, 0.9, 0.2, 1) 0.5s backwards;
}

@keyframes ring-in {
  from {
    opacity: 0;
    transform: scale(0.5) rotate(-120deg);
  }
}

.avatar {
  display: grid;
  place-items: center;
  width: 118px;
  aspect-ratio: 1;
  overflow: hidden;
  border: 3px solid rgba(255, 255, 255, 0.92);
  border-radius: 50%;
  background: linear-gradient(135deg, color-mix(in srgb, var(--c1) 70%, #1a0b2e), color-mix(in srgb, var(--c2) 70%, #1a0b2e));
  box-shadow: 0 0 24px color-mix(in srgb, var(--c2) 55%, transparent);
  color: #fff;
  font-size: 3rem;
  font-weight: 800;
  line-height: 1;
}

.avatar img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Tên màu nhấn, phát sáng và hơi lệch màu như màn hình hỏng */
.name {
  margin: 14px 0 0;
  max-width: 100%;
  color: var(--c2);
  font-size: clamp(1.9rem, 6vw, 2.6rem);
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.15;
  overflow-wrap: anywhere;
  text-shadow:
    1.5px 0 rgba(255, 255, 255, 0.6),
    -1.5px 0 color-mix(in srgb, var(--c1) 70%, #000),
    0 0 18px color-mix(in srgb, var(--c2) 65%, transparent);
}

.name .word {
  display: inline-block;
  white-space: nowrap;
}

.name .ch {
  display: inline-block;
  /* Màu chuyển dần hồng, tím, xanh băng từ chữ đầu tới chữ cuối: --t chạy từ 0 đến 1 (do app.js đặt cho từng chữ).
     Nửa đầu trộn hồng với tím, nửa sau trộn kết quả với xanh băng. */
  color: color-mix(in oklab, color-mix(in oklab, var(--c1), var(--c2) clamp(0%, var(--t, 0) * 200%, 100%)), var(--c3) clamp(0%, (var(--t, 0) - 0.5) * 200%, 100%));
}

/* Từng chữ rơi xuống lần lượt (--i là thứ tự chữ) */
html[data-config="ready"] .name .ch {
  animation: drop 0.8s cubic-bezier(0.2, 0.8, 0.2, 1) backwards;
  animation-delay: calc(0.9s + var(--i, 0) * 45ms);
}

@keyframes drop {
  from {
    opacity: 0;
    transform: translateY(0.6em) scale(0.8);
  }
}

/* Thỉnh thoảng cả tên giật nhẹ kiểu hỏng màn hình: nửa giây trong mỗi chín giây, phần còn lại đứng yên */
html[data-config="ready"] .name {
  animation: glitch 9s steps(1, end) 4.5s infinite;
}

@keyframes glitch {
  0%,
  94% {
    transform: none;
  }
  95% {
    transform: translate(-3px, 0) skewX(-9deg);
    text-shadow: 5px 0 var(--c1), -5px 0 var(--c3), 0 0 18px var(--c2);
  }
  96% {
    transform: translate(3px, 1px) skewX(7deg);
    text-shadow: -5px 0 var(--c1), 5px 0 var(--c3), 0 0 18px var(--c2);
  }
  97% {
    transform: translate(-2px, -1px);
  }
  98%,
  100% {
    transform: none;
  }
}

.bio {
  max-width: 44ch;
  margin: 0;
  color: var(--muted);
  overflow-wrap: anywhere;
}

html[data-config="ready"] .bio,
html[data-config="ready"] .empty {
  animation: fade-up 0.8s ease 1.45s backwards;
}

@keyframes fade-up {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}

.socials {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px 14px;
  margin: 18px 0 0;
  padding: 0;
  list-style: none;
}

html[data-config="ready"] .socials li {
  animation: pop 0.6s cubic-bezier(0.3, 1.6, 0.5, 1) backwards;
  animation-delay: calc(1.6s + var(--i, 0) * 80ms);
}

@keyframes pop {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.4);
  }
}

.social {
  position: relative;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: 14px;
  color: #fff;
  filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.5));
  transition: transform 0.2s, color 0.2s, filter 0.2s;
}

.social svg {
  width: 30px;
  height: 30px;
  fill: currentColor;
}

.socials li:nth-child(3n + 1) {
  --hover: var(--c1);
}

.socials li:nth-child(3n + 2) {
  --hover: var(--c2);
}

.socials li:nth-child(3n) {
  --hover: var(--c3);
}

.social:hover,
.social:focus-visible {
  color: var(--hover, var(--c3));
  filter: drop-shadow(0 0 10px var(--hover, var(--c3)));
  transform: translateY(-3px) scale(1.12);
}

.social:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.tip {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  display: grid;
  padding: 6px 12px;
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.82);
  color: #fff;
  font-size: 0.8125rem;
  line-height: 1.3;
  text-align: center;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, 4px);
  transition: opacity 0.15s, transform 0.15s;
}

.tip small {
  color: var(--muted);
  font-size: inherit;
}

.social:hover .tip,
.social:focus-visible .tip {
  opacity: 1;
  transform: translate(-50%, 0);
}

.empty {
  margin: 14px 0 0;
  color: var(--muted);
}

/* ===== Trình phát nhạc: thanh cố định ở chân trang, kiểu YouTube Music =====
   Màu lấy theo ảnh nền hiện tại: nền xanh đen rất tối, neon xanh lam, tím chàm và hồng magenta. */

:root {
  --bar-h: 72px;
}

.bar {
  position: fixed;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 20;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.5fr) minmax(0, 1fr);
  align-items: center;
  gap: 12px;
  height: var(--bar-h);
  padding: 0 var(--gutter);
  border-top: 1px solid color-mix(in srgb, var(--c3) 24%, transparent);
  background:
    linear-gradient(90deg, color-mix(in srgb, var(--c1) 9%, transparent), transparent 35%, transparent 65%, color-mix(in srgb, var(--c3) 9%, transparent)),
    linear-gradient(180deg, rgba(14, 21, 33, 0.88), rgba(7, 10, 17, 0.95));
  -webkit-backdrop-filter: blur(26px) saturate(1.5);
  backdrop-filter: blur(26px) saturate(1.5);
  box-shadow: 0 -14px 44px rgba(0, 0, 0, 0.5);
}

html[data-config="ready"] .bar {
  animation: bar-up 0.85s cubic-bezier(0.2, 0.7, 0.1, 1) 1.1s backwards;
}

@keyframes bar-up {
  from {
    opacity: 0;
    transform: translateY(100%);
  }
}

/* Có nhạc thì chừa chỗ cho thanh nhạc ở cuối trang */
html:not([data-source=""])[data-source] .stage {
  padding-bottom: calc(var(--bar-h) + 28px);
}

/* Thanh tua mảnh nằm ngay mép trên của thanh nhạc; vùng chạm cao 16 px, nét nhìn thấy chỉ 4 px */
.bar-seek {
  position: absolute;
  top: -8px;
  left: 0;
  width: 100%;
  height: 16px;
  margin: 0;
  background: none;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
}

.bar-seek::-webkit-slider-runnable-track {
  height: 4px;
  background: linear-gradient(90deg, var(--c1), var(--c2), var(--c3)) left / var(--p, 0%) 100% no-repeat, rgba(255, 255, 255, 0.16);
}

.bar-seek::-moz-range-track {
  height: 4px;
  background: rgba(255, 255, 255, 0.16);
}

.bar-seek::-moz-range-progress {
  height: 4px;
  background: linear-gradient(90deg, var(--c1), var(--c2), var(--c3));
}

.bar-seek::-webkit-slider-thumb {
  width: 12px;
  height: 12px;
  margin-top: -4px;
  border: 0;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 10px var(--c3);
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 0.15s, transform 0.15s;
  appearance: none;
  -webkit-appearance: none;
}

.bar-seek::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border: 0;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 10px var(--c3);
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 0.15s, transform 0.15s;
}

.bar-seek:hover::-webkit-slider-thumb,
.bar-seek:focus-visible::-webkit-slider-thumb {
  opacity: 1;
  transform: scale(1);
}

.bar-seek:hover::-moz-range-thumb,
.bar-seek:focus-visible::-moz-range-thumb {
  opacity: 1;
  transform: scale(1);
}

.bar-seek:focus-visible {
  outline-offset: -2px;
}

/* Bên trái: phát lại, phát và tạm dừng, thời gian */
.bar-left {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

.ctl,
.play,
.vol {
  display: grid;
  flex: none;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--text);
  transition: background-color 0.15s, transform 0.15s, color 0.15s;
}

.ctl,
.vol {
  width: 40px;
  height: 40px;
}

.ctl:hover,
.vol:hover {
  background: rgba(255, 255, 255, 0.09);
  color: var(--c3);
}

.ctl svg,
.play svg,
.vol svg {
  width: 24px;
  height: 24px;
  fill: currentColor;
}

/* Nút phát là một đĩa gradient hồng, tím: điểm nhấn duy nhất của thanh */
.play {
  width: 46px;
  height: 46px;
  background: linear-gradient(135deg, var(--c1), var(--c2));
  box-shadow: 0 0 22px color-mix(in srgb, var(--c1) 40%, transparent);
  color: #0a0c14;
}

.play:hover {
  transform: scale(1.07);
}

.bar [data-when] {
  display: none;
}

.bar[data-playing="true"] [data-when="playing"],
.bar[data-playing="false"] [data-when="paused"] {
  display: block;
}

.time {
  margin-left: 6px;
  overflow: hidden;
  color: var(--muted);
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Giữa: ảnh bìa nhỏ, tên bài và nghệ sĩ */
.bar-mid {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  min-width: 0;
}

.cover {
  display: grid;
  flex: none;
  place-items: center;
  width: 46px;
  height: 46px;
  overflow: hidden;
  border-radius: 8px;
  background: linear-gradient(135deg, color-mix(in srgb, var(--c1) 60%, #0b1020), color-mix(in srgb, var(--c3) 45%, #0b1020));
  color: #fff;
  font-size: 1.25rem;
  font-weight: 800;
}

.cover img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.player-meta {
  display: grid;
  min-width: 0;
  line-height: 1.3;
}

.title-row {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.player-meta strong,
.player-meta span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.player-meta strong {
  font-weight: 600;
}

.player-meta > span {
  color: var(--muted);
  font-size: 0.8125rem;
}

/* Thanh equalizer: đứng yên khi tạm dừng, nhảy khi nhạc phát */
.eq {
  display: inline-flex;
  flex: none;
  align-items: flex-end;
  gap: 2px;
  height: 14px;
}

.eq i {
  width: 3px;
  height: 100%;
  border-radius: 2px;
  background: var(--c1);
  transform: scaleY(0.25);
  transform-origin: bottom;
}

.eq i:nth-child(2),
.eq i:nth-child(4) {
  background: var(--c2);
}

.eq i:nth-child(3) {
  background: var(--c3);
}

.bar[data-playing="true"] .eq i {
  animation: eq 0.9s ease-in-out infinite alternate;
}

.bar[data-playing="true"] .eq i:nth-child(2) {
  animation-duration: 0.7s;
  animation-delay: -0.3s;
}

.bar[data-playing="true"] .eq i:nth-child(3) {
  animation-duration: 1.1s;
  animation-delay: -0.6s;
}

.bar[data-playing="true"] .eq i:nth-child(4) {
  animation-duration: 0.8s;
  animation-delay: -0.15s;
}

@keyframes eq {
  from {
    transform: scaleY(0.2);
  }
  to {
    transform: scaleY(1);
  }
}

/* Bên phải: thời gian đã phát và tổng */
.bar-right {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  min-width: 0;
}

/* ===== Âm lượng: nhóm nổi ở góc trên bên trái (nút tắt tiếng và thanh âm lượng) ===== */

.volbox {
  position: fixed;
  top: 16px;
  left: 16px;
  z-index: 25;
  display: flex;
  align-items: center;
  gap: 4px;
  height: 46px;
  padding: 0 16px 0 4px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
}

html[data-config="ready"] .volbox {
  animation: pop 0.6s cubic-bezier(0.3, 1.6, 0.5, 1) 1.2s backwards;
}

.vol {
  color: var(--c3);
}

/* Đang tắt tiếng thì biểu tượng và thanh âm lượng chuyển sang màu hồng để nhìn là biết */
.vol[data-muted="true"] {
  color: var(--c1);
}

.vol [data-when] {
  display: none;
}

.vol[data-muted="false"] [data-when="unmuted"],
.vol[data-muted="true"] [data-when="muted"] {
  display: block;
}

.bar-volume {
  width: 88px;
  height: 28px;
  margin: 0;
  background: none;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
}

.bar-volume::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--c2), var(--c3)) left / var(--p, 70%) 100% no-repeat, rgba(255, 255, 255, 0.18);
}

.bar-volume::-moz-range-track {
  height: 4px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.18);
}

.bar-volume::-moz-range-progress {
  height: 4px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--c2), var(--c3));
}

.bar-volume::-webkit-slider-thumb {
  width: 12px;
  height: 12px;
  margin-top: -4px;
  border: 0;
  border-radius: 50%;
  background: #fff;
  appearance: none;
  -webkit-appearance: none;
}

.bar-volume::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border: 0;
  border-radius: 50%;
  background: #fff;
}

html[data-muted="true"] .bar-volume::-webkit-slider-runnable-track {
  background: linear-gradient(90deg, var(--c1), var(--c2)) left / var(--p, 70%) 100% no-repeat, rgba(255, 255, 255, 0.18);
}

/* ===== Nhạc từ YouTube: video hiện trên trang =====
   YouTube yêu cầu trình phát nhúng luôn hiện và tối thiểu 200 x 200. Màn hình hẹp: nằm cuối trang, trên thanh nhạc.
   Màn hình rộng (còn chỗ ngoài cột giữa): nổi ở góc dưới bên phải, ngay trên thanh nhạc. */

.video {
  justify-self: center;
  width: min(100%, 356px);
  height: 200px;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: #000;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.55);
}

html[data-config="ready"] .video {
  animation: rise 0.95s cubic-bezier(0.2, 0.7, 0.1, 1) 1.2s backwards;
}

.video iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

html:not([data-source="youtube"]) .video {
  display: none;
}

@media (min-width: 1480px) {
  .video {
    position: fixed;
    right: var(--gutter);
    bottom: calc(var(--bar-h) + 16px);
    z-index: 15;
  }
}

/* Không phân tích được âm thanh của YouTube (nằm trong khung riêng) nên vầng sáng không chạy theo nhịp;
   thay vào đó nó thở chậm khi đang phát. */
html[data-source="youtube"][data-playing="true"] .profile::before {
  animation: glow-breathe 2.6s ease-in-out infinite;
}

@keyframes glow-breathe {
  0%,
  100% {
    opacity: 0.12;
  }
  50% {
    opacity: 0.5;
  }
}

/* ===== Game tôi chơi: một thẻ mỏng chỉ có logo, tên hiện khi rê chuột ===== */

.games {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 16px;
  padding: 12px 16px 12px 22px;
  border-radius: 22px;
}

.games h2 {
  margin: 0;
  color: var(--muted);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.game-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.game {
  position: relative;
}

html[data-config="ready"] .game {
  animation: pop 0.55s cubic-bezier(0.3, 1.5, 0.5, 1) backwards;
  animation-delay: calc(1.5s + var(--i, 0) * 70ms);
}

/* Mỗi ô mang màu của chính game đó (--g, --g2 do buildLogo đặt): nền, viền và vầng sáng */
.logo {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--g, #a08fff) 38%, transparent);
  border-radius: 13px;
  background: color-mix(in srgb, var(--g, #a08fff) 16%, rgba(255, 255, 255, 0.05));
  box-shadow: 0 0 16px color-mix(in srgb, var(--g2, #a08fff) 28%, transparent);
  color: #fff;
  font-size: 0.875rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  transition: transform 0.18s, box-shadow 0.18s, border-color 0.18s;
}

.logo img {
  width: 100%;
  height: 100%;
  padding: 12%;
  object-fit: contain;
}

.game:hover .logo {
  border-color: color-mix(in srgb, var(--g, #a08fff) 75%, transparent);
  box-shadow: 0 0 24px color-mix(in srgb, var(--g2, #a08fff) 60%, transparent);
  transform: translateY(-2px) scale(1.07);
}

/* Tên game hiện phía trên ô khi rê chuột */
.game::after {
  content: attr(data-name);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  padding: 4px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: rgba(8, 11, 18, 0.96);
  font-size: 0.75rem;
  line-height: 1.4;
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, 4px);
  transition: opacity 0.15s, transform 0.15s;
  white-space: nowrap;
}

.game:hover::after {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* ===== Thành phố đêm: xe bay, sương, đèn pha =====
   Thêm chiều sâu và chuyển động cho phông nền; tất cả chỉ chuyển động bằng transform và opacity, màu lấy từ --s1..--s4 (đo từ ảnh nền). */

/* Xe bay: những vệt đèn lướt ngang qua thành phố (đỏ cam đuôi xe, trắng xanh đèn pha), mỗi chiếc một độ cao, tốc độ và hướng riêng */
.cars {
  position: absolute;
  inset: 0;
}

.cars i {
  position: absolute;
  top: var(--y);
  left: 0;
  width: var(--l);
  height: var(--h);
  border-radius: 2px;
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--c) 70%, transparent) 72%, #fff);
  box-shadow: 0 0 9px var(--c);
  opacity: var(--o);
  animation: fly var(--t) linear var(--d) infinite;
}

.cars i.back {
  background: linear-gradient(270deg, transparent, color-mix(in srgb, var(--c) 70%, transparent) 72%, #fff);
  animation-name: fly-back;
}

@keyframes fly {
  from {
    transform: translate3d(-200px, 0, 0);
  }
  to {
    transform: translate3d(calc(100vw + 200px), 0, 0);
  }
}

@keyframes fly-back {
  from {
    transform: translate3d(calc(100vw + 200px), 0, 0);
  }
  to {
    transform: translate3d(-200px, 0, 0);
  }
}

/* Sương mù trôi sát chân trang */
.fog {
  position: absolute;
  bottom: -8vh;
  left: -20vw;
  width: 130vw;
  height: 34vh;
  background: radial-gradient(ellipse 50% 60% at 50% 70%, color-mix(in srgb, var(--s2) 26%, transparent), transparent 72%);
  opacity: 0.55;
  animation: fog 38s ease-in-out infinite alternate;
}

.fog.b {
  bottom: -12vh;
  height: 28vh;
  background: radial-gradient(ellipse 50% 60% at 50% 70%, color-mix(in srgb, var(--s3) 22%, transparent), transparent 72%);
  animation-duration: 52s;
  animation-direction: alternate-reverse;
}

@keyframes fog {
  to {
    transform: translate3d(12vw, -2vh, 0);
  }
}

/* Đèn pha: hai chùm sáng từ dưới thành phố quét chậm qua lại trên bầu trời */
.beam {
  position: absolute;
  bottom: -6vh;
  left: var(--x);
  width: 18vmax;
  height: 78vh;
  margin-left: -9vmax;
  background: linear-gradient(0deg, color-mix(in srgb, var(--c) 34%, transparent), transparent 85%);
  clip-path: polygon(46% 100%, 54% 100%, 100% 0, 0 0);
  opacity: 0.45;
  transform-origin: 50% 100%;
  animation: beam var(--t) ease-in-out var(--d) infinite alternate;
}

@keyframes beam {
  from {
    transform: rotate(-17deg);
  }
  to {
    transform: rotate(17deg);
  }
}

/* Chế độ nhẹ: app.js (watchPerformance) đo số khung hình sau khi mở trang; máy dựng chậm thì bỏ các lớp trộn trong suốt lớn nhất,
   phần còn lại (đốm bay, sao, xe bay, hiệu ứng theo chuột) vẫn giữ. */
html[data-quality="lite"] :is(.beam, .fog, .aurora) {
  display: none;
}

/* ===== Phản ứng khi rê chuột ngoài nền =====
   Chuột đi tới đâu, nền sáng lên tới đó: một quầng sáng neon mềm bám theo con trỏ (mạnh hơn ở vùng nền trống, nhẹ khi đang trên thẻ),
   và những đốm sáng tuôn ra phía sau con trỏ rồi tan dần (chỉ ở vùng nền trống). Bấm vào nền thì bung một chùm đốm. */

.cursor-light {
  position: absolute;
  top: 0;
  left: 0;
  width: 460px;
  height: 460px;
  margin: -230px 0 0 -230px;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--s1) 55%, transparent) 0, color-mix(in srgb, var(--s3) 26%, transparent) 34%, transparent 70%);
  mix-blend-mode: screen;
  opacity: 0;
  transition: opacity 0.35s, scale 0.35s ease-out;
}

.cursor-light[data-zone="bg"] {
  opacity: 0.95;
}

.cursor-light[data-zone="card"] {
  opacity: 0.35;
  scale: 0.75;
}

.trail {
  position: absolute;
  top: var(--y);
  left: var(--x);
  width: var(--s);
  height: var(--s);
  margin: calc(var(--s) / -2) 0 0 calc(var(--s) / -2);
  border-radius: 50%;
  background: var(--c);
  box-shadow: 0 0 calc(var(--s) * 2.5) var(--c), 0 0 calc(var(--s) * 6) var(--c);
  animation: trail var(--t) ease-out forwards;
}

@keyframes trail {
  from {
    opacity: 0.95;
    transform: translate3d(0, 0, 0) scale(1);
  }
  to {
    opacity: 0;
    transform: translate3d(var(--dx), var(--dy), 0) scale(0.15);
  }
}

/* ===== Con trỏ chuột kiểu thành phố đêm cyberpunk =====
   Mũi tên góc cạnh viền xanh ngọc, bóng lệch màu hồng (như hình bị lệch màu của màn hình neon), phát sáng nhẹ; trên link và nút
   đổi thành tâm ngắm vòng xanh với bốn vạch hồng. Hai con trỏ là ảnh SVG nhúng thẳng (không tải thêm tệp), chỉ áp dụng cho chuột
   (pointer: fine). Phía trên có thêm một vòng sáng bám theo con trỏ với độ trễ nhẹ, phóng to khi rê lên thứ bấm được, và gợn sóng khi bấm. */

@media (pointer: fine) {
  html,
  body {
    cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cdefs%3E%3Cfilter id='g' x='-40%' y='-40%' width='180%' height='180%'%3E%3CfeGaussianBlur stdDeviation='1.1' result='b'/%3E%3CfeMerge%3E%3CfeMergeNode in='b'/%3E%3CfeMergeNode in='SourceGraphic'/%3E%3C/feMerge%3E%3C/filter%3E%3C/defs%3E%3Cg filter='url(%23g)'%3E%3Cpath d='M4 3V24L9.5 18.8L13 26.6L16.6 25L13.2 17.3L21 16.9Z' transform='translate(1.6 1.4)' fill='none' stroke='%23f65fb5' stroke-width='1.5' stroke-linejoin='round'/%3E%3Cpath d='M4 3V24L9.5 18.8L13 26.6L16.6 25L13.2 17.3L21 16.9Z' fill='%230a0e15' stroke='%233fd8f5' stroke-width='1.6' stroke-linejoin='round'/%3E%3C/g%3E%3C/svg%3E") 4 3, auto;
  }

  a,
  button,
  label,
  input[type="range"] {
    cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cdefs%3E%3Cfilter id='g' x='-40%' y='-40%' width='180%' height='180%'%3E%3CfeGaussianBlur stdDeviation='1.1' result='b'/%3E%3CfeMerge%3E%3CfeMergeNode in='b'/%3E%3CfeMergeNode in='SourceGraphic'/%3E%3C/feMerge%3E%3C/filter%3E%3C/defs%3E%3Cg filter='url(%23g)'%3E%3Ccircle cx='16' cy='16' r='8.5' fill='%230a0e15' fill-opacity='.55' stroke='%233fd8f5' stroke-width='1.6'/%3E%3Cpath d='M16 3.5V9.5M16 22.5V28.5M3.5 16H9.5M22.5 16H28.5' stroke='%23f65fb5' stroke-width='1.8' stroke-linecap='round'/%3E%3Ccircle cx='16' cy='16' r='2.3' fill='%23f65fb5'/%3E%3C/g%3E%3C/svg%3E") 16 16, pointer;
  }
}

.halo {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 60;
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  border: 1px solid color-mix(in srgb, var(--c3) 65%, transparent);
  border-radius: 50%;
  box-shadow:
    0 0 14px color-mix(in srgb, var(--c3) 40%, transparent),
    inset 0 0 9px color-mix(in srgb, var(--c1) 28%, transparent);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s, scale 0.2s ease-out, border-color 0.2s;
}

.halo[data-on="true"] {
  opacity: 1;
}

.halo[data-hot="true"] {
  scale: 1.75;
  border-color: color-mix(in srgb, var(--c1) 85%, transparent);
}

.halo[data-down="true"] {
  scale: 0.7;
}

.ripple {
  position: fixed;
  z-index: 59;
  width: 14px;
  height: 14px;
  margin: -7px 0 0 -7px;
  border: 2px solid var(--c1);
  border-radius: 50%;
  box-shadow: 0 0 14px var(--c1), inset 0 0 8px var(--c3);
  pointer-events: none;
  animation: ripple 0.6s ease-out forwards;
}

@keyframes ripple {
  from {
    opacity: 0.95;
    transform: scale(0.4);
  }
  to {
    opacity: 0;
    transform: scale(4.4);
  }
}

/* ===== Màn hình nhỏ ===== */

@media (max-width: 720px) {
  .bar {
    grid-template-columns: auto minmax(0, 1fr) auto;
  }

  .ctl {
    display: none;
  }

  .bar-mid {
    justify-content: flex-start;
  }
}

@media (max-width: 520px) {
  .profile {
    padding: 32px 20px 26px;
  }

  .avatar-ring {
    width: 124px;
  }

  .avatar {
    width: 100px;
    font-size: 2.5rem;
  }

  .time {
    display: none;
  }

  .games {
    justify-content: center;
    padding: 12px 14px;
  }

  .game-list {
    justify-content: center;
  }

}

/* ===== Giảm chuyển động =====
   Người dùng bật "giảm chuyển động" trong hệ điều hành: tắt mọi animation. Các keyframe đều chỉ có khung "from",
   nên khi tắt, phần tử nằm ở kiểu thường (đã hiện đủ), nội dung không bị mất. */

@media (prefers-reduced-motion: reduce) {
  .bg,
  .sparks i,
  .backdrop,
  .card,
  .card::after,
  .avatar-ring,
  .avatar-ring::before,
  .name,
  .name .ch,
  .bio,
  .empty,
  .socials li,
  .bar,
  .video,
  .eq i,
  .game,
  .gate span,
  html[data-source="youtube"][data-playing="true"] .profile::before {
    animation: none !important;
  }

  .sparks {
    display: none;
  }

  .social,
  .tip,
  .play,
  .ctl,
  .vol,
  .game::after,
  .logo {
    transition: none;
  }
}
