/* 解锁英雄 (spec §40): 「点我解锁英雄！」 on the hero page, the full-screen unlock show
   (js/heroes/unlock-show.js), the new hero flashing on the wall, the AI clip preview and its states in
   英雄图库. The show is a night sky in light and dark mode alike; everything else follows the theme
   tokens. Only transform and opacity move (the GPU does them), the blurs and shadows stand still.
   Colours only from the tokens below (light and dark). */

/* ---------- Tokens (light / dark) ---------- */
:root {
  --hu-night-1: #0B0826;
  --hu-night-2: #1E1760;
  --hu-night-3: #3B2FB0;
  --hu-gold: #FFC233;
  --hu-gold-2: #FF9F1C;
  --hu-gold-3: #FFF3C4;
  --hu-gold-glow: rgba(255, 196, 64, 0.85);
  --hu-gold-soft: rgba(255, 196, 64, 0.34);
  --hu-gold-none: rgba(255, 196, 64, 0);
  --hu-ray: rgba(255, 212, 92, 0.20);
  --hu-ray-none: rgba(255, 212, 92, 0);
  --hu-ring-1: #FFD45C;
  --hu-ring-2: #8E7BFF;
  --hu-ring-3: #5ED8FF;
  --hu-ring-core: rgba(142, 123, 255, 0.35);
  --hu-mask: #000000;
  --hu-flash: #FFFFFF;
  --hu-text: #FFFFFF;
  --hu-text-2: rgba(255, 255, 255, 0.82);
  --hu-name-shadow: rgba(255, 160, 30, 0.50);
  --hu-spark-1: #FFE07A;
  --hu-spark-2: #FFFFFF;
  --hu-spark-3: #9DD7FF;
  --hu-spark-4: #FFB86B;
  --hu-button-glow: rgba(255, 176, 40, 0.80);
  --hu-new: rgba(255, 186, 40, 0.95);
  --hu-pill: rgba(16, 10, 48, 0.62);
}
@media (prefers-color-scheme: dark) {
  :root {
    --hu-button-glow: rgba(255, 196, 64, 0.62);
    --hu-new: rgba(255, 212, 92, 0.90);
  }
}

/* ---------- 「点我解锁英雄！」: big, glowing, breathing ---------- */
.hu-unlock {
  isolation: isolate;
  width: min(100%, 340px);
  min-height: 64px;
  font-size: 20px;
  /* Scrolled into view once the pieces are in (below the board on a phone), clear of the home bar. */
  scroll-margin-bottom: calc(var(--safe-bottom) + var(--gutter));
}
.hu-unlock svg { width: 26px; height: 26px; }
.hu-unlock::before {
  content: "";
  position: absolute;
  inset: -12px;
  z-index: -1;
  border-radius: inherit;
  background: radial-gradient(closest-side, var(--hu-button-glow), var(--hu-gold-none));
  animation: hu-breathe 1.8s ease-in-out infinite;
  pointer-events: none;
}
@keyframes hu-breathe { 0%, 100% { opacity: 0.5; transform: scale(0.94); } 50% { opacity: 1; transform: scale(1.08); } }

/* The new hero on the wall flashes a few times (spec §40.1). */
.hr-card.is-new { position: relative; }
.hr-card.is-new::after {
  content: "";
  position: absolute;
  inset: -3px;
  border-radius: inherit;
  box-shadow: 0 0 0 3px var(--hu-new), 0 0 26px 6px var(--hu-new);
  opacity: 0;
  animation: hu-new 900ms ease-in-out 3;
  pointer-events: none;
}
@keyframes hu-new { 0%, 100% { opacity: 0; } 50% { opacity: 1; } }

