/* ==========================================================================
   CodeRelay — 下载页专属样式表（assets/css/download.css）
   ==========================================================================

   为什么单独成文件
   ---------------------------------------------------------------------
   style.css 是全站共享的：features / download / 404 / index 都加载它。这次下载页
   要整体重排成「像素 + 终端」的语言，会引入终端标题栏、扫描线、环形进度、
   计数器、走马灯等一堆只属于本页的组件。把它们塞进 style.css，另外三个页面
   就要白下载一大段永远用不到的规则，而且这些组件的类名还可能与功能页撞车。

   所以：**所有下载页新样式集中在本文件，且只被 download.html 引用**（排在
   style.css 之后）。新类名统一 `dx-`（download experience）前缀，与既有
   `dl-` 前缀的 DOM 契约（#dl-version / #dl-assets …）刻意区分开：
   前者是「视觉层」，后者是「脚本层的 id」，两种命名混在一起日后极容易
   把 #dl-steps 当成样式钩子随手改掉，而那是一个 JS 契约。

   一、设计语言的三条硬规则
   ---------------------------------------------------------------------
   1. 像素感 = 硬边。新组件一律 2px 实线边框、border-radius: 0、方形色块、
      方角括号；需要「阴影」时用 4px 无模糊的偏移硬影（box-shadow 的 blur
      取 0），而不是柔光。柔和的东西交给背景那三层，组件本身不做柔光。
   2. 代码感 = 等宽。所有编号、端口、文件名、微标签一律 DM Mono + 大写 +
      字距；唯一强调色仍是 --green。全页只用了现成 token，没有新造色值。
   3. 背景一个字节都不动。body::before、.bgcode*、.bgpixels 及其 token 全部
      原样保留。本文件不写任何一条针对它们的规则；额外光效走新增的
      .dx-aura 层（见第 1 节），那是一个独立元素，不改任何既有背景层。

   二、成本纪律（用户的「花哨可以，但要管好开支」）
   ---------------------------------------------------------------------
   · 持续动画全部挂在 .dx-gate 之下，默认 animation-play-state: paused；
     只有 download-fx.js 的 IntersectionObserver 判定区块进入视口、给它加上
     .is-live，动画才开始跑；离开视口立刻回到 paused。浏览器对暂停的合成器
     动画几乎不收钱。
   · 所有持续动画只动 transform / opacity / clip-path（合成或廉价重绘），
     绝不动 left / top / width / height（那会让整段重新排版）。
   · 环形的「画圈」不用 rAF 逐帧算，改成 stroke-dashoffset 的一次性过渡：
     跑一次就结束，不留任何调度。
   · 页面唯一持续存在的开销是四条 CSS 动画（标题扫描、走马灯、光标、环内
     缓转），且全部可见性门控；JS 侧的 rAF 只有一条、一次性、跑完自清。
   · 背景光效是静态渐变，不做脉冲 —— 一层铺满视口的 fixed 图层每帧动一下，
     就要整屏重新合成一次，那才是真正的浪费。要动就动小面积组件。

   三、与既有样式的层级关系
   ---------------------------------------------------------------------
   本文件在 style.css 之后加载，同特异度下后者胜；对少数低于 style.css 的
   选择器（如 inline <style> 里的 #dl-steps），显式用 #download-page 前缀抬高
   特异度，而不是拿 !important 硬压 —— 后者会在以后调试时变成隐形的坑。
   ========================================================================== */

/* ==================================================================
   0. 本页局部变量
   ------------------------------------------------------------------
   只做别名，不引入新色值：全部指向 style.css :root 里已有的 token。
   这样以后换品牌色，本页跟着一起变。
   ================================================================== */
#download-page {
  --dx-bg: var(--app-bg);
  --dx-panel: var(--surface-solid);
  --dx-panel-2: var(--surface-soft);
  --dx-line: var(--line);
  --dx-line-2: var(--line-strong);
  --dx-ink: var(--ink);
  --dx-ink-2: var(--ink-soft);
  --dx-dim: var(--muted);
  --dx-dim-2: var(--subtle);
  --dx-accent: var(--green);
  --dx-accent-soft: var(--green-soft);
  --dx-cool: var(--blue);
  --dx-mono: 'DM Mono', ui-monospace, SFMono-Regular, Consolas, monospace;
  /* 硬影：偏移 4px、模糊 0，正是像素/终端窗口那种「贴在桌面上」的厚度感。 */
  --dx-hard-shadow: 4px 4px 0 rgba(0, 0, 0, .45);
}

/* ==================================================================
   1. 新增背景光效层（dx-aura）
   ------------------------------------------------------------------
   用户明确要求「在原有背景的基础上继续添加光效」。做法是**新增一个元素**，
   而不是改 body::before / .bgcode / .bgpixels —— 那三层的规则与 DOM 一个
   字节都没有被本文件触碰。

   叠放位置：
   · .dx-aura 是 body 里的普通元素、position: fixed、z-index: -1，
     与 .bgcode 同为负层；同为负层时「后绘制者在上」，而它在 DOM 里排在
     .bgcode 之后，所以压在 3D 代码层之上；
   · body 没有 position 也没有 isolation，不自建层叠上下文，所以 -1 确实
     落进根堆叠上下文的负层：在 canvas 底色之上、所有正常流内容之下。
   · bg-pixels.js 会在运行时把 canvas 追加到 body 末尾，因此像素流星仍
     压在本层之上 —— 这正是期望的顺序（流星是前场气氛，光晕是后场底光）。

   成本：纯 linear/radial-gradient，零动画、零滤镜、零图片、零 JS。
   fixed 定位意味着滚动时不需要重新计算，只是既有一层贴图。
   ================================================================== */
