/* ════════════════════════════════════════════════════════════════
   会说话的头像（live/engine.js 挂载的 canvas）
   -----------------------------------------------------------------
   设计约束：
     · 不改变任何现有布局 —— canvas 绝对定位铺满头像容器，原来的 <img> 原样留在
       DOM 里（合规标注 alt 还在、懒加载还在、加载失败兜底还在）；
     · 容器必须已经 overflow:hidden（剧场 .th-avatar / 宫格 .fx-portrait 都满足），
       canvas 自身只负责画，不负责裁圆；
     · 关闭/降级（reduced-motion、没检测到脸、开关关掉）时 <canvas> 直接不存在，
       界面回落到静态头像，不会留下空白或黑圆。

   canvas 层级放在最上面：原 <img> 在下面当"兜底底图"，首帧还没画出来时
   用户看到的是静态头像而不是透明圆。
   ════════════════════════════════════════════════════════════════ */

.liv-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  border-radius: inherit;
  pointer-events: none;          /* 头像在 <button> 里，别把点击吞掉 */
  opacity: 0;
  transition: opacity .35s ease;
}
.liv-canvas.is-ready { opacity: 1; }

/* 底图跟随同一取景：canvas 就绪前后头像构图完全一致，不会"突然放大一下"。
   变量由 engine 按每张脸的实际位置写（--liv-z / --liv-ox / --liv-oy），
   没有画布时这三个变量不存在 → transform 退化为 none。 */
.liv-host > img {
  transform: scale(var(--liv-z, 1));
  transform-origin: var(--liv-ox, 50%) var(--liv-oy, 50%);
  transition: transform .28s ease;
}

/* 剧场席位本身没有定位上下文：补一个 relative，canvas 才能贴住头像圆 */
.th-avatar { position: relative; }

/* 剧场里"正在说话"的呼吸缩放会和 canvas 一起动：canvas 是子元素，会跟着缩放，
   这里不再额外加动画，避免两层缩放叠加成"抽搐"。 */
.th-seat.is-speaking .th-avatar .liv-canvas { will-change: transform; }

@media (prefers-reduced-motion: reduce) {
  .liv-canvas { display: none; }
}
