/* =========================================================
   弈算 2.0 · 服务器重启预告 · 顶边下落面板（restart-notice.css）
   ---------------------------------------------------------
   形态（2026-09-30 第二版重设计）：从**屏幕顶边外边**整块落下一张
        近方形的深色卡片（248 × 212，底部两角 32px 圆角，顶边为直角）。
   行为：**不遮挡、不阻断任何操作**（整体 pointer-events:none）。
   配套脚本：assets/js/restart-notice.js

   当前状态：倒计时数字原地淡入淡出，等待态为八棒指示器。
   完成态先显示固定绿色对勾，外圈从 12 点顺时针扫满。
   倒计时环由 JS 的 setDial() 控制，完成态圆环由 CSS 的 rn-ring-draw 控制。

   ⚠️ 本文件必须排在**所有既有样式表之后**加载（index.html 里排 dispatch.css 之后）。

   ⚠️⚠️ **旧铁律「阴影必须画在 .rn-tab__clip 上」自 2026-09-30 起作废** ——
       那条规则成立的前提是「clip 带 overflow:hidden 且靠 height 生长出面板」。
       新版不再让 clip 裁剪，改为**整块 body 从视口外落下**：
         · 「落下」= `.rn-tab__body` 的 `translateY(-101%) → 0`（纯 transform，不触发重排）
         · 视口顶边本身就是天然裁切线 ⇒ clip **不需要** overflow:hidden
         · 阴影因此移到 `.rn-tab__body`（画在静止的 clip 上会「先冒出一块空影子」）
       ⛔ 别再往 clip 加 overflow:hidden，否则下落中的 body 会被整个裁掉、阴影也进不来。
   ========================================================= */

.rn-tab {
  position: fixed;
  top: 0;                       /* ★ 贴住屏幕顶边 = 与顶部融为一体 ★ */
  left: 0;
  right: 0;
  z-index: 2147483000;          /* 高于一切既有浮层 */
  display: flex;
  justify-content: center;
  align-items: flex-start;
  pointer-events: none;         /* ★ 核心：不挡操作 ★ */
  -webkit-user-select: none;
  user-select: none;
}
.rn-tab[hidden] { display: none; }

/* ---------- 透传层（不裁剪、不画阴影、不参与动画） ---------- */
.rn-tab__clip { flex: none; display: block; }

/* ---------- 面板本体：内联 SVG 渐变挂在 body 下，这里的 url(#rnRingGrad) 指向它 ---------- */
.rn-tab__body {
  position: relative;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0;
  width: 248px;
  height: 212px;
  padding: 18px 22px 20px;
  border-radius: 0 0 32px 32px;   /* 顶边为直角：与顶部融合，不做上圆角 */
  overflow: hidden;               /* 让底部进度线被圆角裁出收口（**不裁自身阴影**） */
  color: #fff;
  background: linear-gradient(180deg, #171a22 0%, #0b0d12 100%);
  box-shadow: 0 22px 56px rgba(0, 0, 0, .38), 0 4px 12px rgba(0, 0, 0, .24);
  transform: translateY(-101%);   /* 起始：整块在屏幕外上方 */
  /* 出场（收回）：ease-in，约为入场时长的 70% */
  transition: transform .40s cubic-bezier(.7, 0, .84, 0);
}
.rn-tab.is-on .rn-tab__body {
  transform: translateY(0);
  /* 入场（落下）：ease-out-expo —— 快落、慢停，像有阻尼地「落定」 */
  transition: transform .58s cubic-bezier(.16, 1, .3, 1);
}

/* 内容层：跟着面板一起落；只补一点淡入，避免「啪」地出现 */
.rn-tab__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  opacity: 0;
  transition: opacity .30s ease .12s;
}
.rn-tab.is-on .rn-tab__inner { opacity: 1; }

/* =========================================================
   中央拨环
   ---------------------------------------------------------
   旧版左上角是「蓝色圆底 + 转圈的时钟图标」—— 纯装饰，容易被当成「卡住了」。
   现在换成**进度环**：环的缺口随剩余时间收缩，环里放大数字 —— 装饰变成信息。
   ========================================================= */