.dx-aura {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    /* 右上角一团绿光：与首屏的版本卡同一侧，把视线拉到「下载」这个动作上 */
    radial-gradient(44% 36% at 82% 4%, var(--bg-code-accent), transparent 72%),
    /* 左侧偏低的冷蓝：平衡绿光，避免整页偏黄绿 */
    radial-gradient(40% 34% at 8% 26%, var(--bg-glow-b), transparent 70%),
    /* 页面底部再垫一层极淡的绿：让长页滚到底时仍有收束感，不出现死黑 */
    radial-gradient(64% 48% at 50% 104%, var(--bg-glow-a), transparent 72%),
    /* 极淡的横向扫描线纹理：3px 周期，只在近看时提供「CRT」的颗粒感。
       与 body::before 的 48px 网格方向不同，两层叠起来才不会互相糊掉 */
    repeating-linear-gradient(to bottom, var(--bg-grid-line) 0 1px, transparent 1px 3px);
  /* 与其余背景层一致的边缘淡出：满屏等强度的光会像一层雾，反而脏。 */
  -webkit-mask-image: radial-gradient(ellipse 108% 92% at 50% 12%, #000 0 42%, transparent 100%);
  mask-image: radial-gradient(ellipse 108% 92% at 50% 12%, #000 0 42%, transparent 100%);
}

/* 用户要求「减少透明/半透明效果」时，本层与其它半透明背景层一起整层移除。
   style.css 已经在同一个查询里关掉了 body::before / .bgcode / .bgpixels，
   这里补上本层，保持口径一致。 */
@media (prefers-reduced-transparency: reduce) {
  .dx-aura { display: none; }
}

/* ==================================================================
   2. 共用零件
   ================================================================== */

/* ---- 2.1 微标签（kicker） ---- */
/* 等宽 + 大写 + 大字距，是「终端标签」的三个识别特征，缺一个就不像。 */
.dx-kicker {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
  color: var(--dx-dim);
  font-family: var(--dx-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .22em;
  text-transform: uppercase;
}

/* 序号方块：实心绿底、深色字，全页唯一的反相元素。
   它把「这一段是第几段」钉在视线里，也让左对齐的标题有一个硬起点。 */
.dx-kicker-idx {
  display: inline-grid;
  place-items: center;
  min-width: 24px;
  height: 18px;
  padding: 0 5px;
  background: var(--dx-accent);
  color: var(--dx-bg);
  font-size: 10.5px;
  letter-spacing: .04em;
}

/* 标签后面的虚线：像终端里补全剩下的提示行，把标签和右侧空间连起来。 */
.dx-kicker-line {
  flex: 1 1 auto;
  height: 1px;
  max-width: 120px;
  background-image: repeating-linear-gradient(
    to right,
    var(--dx-line-2) 0 4px,
    transparent 4px 8px
  );
}

/* ---- 2.2 区块标题 ---- */
.dx-h2 {
  margin: 0;
  color: var(--dx-ink);
  font-size: clamp(22px, 3.1vw, 32px);
  font-weight: 600;
  letter-spacing: -.035em;
  line-height: 1.24;
}

.dx-lead {
  max-width: 640px;
  margin-top: 12px;
  color: var(--dx-dim);
  font-size: 14.5px;
  line-height: 1.74;
}

/* 标题上方的那行导语。带 `.download-hero` 前缀的理由同 3.2 节：
   style.css 有一条 `.download-hero .hero-lead`（0,2,0），比单独的 .dx-lead
   高一档，不加前缀就会被它的 max-width / text-align 压住。 */
.download-hero .dx-lead {
  max-width: 660px;
  margin: 16px 0 0;
  color: var(--dx-dim);
  font-size: 14.5px;
  line-height: 1.74;
  text-wrap: pretty;
}

.dx-accent { color: var(--dx-accent); }

/* ---- 2.3 像素面板 ---- */
/* 一块 2px 实线框 + 对角两枚 L 形角标。只画左上与右下：四角全画会变成
   一个「取景框」，把内容框死得像截图；对角两枚既点出了像素取景的语言，
   又让框线保持通透。
   角标压在边框外沿（-2px），所以这个类**绝不能**和 overflow: hidden 同时用。 */
.dx-panel {
  position: relative;
  border: 2px solid var(--dx-line-2);
  background-color: var(--dx-panel);
  /* 细扫描线肌理：4px 周期、1px 线宽，静态绘制一次，不参与任何动画。 */
  background-image: repeating-linear-gradient(
    to bottom,
    var(--bg-grid-line) 0 1px,
    transparent 1px 4px
  );
}

.dx-panel::before,
.dx-panel::after {
  content: '';
  position: absolute;
  width: 14px;
  height: 14px;
  border: 2px solid var(--dx-accent);
  pointer-events: none;
}
.dx-panel::before {
  top: -2px;
  left: -2px;
  border-right: 0;
  border-bottom: 0;
}
.dx-panel::after {
  right: -2px;
  bottom: -2px;
  border-top: 0;
  border-left: 0;
}

/* ---- 2.4 终端标题栏 ---- */
.dx-term-top {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 13px;
  border-bottom: 2px solid var(--dx-line);
  background: var(--dx-panel-2);
  /* 只为了裁掉下面那条扫光的溢出，不裁内容。 */
  overflow: hidden;
}

/* 三个方形窗口按钮：圆点会立刻把观感拉回普通网页，方点才是像素语言。 */
.dx-chrome { display: inline-flex; gap: 5px; flex: 0 0 auto; }
.dx-chrome i {
  width: 7px;
  height: 7px;
  background: var(--dx-line-2);
}
.dx-chrome i:first-child { background: var(--dx-accent); }

.dx-term-title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  color: var(--dx-dim);
  font-family: var(--dx-mono);
  font-size: 11px;
  letter-spacing: .04em;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dx-term-badge {
  flex: 0 0 auto;
  padding: 1px 7px;
  border: 1px solid var(--dx-accent);
  color: var(--dx-accent);
  font-family: var(--dx-mono);
  font-size: 10px;
  letter-spacing: .14em;
}

/* 方块光标：1.05s、steps(1) 硬切换。真实终端的光标就是「啪」地亮灭，
   渐变淡入淡出会立刻显得像网页。 */
.dx-cursor {
  display: inline-block;
  width: 8px;
  height: 1.02em;
  margin-left: 3px;
  background: var(--dx-accent);
  vertical-align: -.16em;
  animation: dx-blink 1.05s steps(1, end) infinite;
}
.dx-gate .dx-cursor { animation-play-state: paused; }
.dx-gate.is-live .dx-cursor { animation-play-state: running; }

/* ==================================================================
   3. 首屏（dx-hero）
   ================================================================== */
.dx-hero {
  position: relative;
  overflow: hidden;
  padding: clamp(34px, 5vw, 56px) 0 clamp(30px, 4vw, 48px);
  border-bottom: 1px solid var(--dx-line);
}

/* 两栏：左边文案，右边版本卡（构建清单）。窄屏塌成单栏。 */
.dx-hero-grid {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, .92fr);
  gap: clamp(26px, 4vw, 54px);
  align-items: start;
}

/* ---- 3.1 扫描线覆盖层 ---- */
/* 铺在 hero 内部的 CRT 扫描：4px 周期横线 + 一条持续下移的窄亮带。
   它是 hero 这一屏的气氛来源，所以只在这个区块里存在，不铺满全站；
   且被 .dx-gate 门控，hero 滚出视口就停。
   注意这里**没有**用 filter: blur() —— 亮带用渐变做柔边，成本为零。 */
.dx-scan {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background-image: repeating-linear-gradient(
    to bottom,
    rgba(255, 255, 255, .022) 0 1px,
    transparent 1px 4px
  );
  overflow: hidden;
}
.dx-scan::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 26%;
  background: linear-gradient(
    to bottom,
    transparent,
    var(--bg-code-accent),
    transparent
  );
  transform: translate3d(0, -120%, 0);
  animation: dx-scan-run 7.5s linear infinite;
}
.dx-gate .dx-scan::after { animation-play-state: paused; }
.dx-gate.is-live .dx-scan::after { animation-play-state: running; }

/* ---- 3.2 标题：RGB 分离 + 故障闪烁 ---- */
/* 做法说明（也是这次刻意避开的坑）：
   · 不用 filter: blur() / drop-shadow —— 模糊滤镜每帧都要重新栅格化，
     正是「花哨但卡」的典型来源。
   · 改用两份伪元素副本：content 取自 data-dx-text（由 download-fx.js 从
     标题文本同步，语言切换后自动跟上），一份偏红、一份偏蓝，各自用
     clip-path: inset() 只露出一条水平切片，再配 steps 式的抖动位移。
     三色叠加就读作「显示器色差」。
   · 副本只在关键帧的少数几个百分比上出现，其余时间是全透明 ——
     故障感来自「偶发」，而不是一直抖。

   ⚠ 为什么选择器带 `.download-hero` 前缀：style.css 里有一条
   `.download-hero h1 { font-size: clamp(28px, 4.4vw, 44px) }`，特异度
   (0,1,1)，比单类 (0,1,0) 高一档。不加前缀的话本节的字号会被它压住，
   呈现的是旧值而不是这里写的值 —— 这类「明明写了却不生效」最容易在
   日后被误判成缓存问题。同理，下面 .dx-lead 也带上同样的前缀。 */
.download-hero .dx-title {
  position: relative;
  margin: 0;
  color: var(--dx-ink);
  font-size: clamp(30px, 4.6vw, 50px);
  font-weight: 700;
  letter-spacing: -.045em;
  line-height: 1.1;
  text-wrap: balance;
}

/* 副本必须与正文完全重合才有色差效果：同样的 box、同样的字体度量、
   同样的换行宽度。所以它用 absolute + inset: 0 严格铺满标题盒。 */
.dx-title::before,
.dx-title::after {
  content: attr(data-dx-text);
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* 副本文本不可选中，也不进入无障碍树（伪元素本身就不进，这里只是明确意图） */
  opacity: 0;
  clip-path: inset(50% 0 50% 0);
}
.dx-title::before { color: var(--red); }
.dx-title::after { color: var(--dx-cool); }

.dx-gate .dx-title::before { animation-play-state: paused; }
.dx-gate .dx-title::after { animation-play-state: paused; }
.dx-gate.is-live .dx-title::before {
  animation: dx-glitch-a 5.4s steps(1, end) infinite;
  animation-play-state: running;
}
.dx-gate.is-live .dx-title::after {
  animation: dx-glitch-b 5.4s steps(1, end) infinite;
  animation-play-state: running;
}

/* ---- 3.3 徽章与动作 ---- */
.dx-badges {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: 8px;
  margin-top: 20px;
}
/* 徽章退回直角 + 等宽：style.css 给的是 99px 胶囊形，那是首页的柔和语言，
   在这个标题下面会显得格格不入。作用域只在本页。 */
.dx-badges .badge {
  border-radius: 0;
  border-color: var(--dx-line-2);
  background: var(--dx-panel-2);
  font-family: var(--dx-mono);
  font-size: 11px;
  letter-spacing: .04em;
}
.dx-badges .badge-dot { border-radius: 0; }

.dx-hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-top: 24px;
}
/* 按钮同样直角化，并且给主按钮一条 2px 的硬影 —— 唯一的「立体感」来源，
   而且模糊半径为 0，不产生逐帧成本。 */