/* ---------- The show ---------- */
.hu {
  position: fixed;
  inset: 0;
  z-index: 175; /* over sheets and viewers, under the confetti canvas (180) */
  display: grid;
  place-items: center;
  overflow: hidden;
  padding: calc(var(--safe-top) + 60px) 16px calc(var(--safe-bottom) + 16px);
  color: var(--hu-text);
  background: radial-gradient(circle at 50% 40%, var(--hu-night-3) 0%, var(--hu-night-2) 38%, var(--hu-night-1) 78%);
  opacity: 0;
  transition: opacity 420ms var(--ease-out);
  -webkit-user-select: none;
  user-select: none;
}
.hu.is-open { opacity: 1; }
.hu.is-leaving { opacity: 0; transition-duration: 240ms; }
.hu:focus { outline: none; }

.hu-rays {
  position: absolute;
  inset: -60%;
  z-index: 0;
  background: repeating-conic-gradient(from 0deg, var(--hu-ray) 0deg 9deg, var(--hu-ray-none) 9deg 22deg);
  -webkit-mask-image: radial-gradient(circle, var(--hu-mask) 0%, var(--hu-mask) 20%, transparent 58%);
  mask-image: radial-gradient(circle, var(--hu-mask) 0%, var(--hu-mask) 20%, transparent 58%);
  opacity: 0;
  transition: opacity 900ms var(--ease-out);
}
.hu.is-reveal .hu-rays { opacity: 1; animation: hu-spin 26s linear infinite; }
@keyframes hu-spin { to { transform: rotate(360deg); } }

.hu-stage {
  position: relative;
  z-index: 1;
  display: grid;
  justify-items: center;
  gap: 14px;
  width: min(100%, 560px);
  text-align: center;
}
.hu-sparks { position: absolute; inset: 0; z-index: 2; width: 100%; height: 100%; pointer-events: none; }
.hu-flash { position: absolute; inset: 0; z-index: 3; background: var(--hu-flash); opacity: 0; pointer-events: none; }
.hu.is-flash .hu-flash { animation: hu-flash 650ms ease-out both; }
@keyframes hu-flash { 0% { opacity: 0; } 22% { opacity: 0.92; } 100% { opacity: 0; } }
.hu-skip { position: absolute; top: calc(var(--safe-top) + 10px); right: max(14px, var(--safe-right)); z-index: 4; }

/* The hero: a 3:4 box whose size is fixed from the first frame (nothing below it moves). */
.hu-hero {
  --hu-card-w: min(68vw, calc(48dvh * 0.75), 380px);
  position: relative;
  width: var(--hu-card-w);
  aspect-ratio: 3 / 4;
}
.hu-card { position: relative; width: 100%; height: 100%; border-radius: calc(var(--hu-card-w) / 20); transform: scale(0.94); }
.hu-card::after {
  content: "";
  position: absolute;
  inset: -3px;
  border-radius: inherit;
  box-shadow: 0 0 0 3px var(--hu-gold), 0 0 30px 8px var(--hu-gold-glow);
  opacity: 0;
  transition: opacity 600ms var(--ease-out);
  pointer-events: none;
}
.hu.is-reveal .hu-card { animation: hu-pop 900ms var(--ease-spring) both; }
.hu.is-reveal .hu-card::after { opacity: 1; }
@keyframes hu-pop { 0% { transform: scale(0.94); } 50% { transform: scale(1.08); } 100% { transform: scale(1); } }
.hu-card .hj { width: 100%; }

/* Ten pieces fly in from far outside, spinning (the jigsaw's own flight vectors, longer and wilder). */
.hu .hj-piece.is-assemble { opacity: 0; animation: none; }
.hu.is-fly .hj-piece.is-assemble { animation: hu-fly 900ms cubic-bezier(0.2, 0.9, 0.3, 1.12) var(--hu-d, 0ms) both; }
@keyframes hu-fly {
  0% { opacity: 0; transform: translate(calc(var(--fx) * 2.6), calc(var(--fy) * 2.6)) rotate(calc(var(--fr) * 10)) scale(1.5); }
  25% { opacity: 1; }
  85% { transform: translate(0, 0) rotate(0deg) scale(1.03); }
  100% { opacity: 1; transform: none; }
}

