/* ============================================================
   motion.css —— 交互反馈层（v0.3.11）
   ============================================================
   设计约束（照文章那套，也是真能用得住的规矩）：
   · 时长 180 / 260 / 360ms 三档 —— 低于 150ms 感知不到，高于 400ms 变拖沓
   · 缓动一律用曲线，不用 linear（linear 在物理世界里不存在）
   · 只做"反馈"，不阻塞操作：点击立刻发请求，动画并行播
   · 全部尊重 prefers-reduced-motion（开了就出终态，不播过程）

   命名约定：所有类以 m- 开头，全部动画状态用 class 切换，
   避免和 win.css（.pg-* / .set-*）抢样式。
   ============================================================ */

:root {
  /* 三档时长，全部落在 200~400ms 区间：
     低于 200 感知不到"完成了什么"，高于 400 就开始等人 */
  --m-fast: 200ms;
  --m-base: 260ms;
  --m-slow: 360ms;
  /* 三条缓动：出场 / 往返 / 带一点回弹 */
  --m-e-out: cubic-bezier(.22, 1, .36, 1);
  --m-e-in-out: cubic-bezier(.65, 0, .35, 1);
  --m-e-back: cubic-bezier(.34, 1.56, .64, 1);
}

/* ============================================================
   ① 完成反馈按钮
   三段串起来：收缩成圆 → 一笔画出对勾 → 周围迸发粒子
   ============================================================ */