.dx-hero-actions .button {
  border-radius: 0;
  font-family: var(--dx-mono);
  font-size: 13px;
  letter-spacing: .02em;
}
.dx-hero-actions .button-primary { box-shadow: 3px 3px 0 var(--dx-line-2); }
.dx-hero-actions .button-primary:active { box-shadow: none; transform: translate(3px, 3px); }

/* 首屏底部那行提示：像终端打印完一段命令后的说明。 */
.dx-hero-hint {
  margin-top: 18px;
  color: var(--dx-dim-2);
  font-family: var(--dx-mono);
  font-size: 10.5px;
  letter-spacing: .08em;
  line-height: 1.7;
  text-transform: uppercase;
}

/* ---- 3.4 版本卡 = 构建清单面板 ---- */
/* 用户的原话是「元素及其排版」都要重做。版本卡是这一屏的信息核心，
   把它从「圆角卡片 + 两栏」改成一个带标题栏的终端窗口：
   标题栏说明这份数据从哪来，主体是版本号，底部是三条清单项。
   结构与 class 全部沿用（version-card / version-main / version-value /
   version-label / version-sub / version-meta），只换外观。 */
.version-card {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  margin-top: 0;
  padding: 0;
  border: 2px solid var(--dx-line-2);
  border-radius: 0;
  background: var(--dx-bg);
  background-image: repeating-linear-gradient(
    to bottom,
    var(--bg-grid-line) 0 1px,
    transparent 1px 4px
  );
  box-shadow: var(--dx-hard-shadow);
  overflow: hidden;
}

/* 标题栏底部那条循环扫光：像终端在「等响应」。
   1px 窄条、只动 transform，门控同样生效。 */
.version-card .dx-term-top { position: relative; }
.version-card .dx-term-top::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 34%;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--dx-accent), transparent);
  transform: translate3d(-110%, 0, 0);
  animation: dx-sweep 3.6s linear infinite;
  pointer-events: none;
}
.dx-gate .version-card .dx-term-top::after { animation-play-state: paused; }
.dx-gate.is-live .version-card .dx-term-top::after { animation-play-state: running; }

.version-card .version-main {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: clamp(18px, 2.6vw, 24px);
  border-bottom: 2px solid var(--dx-line);
}

.version-card .version-label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--dx-dim-2);
  font-family: var(--dx-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
}
/* 标签前的一枚方点：告诉眼睛「这里是一行状态」，而不是一个小标题。 */
.version-card .version-label::before {
  content: '';
  width: 6px;
  height: 6px;
  background: var(--dx-accent);
  animation: dx-breathe 2.6s ease-in-out infinite;
}
.dx-gate .version-card .version-label::before { animation-play-state: paused; }
.dx-gate.is-live .version-card .version-label::before { animation-play-state: running; }