/* The energy ring: gathers while charging, spins, bursts when the pieces lock. */
.hu-ring {
  position: absolute;
  /* 1.5 × the card's width, centred on the card (3:4): left (1 − 1.5) / 2, top (4/3 − 1.5) / 2 of the width. */
  left: -25%;
  top: -6.25%;
  width: 150%;
  aspect-ratio: 1;
  pointer-events: none;
  opacity: 0;
  transform: scale(0.35);
  transition: opacity 900ms var(--ease-out), transform 1300ms var(--ease-out);
}
.hu-ring::before,
.hu-ring::after { content: ""; position: absolute; inset: 0; border-radius: 50%; }
.hu-ring::before {
  background: conic-gradient(from 0deg, var(--hu-ring-1), var(--hu-ring-2), var(--hu-ring-3), var(--hu-ring-1));
  -webkit-mask-image: radial-gradient(circle, transparent 0 58%, var(--hu-mask) 60% 64%, transparent 67%);
  mask-image: radial-gradient(circle, transparent 0 58%, var(--hu-mask) 60% 64%, transparent 67%);
  animation: hu-spin 1.4s linear infinite;
}
.hu-ring::after { background: radial-gradient(circle, var(--hu-ring-core) 0%, transparent 62%); animation: hu-throb 700ms ease-in-out infinite alternate; }
@keyframes hu-throb { from { opacity: 0.5; transform: scale(0.92); } to { opacity: 1; transform: scale(1.04); } }
.hu.is-charge .hu-ring { opacity: 1; transform: scale(1); }
.hu.is-snap .hu-ring { animation: hu-burst 650ms ease-out forwards; }
@keyframes hu-burst { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(1.7); } }

.hu-glow {
  position: absolute;
  inset: -22%;
  border-radius: 50%;
  background: radial-gradient(circle, var(--hu-gold-soft) 0%, var(--hu-gold-none) 66%);
  opacity: 0;
  transform: scale(0.6);
  transition: opacity 700ms var(--ease-out), transform 1000ms var(--ease-out);
  pointer-events: none;
}
.hu.is-reveal .hu-glow { opacity: 1; transform: scale(1); }

/* The AI clip takes the card's place, then stops on its last frame. */
.hu-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
  opacity: 0;
  transition: opacity 500ms var(--ease-out);
  pointer-events: none;
}
.hu.is-clip .hu-video { opacity: 1; }

/* Words: the name lands like a stamp, the screen shakes a little. Their room is kept from the start. */
.hu-words { display: grid; justify-items: center; gap: 2px; width: 100%; min-width: 0; }
.hu-kicker { font-size: 15px; font-weight: 800; letter-spacing: 0.14em; color: var(--hu-gold); opacity: 0; transform: translateY(8px); transition: opacity 400ms var(--ease-out), transform 500ms var(--ease-out); }
.hu.is-reveal .hu-kicker { opacity: 1; transform: none; }
.hu-name {
  max-width: 100%;
  /* One line, whole: a long name (up to 12 characters) gets smaller to fit the stage (--hu-len: its
     length, set by unlock-show.js; a CJK character with the spacing is about 1.04em). */
  font-size: min(clamp(30px, 8.4vw, 52px), calc(min(100vw - 32px, 560px) / (var(--hu-len, 1) * 1.06)));
  font-weight: 900;
  line-height: 1.15;
  letter-spacing: 0.04em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  background: linear-gradient(180deg, var(--hu-gold-3) 0%, var(--hu-gold) 45%, var(--hu-gold-2) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 4px 14px var(--hu-name-shadow));
  opacity: 0;
  transform: scale(2.6);
}
.hu.is-stamp .hu-name { animation: hu-stamp 420ms cubic-bezier(0.55, 0, 0.75, 0.1) forwards; }
@keyframes hu-stamp {
  0% { opacity: 0; transform: scale(2.6) rotate(-6deg); }
  72% { opacity: 1; transform: scale(0.94) rotate(0deg); }
  100% { opacity: 1; transform: scale(1); }
}
.hu-count { font-size: 17px; font-weight: 700; color: var(--hu-text-2); opacity: 0; transition: opacity 400ms var(--ease-out) 300ms; }
.hu.is-stamp .hu-count { opacity: 1; }
.hu.is-stamp .hu-stage { animation: hu-shake 380ms ease-out 300ms; }
@keyframes hu-shake {
  0%, 100% { transform: none; }
  20% { transform: translate(-7px, 3px); }
  40% { transform: translate(6px, -4px); }
  60% { transform: translate(-4px, 2px); }
  80% { transform: translate(2px, -1px); }
}

