/* ══════════════════════════════════════════════════════════════
   Generate Loader — standalone, copy nguyên thư mục là chạy.
   Không phụ thuộc CSS nào khác. Mọi màu đều là biến có giá trị
   mặc định, muốn đổi theme thì override trên .nvl hoặc :root.
   ══════════════════════════════════════════════════════════════ */

.nvl {
  --nvl-pink: #f0abfc;
  --nvl-rose: #fb7185;
  --nvl-gold: #fbbf24;
  --nvl-violet: #e879f9;
  --nvl-title: #f3f0f8;
  --nvl-muted: #a79fb8;
  --nvl-track: rgba(255, 255, 255, 0.08);
  --nvl-art-size: 175px;

  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 13px;
  padding: 30px 0;
  text-align: center;
}

/* ── khung nghệ thuật ────────────────────────────────────────── */
.nvl-art {
  width: var(--nvl-art-size);
  height: var(--nvl-art-size);
  margin: 0 auto;
  position: relative;
}
.nvl-art::before {
  content: "";
  position: absolute;
  inset: -18px;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(232, 121, 249, 0.22), transparent 72%);
  pointer-events: none;
}

.nvl-scene {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  transform: scale(0.7);
  transition: opacity 0.35s, transform 0.35s;
  pointer-events: none;
  overflow: visible;
}
.nvl-scene.is-on {
  opacity: 1;
  transform: scale(1);
}
/* scene ẩn thì đứng hình — đỡ tốn CPU trên máy yếu */
.nvl-scene:not(.is-on) * {
  animation-play-state: paused;
}
.nvl-scene * {
  transform-box: fill-box;
  transform-origin: center;
}

/* ── chữ ─────────────────────────────────────────────────────── */
.nvl-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--nvl-title);
}
.nvl-message {
  font-size: 0.76rem;
  color: var(--nvl-muted);
}
.nvl-seconds {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--nvl-muted);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

/* ── thanh tiến trình vô hạn ─────────────────────────────────── */
.nvl-bar {
  width: 210px;
  height: 6px;
  border-radius: 99px;
  background: var(--nvl-track);
  overflow: hidden;
  margin: 14px auto 6px;
}
.nvl-bar-fill {
  width: 40%;
  height: 100%;
  border-radius: 99px;
  background: linear-gradient(90deg, var(--nvl-violet), var(--nvl-rose), var(--nvl-gold));
  animation: nvl-slide 1.4s ease-in-out infinite;
}
@keyframes nvl-slide {
  0% { transform: translateX(-120%); }
  100% { transform: translateX(420%); }
}

/* ══ animation của từng scene ═════════════════════════════════ */
.aWave { animation: aWave 1.6s ease-in-out infinite; }
@keyframes aWave {
  0%, 100% { transform: translateY(0) scaleX(1); }
  50% { transform: translateY(-4px) scaleX(1.06); }
}

.aBub { animation: aBub 2.2s ease-in infinite; }
.aBub.b2 { animation-delay: 0.7s; }
.aBub.b3 { animation-delay: 1.3s; }
@keyframes aBub {
  0% { transform: translateY(0); opacity: 0; }
  15% { opacity: 1; }
  100% { transform: translateY(-38px); opacity: 0; }
}

.aTw { animation: aTw 1.5s ease-in-out infinite; }
.aTw.t2 { animation-delay: 0.5s; }
.aTw.t3 { animation-delay: 1s; }
@keyframes aTw {
  0%, 100% { transform: scale(0.4); opacity: 0.2; }
  50% { transform: scale(1.15); opacity: 1; }
}

.aFill { animation: aFill 3.2s ease-in-out infinite; }
@keyframes aFill {
  0% { transform: translateY(96px); }
  55%, 100% { transform: translateY(0); }
}

.aBrush { animation: aBrush 1.05s ease-in-out infinite; }
@keyframes aBrush {
  0%, 100% { transform: translate(-26px, 8px) rotate(-10deg); }
  50% { transform: translate(-44px, 26px) rotate(6deg); }
}

.aHeart { animation: aHeart 1.1s ease-in-out infinite; }
@keyframes aHeart {
  0%, 100% { transform: scale(1); }
  30% { transform: scale(1.1); }
  45% { transform: scale(1.04); }
  60% { transform: scale(1.12); }
}

.aOrbit {
  animation: aOrbit 5s linear infinite;
  transform-origin: 60px 60px;
  transform-box: view-box;
}
@keyframes aOrbit {
  to { transform: rotate(360deg); }
}

.aBloom { animation: aBloom 2.4s ease-in-out infinite; }
@keyframes aBloom {
  0%, 100% { transform: scale(0.82) rotate(-5deg); }
  50% { transform: scale(1) rotate(5deg); }
}

.aCore { animation: aCore 2.4s ease-in-out infinite; }
@keyframes aCore {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.18); }
}

.aGem { animation: aGemBob 1.6s ease-in-out infinite; }
@keyframes aGemBob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-8px); }
}

.aShine { animation: aShine 2.2s ease-in-out infinite; }
@keyframes aShine {
  0%, 55% { transform: translateX(0) skewX(-18deg); }
  100% { transform: translateX(165px) skewX(-18deg); }
}

.aWand { animation: aWand 1.3s ease-in-out infinite; }
@keyframes aWand {
  0%, 100% { transform: rotate(-8deg) translateY(0); }
  50% { transform: rotate(7deg) translateY(-6px); }
}

.aPop { animation: aPop 1.8s ease-in-out infinite; }
.aPop.p2 { animation-delay: 0.6s; }
.aPop.p3 { animation-delay: 1.2s; }
@keyframes aPop {
  0%, 100% { transform: scale(0); opacity: 0; }
  40% { transform: scale(1.2); opacity: 1; }
  60% { transform: scale(1); opacity: 1; }
}

.aMirror { animation: aRingTilt 2.4s ease-in-out infinite; }
.aRing { animation: aRingTilt 2s ease-in-out infinite; }
@keyframes aRingTilt {
  0%, 100% { transform: rotate(-8deg); }
  50% { transform: rotate(8deg); }
}

.aFly { animation: aGemBob 1.4s ease-in-out infinite; }
.aWingL, .aWingR { animation: aFlap 0.55s ease-in-out infinite alternate; }
.aWingL { transform-origin: right center; }
.aWingR { transform-origin: left center; }
@keyframes aFlap {
  from { transform: scaleX(1); }
  to { transform: scaleX(0.45); }
}

.aStar { animation: aBlink 1.4s ease-in-out infinite; }
.aStar.s1 { animation-delay: 0.28s; }
.aStar.s2 { animation-delay: 0.56s; }
.aStar.s3 { animation-delay: 0.84s; }
.aStar.s4 { animation-delay: 1.12s; }
@keyframes aBlink {
  0%, 100% { transform: scale(0.35) rotate(-12deg); opacity: 0.15; }
  50% { transform: scale(1.15) rotate(8deg); opacity: 1; }
}

/* ── tôn trọng người tắt hiệu ứng chuyển động ────────────────── */
@media (prefers-reduced-motion: reduce) {
  .nvl-scene, .nvl-scene *, .nvl-bar-fill {
    animation: none !important;
    transition: none !important;
  }
  .nvl-scene.is-on { opacity: 1; transform: none; }
}