.version-card .version-value {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  color: var(--dx-ink);
  font-family: var(--dx-mono);
  font-size: clamp(26px, 3.6vw, 36px);
  font-weight: 500;
  letter-spacing: -.03em;
  line-height: 1.15;
  /* 版本号由 JS 直接写 textContent，宽度会从 — 变成 v0.x.y；
     tabular-nums 让数字等宽，避免写入瞬间整行左右抽动。 */
  font-variant-numeric: tabular-nums;
}

/* #dl-published 是 JS 写 textContent 的徽标，取不到日期时 JS 会加 hidden。
   这里只负责外观；hidden 的兜底规则在页面 head 的内联样式里（保留不动）。 */
#dl-published {
  border-radius: 0;
  border-color: var(--dx-accent);
  background: var(--dx-accent-soft);
  color: var(--dx-accent);
  font-family: var(--dx-mono);
  font-size: 10.5px;
  letter-spacing: .06em;
}

.version-card .version-sub {
  color: var(--dx-dim);
  font-size: 12.5px;
  line-height: 1.68;
}

/* 清单三条：label 在左、value 在右，等宽数字右对齐，像一份构建产物的属性表。 */
.version-card .version-meta {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 0;
  border-left: 0;
}
.version-card .version-meta div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  padding: 9px 16px;
  border-bottom: 1px solid var(--dx-line);
  font-family: var(--dx-mono);
  font-size: 11.5px;
}
.version-card .version-meta div:last-child { border-bottom: 0; }
.version-card .version-meta span {
  color: var(--dx-dim-2);
  letter-spacing: .04em;
}
.version-card .version-meta strong {
  color: var(--dx-ink-2);
  font-family: var(--dx-mono);
  font-size: 11.5px;
  font-weight: 500;
  text-align: right;
}

/* ==================================================================
   4. 计数器条（dx-stats）
   ------------------------------------------------------------------
   三个真实存在于本页的数字：默认端口 11435、安装步骤 4 步、
   支持的安装包格式 3 种（exe / msi / zip，来自 isInstaller 的白名单）。
   刻意不编造「用户数」「下载量」之类无法核实的数据。
   ================================================================== */
.dx-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2px;                       /* 方格阵列的缝，不用圆角卡片 */
  margin-top: clamp(22px, 3vw, 34px);
  border: 2px solid var(--dx-line-2);
  background: var(--dx-line);     /* 缝的颜色透出来 = 像素网格 */
}

.dx-stat {
  position: relative;
  padding: 16px 16px 14px;
  background-color: var(--dx-panel);
  background-image: repeating-linear-gradient(
    to bottom,
    var(--bg-grid-line) 0 1px,
    transparent 1px 4px
  );
  overflow: hidden;
}

/* 背景大号序号：极低透明度的等宽数字，压在内容下面制造刻度纵深。
   用的是背景系统现成的 --bg-grid-line，不引入新色值。 */
.dx-stat::before {
  content: attr(data-dx-no);
  position: absolute;
  right: 6px;
  bottom: -10px;
  color: var(--bg-grid-line);
  font-family: var(--dx-mono);
  font-size: 54px;
  line-height: 1;
  letter-spacing: -.05em;
  pointer-events: none;
}

.dx-stat-val {
  display: flex;
  align-items: baseline;
  gap: 2px;
  color: var(--dx-ink);
  font-family: var(--dx-mono);
  font-variant-numeric: tabular-nums;
  font-size: clamp(26px, 3.2vw, 34px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -.04em;
}

.dx-stat-unit {
  color: var(--dx-accent);
  font-size: .44em;
  letter-spacing: 0;
}

.dx-stat-label {
  display: block;
  margin-top: 9px;
  color: var(--dx-ink-2);
  font-size: 12.5px;
  font-weight: 500;
}

.dx-stat-sub {
  display: block;
  margin-top: 3px;
  color: var(--dx-dim-2);
  font-family: var(--dx-mono);
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
}

/* ==================================================================
   5. 区块骨架（dx-sec）
   ================================================================== */
.dx-sec {
  position: relative;
  padding: clamp(44px, 6vw, 76px) 0;
}
.dx-sec + .dx-sec { border-top: 1px solid var(--dx-line); }

.dx-sec-head {
  max-width: 720px;
  margin-bottom: clamp(22px, 3vw, 32px);
}

/* ==================================================================
   6. 安装包清单（dx-manifest）
   ================================================================== */

/* 走马灯：一条横向流动的等宽标签带，把安装相关的词像日志一样推过去。
   无缝循环 = 轨道里放两份完全相同的内容、整体位移 -50%。
   它是本页唯一「持续性」的视觉噪音，所以压得很窄、很淡。 */
.dx-ticker {
  position: relative;
  overflow: hidden;
  margin-bottom: clamp(18px, 2.4vw, 26px);
  border: 1px solid var(--dx-line);
  background: var(--dx-panel);
  -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
}
.dx-ticker-track {
  display: flex;
  width: max-content;
  animation: dx-marquee 38s linear infinite;
  will-change: transform;
}
.dx-gate .dx-ticker-track { animation-play-state: paused; }
.dx-gate.is-live .dx-ticker-track { animation-play-state: running; }

.dx-tick {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 8px 16px;
  color: var(--dx-dim-2);
  font-family: var(--dx-mono);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
}
.dx-tick-sep { color: var(--dx-line-2); }
.dx-tick.is-hot { color: var(--dx-accent); }

/* 清单头部：标题 + 计数徽标，右侧一条等宽提示。 */
.dx-manifest-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px 20px;
  margin-bottom: 14px;
}
.dx-manifest-head .dx-h2 { display: flex; align-items: center; gap: 10px; }

/* #dl-asset-count 是 JS 写 textContent 的徽标：写成方块计数器，
   数字变化时因为等宽 + 固定内距，不会让标题左右跳。 */
#dl-asset-count {
  display: inline-grid;
  place-items: center;
  min-width: 26px;
  padding: 1px 7px;
  border-radius: 0;
  border-color: var(--dx-accent);
  background: var(--dx-accent-soft);
  color: var(--dx-accent);
  font-family: var(--dx-mono);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  line-height: 1.5;
}

/* 列表容器：JS 会把它清空再逐条 append .asset-row。
   这里只用「首尾各一条虚线」把它框成一个包列表，不改变子节点结构。 */
.asset-list {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 0;
}

/* 单行包裹成终端包条目：
   ::before 是左侧的状态条（绿），::after 是悬停时扫过的一道绿光。
   两个伪元素都不参与布局，因此 JS 构造的子节点结构（.asset-icon /
   .asset-info / .asset-actions）完全不用改。 */
