/* ============================================================
   全站共享层：动效 + 浏览器原生表面。

   动效主张（只有一个焦点时刻）：
     这个产品的连续性时刻 = **页面/模式切换时外壳不动、正文在换**。
     用 View Transitions 承担；除此之外只保留「解释反馈与状态」的微动效。
     不给每一块内容挂同样的淡入 —— 那是模板感的主要来源。

   被三处引用（同一份文件，不分裂）：
     · 控制台 SPA       webui/index.html
     · AI 工作台 SPA     webui/wb.html
     · PHP 页面外壳      console/views/layout.php
   ============================================================ */

:root {
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);   /* 自然减速，用于出场/到达 */
  --ease-in: cubic-bezier(0.4, 0, 1, 1);       /* 用于退场（比进场快） */
  --ease-spring: cubic-bezier(0.34, 1.4, 0.5, 1); /* 轻微回弹，用于悬停抬升 / 弹入 */
  --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);   /* 平滑过渡 */
}

/* ── 0. 浏览器原生表面：这些不归任何一个设计系统管，所以最容易被漏掉，
        也最能暴露"页面是拼出来的还是做出来的" ──────────────────── */
::selection { background: rgba(109, 155, 255, 0.28); color: #fff; }
:where(input, textarea, [contenteditable]) { caret-color: var(--accent, #6d9bff); }
/* 数据里的数字用等宽数字：数值变化时列宽不跳 */
:where(.mono, .stat__value, .kv__v--mono, .log-row__time, .log-row__ip,
       .sheet__v, .sb-limit__v, .term, .chat__cmd, .logline) {
  font-variant-numeric: tabular-nums;
}

/* ── 1. 跨文档视图转场：整页跳转时外壳原地不动，正文淡出淡入 ────── */
@view-transition { navigation: auto; }

::view-transition-old(root) { animation: vt-leave 0.2s var(--ease-in) both; }
::view-transition-new(root) { animation: vt-enter 0.36s var(--ease-out) both; }

/* 退场：轻微上移 + 极浅的模糊（模糊是材质，不是装饰 —— 它让"离开"比纯透明度更像失焦） */
@keyframes vt-leave {
  to { opacity: 0; transform: translate3d(0, -5px, 0) scale(0.996); filter: blur(2px); }
}
/* 进场：从下方略偏、略模糊推上来，最后落清晰 */
@keyframes vt-enter {
  from { opacity: 0; transform: translate3d(0, 9px, 0) scale(0.996); filter: blur(3px); }
  to   { filter: blur(0); }
}

/* 外壳固定：跳转时侧栏/顶栏/品牌不参与淡出，形成「骨架不动、正文在换」的连续轴 */
.side         { view-transition-name: app-side; }
.top          { view-transition-name: app-top; }
.side__brand  { view-transition-name: app-brand; }

::view-transition-old(app-side),
::view-transition-new(app-side),
::view-transition-old(app-top),
::view-transition-new(app-top),
::view-transition-old(app-brand),
::view-transition-new(app-brand) {
  animation: none;   /* 静态保留：定位一致的两个快照叠加，视觉上等于没动 */
}

/* 工作台（code.zgric.top）同款：顶栏与状态栏原地不动，只有舞台参与转场。
   名字由 wb.css 在本页声明；这里只补「静态保留」。
   注意：**不要在 motion.css 里给 `.bar` 起名** —— 控制台的进度条也用 `.bar`，
   一页两根就撞成 duplicate view-transition-name。 */
::view-transition-old(wb-bar),
::view-transition-new(wb-bar),
::view-transition-old(wb-status),
::view-transition-new(wb-status) {
  animation: none;
}

/* ── 2. 同文档模式切换（工作台 代码 ↔ 对话）：按方向横向滑移 ──────
      方向由 JS 写在 <html data-vt> 上；往哪边走是看得出来的，
      比"整页交叉淡入"更像换了一屏。 */
html[data-vt="fwd"]::view-transition-old(root)  { animation: vt-out-left 0.22s var(--ease-in) both; }
html[data-vt="fwd"]::view-transition-new(root)  { animation: vt-in-right 0.38s var(--ease-out) both; }
html[data-vt="back"]::view-transition-old(root) { animation: vt-out-right 0.22s var(--ease-in) both; }
html[data-vt="back"]::view-transition-new(root) { animation: vt-in-left 0.38s var(--ease-out) both; }

@keyframes vt-out-left  { to   { opacity: 0; transform: translate3d(-2.2%, 0, 0); filter: blur(2px); } }
@keyframes vt-in-right  { from { opacity: 0; transform: translate3d(2.6%, 0, 0); filter: blur(3px); } to { filter: blur(0); } }
@keyframes vt-out-right { to   { opacity: 0; transform: translate3d(2.2%, 0, 0); filter: blur(2px); } }
@keyframes vt-in-left   { from { opacity: 0; transform: translate3d(-2.6%, 0, 0); filter: blur(3px); } to { filter: blur(0); } }

/* ── 3. 一次编排好的入场 ──────────────────────────────────────
      只给页面的焦点区域用（空态引导、门禁卡片、一排并列的卡）。
      默认状态就是可见的 —— 脚本挂了页面照常看。 */
@keyframes rise-in { from { opacity: 0; transform: translate3d(0, 10px, 0); } }
.anim { animation: rise-in 0.44s var(--ease-out) both; }
/* 并列的列表可以错峰，但上限 4 档（总延迟 ≤ 180ms）；再多就是在让用户等动画 */
.anim[style*="--i"] { animation-delay: calc(min(var(--i, 0), 4) * 45ms); }

/* 视图切换兜底（配合 Vue <Transition>）*/
.view-enter-active { transition: opacity 0.3s var(--ease-out), transform 0.3s var(--ease-out); }
.view-leave-active { transition: opacity 0.16s var(--ease-in), transform 0.16s var(--ease-in); }
.view-enter-from   { opacity: 0; transform: translate3d(0, 8px, 0); }
.view-leave-to     { opacity: 0; transform: translate3d(0, -5px, 0); }

/* ── 4. 微交互：按压 / 悬浮 / 焦点 ───────────────────────────── */
.btn {
  transition: transform 0.12s var(--ease-out), background 0.18s ease,
              border-color 0.18s ease, color 0.18s ease, box-shadow 0.18s ease;
}
.btn:active:not(:disabled) { transform: translateY(1px) scale(0.985); }

.lift {
  transition: transform 0.26s var(--ease-spring), border-color 0.2s var(--ease-out),
              box-shadow 0.26s var(--ease-out);
}
.lift:hover {
  transform: translateY(-3px);
  border-color: var(--line-strong);
  box-shadow: 0 14px 30px -20px color-mix(in srgb, var(--accent) 70%, transparent);
}

:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--accent-line, rgba(109, 155, 255, 0.5));
  outline-offset: 2px;
  border-radius: 8px;
}

/* ── 5. 骨架屏：加载态不跳版 ────────────────────────────────── */
@keyframes sk-shimmer { to { background-position: -200% 0; } }
.sk {
  border-radius: 8px;
  background: linear-gradient(90deg,
    rgba(255, 255, 255, 0.025) 25%,
    rgba(255, 255, 255, 0.06) 37%,
    rgba(255, 255, 255, 0.025) 63%);
  background-size: 200% 100%;
  animation: sk-shimmer 1.4s linear infinite;
}
.sk--line { height: 12px; }
.sk--num  { height: 26px; width: 72px; }

/* ── 6. 进度条（内存/磁盘占用）────────────────────────────── */
.bar { height: 6px; border-radius: 999px; background: rgba(255, 255, 255, 0.07); overflow: hidden; }
.bar__fill {
  height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--accent, #6d9bff), #8fb4ff);
  transform-origin: left center;
  animation: bar-grow 0.7s var(--ease-out) both;
  /* 轮询时 width 变化平滑滑动，不咔一下 */
  transition: width 0.5s var(--ease-out);
}
@keyframes bar-grow { from { transform: scaleX(0); } }

/* ── 6b. 顶部路由进度条：站内切视图 / 首屏就绪时扫一下，给「正在发生」的信号
       2px 细条 + 强调色微光（box-shadow），像那种后台顶部的加载线。 */
.route-bar {
  position: fixed; top: 0; left: 0; right: 0; height: 2px;
  z-index: 60; pointer-events: none; opacity: 0;
  transition: opacity 0.18s ease;
}
.route-bar.is-on { opacity: 1; }
.route-bar > i {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, var(--accent, #6d9bff), color-mix(in srgb, var(--accent, #6d9bff) 35%, #fff));
  box-shadow: 0 0 9px color-mix(in srgb, var(--accent, #6d9bff) 80%, transparent);
}
.route-bar.is-on > i { animation: route-fill 0.28s var(--ease-out, ease) forwards; }
@keyframes route-fill {
  0%   { width: 0;    opacity: 0.9; }
  70%  { width: 82%; }
  100% { width: 100%; opacity: 0; }
}

/* ── 7. 数值变化时闪一下（只表达"它变了"）──────────────────── */
@keyframes flash { 0%, 100% { color: var(--text, #e9edf6); } 30% { color: var(--accent, #6d9bff); } }
.flash { animation: flash 0.9s ease; }

/* ── 7b. 状态点呼吸：运行中 / 在线不是静止的，要"活"起来 ─────────
       用 currentColor 取状态色，on/warn 各自呼吸各自的色，不串色。 */
@keyframes dot-breathe {
  0%, 100% { box-shadow: 0 0 0 3px color-mix(in srgb, currentColor 22%, transparent); }
  50%      { box-shadow: 0 0 0 6px color-mix(in srgb, currentColor 4%, transparent); }
}
.dot--on, .wb-dot--on { animation: dot-breathe 2.6s var(--ease-soft, ease-in-out) infinite; }

/* ── 8. 尊重系统「减少动态效果」───────────────────────────────
      去掉位移与模糊，保留透明度与状态变化（反馈仍然看得见）。 */
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }

  ::view-transition-old(root),
  ::view-transition-new(root),
  html[data-vt] ::view-transition-old(root),
  html[data-vt] ::view-transition-new(root) { animation: none !important; }

  @keyframes rise-in { from { opacity: 0; } }
  @keyframes vt-leave { to { opacity: 0; } }
  @keyframes vt-enter { from { opacity: 0; } }
  @keyframes vt-out-left  { to   { opacity: 0; } }
  @keyframes vt-in-right  { from { opacity: 0; } }
  @keyframes vt-out-right { to   { opacity: 0; } }
  @keyframes vt-in-left   { from { opacity: 0; } }

  .btn:active:not(:disabled) { transform: none; }
  .lift:hover { transform: none; }
  .sk { animation: none; background: rgba(255, 255, 255, 0.05); }
  .bar__fill { animation: none; }
  .dot--on, .wb-dot--on { animation: none; }
  .route-bar { display: none; }
}

/* ── 9. 个人中心里的「动效」开关（等价于上面的 reduce，但由用户显式选择）
      用 * 兜底：偏好是"关"，就真的什么都不动，不给漏网的 keyframe 留口子。 */
html[data-motion="off"] *, html[data-motion="off"] *::before, html[data-motion="off"] *::after {
  animation-duration: 0.001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  scroll-behavior: auto !important;
}

html[data-motion="off"] ::view-transition-old(root),
html[data-motion="off"] ::view-transition-new(root) { animation: none !important; }
