/* ==========================================================================
   base/effects.css — 动效增强层（可爱系）
   ─────────────────────────────────────────────────────────────────────────
   加载顺序：组件层之后、typography.css 之前。
   只做"动"和"装饰"，不碰任何比例；所有值都走 tokens.css 的令牌。

   本层七件事：
     1. 氛围层       —— 粒子画布 + 飘浮颜文字贴纸的容器
     2. 入场上场     —— 卡片 / 圆钮 / 标题的弹入变体（比 reveal 更有戏）
     3. 常驻呼吸     —— 圆钮 / 头像 / 徽章的 idle 飘浮（用 translate 属性，
                        与 hover 的 transform 互不打架）
     4. 悬停加料     —— 按钮 sparkle、卡片 3D 微倾、brand 摇摆
     5. 加载呼吸     —— 空状态 / 骨架屏
     6. 氛围光带     —— 页面底部糖果飘带 + 进度条流光
     7. 降级         —— prefers-reduced-motion 全量关停
   ========================================================================== */

/* ==========================================================================
   1 · 氛围层
   ========================================================================== */

.ambient {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

/* 飘浮颜文字贴纸：极淡、极慢，只做"空气里有东西"的暗示 */
.kaomoji-float {
  position: absolute;
  font-family: var(--font-kaomoji);
  font-weight: 400;
  font-size: clamp(18px, 2.4vw, 30px);
  line-height: 1;
  color: var(--candy-pink);
  opacity: 0.22;
  white-space: nowrap;
  user-select: none;
  animation: kaoFloat 16s var(--ease-sine) infinite;
}

.kaomoji-float.k1 { top: 14%; left: 3%;  color: var(--candy-pink);     animation-duration: 15s; }
.kaomoji-float.k2 { top: 34%; right: 4%; color: var(--candy-purple);   animation-duration: 19s; animation-delay: -4s; }
.kaomoji-float.k3 { top: 62%; left: 6%;  color: var(--candy-mint);     animation-duration: 17s; animation-delay: -8s; }
.kaomoji-float.k4 { top: 78%; right: 7%; color: var(--champagne-deep); animation-duration: 21s; animation-delay: -12s; }
.kaomoji-float.k5 { top: 48%; left: 46%; color: var(--candy-blue);     animation-duration: 18s; animation-delay: -6s; font-size: clamp(14px, 1.8vw, 22px); }
.kaomoji-float.k6 { top: 8%;  right: 22%; color: var(--candy-red);     animation-duration: 20s; animation-delay: -10s; }

@keyframes kaoFloat {
  0% {
    transform: translate3d(0, 0, 0) rotate(-3deg);
  }

  33% {
    transform: translate3d(10px, -16px, 0) rotate(4deg);
  }

  66% {
    transform: translate3d(-8px, -26px, 0) rotate(-2deg);
  }

  100% {
    transform: translate3d(0, 0, 0) rotate(-3deg);
  }
}

/* 看板上的"糖霜"高光：悬停时贴纸会亮一下 */

/* ==========================================================================
   2 · 入场上场（比基础 reveal 更有戏，按索引错开）
   ⚠ 全部只用独立属性 translate / rotate / scale 做位移，
     不用 transform —— 因为动画带 forwards 填充，会锁死 transform，
     那样卡片和圆钮的 hover 抬起（transform: var(--lift)）就全废了。
   ========================================================================== */

/* 圆钮：从"缩一下"弹回来，像刚从糖罐里蹦出来 */
.module-circle.reveal.in-view {
  animation: popIn 0.5s var(--ease-bounce) both;
}

@keyframes popIn {
  0% {
    opacity: 0;
    scale: 0.72;
    rotate: -6deg;
  }

  60% {
    opacity: 1;
    scale: 1.04;
    rotate: 2deg;
  }

  100% {
    opacity: 1;
    scale: 1;
    rotate: 0deg;
  }
}

/* 卡片：带一点点倾斜地"拍"上来 */
.poster-card.reveal.in-view,
.companion-card.reveal.in-view,
.message-item.reveal.in-view {
  animation: tiltIn 0.55s var(--ease-out) both;
}

@keyframes tiltIn {
  0% {
    opacity: 0;
    translate: 0 20px;
    rotate: -1.4deg;
    scale: 0.98;
  }

  100% {
    opacity: 1;
    translate: 0 0;
    rotate: 0deg;
    scale: 1;
  }
}

/* 标题条：从中间"抿"开 */
.section-bar h2,
.section-bar h3 {
  animation: barTitleIn 0.6s var(--ease-bounce) both;
}

@keyframes barTitleIn {
  0% {
    opacity: 0;
    scale: 0.82;
    letter-spacing: 0.3em;
  }

  100% {
    opacity: 1;
    scale: 1;
    letter-spacing: 0.03em;
  }
}

/* 首屏大标题：整块"落"下来 */
.profile h1 {
  animation: heroDrop 0.9s var(--ease-bounce) both;
  animation-delay: 0.06s;
}

@keyframes heroDrop {
  0% {
    opacity: 0;
    translate: 0 -18px;
    scale: 0.94;
  }

  55% {
    opacity: 1;
    translate: 0 4px;
    scale: 1.02;
  }

  100% {
    opacity: 1;
    translate: 0 0;
    scale: 1;
  }
}

/* ==========================================================================
   3 · 常驻呼吸（idle）
   ⚠ 关键技巧：用独立属性 `translate` 做漂浮，而不是 `transform`。
     hover / active 的位移走 `transform`，两者由浏览器分别合成、互不覆盖，
     所以不会出现"动画把 hover 效果吃掉"的问题。
   ========================================================================== */

.module-circle {
  animation: bobSoft 4.6s var(--ease-sine) infinite;
  animation-delay: var(--bob-delay, 0s);
}

.module-circle:nth-child(2) { --bob-delay: -0.7s; }
.module-circle:nth-child(3) { --bob-delay: -1.4s; }
.module-circle:nth-child(4) { --bob-delay: -2.1s; }
.module-circle:nth-child(5) { --bob-delay: -2.8s; }

@keyframes bobSoft {
  0%,
  100% {
    translate: 0 0;
  }

  50% {
    translate: 0 -5px;
  }
}

/* ⚠ .reveal.in-view 那条规则（上面第 2 节）把整个 animation 简写覆盖掉了，
   所以这里必须把"入场弹入 + 常驻呼吸"两条动画一起重新声明，
   并且给出各自的 delay —— 否则圆钮只会弹一下，再也不会飘。
   延迟用 --bob-delay 复用，保证每个圆钮的呼吸相位仍然错开。 */
.module-circle.reveal.in-view {
  animation-name: popIn, bobSoft;
  animation-duration: 0.5s, 4.6s;
  animation-timing-function: var(--ease-bounce), var(--ease-sine);
  animation-fill-mode: both, none;
  animation-iteration-count: 1, infinite;
  animation-delay: 0s, var(--bob-delay, 0s);
}

/* 头像：非常轻的呼吸（缩放走独立属性 scale，不干扰 hover 的 transform） */
.profile-avatar {
  animation: avatarBreath 6s var(--ease-sine) infinite;
}

@keyframes avatarBreath {
  0%,
  100% {
    scale: 1;
  }

  50% {
    scale: 1.022;
  }
}

/* 序号徽章 / 计数：心跳一下，提示"这里有个数字" */
.poster-index,
.sidebar-badge {
  animation: badgePop 3.2s var(--ease-sine) infinite;
}

@keyframes badgePop {
  0%,
  88%,
  100% {
    transform: scale(1) rotate(0deg);
  }

  92% {
    transform: scale(1.14) rotate(-4deg);
  }

  96% {
    transform: scale(1.06) rotate(3deg);
  }
}

/* 轮播圆点：当前项呼吸 */
.carousel-dot.active {
  animation: dotPulse 1.8s var(--ease-sine) infinite;
}

@keyframes dotPulse {
  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.55;
  }
}