.asset-row {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 14px;
  padding: 14px 16px 14px 20px;
  border: 1px solid var(--dx-line);
  border-left: 2px solid var(--dx-line-2);
  border-radius: 0;
  background: var(--dx-panel);
  background-image: repeating-linear-gradient(
    to bottom,
    var(--bg-grid-line) 0 1px,
    transparent 1px 4px
  );
  overflow: hidden;
  /* 一次性入场：JS 插入行的时间点就是「内容就绪」，从这里开始错峰滑入。
     用 nth-child 给固定的 60ms 阶梯，零 JS、零额外状态。 */
  animation: dx-row-in 460ms var(--ease-out) both;
  transition: border-left-color var(--anim-base) ease, background-color var(--anim-base) ease;
}
.asset-row:nth-child(1) { animation-delay: 0ms; }
.asset-row:nth-child(2) { animation-delay: 60ms; }
.asset-row:nth-child(3) { animation-delay: 120ms; }
.asset-row:nth-child(4) { animation-delay: 180ms; }
.asset-row:nth-child(5) { animation-delay: 240ms; }
.asset-row:nth-child(6) { animation-delay: 300ms; }
.asset-row:nth-child(n+7) { animation-delay: 340ms; }

/* 左侧像素状态点：6px 硬方块，绿色 —— 与终端状态栏的语义一致（可用/就绪）。 */
.asset-row::before {
  content: '';
  position: absolute;
  left: 8px;
  top: 50%;
  width: 5px;
  height: 5px;
  margin-top: -2.5px;
  background: var(--dx-accent);
  opacity: .55;
}

/* 悬停扫光：一条从左侧滑入、从右侧滑出的斜向绿带。
   纯 CSS 过渡，只在 :hover 时发生，不占任何常驻资源。 */
.asset-row::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 40%;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--dx-accent-soft), transparent);
  transform: translate3d(-160%, 0, 0);
  opacity: 0;
  transition: transform 520ms var(--ease-out), opacity 180ms linear;
}
.asset-row:hover::after,
.asset-row:focus-within::after {
  transform: translate3d(320%, 0, 0);
  opacity: 1;
}
.asset-row:hover,
.asset-row:focus-within {
  border-left-color: var(--dx-accent);
  background-color: var(--dx-panel-2);
}

/* 下载图标：从圆角软块改成方形像素块。 */
.asset-icon {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: 1px solid var(--dx-accent);
  border-radius: 0;
  color: var(--dx-accent);
  background: var(--dx-accent-soft);
  flex: 0 0 auto;
}

.asset-info { min-width: 0; }

.asset-name {
  display: block;
  overflow: hidden;
  color: var(--dx-ink);
  font-family: var(--dx-mono);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -.01em;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 大小读数：前面补一个等宽标签「SIZE ·」，让这一行读起来像包管理器的
   属性行，而不是一句说明。标签用纯 CSS content 补，不占 DOM 契约。 */
.asset-meta {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 4px 0 0;
  color: var(--dx-dim-2);
  font-family: var(--dx-mono);
  font-size: 11px;
  letter-spacing: .06em;
}
.asset-meta::before {
  content: 'SIZE';
  color: var(--dx-line-2);
  font-size: 9.5px;
  letter-spacing: .2em;
}

.asset-actions { display: flex; align-items: center; gap: 8px; }

/* JS 用 class="button button-primary button-small" 构造下载按钮。
   这里只把它压成直角 + 等宽，不动尺寸语义（可点区域仍由 .button 保证）。 */
.asset-actions .button {
  border-radius: 0;
  font-family: var(--dx-mono);
  font-size: 12px;
  letter-spacing: .02em;
  min-height: 32px;
}

/* 加载占位 / 失败提示 / noscript 兜底都走 .download-note。
   改成终端告警行的样子：左侧一条黄线 + 等宽字。 */
.download-note {
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  border: 1px solid var(--dx-line);
  border-left: 2px solid var(--yellow);
  border-radius: 0;
  background: var(--dx-panel-2);
  color: var(--dx-dim);
  font-family: var(--dx-mono);
  font-size: 12px;
  line-height: 1.7;
}
.download-note svg { color: var(--yellow); margin-top: 0; }

/* main.js 兜底态与页面内联脚本补的按钮都放在 .error-actions 里。 */
#dl-assets .error-actions {
  justify-content: flex-start;
  margin-top: 12px;
}
#dl-assets .error-actions .button { border-radius: 0; font-family: var(--dx-mono); font-size: 12px; }

/* ==================================================================
   7. 系统要求（dx-specs）—— 规格表 + 从左滑入
   ================================================================== */
/* 把四张卡片压成一张「规格表」：左侧是等宽大写标签，右侧是值，
   行与行只隔一条 1px 线。这样读起来像终端里 `systeminfo` 的输出，
   而不是四张营销卡片。 */
.dx-specs .requirements-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  border: 2px solid var(--dx-line-2);
  background: var(--dx-panel);
}

.dx-specs .requirement {
  display: grid;
  grid-template-columns: minmax(110px, 190px) minmax(0, 1fr);
  align-items: baseline;
  gap: 14px;
  padding: 14px 18px;
  border: 0;
  border-bottom: 1px solid var(--dx-line);
  border-radius: 0;
  background: transparent;
}
.dx-specs .requirement:last-child { border-bottom: 0; }

/* 左侧序号：用 CSS 计数器自动编号，不用改 HTML（也就不会碰 i18n 结构）。
   序号是纯视觉的「行号」，读屏不会读到 —— 所以它必须是背景/伪元素，
   而不是真实文本节点。 */
.dx-specs .requirements-grid { counter-reset: dx-spec; }
.dx-specs .requirement { counter-increment: dx-spec; }
.dx-specs .requirement dt {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--dx-dim-2);
  font-family: var(--dx-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
}
.dx-specs .requirement dt::before {
  content: counter(dx-spec, decimal-leading-zero);
  color: var(--dx-accent);
  letter-spacing: .04em;
}
.dx-specs .requirement dd {
  margin: 0;
  color: var(--dx-ink-2);
  font-family: var(--dx-mono);
  font-size: 12.5px;
  letter-spacing: .01em;
}

/* ---- 从左滑入 ---- */
/* 复用 main.js 已在跑的 [data-reveal] 观察器（零新增开销），只把初始位移
   从「上移 18px」换成「左侧滑入」。style.css 的隐藏态写在
   prefers-reduced-motion: no-preference 里，这里同样包一层，保持口径一致；
   移出视口后 main.js 会摘掉 .is-revealed，滚回来可以重播。 */
