/* Aevi 动效层
   照 webview-native-feel/motions.md 实现：
   一、左缘滑动返回（双层舞台 + 跟手 + 松手走或回）
   二、抽屉与小卡开合成对
   三、列表删除收拢
   五、推入转场（滑返的镜像）
   六、进场纪律（柔进场 + 动画抑制名单）
   两条铁律：跟手 > 好看；退场和进场同等重要。 */

/* ---------- 一 / 五：转场舞台 ---------- */

/* 快照层：转场期间浮在 page-host 矩形上的“那一页”。
   位置由 motion.js 每次按 page-host 的实际矩形写进行内样式。 */
.motion-stage {
  position: fixed;
  z-index: 30;
  overflow: hidden;
  background: var(--bg);
  pointer-events: none;
  will-change: transform;
}

/* 不设 bottom：让内容按原高度铺开，靠 .motion-stage 的 overflow 裁切，
   再用 translateY 把它移到旧页当时的滚动位置。 */
.motion-stage-inner {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  padding: 22px 20px 28px;
}

.motion-stage-inner > * {
  width: min(1120px, 100%);
  margin-right: auto;
  margin-left: auto;
}

/* 黑纱：蒙在“被压在下面的那一页”上，随进度淡入淡出。
   它是独立的 fixed 层，靠 z-index 决定自己蒙的是快照还是真实页面：
   push  →  page-host(32) > scrim(31) > stage(30)
   pop   →  stage(30)     > scrim(29) > page-host(28) */
.motion-scrim {
  position: fixed;
  z-index: 31;
  background: rgba(0, 0, 0, 0.16);
  pointer-events: none;
  opacity: 0;
}

.motion-scrim.motion-scrim-under {
  z-index: 29;
}

/* 转场期间的真实页面。push 时它是新页（要盖住快照），
   pop 时它是下层的返回目标（要被快照盖住）。 */
.page-host.motion-live {
  position: relative;
  z-index: 32;
  background: var(--bg);
  will-change: transform;
}

/* pop 时真实页面是被快照盖住的下层，特异性要压过 .motion-live。 */
.page-host.motion-live.motion-under {
  z-index: 28;
}

/* 推入：新页从右整屏滑入。 */
@keyframes aevi-push-in {
  from {
    transform: translateX(100%);
  }
  to {
    transform: translateX(0);
  }
}

/* 旧页退向 -18%（就是它将来被滑返露出时的姿势）。 */
@keyframes aevi-under-back {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-18%);
  }
}

/* 返回：上层滑出右缘。 */
@keyframes aevi-pop-out {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(100%);
  }
}

/* 返回：下层从 -18% 视差回位。 */
@keyframes aevi-under-forward {
  from {
    transform: translateX(-18%);
  }
  to {
    transform: translateX(0);
  }
}

