/* ============================================================
   清清童创 · v3.0 动效系统
   版本：v3.0-p1 (2026-07-06)
   职责：弹性动画 / 入场序列 / 状态过渡 / 角色微动效 / 页面转场 / 触觉反馈
   依赖：v3-tokens.css（easing/duration/stagger 变量，已定义不重复）
   MOTION_INTENSITY = 5（儿童精品：有趣但不眩晕）
   纯 CSS，零 JS 依赖
   ============================================================ */

/* ============================================================
   1. 弹性动画 Spring / Bounce
   曲线已在 v3-tokens.css 定义：
     --ease-spring: cubic-bezier(0.34,1.56,0.64,1)
     --ease-bounce: cubic-bezier(0.68,-0.55,0.27,1.55)
   这里提供实用工具类和预设动画
   ============================================================ */

/* ── 弹性入场（通用） ── */
@keyframes spring-in {
  0% {
    opacity: 0;
    transform: scale(0.88);
  }
  60% {
    opacity: 1;
    transform: scale(1.04);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes bounce-in {
  0% {
    opacity: 0;
    transform: translateY(24px);
  }
  50% {
    opacity: 1;
    transform: translateY(-6px);
  }
  85% {
    transform: translateY(3px);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

/* 放大弹入 */
.spring-in {
  animation: spring-in var(--duration-normal, 350ms) var(--ease-spring) both;
}

/* 弹跳闪入 */
.bounce-in {
  animation: bounce-in var(--duration-slow, 500ms) var(--ease-bounce) both;
}

/* 淡入上浮 */
@keyframes fade-slide-up {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.fade-slide-up {
  animation: fade-slide-up var(--duration-normal, 350ms) var(--ease-smooth) both;
}

/* 淡入下浮 */
@keyframes fade-slide-down {
  from {
    opacity: 0;
    transform: translateY(-12px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.fade-slide-down {
  animation: fade-slide-down var(--duration-fast, 200ms) var(--ease-smooth) both;
}

/* 缩放弹入 */
@keyframes scale-pop {
  0% {
    opacity: 0;
    transform: scale(0.8);
  }
  70% {
    opacity: 1;
    transform: scale(1.06);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

.scale-pop {
  animation: scale-pop var(--duration-normal, 350ms) var(--ease-spring) both;
}


/* ============================================================
   2. 交错入场序列 Stagger Entrance
   容器 .entrance-stagger 子元素 .entrance-item 依次进入
   使用方式：
     <div class="entrance-stagger" style="--stagger-count:6">
       <div class="entrance-item" style="--stagger-index:0">...</div>
       <div class="entrance-item" style="--stagger-index:1">...</div>
     </div>
   延迟 = var(--stagger-index) × var(--stagger-card, 60ms)
   ============================================================ */

.entrance-stagger {
  /* 容器仅作为定位上下文，无额外样式 */
}

.entrance-item {
  opacity: 0;
  transform: translateY(20px);
  animation: stagger-enter var(--duration-normal, 350ms) var(--ease-smooth) forwards;
  animation-delay: calc(var(--stagger-index, 0) * var(--stagger-card, 60ms));
}

/* ── 交错入场关键帧 ── */
@keyframes stagger-enter {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ── 使用列表延迟的变体 ── */
.entrance-item-list {
  animation-delay: calc(var(--stagger-index, 0) * var(--stagger-list, 80ms));
}

/* ── 卡片 Grid 入场变体（更大位移，更慢速度） ── */
.entrance-item-card {
  animation-delay: calc(var(--stagger-index, 0) * var(--stagger-card, 60ms) + 100ms);
}

@keyframes stagger-card-enter {
  from {
    opacity: 0;
    transform: translateY(28px) scale(0.96);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.entrance-item-card {
  animation-name: stagger-card-enter;
  animation-duration: var(--duration-slow, 500ms);
  animation-timing-function: var(--ease-spring);
}

/* ── 屏幕可见时才触发（用 animation-play-state + will-change hint） ── */
.entrance-item-lazy {
  will-change: opacity, transform;
}


/* ============================================================
   3. 状态过渡动画 Transition States
   loading → ready → error 三态切换
   骨骼屏 → 内容淡入平滑过渡
   ============================================================ */

/* ── 进入过渡 ── */
.transition-enter {
  animation: state-enter var(--duration-reveal, 700ms) var(--ease-reveal) both;
}

@keyframes state-enter {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ── 离开过渡 ── */
.transition-exit {
  animation: state-exit var(--duration-fast, 200ms) var(--ease-smooth) both;
}

@keyframes state-exit {
  from {
    opacity: 1;
    transform: scale(1);
  }
  to {
    opacity: 0;
    transform: scale(0.96);
  }
}

/* ── Loading → Ready：骨骼屏淡出 + 内容淡入 ── */

/* 骨骼屏闪烁动画 */
@keyframes skeleton-shimmer {
  0% {
    background-position: -200px 0;
  }
  100% {
    background-position: calc(200px + 100%) 0;
  }
}

/* 骨骼屏占位 */
.skeleton {
  background: linear-gradient(
    90deg,
    var(--color-bg-secondary, #e8e8f0) 0%,
    var(--color-bg-tertiary, #f0f0f8) 40%,
    var(--color-bg-secondary, #e8e8f0) 80%
  );
  background-size: 200px 100%;
  animation: skeleton-shimmer 1.8s linear infinite;
  border-radius: var(--radius-md, 12px);
}

/* 内容包裹层：从骨骼屏切换到真实内容时使用 */
.content-reveal {
  position: relative;
}

/* 使用 view-transition 风格的交错 */
.content-reveal .skeleton {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  transition:
    opacity var(--duration-normal, 350ms) var(--ease-smooth);
}

.content-reveal.ready .skeleton {
  opacity: 0;
  pointer-events: none;
}

.content-reveal.ready .content-reveal-inner {
  animation: state-enter var(--duration-reveal, 700ms) var(--ease-reveal) both;
}

/* ── Error 状态 ── */
@keyframes error-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-6px); }
  40% { transform: translateX(6px); }
  60% { transform: translateX(-4px); }
  80% { transform: translateX(4px); }
}

.error-shake {
  animation: error-shake 0.5s var(--ease-smooth);
}

/* Error 状态重试按钮脉冲 */
@keyframes retry-pulse {
  0%, 100% {
    box-shadow: 0 0 0 0 rgba(255, 169, 77, 0.4);
  }
  50% {
    box-shadow: 0 0 0 8px rgba(255, 169, 77, 0);
  }
}

.error-retry-btn {
  animation: retry-pulse 2s var(--ease-smooth) infinite;
}

/* ── 状态容器通用类 ── */
.state-container {
  position: relative;
  min-height: 200px;
}

.state-container > .state-loading,
.state-container > .state-error,
.state-container > .state-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition:
    opacity var(--duration-normal, 350ms) var(--ease-smooth),
    visibility var(--duration-normal, 350ms) var(--ease-smooth);
}

.state-container > .state-loading {
  opacity: 1;
  visibility: visible;
}

.state-container > .state-error,
.state-container > .state-empty {
  opacity: 0;
  visibility: hidden;
}

.state-container.ready > .state-loading {
  opacity: 0;
  visibility: hidden;
}

.state-container.error > .state-error {
  opacity: 1;
  visibility: visible;
}

.state-container.empty > .state-empty {
  opacity: 1;
  visibility: visible;
}


/* ============================================================
   4. 角色微动效 Character Micro-interactions
   奇奇（机器狗🐕）呼吸动画 + 漂浮 + 眨眼
   仅纯 CSS，柔和有趣，不眩晕
   ============================================================ */

/* ── 奇奇呼吸动画（核心） ── */
@keyframes qiki-breathe {
  0%, 100% {
    transform: scale(1) translateY(0);
  }
  30% {
    transform: scale(1.04) translateY(-3px);
  }
  50% {
    transform: scale(1.05) translateY(-5px);
  }
  70% {
    transform: scale(1.01) translateY(-1px);
  }
}

.qiki-breathe {
  display: inline-block;
  animation: qiki-breathe 3.5s ease-in-out infinite;
  transform-origin: center bottom;
}

/* ── 漂浮动画（图标类通用） ── */
@keyframes gentle-float {
  0%, 100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-6px);
  }
}

.gentle-float {
  animation: gentle-float 3s ease-in-out infinite;
}

/* ── 眨眼效果（emoji 用） ── */
@keyframes blink-eyes {
  0%, 92%, 100% {
    transform: scaleY(1);
  }
  96% {
    transform: scaleY(0.1);
  }
}

.blink {
  display: inline-block;
  animation: blink-eyes 4s ease-in-out infinite;
  transform-origin: center;
}

/* ── 摇尾巴（emoji 微摆动） ── */
@keyframes tail-wag {
  0%, 100% {
    transform: rotate(0deg);
  }
  25% {
    transform: rotate(-8deg);
  }
  75% {
    transform: rotate(8deg);
  }
}

.tail-wag {
  display: inline-block;
  animation: tail-wag 1.2s ease-in-out infinite;
  transform-origin: center top;
}

/* ── 星星闪烁 ── */
@keyframes twinkle {
  0%, 100% {
    opacity: 0.4;
    transform: scale(0.8);
  }
  50% {
    opacity: 1;
    transform: scale(1.15);
  }
}

.twinkle {
  animation: twinkle 2s ease-in-out infinite;
}

.twinkle-slow {
  animation-duration: 3s;
}

.twinkle-fast {
  animation-duration: 1.2s;
}

/* ── 点赞/爱心跳动 ── */
@keyframes heart-beat {
  0%, 100% {
    transform: scale(1);
  }
  15% {
    transform: scale(1.3);
  }
  30% {
    transform: scale(1);
  }
  45% {
    transform: scale(1.2);
  }
  60% {
    transform: scale(1);
  }
}

.heart-beat {
  display: inline-block;
  animation: heart-beat 1.4s ease-in-out infinite;
  transform-origin: center;
}


/* ============================================================
   5. 页面转场 Page Transitions
   页面间淡入 + slide-up 组合，移动端友好
   配合 #page-container 使用
   ============================================================ */

/* ── 页面淡入（新页面挂载时触发） ── */
@keyframes page-fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes page-slide-up {
  from {
    opacity: 0;
    transform: translateY(24px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* 页面容器基础转场 */
#page-container {
  animation: page-fade-in var(--duration-normal, 350ms) var(--ease-smooth);
}

/* 带滑动感的页面转场（用于前进导航） */
#page-container.page-slide-in {
  animation: page-slide-up var(--duration-slow, 500ms) var(--ease-reveal) both;
}

/* 后退页面（轻微下滑） */
@keyframes page-slide-back {
  from {
    opacity: 0;
    transform: translateY(-12px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

#page-container.page-slide-back {
  animation: page-slide-back var(--duration-fast, 200ms) var(--ease-smooth) both;
}

/* ── 模态弹窗（底部弹出） ── */
@keyframes modal-slide-up {
  from {
    opacity: 0;
    transform: translateY(100%);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.modal-slide-up {
  animation: modal-slide-up var(--duration-normal, 350ms) var(--ease-spring) both;
}

/* 遮罩淡入 */
@keyframes overlay-fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.overlay-fade-in {
  animation: overlay-fade-in var(--duration-fast, 200ms) var(--ease-smooth) both;
}


/* ============================================================
   6. 触觉反馈增强 Haptic Feedback
   纯 CSS 点击反馈，无需 JS
   按压涟漪引用自 buttons-3d.css 的 .btn-ripple
   ============================================================ */

/* ── 弹性回弹 tap-bounce ── */
.tap-bounce {
  transition: transform var(--duration-instant, 100ms) var(--ease-bounce);
}

.tap-bounce:active {
  transform: scale(0.92);
}

/* ── 缩放反馈 tap-shrink ── */
.tap-shrink {
  transition: transform var(--duration-instant, 100ms) var(--ease-smooth);
}

.tap-shrink:active {
  transform: scale(0.95);
}

/* ── 按压下沉 tap-press（轻微阴影反馈） ── */
.tap-press {
  transition:
    transform var(--duration-instant, 100ms) var(--ease-smooth),
    box-shadow var(--duration-instant, 100ms) var(--ease-smooth);
}

.tap-press:active {
  transform: translateY(2px);
  box-shadow: 0 2px 8px rgba(0,0,0,0.06);
}

/* ── 弹性按压（回弹 + 下沉组合） ── */
.tap-spring {
  transition: transform var(--duration-instant, 100ms) var(--ease-spring);
}

.tap-spring:active {
  transform: scale(0.96) translateY(1px);
}

/* ── 涟漪扩散（独立涟漪，不依赖 .btn-ripple） ── */
@keyframes tap-ripple-expand {
  from {
    width: 0;
    height: 0;
    opacity: 0.3;
  }
  to {
    width: 200%;
    height: 200%;
    opacity: 0;
  }
}

.tap-ripple {
  position: relative;
  overflow: hidden;
}

.tap-ripple::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  border-radius: 50%;
  background: rgba(180, 167, 246, 0.25);
  transform: translate(-50%, -50%);
  pointer-events: none;
}

.tap-ripple:active::after {
  animation: tap-ripple-expand var(--duration-slow, 500ms) var(--ease-smooth);
}


/* ============================================================
   7. 加载指示器 Loading Indicators
   儿童友好的加载动画
   ============================================================ */

/* ── 点状加载（三色跳动） ── */
@keyframes dot-bounce {
  0%, 80%, 100% {
    transform: scale(0.4);
    opacity: 0.4;
  }
  40% {
    transform: scale(1);
    opacity: 1;
  }
}

.dots-loader {
  display: inline-flex;
  gap: 6px;
  align-items: center;
}

.dots-loader .dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--color-purple, #B4A7F6);
  animation: dot-bounce 1.4s ease-in-out infinite;
}

.dots-loader .dot:nth-child(2) {
  animation-delay: 0.2s;
  background: var(--color-pink, #FF8FA3);
}

.dots-loader .dot:nth-child(3) {
  animation-delay: 0.4s;
  background: var(--color-orange, #FFA94D);
}

/* ── 旋转加载（柔和圆环） ── */
@keyframes spin-loader {
  to {
    transform: rotate(360deg);
  }
}

.spin-loader {
  display: inline-block;
  width: 32px;
  height: 32px;
  border: 3px solid var(--color-bg-tertiary, #e0e0f0);
  border-top-color: var(--color-purple, #B4A7F6);
  border-radius: 50%;
  animation: spin-loader 0.8s linear infinite;
}

/* ── 进度条（不确定） ── */
@keyframes loading-bar-indeterminate {
  0% {
    transform: translateX(-100%);
  }
  50% {
    transform: translateX(60%);
  }
  100% {
    transform: translateX(200%);
  }
}

.loading-bar {
  position: relative;
  height: 4px;
  background: var(--color-bg-secondary, #e8e8f0);
  border-radius: 2px;
  overflow: hidden;
}

.loading-bar::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 40%;
  background: linear-gradient(
    90deg,
    transparent,
    var(--color-purple, #B4A7F6),
    transparent
  );
  border-radius: 2px;
  animation: loading-bar-indeterminate 1.8s var(--ease-smooth) infinite;
}


/* ============================================================
   8. 性能保护与可访问性
   MOTION_INTENSITY = 5 — 有趣但不眩晕
   @media (prefers-reduced-motion: reduce) 关闭所有非必要动画
   移动端低频设备自动降级
   ============================================================ */

/* ── 减动效用户偏好 ── */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .qiki-breathe,
  .gentle-float,
  .blink,
  .tail-wag,
  .twinkle,
  .heart-beat {
    animation: none !important;
  }

  .dots-loader .dot,
  .spin-loader,
  .loading-bar::after {
    animation: none !important;
  }

  .tap-bounce:active,
  .tap-shrink:active,
  .tap-press:active,
  .tap-spring:active {
    transform: none !important;
  }

  .skeleton {
    animation: none !important;
  }

  .error-retry-btn,
  .error-shake {
    animation: none !important;
  }

  /* 为减动效用户提供静态 opacity fallback */
  .entrance-item {
    opacity: 1;
    transform: none;
    animation: none !important;
  }

  #page-container {
    animation: none !important;
  }
}

/* ── 低频设备降级（低帧率/省电模式） ── */
@media (update: slow) {
  .skeleton {
    animation-duration: 3s;
  }

  .qiki-breathe {
    animation-duration: 5s;
  }

  .gentle-float {
    animation-duration: 4.5s;
  }
}

/* ── 视口外动画暂停（节省 GPU） ── */
/* 配合 intersection observer 或 scroll-driven 场景，
   这里由 JS 层控制给容器加 .in-viewport 类 */
.out-of-viewport .qiki-breathe,
.out-of-viewport .gentle-float,
.out-of-viewport .skeleton,
.out-of-viewport .twinkle,
.out-of-viewport .heart-beat {
  animation-play-state: paused;
}


/* ============================================================
   9. 暗色模式适配 Dark Mode
   骨骼屏、加载器颜色适配暗色背景
   ============================================================ */

body.dark-mode {
  /* 骨骼屏暗色 */
  .skeleton {
    background: linear-gradient(
      90deg,
      #2a2a44 0%,
      #3a3a58 40%,
      #2a2a44 80%
    );
    background-size: 200px 100%;
  }

  /* 加载器暗色 */
  .spin-loader {
    border-color: rgba(255, 255, 255, 0.1);
    border-top-color: var(--color-purple-light, #B4A7F6);
  }

  .loading-bar {
    background: rgba(255, 255, 255, 0.08);
  }

  /* 涟漪暗色 */
  .tap-ripple::after {
    background: rgba(180, 167, 246, 0.12);
  }

  /* 按压反馈暗色 */
  .tap-press:active {
    box-shadow: 0 2px 8px rgba(0,0,0,0.3);
  }
}


/* ============================================================
   10. 工具类速查 Utility Quick Reference
   方便开发时快速引用
   ============================================================ */

/*
   弹性动画类：
     .spring-in           — 放大弹入
     .bounce-in           — 弹跳闪入
     .fade-slide-up       — 淡入上浮
     .fade-slide-down     — 淡入下浮
     .scale-pop           — 缩放弹入

   入场序列：
     .entrance-stagger    — 交错容器
     .entrance-item       — 交错子元素（卡片延迟）
     .entrance-item-list  — 交错子元素（列表延迟）
     .entrance-item-card  — 卡片 Grid 入场变体

   状态过渡：
     .transition-enter    — 进入过渡
     .transition-exit     — 离开过渡
     .state-container     — 状态容器（loading/error/empty）
     .skeleton            — 骨骼屏
     .content-reveal      — 内容揭示包裹层

   角色微动效：
     .qiki-breathe        — 奇奇呼吸动画
     .gentle-float        — 轻柔漂浮
     .blink               — 眨眼
     .tail-wag            — 摇尾巴
     .twinkle             — 闪烁（*.twinkle-slow / *.twinkle-fast）
     .heart-beat          — 心跳

   页面转场：
     #page-container                     — 基础淡入
     #page-container.page-slide-in       — 前进滑入
     #page-container.page-slide-back     — 后退滑入
     .modal-slide-up                     — 底部弹窗
     .overlay-fade-in                    — 遮罩淡入

   触觉反馈：
     .tap-bounce                         — 弹性回弹
     .tap-shrink                         — 缩放反馈
     .tap-press                          — 按压下沉
     .tap-spring                         — 弹性按压
     .tap-ripple                         — 独立涟漪

   加载指示器：
     .dots-loader                        — 三点跳动
     .spin-loader                        — 圆环旋转
     .loading-bar                        — 进度条

   可访问性：
     @media (prefers-reduced-motion: reduce) — 自动关闭所有非必要动画
     @media (update: slow)                    — 低频设备降级
     .out-of-viewport                        — 视口外动画暂停
*/
