/* ==========================================================================
   动效系统 —— base.html 与 layouts/auth_base.html 共用

   取舍原则:一天点上百次的东西(导航、表格、筛选)只给快而轻的按压反馈;
   "炫"留给低频、有情绪价值的时刻:登录、切换外观、本次会话第一次进入某页。

   只动 opacity 与独立的 scale / translate 属性 —— 它们和 Tailwind 的 transform
   工具类(-translate-x-1/2 居中、hover:scale-110 等)叠加而不是互相覆盖。
   ========================================================================== */

:root {
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);

  --motion-press: 160ms;
  --motion-hover: 200ms;
  --motion-popover: 200ms;
  --motion-popover-exit: 150ms;
  --motion-modal: 250ms;
  --motion-modal-exit: 180ms;
}

/* ---------- 按压反馈 ----------
   按下轻微收缩、松开回弹;颜色/阴影/悬浮位移沿用 hover 的 ease。
   :not(.no-press) 既是退出开关,也把优先级抬过 Tailwind 的 .transition-* 工具类。 */
button:not(.no-press),
.nav-btn,
a.stat-card,
.press {
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, box-shadow, opacity, transform, scale;
  transition-duration: var(--motion-hover), var(--motion-hover), var(--motion-hover), var(--motion-hover), var(--motion-hover),
    var(--motion-hover), var(--motion-hover), var(--motion-hover), var(--motion-hover), var(--motion-press);
  transition-timing-function: ease, ease, ease, ease, ease, ease, ease, ease, ease, var(--ease-out);
}

button:not(.no-press):not(:disabled):active {
  scale: 0.97;
}

/* 整行导航与大卡片面积大,收得更少 */
.nav-btn:active,
a.stat-card:active,
.press:active {
  scale: 0.98;
}

/* ---------- 下拉面板:从触发按钮处长出来 ---------- */
#appearance-panel,
#notif-panel,
#assistant-panel {
  transition-property: opacity, scale, display;
  transition-duration: var(--motion-popover);
  transition-timing-function: var(--ease-out);
  transition-behavior: allow-discrete;
}

#appearance-panel,
#notif-panel {
  transform-origin: top right;
}

#assistant-panel {
  transform-origin: bottom right;
}

#appearance-panel.hidden,
#notif-panel.hidden,
#assistant-panel.hidden {
  opacity: 0;
  scale: 0.95;
  pointer-events: none;
  transition-duration: var(--motion-popover-exit);
}

@starting-style {
  #appearance-panel,
  #notif-panel,
  #assistant-panel {
    opacity: 0;
    scale: 0.95;
  }
}

/* ---------- 弹窗 ----------
   覆盖所有用 .hidden 开关的全屏弹窗(.fixed.inset-0.z-50),各页 JS 不用改:
   遮罩淡入,面板从 96% 放大;关闭沿原路退出,稍快。整屏遮罩子层(.inset-0)只淡不缩。 */
.fixed.inset-0.z-50 {
  transition-property: opacity, display;
  transition-duration: var(--motion-modal);
  transition-timing-function: var(--ease-out);
  transition-behavior: allow-discrete;
}

.fixed.inset-0.z-50 > :not(.inset-0) {
  transition-property: opacity, scale;
  transition-duration: var(--motion-modal);
  transition-timing-function: var(--ease-out);
}

.fixed.inset-0.z-50.hidden {
  opacity: 0;
  pointer-events: none;
  transition-duration: var(--motion-modal-exit);
}

.fixed.inset-0.z-50.hidden > :not(.inset-0) {
  opacity: 0;
  scale: 0.96;
  transition-duration: var(--motion-modal-exit);
}

@starting-style {
  .fixed.inset-0.z-50 {
    opacity: 0;
  }

  .fixed.inset-0.z-50 > :not(.inset-0) {
    opacity: 0;
    scale: 0.96;
  }
}

/* ---------- 闪现消息:从顶栏方向落下 ---------- */
@keyframes motion-drop-in {
  from {
    opacity: 0;
    translate: 0 -6px;
  }
}

.flash-msg {
  animation: motion-drop-in 320ms var(--ease-out) backwards;
}

.flash-msg:nth-child(2) { animation-delay: 60ms; }
.flash-msg:nth-child(3) { animation-delay: 120ms; }

/* ---------- 首次进入:卡片依次浮现 ----------
   html.motion-first-view 由 <head> 里的脚本按"本次会话第一次打开这个路径"添加,
   来回切页时不再重播。容器可用 --motion-base / --motion-step / --motion-dur / --motion-rise 调节奏。
   只用 backwards 填充:播完不残留样式,不影响卡片自己的 hover 位移。 */
@keyframes motion-rise {
  from {
    opacity: 0;
    translate: 0 var(--motion-rise, 10px);
  }
}

html.motion-first-view [data-motion-stagger] > * {
  animation: motion-rise var(--motion-dur, 460ms) var(--ease-out) backwards;
  animation-delay: calc(var(--motion-base, 0ms) + var(--motion-i, 0) * var(--motion-step, 40ms));
}

