/* ===================== 右下角常驻安全员「小安」=====================
 * 与业务样式完全解耦：自带全部视觉，不依赖 exam/admin 主题变量，
 * 两个页面（考生端/后台）共用这一份。z-index 85：
 * 高于内容(1)/抽屉(80)/彩带(60)，低于弹窗(100)与toast(999)。
 */
.hse-mascot {
  position: fixed; right: 16px; bottom: calc(72px + env(safe-area-inset-bottom, 0px));
  z-index: 85;
  --hm-size: 112px;          /* 后台「吉祥物形象」可改，由 JS 写入 */
  font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "MiSans", "Microsoft YaHei", sans-serif;
  user-select: none; -webkit-user-select: none; -webkit-tap-highlight-color: transparent;
  transition: opacity .25s ease, transform .25s ease;
}
.hse-mascot.hm-hidden { opacity: 0; transform: scale(.4); pointer-events: none; }

/* 按钮避让：left/top 过渡让走位有动画（时长由 JS 按段设置内联覆盖） */
.hse-mascot.hm-shifting {
  transition: left .56s cubic-bezier(.22, .9, .3, 1), top .56s cubic-bezier(.22, .9, .3, 1),
    opacity .25s ease, transform .25s ease;
}
/* 无处可躲时淡出让路，通道恢复后自动回来 */
.hse-mascot.hm-fade { opacity: .08; pointer-events: none; }

/* ---------- 形象：本体由 bloub 引擎逐帧渲染，这里只管盒子与点击 ----------
   引擎 viewBox 为 316 见方，云(形体 nuage)实占 194，视觉直径约为盒子的 61%。 */
.hm-body { position: relative; width: var(--hm-size); height: var(--hm-size); }
/* 手机端：后台设的尺寸再大也不能超过 84px，否则会顶到内容。
   注意 JS 的 applyLook 会按同一口径收敛，两边必须一致才不会打架。 */
@media (max-width: 767px) { .hm-body { width: min(var(--hm-size), 96px); height: min(var(--hm-size), 96px); } }

.hm-char {
  width: 100%; height: 100%; display: block; cursor: grab; touch-action: none;
  outline: none; border-radius: 30px; pointer-events: none;
}
.hm-char:focus-visible { box-shadow: 0 0 0 3px rgba(245, 181, 46, .6); }
.hm-dragging .hm-char { cursor: grabbing; }

/* SVG 整体不吃事件：只有身体轮廓（纸底 path）可点可拖，眼睛孔洞、装饰弧线、
   粒子与蓝点全部穿透，不挡住底下任何按钮。 */
.hm-svg { width: 100%; height: 100%; display: block; overflow: visible; pointer-events: none; }
.hm-paper { pointer-events: visiblePainted; }

/* 台词气泡出现时身形轻轻一顿（引擎照旧在跑，这里只叠一层极轻的呼吸） */
.hm-talking .hm-body-grp { animation: hmBreathe .5s ease-in-out infinite alternate; transform-origin: 50% 50%; }
@keyframes hmBreathe { from { transform: scale(1); } to { transform: scale(1.012); } }

/* ---------- 避让后回归初始位：回家的路也要有动画 ---------- */
.hse-mascot.hm-homecoming {
  transition: left .82s cubic-bezier(.34, .9, .28, 1), top .82s cubic-bezier(.34, .9, .28, 1),
    opacity .25s ease, transform .25s ease;
}

/* 点击弹跳（挂在 .hm-char 上，呼吸动画在子级 svg，互不覆盖） */
.hm-bounce { animation: hmBounce .62s cubic-bezier(.28, .84, .42, 1); transform-origin: 50% 100%; }
@keyframes hmBounce {
  0% { transform: translateY(0) scale(1, 1); }
  30% { transform: translateY(-21px) scale(.93, 1.07); }
  56% { transform: translateY(0) scale(1.07, .92); }
  76% { transform: translateY(-6px) scale(.98, 1.02); }
  100% { transform: translateY(0) scale(1, 1); }
}

/* 登场飞入 */
.hse-mascot.hm-enter .hm-body { animation: hmIn .8s cubic-bezier(.34, 1.56, .64, 1) both; }
@keyframes hmIn {
  from { transform: translate(70px, 110px) scale(.3); opacity: 0; }
  to { transform: none; opacity: 1; }
}

/* ---------- 台词气泡 ----------
   定位完全交给 JS：left/top 相对 root 写入，max-width 按避障结果逐级收缩
   （240 → 140），箭头靠 --hm-arrow-x 对准吉祥物中心。
   为什么不能用 right/bottom 写死：那样气泡只会往左单向生长，吉祥物钉到
   屏幕中央（答题陪考）时气泡仍贴在左侧，看起来像"长在另一个人身上"。 */