@media (prefers-reduced-motion: no-preference) {
  #download-page .dx-from-l[data-reveal] {
    opacity: 0;
    transform: translate3d(-30px, 0, 0);
    transition: opacity var(--anim-slower) var(--ease-out),
                transform var(--anim-slower) var(--ease-out);
    transition-delay: var(--reveal-delay, 0ms);
  }
  #download-page .dx-from-l[data-reveal].is-revealed {
    opacity: 1;
    transform: none;
  }
}

/* ==================================================================
   8. 安装步骤（dx-steps）—— 终端步骤条 + 从右滑入
   ================================================================== */
/* 上一段的规格表是从左滑入，这一段换成从右：整页的入场方向交替，
   滚动到此处时会读作「换了一个方向继续铺」。 */
/* 注意特异度：页面 head 的内联 <style> 里有一条 #dl-steps 的栅格覆盖
   （那是一条 id 选择器）。这里用 #download-page #dl-steps 两个 id 压过去，
   而不是用 !important —— 后者以后会变成调试时看不见的坑。 */
#download-page #dl-steps {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 0;
}

.dx-step {
  position: relative;
  padding: 18px 18px 16px 20px;
  border: 1px solid var(--dx-line);
  border-left: 2px solid var(--dx-line-2);
  border-radius: 0;
  background: var(--dx-panel);
  background-image: repeating-linear-gradient(
    to bottom,
    var(--bg-grid-line) 0 1px,
    transparent 1px 4px
  );
  transition: border-left-color var(--anim-base) ease;
}
.dx-step:hover { border-left-color: var(--dx-accent); }

/* 步骤序号：实心黑底 + 绿框的方块，压在第一行左侧。
   原来的 .step-num 是 26px 圆角方块，这里改成直角并在右侧接一条虚线，
   把「这一步 → 下一步」的流向画出来。 */
.dx-step .step-num {
  display: inline-grid;
  place-items: center;
  width: 26px;
  height: 26px;
  margin-bottom: 12px;
  border: 1px solid var(--dx-accent);
  border-radius: 0;
  background: var(--dx-accent-soft);
  color: var(--dx-accent);
  font-family: var(--dx-mono);
  font-size: 12px;
  font-weight: 500;
}
.dx-step .step-num::after {
  content: '';
  position: absolute;
  left: 46px;
  top: 31px;
  right: 18px;
  height: 1px;
  background-image: repeating-linear-gradient(
    to right,
    var(--dx-line-2) 0 4px,
    transparent 4px 8px
  );
  pointer-events: none;
}

.dx-step h3 {
  font-size: 14.5px;
  letter-spacing: -.02em;
  color: var(--dx-ink);
}
.dx-step p {
  margin-top: 7px;
  color: var(--dx-dim);
  font-size: 13px;
  line-height: 1.68;
}

/* ---- 从右滑入 ---- */
@media (prefers-reduced-motion: no-preference) {
  #download-page .dx-from-r[data-reveal] {
    opacity: 0;
    transform: translate3d(30px, 0, 0);
    transition: opacity var(--anim-slower) var(--ease-out),
                transform var(--anim-slower) var(--ease-out);
    transition-delay: var(--reveal-delay, 0ms);
  }
  #download-page .dx-from-r[data-reveal].is-revealed {
    opacity: 1;
    transform: none;
  }
}

/* ==================================================================
   9. 画圈（dx-ring）—— SVG 描边绘制
   ------------------------------------------------------------------
   用户点名要「画圈」。实现方式是最省的一种：stroke-dasharray 设为周长、
   stroke-dashoffset 从周长过渡到 0，配一条 1100ms 的 CSS 过渡。
   · 不需要 rAF：过渡由合成/重绘驱动，一次性跑完就结束；
   · 不需要计时器：所以也不存在「跑完忘了回收」的问题；
   · 触发点是 download-fx.js 的一次性观察器，命中后加 .is-drawn 并
     立刻 unobserve 自己。
   环心放的是本页真实存在的两个事实：架构 x64、系统 Windows 10/11。
   环本身是装饰（画满一整圈），不承担任何虚构的百分比。
   ================================================================== */
.dx-ring-wrap {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: clamp(18px, 3vw, 34px);
  padding: clamp(20px, 3vw, 30px);
  margin-top: clamp(20px, 2.6vw, 28px);
}

.dx-ring {
  position: relative;
  width: 172px;
  height: 172px;
  flex: 0 0 auto;
}

.dx-ring-svg {
  display: block;
  width: 100%;
  height: 100%;
  /* 从 12 点方向开始画：SVG 的 0° 在 3 点方向，不转这一个直角，
     画圈会从右侧起笔，读起来别扭。 */
  transform: rotate(-90deg);
  overflow: visible;
}

.dx-ring-track {
  fill: none;
  stroke: var(--dx-line-2);
  stroke-width: 2;
}

/* r = 70 → 周长 = 2πr ≈ 439.82。dasharray 写 440 与 HTML 的 viewBox 配好，
   差的那 0.18 肉眼不可见。 */
.dx-ring-draw {
  fill: none;
  stroke: var(--dx-accent);
  stroke-width: 3;
  stroke-linecap: butt;          /* 直角端点 = 像素语言，不用圆头 */
  stroke-dasharray: 440;
  stroke-dashoffset: 440;
  transition: stroke-dashoffset 1150ms var(--ease-out);
}
.dx-ring.is-drawn .dx-ring-draw { stroke-dashoffset: 0; }

/* 失败安全：如果 download-fx.js 没加载 / 解析报错（html 上没有 .dx-js），
   圈永远等不到 .is-drawn，就会留下一段「画不出来」的空环。
   这里给无 JS 场景一个终态：圈直接画满。 */
html:not(.dx-js) .dx-ring-draw { stroke-dashoffset: 0; }

/* 内圈虚线：极慢的自转。它是本页唯一「常驻旋转」的元素，因此尺寸很小
   （r = 54，只有环的 1/3 面积），且被 .dx-gate 严格门控。 */
.dx-ring-spin {
  fill: none;
  stroke: var(--dx-line-2);
  stroke-width: 1;
  stroke-dasharray: 3 7;
  transform-origin: 50% 50%;
  animation: dx-spin 26s linear infinite;
}
.dx-gate .dx-ring-spin { animation-play-state: paused; }
.dx-gate.is-live .dx-ring-spin { animation-play-state: running; }

.dx-ring-center {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  gap: 4px;
  text-align: center;
  pointer-events: none;
}
.dx-ring-big {
  color: var(--dx-ink);
  font-family: var(--dx-mono);
  font-size: 30px;
  font-weight: 500;
  letter-spacing: -.04em;
  line-height: 1;
}
.dx-ring-small {
  color: var(--dx-accent);
  font-family: var(--dx-mono);
  font-size: 10px;
  letter-spacing: .2em;
  text-transform: uppercase;
}