.m-done {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: visible;
  /* 宽度收缩用 fast；底色/描边用 base（两段错开，看起来才是一串而不是一坨） */
  transition: width var(--m-fast) var(--m-e-out),
              background-color var(--m-base) var(--m-e-out),
              border-color var(--m-base) var(--m-e-out),
              color var(--m-fast) var(--m-e-out);
}
.m-done .m-done-txt {
  display: inline-block;
  transition: opacity 120ms var(--m-e-out), transform 120ms var(--m-e-out);
}
.m-done.is-go .m-done-txt {
  opacity: 0;
  transform: scale(.7);
}
/* 覆盖层：正方形（配合 border-radius:50% 就是圆），装对勾 */
.m-done .m-done-face {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  opacity: 0;
  transform: scale(.55);
  transition: transform var(--m-base) var(--m-e-back), opacity 140ms var(--m-e-out);
}
.m-done.is-go .m-done-face {
  opacity: 1;
  transform: scale(1);
}
/* 一笔画对勾：靠 stroke-dashoffset 从"全断"走到"全连" */
.m-done .m-done-face svg path {
  stroke-dasharray: 26;
  stroke-dashoffset: 26;
  transition: stroke-dashoffset var(--m-base) var(--m-e-out) 80ms;
}
.m-done.is-tick .m-done-face svg path {
  stroke-dashoffset: 0;
}
/* 粒子：JS 预置 --dx/--dy（不用 CSS 三角函数，兼容性更稳） */
.m-done .m-p {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 4px;
  height: 4px;
  margin: -2px 0 0 -2px;
  border-radius: 50%;
  background: var(--m-pc, #37dd86);
  opacity: 0;
  pointer-events: none;
}
.m-done.is-burst .m-p {
  animation: mBurst 520ms var(--m-e-out) forwards;
  animation-delay: calc(var(--i) * 11ms);
}
@keyframes mBurst {
  0%   { opacity: 1; transform: translate(0, 0) scale(1); }
  70%  { opacity: .9; }
  100% { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(.25); }
}
/* 完成后的落定态：变绿、禁用，不再让人重复点 */
.m-done.is-settled {
  background: rgba(55, 221, 134, .16) !important;
  border-color: rgba(55, 221, 134, .55) !important;
  color: #7ff0b4 !important;
  cursor: default;
}

/* ============================================================
   ② 勾选联动：进度环 + 数字滚动 + 颜色跟随
   ============================================================ */
.m-ring-wrap {
  display: flex;
  align-items: center;
  gap: 10px;
}
.m-ring {
  width: 38px;
  height: 38px;
  flex: 0 0 auto;
  /* 起点转到 12 点方向，进度才是"从顶上顺时针长" */
  transform: rotate(-90deg);
}
.m-ring circle {
  fill: none;
  stroke-width: 4;
}
.m-ring .m-ring-bg {
  stroke: rgba(255, 255, 255, .085);
}
.m-ring .m-ring-fg {
  stroke: var(--m-ring-c, #f5a524);
  stroke-linecap: round;
  transition: stroke-dashoffset var(--m-slow) var(--m-e-out),
              stroke var(--m-slow) var(--m-e-out);
}
.m-ring-txt {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
}
.m-ring-txt b {
  font-size: 15px;
  font-weight: 700;
  color: #eef3f8;
  font-variant-numeric: tabular-nums;
}
.m-ring-txt span {
  font-size: 9.5px;
  color: #5c6b7d;
  letter-spacing: .04em;
}
/* 背景色跟随：整块 KPI 区随完成率从冷到暖（极轻，不抢数字） */
.pg-kpis.m-tinted {
  transition: background-color var(--m-slow) var(--m-e-out);
}

/* ============================================================
   ③ 叠卡展开：层叠 → 点击扇形展开 → 再点收回
   ============================================================ */
.td-stack {
  margin-top: 12px;
  position: relative;
}
.td-stack .m-card {
  position: relative;
  background: linear-gradient(180deg, rgba(255, 255, 255, .05), rgba(255, 255, 255, .012));
  border: 1px solid rgba(255, 255, 255, .09);
  border-radius: 9px;
  padding: 9px 11px;
  cursor: pointer;
  transform-origin: 50% 0;
  transition: transform var(--m-slow) var(--m-e-back),
              margin-top var(--m-slow) var(--m-e-out),
              opacity var(--m-base) var(--m-e-out),
              border-color var(--m-base) var(--m-e-out);
  transition-delay: calc(var(--i) * 45ms);
}
/* 叠：后续卡片往上压，越往下越淡越小（堆叠的透视感） */
/* 卡片固定最小高（≈46px），负 margin 留 8px 露边 ——
   完全压死的话看上去就是一张卡，叠卡的意义就没了 */
.td-stack .m-card {
  min-height: 46px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.td-stack .m-card + .m-card {
  margin-top: -38px;
}
.mc-t {
  font-size: 11.5px;
  color: #dfe8f2;
  line-height: 1.35;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.td-stack .m-card:not(:first-child) {
  transform: translateY(calc(var(--i) * 5px)) scale(calc(1 - var(--i) * .04));
  opacity: calc(1 - var(--i) * .26);
}
/* 展开：顺序带 stagger（transition-delay 已按 --i 排好） */
.td-stack.open .m-card + .m-card {
  margin-top: 7px;
}
.td-stack.open .m-card {
  transform: translate(calc(var(--i) * 10px), 0) rotate(calc(var(--i) * .9deg)) scale(1);
  opacity: 1;
  border-color: rgba(45, 226, 230, .26);
}
.td-stack .m-card-hint {
  font-size: 9px;
  color: #5c6b7d;
  letter-spacing: .05em;
  margin-top: 2px;
}
.td-stack.open .m-card-hint { color: #7d8b9c; }

/* ============================================================
   ④ 吸附卡 + 时间线逐段绘制
   卡片横向 scroll-snap 吸附；停稳后左侧时间线从上往下画出来
   ============================================================ */
.m-snap {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  /* 边界不把整页拖着一起弹 */
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  padding: 2px 0 8px;
}
.m-snap::-webkit-scrollbar { display: none; }
.m-snap .m-snap-card {
  flex: 0 0 auto;
  min-width: 168px;
  scroll-snap-align: center;
  background: linear-gradient(180deg, rgba(255, 255, 255, .05), rgba(255, 255, 255, .012));
  border: 1px solid rgba(255, 255, 255, .09);
  border-radius: 10px;
  padding: 10px 12px;
  /* 吸附后有一个轻微的"落定"反馈：靠 class 切换，不用 animation */
  transition: border-color var(--m-base) var(--m-e-out),
              transform var(--m-base) var(--m-e-out),
              background-color var(--m-base) var(--m-e-out);
}
/* 小标题：日程页里「快速跳日期」「X 的时间线」 */
.m-sec-h {
  font-size: 10px;
  font-weight: 600;
  color: #8d9bad;
  letter-spacing: .07em;
  margin: 14px 0 7px;
  display: flex;
  align-items: baseline;
  gap: 7px;
}
.m-sec-h small {
  font-weight: 400;
  font-size: 9px;
  color: #4f5f70;
  letter-spacing: .02em;
}
.m-snap-time {
  font-size: 12px;
  color: #7fe6ef;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.m-snap-t {
  font-size: 12px;
  color: #eef3f8;
  margin-top: 2px;
  line-height: 1.35;
}
.m-snap-m {
  font-size: 9.5px;
  color: #6b7a8b;
  margin-top: 3px;
}
.m-snap .m-snap-card.is-center {
  border-color: rgba(45, 226, 230, .45);
  background: rgba(45, 226, 230, .075);
  transform: scale(1.02);
}

/* 时间线：竖线 scaleY 从 0 长到 1，节点依次点亮 */
.m-tl {
  position: relative;
  padding-left: 20px;
  margin-top: 12px;
}
.m-tl-rail {
  position: absolute;
  left: 6px;
  top: 8px;
  bottom: 8px;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(180deg, rgba(45, 226, 230, .55), rgba(45, 226, 230, .06));
  transform: scaleY(0);
  transform-origin: top;
  transition: transform var(--m-slow) var(--m-e-out);
}
.m-tl.on .m-tl-rail { transform: scaleY(1); }
.m-tl-row {
  position: relative;
  padding: 5px 0;
  font-size: 11px;
  color: #c3d0dd;
  opacity: 0;
  transform: translateX(-5px);
  transition: opacity var(--m-base) var(--m-e-out),
              transform var(--m-base) var(--m-e-out);
}
.m-tl.on .m-tl-row {
  opacity: 1;
  transform: none;
  transition-delay: calc(var(--i) * 70ms + 80ms);
}
.m-tl-dot {
  position: absolute;
  left: -18px;
  top: 9px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #2de2e6;
  box-shadow: 0 0 10px rgba(45, 226, 230, .55);
  transform: scale(.3);
  transition: transform var(--m-base) var(--m-e-back);
}
.m-tl.on .m-tl-dot {
  transform: scale(1);
  transition-delay: calc(var(--i) * 70ms + 80ms);
}
.m-tl-time {
  color: #7fe6ef;
  font-variant-numeric: tabular-nums;
  margin-right: 7px;
}
.m-tl-tag {
  font-size: 9px;
  color: #8d9bad;
  margin-left: 6px;
}

/* ============================================================
   ⑤ 惯性滚轮：拖动 → 动量衰减 → 吸附刻度 → 边界橡皮筋回弹
   （这段是纯 JS 控制的 transform，CSS 只负责外观）
   ============================================================ */
.m-wheel {
  position: relative;
  overflow: hidden;
  /* 限宽：滚轮是"一条带子"，占满整行就没有可滚空间，惯性也就没意义了 */
  max-width: 560px;
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
  cursor: grab;
  padding: 2px 0;
}
.m-wheel.grabbing { cursor: grabbing; }
.m-wheel-track {
  display: flex;
  gap: 8px;
  will-change: transform;
}
.m-wheel-item {
  flex: 0 0 auto;
  min-width: 66px;
  text-align: center;
  padding: 7px 9px;
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, .08);
  background: rgba(255, 255, 255, .022);
  font-size: 11px;
  color: #a7b6c6;
  transition: border-color var(--m-base) var(--m-e-out),
              background-color var(--m-base) var(--m-e-out),
              color var(--m-base) var(--m-e-out),
              transform var(--m-base) var(--m-e-back);
}
.m-wheel-item.on {
  border-color: rgba(45, 226, 230, .55);
  background: rgba(45, 226, 230, .13);
  color: #b6f5fb;
  transform: scale(1.05);
}
.m-wheel-item small {
  display: block;
  font-size: 8.5px;
  color: #5c6b7d;
  margin-top: 1px;
}
.m-wheel-item.on small { color: #7fe6ef; }
/* 两边渐隐，让滚轮看起来是"转进去"的 */
.m-wheel-edge {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 26px;
  pointer-events: none;
  z-index: 2;
}
.m-wheel-edge.l {
  left: 0;
  background: linear-gradient(90deg, var(--m-edge-bg, #0e151e), transparent);
}
.m-wheel-edge.r {
  right: 0;
  background: linear-gradient(270deg, var(--m-edge-bg, #0e151e), transparent);
}

/* ============================================================
   ⑥ 圆形扩散转场：新页面从手指按下的坐标向外铺满
   ============================================================ */
.view.m-reveal {
  /* 干掉原有的 viewIn（opacity+translate），否则两套动画打架 */
  animation: none !important;
  clip-path: circle(0px at var(--m-ox, 50%) var(--m-oy, 50%));
}
.view.m-reveal.in {
  clip-path: circle(var(--m-or, 150%) at var(--m-ox, 50%) var(--m-oy, 50%));
  transition: clip-path var(--m-slow) var(--m-e-out);
}

/* ============================================================
   无障碍：系统开了"减少动态效果" → 全部直接出终态
   （这不是可选项，是细节的一部分：有人会因为动效头晕）
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .m-done,
  .m-done .m-done-face,
  .m-done .m-done-txt,
  .m-done .m-done-face svg path,
  .m-ring .m-ring-fg,
  .pg-kpis.m-tinted,
  .td-stack .m-card,
  .m-snap .m-snap-card,
  .m-tl-rail,
  .m-tl-row,
  .m-tl-dot,
  .m-wheel-item {
    transition: none !important;
    animation: none !important;
  }
  .m-done.is-burst .m-p { display: none; }
  .view.m-reveal,
  .view.m-reveal.in { clip-path: none !important; }
}

/* 默认不显示卡堆（桌面屏幕够宽，清单信息密度更高） */
.td-stack { display: none; }

/* 手机上：卡堆替代清单 —— 竖屏放 9 行清单就占满一屏 */
@media (max-width: 767px) {
  .td-stack { display: block; }
  .td-list { display: none; }
  .td-stack .m-card + .m-card { margin-top: -36px; }
  .m-snap .m-snap-card { min-width: 156px; }
  .m-wheel-item { min-width: 60px; }
}