/* ==========================================================================
   4 · 悬停加料
   ========================================================================== */

/* 按钮：悬停时右上角冒一颗小糖粒（纯 CSS 伪元素） */
.btn {
  isolation: isolate;
}

.btn::after {
  content: "";
  position: absolute;
  top: 6px;
  right: 10px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #fff;
  border: 1.5px solid var(--ink);
  opacity: 0;
  transform: scale(0.4);
  transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease-bounce);
  pointer-events: none;
}

.btn:hover::after {
  opacity: 1;
  transform: scale(1);
}

/* 文字按钮没有实心底，不放糖粒 */
.btn-text::after {
  display: none;
}

/* brand：悬停摇一摇的小动作已随棒棒糖装饰一并移除 */

/* 导航胶囊：激活项带一点"贴上去"的糖粒点 */
.nav-pill.active::before {
  content: "";
  position: absolute;
  top: -3px;
  right: 4px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--candy-yellow);
  border: 1.5px solid var(--ink);
}

.nav-pill {
  position: relative;
}

/* chip / 徽章悬停轻微抖一下 */
.chip:hover {
  animation: chipShake 0.4s var(--ease-pop);
}

@keyframes chipShake {
  0%, 100% { transform: translate(0, 0); }
  35% { transform: translate(-1.5px, -1.5px); }
  70% { transform: translate(1px, 1px); }
}