.hm-bubble {
  position: absolute; left: 0; top: 0;
  width: max-content; max-width: 240px;
  background: #fff; color: #1f2a44;
  border: 1px solid rgba(16, 24, 40, .08);
  border-radius: 14px; padding: 9px 13px;
  font-size: 13px; line-height: 1.55; font-weight: 500;
  box-shadow: 0 12px 30px rgba(16, 24, 40, .16);
  opacity: 0; transform: translateY(8px) scale(.94);
  transition: opacity .22s ease, transform .22s cubic-bezier(.34, 1.56, .64, 1);
  pointer-events: none;
  /* 宽度变化时平滑过渡，避障缩窄不会"啪"地跳一下 */
  transition: opacity .22s ease, transform .22s cubic-bezier(.34, 1.56, .64, 1), max-width .18s ease;
}
.hm-bubble.hm-bubble-in { opacity: 1; transform: none; }
.hm-bubble::after {
  content: ""; position: absolute; left: var(--hm-arrow-x, 20px); bottom: -6px;
  width: 11px; height: 11px; background: #fff; margin-left: -6px;
  border-right: 1px solid rgba(16, 24, 40, .08);
  border-bottom: 1px solid rgba(16, 24, 40, .08);
  transform: rotate(45deg);
}
/* 上方实在没地方：翻到吉祥物下方，箭头随之翻到顶边 */
.hm-bubble.hm-bubble-below::after {
  bottom: auto; top: -6px;
  border-right: none; border-bottom: none;
  border-left: 1px solid rgba(16, 24, 40, .08);
  border-top: 1px solid rgba(16, 24, 40, .08);
}

/* ---------- 收起按钮 ---------- */
.hm-close {
  position: absolute; top: -5px; right: -5px;
  width: 24px; height: 24px; border-radius: 50%;
  background: #fff; border: 1px solid rgba(16, 24, 40, .1);
  color: #64748b; display: grid; place-items: center;
  cursor: pointer; padding: 0;
  box-shadow: 0 4px 12px rgba(16, 24, 40, .14);
  opacity: 0; transform: scale(.5);
  transition: opacity .18s ease, transform .18s ease, color .18s ease;
}
.hm-body:hover .hm-close, .hm-close:focus-visible { opacity: 1; transform: scale(1); }
.hm-close svg { width: 11px; height: 11px; }
.hm-close:hover { color: #e11d48; }

/* ---------- 答题页静音态 ----------
   小安钉在屏幕下方居中时正好压在「答题卡」按钮上，收起后的小图标又正好压在
   「下一题」上，考生点按钮会先命中它（被拖走或弹气泡），像是按钮失灵。
   答题页里它只做视觉陪伴：事件全部穿透，收起态的小图标直接不出现。 */
body.hm-quiet .hse-mascot,
body.hm-quiet .hse-mascot .hm-paper,
body.hm-quiet .hse-mascot .hm-close,
body.hm-quiet .hse-mascot-tab { pointer-events: none; }
body.hm-quiet .hse-mascot .hm-char { cursor: default; }
body.hm-quiet .hse-mascot-tab { display: none; }

/* ---------- 收起后的头盔小图标 ---------- */
.hse-mascot-tab {
  position: fixed; right: 16px; bottom: calc(72px + env(safe-area-inset-bottom, 0px));
  z-index: 85; width: 44px; height: 44px; border-radius: 50%;
  background: #fff; border: 1px solid rgba(16, 24, 40, .1);
  box-shadow: 0 10px 26px rgba(16, 24, 40, .18);
  display: none; place-items: center; cursor: pointer; padding: 0;
}
.hse-mascot-tab.hm-show { display: grid; animation: hmPop .42s cubic-bezier(.34, 1.56, .64, 1); }
.hse-mascot-tab svg { width: 26px; height: 26px; }
@keyframes hmPop {
  from { transform: scale(0); }
  to { transform: scale(1); }
}

/* ---------- 点击特效粒子 ---------- */
.hm-fx {
  position: absolute; bottom: 70px; left: 0;
  width: 16px; height: 16px; pointer-events: none;
  animation: hmFxUp 1s ease-out forwards;
}
.hm-fx svg { width: 100%; height: 100%; display: block; }
@keyframes hmFxUp {
  0% { opacity: 0; transform: translate(0, 0) scale(.5); }
  20% { opacity: 1; }
  100% { opacity: 0; transform: translate(var(--dx, 0), -66px) scale(1.15); }
}

/* ---------- 减弱动效降级 ---------- */
@media (prefers-reduced-motion: reduce) {
  .hm-bounce, .hm-talking .hm-body-grp,
  .hse-mascot.hm-enter .hm-body, .hm-fx, .hse-mascot-tab.hm-show {
    animation: none !important;
  }
  .hm-bubble { transition: none; }
  .hse-mascot, .hse-mascot.hm-shifting, .hse-mascot.hm-homecoming {
    transition: opacity .01ms linear !important;
  }
}