/* 先归零：嵌套编排时子项不能继承外层容器给自己父级的序号 */
[data-motion-stagger] > * { --motion-i: 0; }
[data-motion-stagger] > :nth-child(2) { --motion-i: 1; }
[data-motion-stagger] > :nth-child(3) { --motion-i: 2; }
[data-motion-stagger] > :nth-child(4) { --motion-i: 3; }
[data-motion-stagger] > :nth-child(5) { --motion-i: 4; }
[data-motion-stagger] > :nth-child(6) { --motion-i: 5; }
[data-motion-stagger] > :nth-child(7) { --motion-i: 6; }
[data-motion-stagger] > :nth-child(8) { --motion-i: 7; }
[data-motion-stagger] > :nth-child(9) { --motion-i: 8; }
[data-motion-stagger] > :nth-child(n+10) { --motion-i: 9; }

/* ---------- 切换外观:新外观从点击处圆形扩散铺开 ----------
   动画本体在 base.html 外观设置脚本里(View Transitions + clip-path)。
   这里关掉默认交叉淡入,并在切换瞬间冻结页面上的过渡,让新外观一次到位。 */
html.appearance-revealing::view-transition-old(root),
html.appearance-revealing::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
}

html.appearance-revealing,
html.appearance-revealing *,
html.appearance-revealing *::before,
html.appearance-revealing *::after {
  transition: none !important;
}

/* ---------- 站内跳转:新页面淡入盖住旧页面 ----------
   每次点侧栏都是整页刷新。跨文档 View Transitions 让浏览器先留住旧画面,新页面
   就绪后 200ms 淡入接上,不再硬切。只做整屏叠加淡入(旧画面不动、普通混合),
   相同的侧栏/背景自然保持不动;不给会随滚动位移的元素单独命名,
   否则从滚动过的页面跳走时,顶栏会从屏幕外滑进来。 */
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }
}

html.page-revealing::view-transition-old(root) {
  animation: none;
  mix-blend-mode: normal;
}

html.page-revealing::view-transition-new(root) {
  animation: motion-fade-in 200ms var(--ease-out) both;
  mix-blend-mode: normal;
}

/* 跳转进度条:点下 150ms 后还没跳走才出现,把"卡住"变成"在加载";
   快速跳转时根本看不到。由 motion.js 在站内链接点击/表单提交时加 html.nav-pending。 */
.nav-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 9999;
  height: 2px;
  background: linear-gradient(90deg, var(--theme-primary-400, #a78bfa), var(--theme-primary-600, #7c3aed));
  transform-origin: left center;
  scale: 0 1;
  opacity: 0;
  pointer-events: none;
}

html.nav-pending .nav-progress {
  scale: 0.9 1;
  opacity: 1;
  transition: scale 3s var(--ease-out) 150ms, opacity 150ms ease 150ms;
}

/* ---------- 登录页:品牌时刻 ---------- */
@keyframes motion-pop {
  from {
    opacity: 0;
    scale: 0.9;
  }
}

@keyframes motion-shine {
  to {
    translate: 110% 0;
  }
}

.auth-logo {
  position: relative;
  animation: motion-pop 640ms var(--ease-out) backwards;
}

/* Logo 上一道一次性的高光扫过 */
.auth-logo::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(115deg, transparent 35%, rgba(255, 255, 255, 0.7) 50%, transparent 65%);
  translate: -110% 0;
  animation: motion-shine 1000ms var(--ease-in-out) 520ms forwards;
  pointer-events: none;
}

/* 卡片跟随指针的光斑:描边高光 + 内部柔光。图层由 motion.js 插入,
   坐标只写在图层自己身上,不触发卡片内其他元素重算样式。 */
[data-spotlight] {
  position: relative;
  isolation: isolate;
}

.spotlight-layer {
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity 300ms ease;
}

[data-spotlight-active] > .spotlight-layer {
  opacity: 1;
}

.spotlight-layer::before,
.spotlight-layer::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

.spotlight-layer::before {
  padding: 1px;
  background: radial-gradient(240px circle at var(--spot-x, 50%) var(--spot-y, 0%), rgba(167, 139, 250, 0.95), rgba(139, 92, 246, 0.28) 45%, transparent 72%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}

.spotlight-layer::after {
  background: radial-gradient(420px circle at var(--spot-x, 50%) var(--spot-y, 0%), rgba(139, 92, 246, 0.09), transparent 65%);
}

.dark .spotlight-layer::after {
  background: radial-gradient(420px circle at var(--spot-x, 50%) var(--spot-y, 0%), rgba(167, 139, 250, 0.14), transparent 65%);
}

/* ---------- 减少动效:保留淡入淡出,去掉位移与缩放 ---------- */
@keyframes motion-fade-in {
  from {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  button:not(.no-press):not(:disabled):active,
  .nav-btn:active,
  a.stat-card:active,
  .press:active {
    scale: none;
  }

  #appearance-panel.hidden,
  #notif-panel.hidden,
  #assistant-panel.hidden,
  .fixed.inset-0.z-50.hidden > :not(.inset-0) {
    scale: none;
  }

  @starting-style {
    #appearance-panel,
    #notif-panel,
    #assistant-panel,
    .fixed.inset-0.z-50 > :not(.inset-0) {
      scale: none;
    }
  }

  .flash-msg {
    animation-name: motion-fade-in;
  }

  html.motion-first-view [data-motion-stagger] > * {
    animation: none;
  }

  .auth-logo,
  .auth-logo::after,
  .animate-blob {
    animation: none;
  }

  .auth-logo::after,
  .spotlight-layer {
    display: none;
  }
}