.rn-tab__dial {
  position: relative;
  flex: none;
  width: 94px;
  height: 94px;
}
.rn-tab__ring {
  position: absolute;
  inset: 0;
  display: block;
  width: 94px;
  height: 94px;
  transform: rotate(-90deg);      /* 让弧从 12 点方向起算 */
}
.rn-tab__ring-track,
.rn-tab__ring-arc { fill: none; stroke-width: 3; }
.rn-tab__ring-track {
  stroke: rgba(255, 255, 255, .09);
  transition: stroke .25s ease;   /* 等待态会把它提亮一点，当「容器」用 */
}
.rn-tab__ring-arc {
  stroke: url(#rnRingGrad);       /* 白 → 淡蓝，克制的一点点色 */
  stroke-linecap: round;
  stroke-dasharray: 282.7434;     /* 2πr，r = 45 */
  stroke-dashoffset: 0;           /* JS 按剩余时间写入：**负值** ⇒ 缺口自 12 点**顺时针**扩大
                                     （= 剩余弧逆时针缩短），见 restart-notice.js 的 setDial() */
  transition: stroke-dashoffset .18s linear, opacity .25s ease;
}

/* ---------- 环内：大数字（英雄元素） ---------- */
.rn-tab__count { position: absolute; inset: 0; }
.rn-tab__body .rn-tab__count[hidden] { display: none; }
.rn-tab__num,
.rn-tab__ghost {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 43px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.rn-tab__num { color: #fff; }
.rn-tab__ghost { color: #cfe2ff; opacity: 0; pointer-events: none; }

/* 换字（★ 第四版：**原地换，绝不位移**）-------------------------------
   用户实测反馈：「倒计时动画不能是上移下移，你这数字都出了这个圈了，这个不行啊」。
   上一版让新值从下方 72% 处升起 ⇒ 43px 的字走 31px，上下边缘直接顶出 88px 的环内圈。
   现在**完全不做位移**，只做「原地淡出 + 原地淡入」，配一点点缩放当呼吸：
     t = 0 ~ 200ms   旧值：opacity 1 → 0，scale 1 → .94，blur 0 → 2px
     t = 200 ~ 500ms 新值：opacity 0 → 1，scale 1.06 → 1，blur 3px → 0
   ⇒ 两窗**零重叠**；且缩放幅度只有 ±6%（43px 字 = ±2.6px），
     叠在 88px 的环内圈里**绝不可能出圈**。

   ⚠️ ghostA 已**停用**（它写的是新值，与新字同位叠加）——节点保留以免动到外部结构，
      CSS 里不再给它任何动画，JS 也不再写值。 */
.rn-tab__num.is-pop {
  /* `both` = 延迟期间保持 0% 帧（透明度 0 / 略大），否则会先「啪」地显形再跳一下 */
  animation: rn-num-in .30s cubic-bezier(.16, 1, .3, 1) .20s both;
}
@keyframes rn-num-in {
  0%   { opacity: 0; transform: scale(1.06); filter: blur(3px); }
  60%  { opacity: 1; }
  100% { opacity: 1; transform: scale(1);    filter: blur(0); }
}
/* ghostB = **旧值**（由 JS 写入）：原地淡出并微微收小 */
.rn-tab__ghost--b.is-echo { animation: rn-num-out .20s cubic-bezier(.4, 0, 1, 1) both; }
@keyframes rn-num-out {
  0%   { opacity: 1; transform: scale(1);   filter: blur(0); }
  100% { opacity: 0; transform: scale(.94); filter: blur(2px); }
}

/* =========================================================
   忙碌态（★ 第四版：Apple 原版「活动指示器」）
   ---------------------------------------------------------
   用户要求「再看看还有没有更好的设计，去网上找一找」。
   查 Apple HIG 与各家设计系统后确认：
     · 苹果的 Activity Indicator = **8 或 12 根圆头短棒绕圈排布、依次变暗**，
       而且**刻意不做旋转** —— HIG 的说法是 indeterminate 状态要
       "calm, not urgent"（平静，不催人）。
     · Material 那种「弧长边转边伸缩 + 旋转」属于「呼吸式」做法，观感偏躁；
       「双弧对转」则是仪表盘/科技风那一挂 —— 都不是苹果味。
   所以等待态改为：**外环淡出、只留一圈淡底环当容器，环内跑 8 根棒**。
   —— 动效焦点只有一个，最干净，也最像苹果。
   ========================================================= */
.rn-tab__busy {
  position: absolute;
  left: 50%;
  top: 50%;
  display: block;
  width: 56px;
  height: 56px;
  margin: -28px 0 0 -28px;        /* 在 94px 的 dial 里居中 */
}
.rn-tab__body .rn-tab__busy[hidden] { display: none; }
.rn-tab__busy i {
  position: absolute;
  left: calc(50% - 2px);          /* 棒宽 4px */
  top: 0;
  width: 4px;
  height: 15px;
  border-radius: 2px;             /* 圆头，与苹果一致 */
  background: #e8f1ff;
  /* 绕容器中心（半径 28px）旋转 ⇒ 8 根均匀铺满一圈 */
  transform-origin: 50% 28px;
  animation: rn-spoke 1s linear infinite;
}
/* 8 根各转 45°，并错开 1/8 周期 —— 视觉上就是一颗光点在绕圈跑 */
.rn-tab__busy i:nth-child(1) { transform: rotate(0deg);   animation-delay: -0.875s; }
.rn-tab__busy i:nth-child(2) { transform: rotate(45deg);  animation-delay: -0.750s; }
.rn-tab__busy i:nth-child(3) { transform: rotate(90deg);  animation-delay: -0.625s; }
.rn-tab__busy i:nth-child(4) { transform: rotate(135deg); animation-delay: -0.500s; }
.rn-tab__busy i:nth-child(5) { transform: rotate(180deg); animation-delay: -0.375s; }
.rn-tab__busy i:nth-child(6) { transform: rotate(225deg); animation-delay: -0.250s; }
.rn-tab__busy i:nth-child(7) { transform: rotate(270deg); animation-delay: -0.125s; }
.rn-tab__busy i:nth-child(8) { transform: rotate(315deg); animation-delay: 0s; }
/* 每根棒：全亮 → 线性变暗，然后靠负延迟接回全亮 ⇒ 无缝的「跑动光点」 */
@keyframes rn-spoke {
  from { opacity: .95; }
  to   { opacity: .12; }
}

.rn-tab.is-busy .rn-tab__ring-arc { opacity: 0; }          /* 外弧收掉，交棒给棒状指示器 */
.rn-tab.is-busy .rn-tab__ring-track { stroke: rgba(255, 255, 255, .14); }
.rn-tab.is-busy .rn-tab__bar i { background: rgba(255, 255, 255, .16); }

/* ---------- 完成态：对勾与外圈**同时**开跑、同时结束，动画一停就收回面板 ---------- */
.rn-tab__done {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: #69b86b;
}
.rn-tab__body .rn-tab__done[hidden] { display: none; }
.rn-tab.is-done-pending .rn-tab__done { opacity: 0; }
.rn-tab.is-done .rn-tab__done { opacity: 1; }
.rn-tab__done-ring {
  position: absolute;
  top: 50%;
  left: 50%;
  display: block;
  width: 104px;
  height: 104px;
  transform: translate(-50%, -50%) rotate(-90deg);
  overflow: visible;
}
.rn-tab__done-ring circle {
  fill: none;
  stroke-width: 4;
  /* ⚠️⚠️ 这里**绝对不许**再写 `vector-effect: non-scaling-stroke`。
     它会把 `stroke-dasharray` 的单位从「用户单位」偷换成「屏幕像素」，
     而 282.7434 是按 r=45 的用户单位算出来的（2πr）。容器 104px / viewBox 100
     ⇒ 屏幕周长 294.05px，虚线短 11.3px ⇒ **12 点左侧固定一道约 10° 的缺口，圈永远合不拢**。
     2026-10-07 实测对照：`tmp/_ring_close_probe.html` + `tmp/shots/ring-close-probe.png`
     —— A（带 non-scaling）有缺口、B（去掉）完全闭合、C（带 non-scaling + pathLength）仍不合。
     本环尺寸固定 104px、面板只做 translateY 不做 scale ⇒ 不加它也足够清晰。 */
}
.rn-tab__done-ring-track { stroke: rgba(105, 184, 107, .22); }
.rn-tab__done-ring-progress {
  stroke: #69b86b;
  stroke-linecap: round;
  stroke-dasharray: 282.7434;
  stroke-dashoffset: 282.7434;
}
.rn-tab.is-done .rn-tab__done-ring-progress {
  /* ⚠️ 与对勾**同起同落**：同是 .62s、delay 0，两条动画一起跑完。
     用户 2026-10-07 裁定「这两个动画是同时」，且「动画完成后立即收回」——
     所以这里不许再给外圈加 delay（加了对勾就得等它，收面板的时机也要跟着改）。 */
  animation: rn-ring-draw .62s ease-out both;
}
@keyframes rn-ring-draw {
  from { stroke-dashoffset: 282.7434; }
  to { stroke-dashoffset: 0; }
}
.rn-tab__done-check {
  position: absolute;
  top: 50%;
  left: 50%;
  display: block;
  width: 52px;
  height: 52px;
  transform: translate(-50%, -50%);
}
/* 对勾「一笔描出来」：stroke-dashoffset 由满 → 0。
   ⚠️ dasharray 必须 ≥ path 的真实长度，否则末笔描不到头。
      `M5 12.5 10 17.5 19 7` 的几何长度 = 7.0711 + 13.8293 = 20.9004 ⇒ 取 21.5 留余量。
   ⚠️ path 的数据必须**从对勾的小头（左下短笔画）写起** —— 描边动画是从 path 起点画起的；
      数据反着写就变成从右上大头倒着画（用户当场看破过一次）。 */
.rn-tab__done-check path {
  stroke-dasharray: 21.5;
  stroke-dashoffset: 21.5;
}
.rn-tab.is-done .rn-tab__done-check path {
  /* 与外圈同时开跑、同时结束，都是 .62s —— 改这里必须同步改上面那条 rn-ring-draw */
  animation: rn-check-draw .62s cubic-bezier(.35, .8, .3, 1) both;
}
@keyframes rn-check-draw {
  from { stroke-dashoffset: 21.5; }
  to { stroke-dashoffset: 0; }
}
.rn-tab.is-done .rn-tab__ring-track,
.rn-tab.is-done .rn-tab__ring-arc,
.rn-tab.is-done-pending .rn-tab__ring-track,
.rn-tab.is-done-pending .rn-tab__ring-arc {
  opacity: 0;
}
.rn-tab.is-done .rn-tab__bar i,
.rn-tab.is-done-pending .rn-tab__bar i {
  background: linear-gradient(90deg, rgba(105, 184, 107, .30), #69b86b);
}

/* ---------- 文案 ---------- */
.rn-tab__label {
  font-size: 15px;
  font-weight: 500;
  line-height: 20px;
  letter-spacing: .2px;
  white-space: nowrap;
  color: rgba(255, 255, 255, .94);
}
.rn-tab__reason {
  font-size: 12.5px;
  line-height: 16px;
  letter-spacing: .4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 200px;
  color: rgba(255, 255, 255, .40);
}
.rn-tab__body .rn-tab__reason[hidden] { display: none; }

/* ---------- 底部进度细线：整条贴底，两端由圆角裁出收口 ---------- */
.rn-tab__bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: rgba(255, 255, 255, .07);
  overflow: hidden;
}
.rn-tab__bar i {
  display: block;
  width: 100%;
  height: 100%;
  transform-origin: left center;   /* 配 scaleX 使用 —— 渐变会被一起压缩，
                                      所以「亮头」永远正好停在推进的前沿 */
  transition: transform .16s linear;
  background: linear-gradient(90deg,
              rgba(190, 214, 255, .14), rgba(255, 255, 255, .52) 74%, rgba(255, 255, 255, .78));
}

/* ---------- 窄屏 ---------- */
@media (max-width: 560px) {
  .rn-tab__body {
    width: 232px;
    height: 192px;
    padding: 14px 18px 18px;
    border-radius: 0 0 28px 28px;
  }
  .rn-tab__inner { gap: 12px; }
  .rn-tab__dial, .rn-tab__ring { width: 88px; height: 88px; }
  .rn-tab__num, .rn-tab__ghost { font-size: 40px; }
  .rn-tab__busy { width: 52px; height: 52px; margin: -26px 0 0 -26px; }
  .rn-tab__busy i { height: 14px; transform-origin: 50% 26px; }
  .rn-tab__label { font-size: 13.5px; line-height: 18px; }
  .rn-tab__reason { font-size: 11.5px; line-height: 15px; max-width: 180px; }
  .rn-tab__done-check { width: 54px; height: 54px; }
}

/* ---------- 减弱动效 ----------
   保留「信息类」动效（进度环照常收缩），只去掉「空间位移类」动效。
   ⚠️ body / inner 保持 transition:none —— 这也是无头截图「落终态」那条路子依赖的分支。 */
@media (prefers-reduced-motion: reduce) {
  .rn-tab__body { transition: none; }
  .rn-tab__inner { transition: none; }
  .rn-tab__ring-arc { transition: none; }
  .rn-tab__num.is-pop,
  .rn-tab__ghost.is-echo { animation: none; }
  .rn-tab__ghost { display: none; }
  /* 减弱动效时直接显示完整圆环与对勾。 */
  .rn-tab.is-done .rn-tab__done-ring-progress { animation: none; stroke-dashoffset: 0; }
  .rn-tab.is-done .rn-tab__done-check path { animation: none; stroke-dashoffset: 0; }
  /* 等待态：棒不闪，静态摆成放射状（一眼也能看出「在等」） */
  .rn-tab__busy i { animation: none; opacity: .45; }
  .rn-tab__bar i { transition: none; }
}