/* The end card's buttons: equal halves, in place (invisible) from the start. */
.hu-actions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--gap);
  width: min(100%, 420px);
  margin-top: 4px;
  opacity: 0;
  transform: translateY(10px);
  pointer-events: none;
  transition: opacity 400ms var(--ease-out), transform 500ms var(--ease-out);
}
.hu-actions.is-single { grid-template-columns: minmax(0, 1fr); }
.hu-actions .btn { width: 100%; min-width: 0; padding: 0 14px; }
.hu-actions .btn span { overflow: hidden; text-overflow: ellipsis; }
.hu.is-end .hu-actions { opacity: 1; transform: none; pointer-events: auto; }

/* 跳过: everything at its end state at once. */
.hu.is-skipped .hj-piece.is-assemble { animation: none; opacity: 1; }
.hu.is-skipped .hu-ring,
.hu.is-skipped .hu-flash { display: none; }
.hu.is-skipped .hu-card,
.hu.is-skipped .hu-stage { animation: none; transform: none; }
.hu.is-skipped .hu-name { animation: none; opacity: 1; transform: none; }

/* Reduced motion: a fade, the hero, its name and the voice. */
.hu.is-reduced .hu-ring,
.hu.is-reduced .hu-flash,
.hu.is-reduced .hu-rays { display: none; }
.hu.is-reduced .hu-card,
.hu.is-reduced .hu-stage { animation: none; transform: none; }
.hu.is-reduced .hu-name { animation: none; opacity: 1; transform: none; }
.hu.is-reduced .hu-kicker,
.hu.is-reduced .hu-count,
.hu.is-reduced .hu-actions { transition: opacity 300ms var(--ease-out); transform: none; }
@media (prefers-reduced-motion: reduce) {
  .hu-unlock::before, .hr-card.is-new::after, .hu-ring::before, .hu-ring::after, .hu.is-reveal .hu-rays { animation: none; }
  .hu-unlock::before { opacity: 0.8; }
  .hr-card.is-new::after { opacity: 1; }
}

/* Short screens (a phone in landscape): a smaller hero so the buttons stay on screen. */
@media (max-height: 560px) {
  .hu { padding-top: calc(var(--safe-top) + 12px); }
  .hu-hero { --hu-card-w: min(40vw, calc(42dvh * 0.75), 300px); }
  .hu-stage { gap: 8px; }
}

/* 「再看一次解锁动画」 / 「看看解锁动画」 on a finished hero's big picture. */
.hv-replay { position: absolute; left: 50%; bottom: 14px; z-index: 1; max-width: calc(100% - 28px); translate: -50% 0; background: var(--hu-pill); }
.hv-replay span { overflow: hidden; text-overflow: ellipsis; }

/* ---------- The AI clip in 英雄图库 (parents) ---------- */
.hu-preview-frame { position: relative; width: min(92vw, 560px, calc(70dvh * 3 / 4)); aspect-ratio: 3 / 4; border-radius: 22px; overflow: hidden; background: var(--hero-glass); }
.hu-preview { display: block; width: 100%; height: 100%; object-fit: cover; }
.hu-preview-frame .hv-slot { pointer-events: none; }
.ha-video-line { display: block; margin-top: 4px; font-size: 13px; color: var(--hero-text-2); }
.ha-video-note { display: inline-block; white-space: nowrap; }