/* 目录/侧栏项：悬停时前面冒一个小糖点 */
.sidebar-link,
.drawer-link,
.tab-btn {
  position: relative;
}

/* ==========================================================================
   5 · 加载呼吸
   ========================================================================== */

.empty {
  animation: emptyBreath 3.4s var(--ease-sine) infinite;
}

@keyframes emptyBreath {
  0%,
  100% {
    box-shadow: var(--hard-sm);
  }

  50% {
    box-shadow: var(--hard);
  }
}

/* ==========================================================================
   6 · 氛围光带
   ========================================================================== */

/* 阅读进度条：叠一道流动的奶釉，让它看起来是"糖浆在走" */
.scroll-progress::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255, 255, 255, 0.75) 45%,
    transparent 90%
  );
  animation: progressSheen 2.4s var(--ease-sine) infinite;
}

@keyframes progressSheen {
  0% {
    transform: translateX(-100%);
  }

  100% {
    transform: translateX(100%);
  }
}

/* 顶部氛围光：一层极慢的色相漂移，让整页"活"着 */
body::before {
  content: "";
  position: fixed;
  top: -30vh;
  left: 0;
  right: 0;
  height: 90vh;
  z-index: -1;
  pointer-events: none;
  opacity: 0.5;
  background:
    radial-gradient(closest-side, rgba(255, 143, 177, 0.22), transparent),
    radial-gradient(closest-side, rgba(179, 157, 255, 0.2), transparent),
    radial-gradient(closest-side, rgba(255, 224, 102, 0.18), transparent);
  background-size: 46% 60%, 38% 55%, 34% 50%;
  background-position: 18% 40%, 76% 30%, 48% 70%;
  background-repeat: no-repeat;
  filter: blur(52px);
  animation: auraHue 24s var(--ease-sine) infinite alternate;
}

@keyframes auraHue {
  0% {
    filter: blur(52px) hue-rotate(0deg);
    transform: translateY(0) scale(1);
  }

  100% {
    filter: blur(52px) hue-rotate(14deg);
    transform: translateY(3%) scale(1.06);
  }
}

/* 返回顶部：悬停时箭头跳一下 */
.back-to-top:hover {
  animation: arrowHop 0.6s var(--ease-bounce);
}

@keyframes arrowHop {
  0% { transform: translate(-2px, -2px) scale(1.04); }
  40% { transform: translate(-2px, -9px) scale(1.1); }
  100% { transform: translate(-2px, -2px) scale(1.04); }
}

/* ==========================================================================
   7 · 降级
   ========================================================================== */

@media (max-width: 768px) {
  /* 移动端：贴纸只留两个，避免糊一屏 */
  .kaomoji-float.k3,
  .kaomoji-float.k4,
  .kaomoji-float.k5,
  .kaomoji-float.k6 {
    display: none;
  }

  .kaomoji-float {
    opacity: 0.18;
  }
}

@media (prefers-reduced-motion: reduce) {
  .kaomoji-float,
  .module-circle,
  .profile-avatar,
  .poster-index,
  .sidebar-badge,
  .carousel-dot.active,
  .empty,
  .scroll-progress::after,
  .section-bar::after,
  body::before,
  .profile h1,
  .section-bar h2,
  .section-bar h3 {
    animation: none !important;
  }

  /* ⚠️ 上面把动画整体关停后，`popIn` / `revealUp` 的 forwards 填充也一并消失，
     于是这些元素退回基础样式 `.reveal { opacity: 0 }` —— 圆钮（陪陪展示、
     价格表下的所有 .module-circle）会**永久隐形**，看起来像"图片丢了"。
     必须在同一媒体查询里把可见性显式补回来。 */
  .reveal,
  .reveal.in-view,
  .module-circle {
    opacity: 1 !important;
    translate: none !important;
    scale: none !important;
    rotate: none !important;
  }

  .btn::after {
    display: none;
  }
}
