/* live2d.css — flip the songs header card to its back face to reveal
   the Live2D mascot, plus the floating-when-detached mascot widget. */

/* ── flip card ──────────────────────────────────────────────────────── */
/* The .header-card already has the manual tilt transform; we set
   `perspective` here so the inner .card-faces (a separate element) can
   pivot in 3D without fighting the tilt transform on the parent. */
.header-card { perspective: 1200px; }

.card-faces {
  position: relative;
  transform-style: preserve-3d;
  transition: transform 0.7s cubic-bezier(.4, .1, .35, 1);
}
.header-card.flipped .card-faces { transform: rotateY(180deg); }

.card-front, .card-back {
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
.card-back {
  position: absolute;
  inset: 0;
  transform: rotateY(180deg);
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.header-card.flipped .card-back { pointer-events: auto; }
.header-card.flipped .card-front { pointer-events: none; }

/* hover hint on the avatar — gives an affordance that it's clickable.
   No popup pill: the click is on the wrap, and on mobile there's no
   hover anyway. */
.avatar-wrap { cursor: pointer; transition: transform .25s cubic-bezier(.4,1.5,.5,1); }
.avatar-wrap:hover { transform: scale(1.04); }
.avatar-wrap:hover #avatar {
  box-shadow:
    0 0 0 2px var(--blue),
    0 6px 18px rgba(var(--blue-rgb), 0.3);
}

/* back-face content: just a label. The mascot canvas (body child, fixed
   z-index 101) sits over this rect, so its own corner-button is the
   actual flip-back affordance — putting the button on .card-back would
   end up under the mascot's pointer-events shadow. */
/* Long-press progress ring traces the card's rounded border via an SVG
   <rect> with absolute pixel coords (JS keeps it sized to the card via
   syncTo). The rect's rx matches the card's border-radius regardless of
   aspect ratio. */
.live2d-press-ring {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity .25s ease;
  z-index: 3;  /* above .card-faces so the ring frames the flipping content */
}
.live2d-press-ring.active { opacity: 1; }
.live2d-press-ring rect {
  fill: none;
  stroke-linecap: round;
  stroke: var(--blue);
  stroke-width: 2.5;
  /* pathLength=100 normalises the perimeter; dasharray/offset are in
     percent units regardless of the rect's actual dimensions. */
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  transition: stroke-dashoffset .15s ease;
}

/* "加载中" label shown only while boot() is in flight (libs + model blob
   download + initialisation). Removed once the mascot fades in. */
.card-back-label {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Zen Maru Gothic', sans-serif;
  font-size: 11px;
  letter-spacing: 4px;
  color: var(--text3);
  pointer-events: none;
  opacity: 0;
  transition: opacity .25s ease;
  z-index: 2;
}
.card-back-label.active { opacity: 1; }
.card-back-label::before { content: '✦ '; color: var(--bow); }
.card-back-label::after  { content: ' ✦'; color: var(--bow); }

/* card highlights as a drop target while the mascot is being dragged
   over it. */
.header-card.drop-hover {
  box-shadow:
    0 0 0 2px var(--blue),
    0 14px 40px rgba(var(--blue-rgb), 0.25) !important;
}

/* ── mascot widget ──────────────────────────────────────────────────── */
/* While attached, the mascot lives inside .card-back and auto-fills it
   via inset:0 — no JS positioning, no measuring through 3D transforms.
   On long-press detach, JS reparents it to body and switches it to
   position:fixed with explicit coords so it can float freely. */
.live2d-mascot {
  pointer-events: none;
  touch-action: none;
  cursor: pointer;
  opacity: 0;
  filter: drop-shadow(0 4px 10px rgba(var(--blue-rgb), 0.20));
  transition: opacity .22s ease, filter .18s ease;
}
.live2d-mascot.attached {
  position: absolute;
  inset: 0;
  z-index: 2;
}
.live2d-mascot.detached {
  position: fixed;
  z-index: 101;
  filter: drop-shadow(0 8px 18px rgba(var(--blue-rgb), 0.30));
  cursor: grab;
}
.live2d-mascot.detached.dragging { cursor: grabbing; }
.live2d-mascot.shown { opacity: 1; pointer-events: auto; }
.live2d-mascot canvas { display: block; width: 100%; height: 100%; }
.live2d-mascot.snapping {
  transition: left .28s cubic-bezier(.4,1.5,.5,1),
              top  .28s cubic-bezier(.4,1.5,.5,1),
              width .28s ease, height .28s ease,
              filter .2s ease, opacity .22s ease;
}

/* flip-back button — child of .card-back so it stays anchored to the card
   even when the mascot is dragged out. z-index above the mascot wrapper
   (z:2) so it stays clickable while the mascot is attached. */
.card-flip-back {
  position: absolute;
  top: 6px; right: 6px;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--surface-strong);
  border: 1px solid var(--surface-hover);
  color: var(--text2);
  font-size: 16px; line-height: 1;
  display: grid; place-items: center;
  cursor: pointer;
  z-index: 4;
  opacity: 0.85;
  transition: background .15s, color .15s, opacity .15s;
  font-family: inherit;
  padding: 0;
}
.card-flip-back:hover {
  background: var(--blue);
  color: white;
  opacity: 1;
}

/* Subtle pulse while the long-press is in progress. */
.live2d-mascot.about-to-detach {
  animation: live2d-mascot-hint 0.42s ease-in-out infinite alternate;
}
@keyframes live2d-mascot-hint {
  from { transform: translate(0, 0)    scale(1);     }
  to   { transform: translate(0, -2px) scale(1.012); }
}

/* "Ready to drag" cue when the ring fills:
   - ring bursts outward + thicker stroke + fade
   - mascot does one scale bump
   The cursor change to 'grab' on .detached completes the affordance. */
.live2d-press-ring.burst {
  opacity: 1;
  animation: live2d-ring-burst .55s ease-out forwards;
}
.live2d-press-ring.burst rect { stroke-width: 4; }
@keyframes live2d-ring-burst {
  0%   { transform: scale(1);    opacity: 1;   }
  60%  { transform: scale(1.18); opacity: .55; }
  100% { transform: scale(1.30); opacity: 0;   }
}
.live2d-mascot.just-detached {
  animation: live2d-detach-bump .55s cubic-bezier(.34, 1.56, .64, 1);
}
@keyframes live2d-detach-bump {
  0%   { transform: scale(1);    }
  35%  { transform: scale(1.08); }
  100% { transform: scale(1);    }
}