@keyframes aevi-dim-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes aevi-dim-out {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

/* 左缘阴影：撕开的层次感，滑出过程中随行淡掉。 */
@keyframes aevi-edge-shadow-out {
  from {
    box-shadow: -12px 0 24px rgba(0, 0, 0, 0.12);
  }
  to {
    box-shadow: -12px 0 24px rgba(0, 0, 0, 0);
  }
}

.page-host.motion-push-in {
  animation:
    aevi-push-in 320ms cubic-bezier(0.22, 1, 0.36, 1) both,
    aevi-edge-shadow-out 320ms ease-in both reverse;
}

.motion-stage.motion-stage-back {
  animation: aevi-under-back 320ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

.motion-scrim.motion-scrim-in {
  animation: aevi-dim-in 320ms ease both;
}

.motion-scrim.motion-scrim-out {
  animation: aevi-dim-out 300ms ease both;
}

.motion-stage.motion-stage-out {
  box-shadow: -12px 0 24px rgba(0, 0, 0, 0.12);
  animation:
    aevi-pop-out 320ms cubic-bezier(0.22, 1, 0.36, 1) both,
    aevi-edge-shadow-out 300ms ease-in both;
}

.page-host.motion-under-forward {
  animation: aevi-under-forward 320ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* 手势期间：跟手层不许有过渡，位置逐帧由 JS 写死。 */
.motion-stage.motion-dragging,
.motion-scrim.motion-dragging,
.page-host.motion-dragging {
  animation: none !important;
  transition: none !important;
}

/* ---------- 二：抽屉与小卡，开合成对 ---------- */

@keyframes aevi-sheet-up {
  from {
    transform: translateY(100%);
  }
  to {
    transform: translateY(0);
  }
}

@keyframes aevi-card-in {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.94);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* 关门 = 同一路倒放，播完才真卸载（见 motion.js 的 dismiss）。 */
.drawer-scrim.motion-closing {
  animation: drawer-scrim-in 200ms ease both reverse;
}

.chat-drawer.motion-closing {
  animation: drawer-in 210ms ease-in both reverse;
}

/* 弹窗（编辑器、标签提示词）原来只有硬出现，这里补上开合两头。 */
.modal-layer {
  animation: aevi-dim-in 200ms ease both;
}

.modal-layer > .modal-card {
  animation: aevi-card-in 240ms cubic-bezier(0.22, 1.1, 0.36, 1) both;
}

.modal-layer.motion-closing {
  animation: aevi-dim-in 190ms ease both reverse;
}

.modal-layer.motion-closing > .modal-card {
  animation: aevi-card-in 190ms ease-in both reverse;
}

/* 语音通话层是整屏，走底部推起。 */
.voice-call-layer {
  animation: aevi-sheet-up 320ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

.voice-call-layer.motion-closing {
  animation: aevi-sheet-up 260ms ease-in both reverse;
}

/* 书斋的弹层：卡片 pop、底部 sheet 上推，关门各自倒放。 */
.study-modal-backdrop.motion-closing,
.study-sheet-backdrop.motion-closing {
  animation: studyFadeIn 190ms ease both reverse;
}

.study-modal-backdrop.motion-closing .study-subject-modal,
.study-modal-backdrop.motion-closing .study-dday-modal,
.study-modal-backdrop.motion-closing .study-delete-confirm,
.study-modal-backdrop.motion-closing .study-record-modal,
.study-modal-backdrop.motion-closing .study-date-modal {
  animation: studyPopIn 190ms ease-in both reverse;
}

.study-sheet-backdrop.motion-closing .study-action-sheet,
.study-sheet-backdrop.motion-closing .study-bottom-sheet,
.study-sheet-backdrop.motion-closing .study-todo-sheet {
  animation: studySheetIn 200ms ease-in both reverse;
}

/* ---------- 六：内容柔进场 ---------- */

@keyframes aevi-soft-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.motion-soft-in {
  animation: aevi-soft-in 320ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* 平级切换（底栏 tab、分段标签）：柔进场，不假装有上下级。 */
.motion-fade-in {
  animation: aevi-soft-in 220ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* ---------- 六：动画抑制名单 ----------
   转场交接、快照层渲染时挂 data-motion-busy；抑制手法必须是
   animation-duration: 0s（不是 animation: none —— 见 README 坑 13：
   none 会让后续重新赋值的动画不重播）。
   新加页面级进场动画类 = 必须登记进这张名单，这是纪律不是技术。 */
html[data-motion-busy="1"] .motion-stage-inner .message-row,
html[data-motion-busy="1"] .motion-stage-inner .study-root,
html[data-motion-busy="1"] .motion-stage-inner .motion-soft-in,
html[data-motion-busy="1"] .motion-stage-inner .study-modal-backdrop,
html[data-motion-busy="1"] .motion-stage-inner .study-sheet-backdrop,
html[data-motion-busy="1"] .motion-stage-inner .study-subject-modal,
html[data-motion-busy="1"] .motion-stage-inner .study-dday-modal,
html[data-motion-busy="1"] .motion-stage-inner .study-delete-confirm,
html[data-motion-busy="1"] .motion-stage-inner .study-record-modal,
html[data-motion-busy="1"] .motion-stage-inner .study-date-modal,
html[data-motion-busy="1"] .motion-stage-inner .study-action-sheet,
html[data-motion-busy="1"] .motion-stage-inner .study-bottom-sheet,
html[data-motion-busy="1"] .motion-stage-inner .study-todo-sheet,
html[data-motion-no-replay="1"] .page-host,
html[data-motion-no-replay="1"] .study-root,
html[data-motion-no-replay="1"] .motion-soft-in,
html[data-motion-no-replay="1"] .motion-fade-in,
html[data-motion-no-replay="1"] .message-row {
  animation-duration: 0s !important;
}

/* ---------- 移动端：抽屉是从下面长出来的面板 ---------- */

@media (max-width: 760px) {
  .chat-drawer {
    animation: aevi-sheet-up 380ms cubic-bezier(0.22, 1.1, 0.36, 1) both;
  }

  .chat-drawer.motion-closing {
    animation: aevi-sheet-up 230ms ease-in both reverse;
  }

  .motion-stage-inner {
    padding: 16px 14px 22px;
  }
}

/* ---------- 无障碍：不要动画就全退化成直切 ---------- */

@media (prefers-reduced-motion: reduce) {
  .motion-stage,
  .motion-scrim,
  .page-host.motion-push-in,
  .page-host.motion-under-forward,
  .modal-layer,
  .modal-layer > .modal-card,
  .voice-call-layer,
  .chat-drawer,
  .drawer-scrim,
  .motion-soft-in,
  .motion-stage.motion-stage-back,
  .motion-stage.motion-stage-out,
  [class*="motion-closing"] {
    animation-duration: 0.01ms !important;
  }
}