.dx-ring-copy { min-width: 0; }
.dx-ring-copy h3 {
  color: var(--dx-ink);
  font-size: clamp(15px, 1.9vw, 19px);
  letter-spacing: -.025em;
}
.dx-ring-copy p {
  margin-top: 8px;
  color: var(--dx-dim);
  font-size: 13px;
  line-height: 1.72;
}
/* 环下方的三项小标记：端口 / 协议 / 许可，都是本页已有的事实。 */
.dx-ring-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 8px;
  margin-top: 14px;
}
.dx-ring-tag {
  padding: 3px 8px;
  border: 1px solid var(--dx-line);
  color: var(--dx-dim-2);
  font-family: var(--dx-mono);
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
}

/* ==================================================================
   10. 说明区（dx-notes）
   ------------------------------------------------------------------
   对应原来的「关于更新」五行 trust-list。用户点名的动画已经在前四段
   用完，这里刻意**不再**加新方向：每段都换方向会从「节奏」变成「噪音」。
   这一段的处理是「终端日志」：左侧一列方点 + 一条竖线串起五行。
   ================================================================== */
.dx-notes .trust-list {
  display: flex;
  flex-direction: column;
  gap: 0;
  border: 2px solid var(--dx-line-2);
  background: var(--dx-panel);
}

.dx-notes .trust-item {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 13px;
  padding: 16px 18px;
  border: 0;
  border-bottom: 1px solid var(--dx-line);
  border-radius: 0;
  background: transparent;
}
.dx-notes .trust-item:last-child { border-bottom: 0; }

.dx-notes .trust-item .trust-icon {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  flex: 0 0 auto;
  border: 1px solid var(--dx-line-2);
  border-radius: 0;
  color: var(--dx-accent);
  background: var(--dx-panel-2);
}

.dx-notes .trust-item h3 {
  color: var(--dx-ink);
  font-family: var(--dx-mono);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: .01em;
}
.dx-notes .trust-item p {
  margin-top: 6px;
  color: var(--dx-dim);
  font-size: 13px;
  line-height: 1.7;
}

/* ==================================================================
   11. 收尾（dx-cta）
   ================================================================== */
.dx-cta { padding: clamp(48px, 6.4vw, 84px) 0 clamp(56px, 7vw, 96px); }

.dx-cta-frame {
  padding: clamp(28px, 4.6vw, 52px) clamp(20px, 4vw, 46px);
  text-align: center;
  /* 一层极淡的绿光托底，取背景系统现成的 --bg-glow-a，
     保证新组件的光和背景层是同一个色温。 */
  background-image:
    radial-gradient(120% 130% at 50% 0%, var(--bg-glow-a), transparent 64%),
    repeating-linear-gradient(to bottom, var(--bg-grid-line) 0 1px, transparent 1px 4px);
}

.dx-cta .dx-kicker { justify-content: center; }

.dx-cta-h {
  color: var(--dx-ink);
  font-size: clamp(24px, 3.8vw, 40px);
  font-weight: 600;
  letter-spacing: -.04em;
  line-height: 1.2;
  text-wrap: balance;
}

.dx-cta-lead {
  max-width: 560px;
  margin: 14px auto 0;
  color: var(--dx-dim);
  font-size: 14px;
  line-height: 1.72;
}

.dx-cta-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-top: 26px;
}
.dx-cta-actions .button {
  border-radius: 0;
  min-height: 44px;
  font-family: var(--dx-mono);
  font-size: 13px;
  letter-spacing: .02em;
}

/* 终端提示行：收尾处再敲一次「命令」，把整页语言收口。 */
.dx-cta-prompt {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  margin-top: 26px;
  padding: 9px 14px;
  border: 1px solid var(--dx-line);
  background: var(--dx-bg);
  color: var(--dx-ink-2);
  font-family: var(--dx-mono);
  font-size: 11.5px;
  letter-spacing: .02em;
  text-align: left;
}
.dx-cta-prompt .dx-prompt-sign { color: var(--dx-accent); margin-right: 6px; }

/* ==================================================================
   12. 关键帧
   ================================================================== */

/* 光标硬切换：0–49% 亮、50–100% 灭。steps(1) 保证没有中间过渡。 */
@keyframes dx-blink {
  0%, 49%   { opacity: 1; }
  50%, 100% { opacity: 0; }
}

/* 状态点呼吸：用 opacity 而不是 scale —— 5px 的方块缩放看不出变化，
   只会让边缘抖。 */
@keyframes dx-breathe {
  0%, 100% { opacity: .35; }
  50%      { opacity: 1; }
}

/* 扫描线：一条窄亮带自上而下扫过 hero。
   translate3d 走合成器；百分比相对的是 ::after 自己的高度（26% 的 hero），
   所以 -120% → 460% 恰好把亮带从框外扫到框外。 */
@keyframes dx-scan-run {
  from { transform: translate3d(0, -120%, 0); }
  to   { transform: translate3d(0, 460%, 0); }
}

/* 标题栏扫光：从完全左侧之外滑到完全右侧之外。 */
@keyframes dx-sweep {
  from { transform: translate3d(-110%, 0, 0); }
  to   { transform: translate3d(330%, 0, 0); }
}

/* 走马灯：轨道含两份内容，-50% 恰好等于一份的宽度，接缝不可见。 */
@keyframes dx-marquee {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* 内圈缓转。26s 一圈，慢到不抢戏，又足以让页面「活着」。 */
@keyframes dx-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* 资产行入场：只动 opacity + transform。 */
@keyframes dx-row-in {
  from { opacity: 0; transform: translate3d(-12px, 0, 0); }
  to   { opacity: 1; transform: none; }
}

/* 故障闪烁 A（红通道）。
   steps(1, end) 让每个关键帧之间没有插值 —— 故障是「跳变」，不是「滑动」。
   时间轴上 0–62% 完全静止（透明），62–86% 里做 4 次短促的切片抖动，
   然后回到静止。整个周期 5.4s，也就是平均每秒只抖 0.4 次左右：
   足够让人注意到「这行字有点不对」，又不会变成持续噪声。 */
@keyframes dx-glitch-a {
  0%, 62%, 86%, 100% {
    opacity: 0;
    clip-path: inset(50% 0 50% 0);
    transform: translate3d(0, 0, 0);
  }
  63% {
    opacity: .85;
    clip-path: inset(8% 0 72% 0);
    transform: translate3d(-3px, 0, 0);
  }
  66% {
    opacity: .7;
    clip-path: inset(56% 0 24% 0);
    transform: translate3d(3px, 0, 0);
  }
  69% {
    opacity: .9;
    clip-path: inset(30% 0 52% 0);
    transform: translate3d(-2px, 0, 0);
  }
  72% {
    opacity: 0;
    clip-path: inset(50% 0 50% 0);
  }
  79% {
    opacity: .8;
    clip-path: inset(70% 0 12% 0);
    transform: translate3d(2px, 0, 0);
  }
  82% {
    opacity: .6;
    clip-path: inset(20% 0 62% 0);
    transform: translate3d(-1px, 0, 0);
  }
}

/* 故障闪烁 B（蓝通道）。与 A 用同一周期但错开 2 个百分比，
   两个通道不同步，才会出现「红蓝分离」的错觉；完全同步就只是重影。 */
@keyframes dx-glitch-b {
  0%, 60%, 88%, 100% {
    opacity: 0;
    clip-path: inset(50% 0 50% 0);
    transform: translate3d(0, 0, 0);
  }
  61% {
    opacity: .8;
    clip-path: inset(64% 0 18% 0);
    transform: translate3d(3px, 0, 0);
  }
  65% {
    opacity: .65;
    clip-path: inset(12% 0 66% 0);
    transform: translate3d(-3px, 0, 0);
  }
  68% {
    opacity: .85;
    clip-path: inset(44% 0 38% 0);
    transform: translate3d(2px, 0, 0);
  }
  71% {
    opacity: 0;
    clip-path: inset(50% 0 50% 0);
  }
  80% {
    opacity: .75;
    clip-path: inset(26% 0 56% 0);
    transform: translate3d(-2px, 0, 0);
  }
  84% {
    opacity: .5;
    clip-path: inset(78% 0 6% 0);
    transform: translate3d(1px, 0, 0);
  }
}

/* ==================================================================
   13. 响应式
   ================================================================== */
@media (max-width: 1040px) {
  .dx-hero-grid { grid-template-columns: minmax(0, 1fr); }
  .version-card { margin-top: 6px; }
}

@media (max-width: 860px) {
  .dx-stats { grid-template-columns: 1fr; }
  .dx-ring-wrap { grid-template-columns: 1fr; justify-items: center; text-align: center; }
  .dx-ring-copy h3, .dx-ring-copy p { text-align: center; }
  .dx-ring-tags { justify-content: center; }
  #download-page #dl-steps { grid-template-columns: 1fr; }
}

@media (max-width: 720px) {
  .dx-scan { display: none; }
  .dx-specs .requirement { grid-template-columns: 1fr; gap: 6px; }
  .dx-step .step-num::after { display: none; }
  .dx-tick { font-size: 10px; padding: 7px 12px; }
  .asset-row { grid-template-columns: auto minmax(0, 1fr); }
  .asset-actions { grid-column: 1 / -1; }
  .asset-actions .button { width: 100%; }
  .version-card .version-meta div { flex-direction: column; gap: 2px; }
  .version-card .version-meta strong { text-align: left; }
  .dx-cta-actions .button { width: 100%; }
}

@media (max-width: 420px) {
  .download-hero .dx-title { font-size: 27px; }
  .dx-ring { width: 148px; height: 148px; }
  .dx-stat::before { font-size: 44px; }
}

/* ==================================================================
   14. 动效降级（prefers-reduced-motion: reduce）
   ------------------------------------------------------------------
   口径与 style.css / home.css 一致：**显式给出终态**，而不是把时长压到
   0.01ms。隐式兜底会让一次性动画「跳一帧然后定格」，观感反而像故障。
   这里逐项给出终点：
   · 故障副本 -> 永久透明（标题恢复成一行干净的字）；
   · 扫描带 / 走马灯 / 光标 / 呼吸点 / 环内旋转 -> animation: none；
   · 环形 -> 直接画满（stroke-dashoffset: 0），不保留绘制过程；
   · 从左/右滑入的初始位移 -> 归零（内容从一开始就在位置上）。
   注：style.css 里那条通配的 animation-duration: .01ms 仍会作用于本页，
   所以这里必须显式写 animation: none 才能在观感上真正「不闪」。
   ================================================================== */
@media (prefers-reduced-motion: reduce) {
  .dx-title::before,
  .dx-title::after { animation: none !important; opacity: 0 !important; clip-path: inset(50% 0 50% 0) !important; }

  .dx-scan::after,
  .version-card .dx-term-top::after,
  .dx-ticker-track,
  .dx-cursor,
  .version-card .version-label::before,
  .dx-ring-spin,
  .asset-row { animation: none !important; }

  .dx-ring-draw { transition: none !important; stroke-dashoffset: 0 !important; }

  #download-page .dx-from-l[data-reveal],
  #download-page .dx-from-r[data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }

  /* 悬停扫光也一并关掉：减少动效的人同样不希望指针划过时有东西飞过。 */
  .asset-row::after { display: none !important; }
}

/* ==================================================================
   15. 打印
   ------------------------------------------------------------------
   本页新组件里有大量「屏幕专属」的东西：扫描线、走马灯、光标、故障副本、
   硬影、环形旋转。纸上它们没有意义，只会吃墨、灰度打印时糊成脏灰。
   ================================================================== */
@media print {
  .dx-aura,
  .dx-scan,
  .dx-ticker,
  .dx-cursor,
  .dx-title::before,
  .dx-title::after,
  .dx-ring-spin,
  .dx-cta-prompt { display: none !important; }

  /* 面板退回白底黑字；边框保留（规格表在纸上要靠框线读）。 */
  .dx-panel,
  .version-card,
  .dx-stat,
  .dx-step,
  .dx-cta-frame,
  .dx-specs .requirements-grid,
  .dx-notes .trust-list,
  .asset-row,
  .download-note {
    background: #fff !important;
    background-image: none !important;
    border-color: #000 !important;
    box-shadow: none !important;
  }
  .dx-panel::before,
  .dx-panel::after,
  .asset-row::before,
  .asset-row::after { display: none !important; }

  .dx-title,
  .dx-h2,
  .dx-lead,
  .dx-cta-h,
  .dx-cta-lead,
  .version-card .version-value,
  .version-card .version-sub,
  .asset-name,
  .asset-meta,
  .dx-step h3,
  .dx-step p,
  .dx-notes .trust-item h3,
  .dx-notes .trust-item p { color: #000 !important; }

  /* 环形在纸上是「已经画完」的状态；动画一律不参与分页输出。 */
  .dx-ring-draw { stroke-dashoffset: 0 !important; stroke: #000 !important; }
  .dx-ring-track { stroke: #000 !important; }

  .dx-sec { padding: 16px 0; break-inside: avoid; }
  .dx-stat { break-inside: avoid; }
  .dx-hero { padding: 12px 0; }
}
