/* ==========================================================================
   BoardRaid — 下载站样式
   --------------------------------------------------------------------------
   设计取向（改之前先读，否则很容易把这几条取舍破坏掉）：

   1. **克制的深色极简 + 像素美学**。中性近黑底（不用蓝黑色），单一强调色（品牌金），
      靠留白与字重拉层级，而不是靠阴影与彩色块。参考的同类站点（MCSRRanked / Draftout）
      都是这个路子：暗底 + 像素化标识 + 极少的装饰。
   2. **不用位图装饰 —— 只有一处破例**。品牌标记是 SVG，卡板的格子/斜角/金色态
      都是 HTML/CSS 画的；但格子里那个**图标是游戏里的 16x16 纹理本身**
      （`assets/tasks/`，见下面"卡板示意图"一节）。这是有意的：物品图标用 CSS
      重画既做不到、也不诚实（画出来一眼假）。其余装饰仍然零位图。
   3. **零依赖、零构建**。一个 CSS + 一个 JS，丢到任意静态托管即可。
   4. 数字一律等宽（.mono / .stat__value）：版本号、大小、人数对齐后更专业，也更好比对。
   ========================================================================== */

:root {
  /* 中性深灰阶（偏 zinc，不是蓝黑） */
  --bg:        #131316;
  --bg-alt:    #17171a;
  --panel:     #1c1c20;
  --panel-2:   #202024;
  --line:      rgba(255, 255, 255, 0.07);
  --line-2:    rgba(255, 255, 255, 0.14);

  --text:      #a1a1aa;
  --title:     #f4f4f5;
  --dim:       #71717a;

  /* 品牌金：与游戏内 UI、以及品牌标记同一套色 */
  --gold:      #ffd866;
  --gold-2:    #e4b445;
  --gold-dim:  rgba(255, 216, 102, 0.14);

  --radius:    12px;
  --wrap:      1120px;
  --topbar-h:  50px;          /* 首屏高度要用它算：hero 占满"顶栏以下的整屏"，分界线才落在屏幕最底 */
  --mono:      ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

/* scroll-padding-top：顶栏是 sticky 的，锚点跳过去时标题会正好被压在它底下 ——
   少了这一条，「了解更多」跳完看不见小节标题，只看见一段正文的中间。
   （有 JS 时锚点滚动由 motion.js 接管，它自己算这个偏移。） */
html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--topbar-h) + 16px);
  /* 滚动条也按站点配色走：系统默认那条亮灰在暗底上很扎眼，
     而它偏偏一直停在视线右边。不支持这两个属性的浏览器保持原样。 */
  scrollbar-color: #33333a var(--bg);
  scrollbar-width: thin;
}

::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb {
  background: #2e2e35;
  border: 3px solid var(--bg);
  border-radius: 999px;
}
::-webkit-scrollbar-thumb:hover { background: var(--gold-2); }

/* 选中文字用品牌金：暗底上默认那条蓝选中框与本站的单一强调色打架 */
::selection { background: var(--gold); color: #1a1405; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.7 -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, "Microsoft YaHei",
        "PingFang SC", "Hiragino Sans GB", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
}

code {
  font-family: var(--mono);
  font-size: 0.88em;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 1px 6px;
  white-space: nowrap;
  color: var(--title);
}

/* 链接的颜色变化也给一点过渡：整站其它可点的东西都是渐变过来的，
   只有文字链接"啪"地变色的话，会显得这一类元素没做完。 */
a { color: var(--gold); text-decoration: none; transition: color 160ms ease; }
a:hover { text-decoration: underline; }

:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
  border-radius: 4px;
}

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }
.muted { color: var(--dim); }

/* 小标签：全大写 + 加宽字距，用来标小节名 */
.eyebrow {
  margin: 0 0 14px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold);
}

/* 下载页的眉标大一档：那一页靠「启动器 / 路线 A / 路线 B」分区，
   眉标在那儿承担的就是小标题，12px 显得太轻（来自反馈）。
   只在下载页放大 —— 主页那几段的眉标是"分类标签"，跟着放大会抢标题的层级。 */
body[data-page="download"] .eyebrow { font-size: 15px; }

/* ============================ 顶栏 ============================ */

/* 顶栏做得**细**（参考站都在 40~50px 之间）：它是导航，不是内容的一部分，
   占的高度越少，首屏给字标与下载按钮的空间越多。 */
.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(19, 19, 22, 0.88);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
  /* 贴顶态（滚起来之后加深底色 + 落一点阴影）要渐变过来，
     否则跨过那 6px 阈值的一瞬间顶栏会硬切一下 */
  transition: background 220ms ease, border-color 220ms ease, box-shadow 220ms ease;
}

/* 【顶栏通栏，不受 --wrap 约束】品牌标记要贴在"屏幕"左上角，而不是内容栏的左上角 ——
   否则宽屏下它会跟着内容一起缩进，看着像整条顶栏缩在中间。
   用 grid 三列（1fr auto 1fr）而不是 flex：导航是"整条顶栏居中"，
   而不是"剩余空间居中" —— 后者在品牌长短变化时会左右漂移。 */
.topbar__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 14px;
  height: var(--topbar-h);
  max-width: none;
  padding: 0 22px;
}

.brand {
  justify-self: start;
  display: flex;
  align-items: center;
  gap: 9px;
  color: var(--title);
}
.brand:hover { text-decoration: none; }

/* 像素标记：放大时保持硬边（换成 PNG 像素图时这一条很重要） */
.brand__mark {
  display: block;
  border-radius: 6px;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}

.brand__name {
  font-weight: 700;
  font-size: 14px;
  letter-spacing: 0.08em;
}

.nav {
  justify-self: center;
  display: flex;
  gap: 26px;
  font-size: 14px;
}
/* 右栏的按钮必须靠右收住：grid 子项默认 justify-self: stretch，
   不写这条它会被拉成和右栏（1fr）同宽的一条横杠。 */
.topbar__inner > .btn { justify-self: end; }
.nav a {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--dim);
}
.nav a:hover { color: var(--title); text-decoration: none; }

/* 导航底下那条 2px 金线：悬停时从中间展开，当前页常驻。
   用 transform 而不是 width/border —— 前者不触发布局，快速划过导航时不会掉帧。
   "我在哪一页"原来完全没有标记（三个页面的导航标记一模一样），
   当前页由 motion.js 按地址判定后加 .is-current（见那里的注释）。 */
.nav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -7px;
  height: 2px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: 50% 50%;
  transition: transform 240ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.nav a:hover::after { transform: scaleX(1); }
.nav a.is-current { color: var(--title); }
.nav a.is-current::after { transform: scaleX(1); }

/* 线性图标统一风格：1.5px 描边、圆角端点。全站不用图标字体（少一个请求、也不会有缺字形方块） */
.ic {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.ic rect { fill: currentColor; stroke: none; }

/* 窄窗口：只砍导航，品牌与下载按钮永远留着 */
@media (max-width: 760px) {
  .nav { display: none; }
}

/* ============================ 按钮 ============================ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 11px 20px;
  border: 1px solid transparent;
  border-radius: 10px;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.14s ease, border-color 0.14s ease, transform 0.14s ease;
}
.btn:hover { text-decoration: none; transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn--primary {
  background: var(--gold);
  color: #1a1405;
}
.btn--primary:hover { background: #ffe089; }

/* 次级按钮：细描边 + 半透明底。参考站的两个按钮就是这个关系 —— 一个亮的实心、一个描边 */
.btn--outline {
  background: rgba(255, 255, 255, 0.03);
  border-color: var(--line-2);
  color: var(--title);
}
.btn--outline:hover {
  border-color: rgba(255, 255, 255, 0.34);
  background: rgba(255, 255, 255, 0.06);
}

/* 全大写 + 加宽字距：并排两个按钮时的"电竞感"主要来自这一条。
   中文不受 uppercase 影响，但字距照样生效，所以中英混排也不会失衡。 */
.btn--up { text-transform: uppercase; letter-spacing: 0.1em; font-size: 13px; }
.btn--wide { min-width: 168px; }

.btn--lg { padding: 15px 28px; font-size: 16px; }
.btn--sm { padding: 7px 13px; font-size: 13px; }
.btn--tiny {
  padding: 4px 10px;
  font-size: 12px;
  background: transparent;
  border-color: var(--line-2);
  color: var(--text);
}

.btn__meta { font-weight: 500; opacity: 0.7; font-size: 12px; font-family: var(--mono); }

/* ============================ 首屏 ============================ */

/* 满屏首屏：内容居中，只有"标签 → 字标 → 副标题 → 按钮"四层。
   这是参考站（Draftout / MCSR Ranked）的共同结构 —— 首屏不解释产品，
   只回答两件事：这是什么（字标）、我该点哪里（下载）。 */
.hero {
  position: relative;
  /* 占满"顶栏以下的整屏"：这样那条分界线正好落在首屏最底部，往下滚才是内容 ——
     参考站都是这个做法，"庞大感"很大一部分来自首屏不留半截内容。 */
  min-height: calc(100vh - var(--topbar-h));
  display: grid;
  place-items: center;
  overflow: hidden;
  text-align: center;
  border-bottom: 1px solid var(--line);
}

/* 首屏背景：一张 Minecraft 风格的沙漠羊驼（游戏内的"沙漠骆驼"就是它），模糊后当氛围底。
   三层叠加，顺序不能反：照片 → 压暗遮罩 → 内容。

   【为什么必须先降亮度、再模糊，而不是只压遮罩】原图是明亮的黄昏；只叠一层半透明黑
   会得到"灰蒙蒙的亮"，白字照样读不清，而模糊半径里的高光还会透出来形成光斑。
   先 brightness(0.46) 把动态范围压下去，再 blur，画面才是干净的暗底。 */
.hero__photo {
  position: absolute;
  inset: 0;
  background-image: url("brand/hero.jpg");
  background-size: cover;
  background-position: 62% 42%;   /* 把羊驼从正中挪开，别正好顶在字标后面 */
  filter: blur(11px) brightness(0.46) saturate(0.9);
  transform: scale(1.1);          /* 放大一圈，免得模糊后四边露出透明边 */
}

.hero__veil {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(880px 460px at 50% 24%, rgba(255, 216, 102, 0.12), transparent 62%),
    linear-gradient(180deg, rgba(19, 19, 22, 0.5) 0%, rgba(19, 19, 22, 0.72) 52%, var(--bg) 100%);
}

/* 首屏内容不吃 --wrap 的 1120px 上限：字标要按视口宽度算（≥ 屏宽 2/3），
   被内容栏卡住的话在宽屏上就永远达不到那个比例 */
.hero__inner {
  position: relative;
  max-width: none;
  padding-top: 26px;
  padding-bottom: 26px;
}

/* 小方框标签：参考站都用一个细框小字把"现在是什么状态"放在最上面 */
.labelbox {
  display: inline-block;
  margin: 0 0 34px;
  padding: 8px 18px;
  border: 1px solid var(--line-2);
  border-radius: 4px;
  font-size: clamp(13px, 1.05vw, 17px);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text);
}
/* 分区标题用的同款标签，但去掉框：整页框太多会吵 */
.labelbox--plain {
  display: block;
  margin: 0 0 14px;
  padding: 0;
  border: 0;
  color: var(--gold);
}

/* 字标：像素标记 + 像素字。整体是 h1（alt 里带 BoardRaid，无障碍与 SEO 都对）。

   【尺寸按视口走，且要占到屏宽的 2/3 以上】首屏的全部分量都压在这一行上，
   所以宽度用 vw 而不是固定 px：窄屏缩、宽屏涨。上限 1320px 是为了不让超宽屏
   出现"一行字撑破整屏"的滑稽感。 */
.wordmark {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 30px;
  margin: 0;
}
.wordmark__mark,
.wordmark__text {
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}
.wordmark__mark { width: clamp(84px, 8.6vw, 172px); height: auto; }
.wordmark__text { width: min(66vw, 1320px); height: auto; }

/* 中文名：放大到与字标同一量级（字标像素大写高度约等于它宽度的 13%），
   两行叠起来才是完整的品牌锁形，而不是"大字 + 小注" */
.wordmark__cn {
  margin: 22px 0 0;
  font-size: clamp(38px, 5.6vw, 112px);
  font-weight: 700;
  letter-spacing: 0.22em;
  text-indent: 0.22em;
  color: var(--text);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 16px;
  margin-top: 44px;
}
/* 首屏的主按钮要撑起首屏的分量：用两条类的选择器压过 .btn--up 的字号 */
.hero__actions .btn {
  padding: 18px 44px;
  font-size: clamp(17px, 1.4vw, 24px);
}

/* 滚动提示（参考站都有）：一个字的成本换来"下面还有内容"的暗示 */
.scrollhint {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  margin-top: 60px;
  font-size: clamp(14px, 1.1vw, 19px);
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--dim);
}
.scrollhint:hover { color: var(--title); text-decoration: none; }
.scrollhint__chev { width: 1.5em; height: 1.5em; }

/* 那个箭头轻轻上下点两下：它是首屏唯一在暗示"下面还有东西"的元素，
   幅度必须小（3px）、周期必须慢（1.9s）—— 参考站里这类提示做大了就成了干扰。
   纯 CSS，不需要 JS；开了"减少动效"就不播（见文件末尾那个块）。 */
@media (prefers-reduced-motion: no-preference) {
  .scrollhint__chev { animation: br-bob 1.9s ease-in-out infinite; }
}
@keyframes br-bob {
  0%, 100% { transform: translateY(-1px); }
  50%      { transform: translateY(2px); }
}


/* ============================ 卡板示意图 ============================ */

/*
  形态照抄游戏内的卡槽：方形格、内凹斜角（光从左上来 —— 左上压暗、右下提亮）、
  图标在上、名字在下；名字最多两行，与游戏里一致（长名字在游戏里也是折两行）。

  **全站唯一用位图的地方**，见文件头第 2 条：图标就是游戏里的 16x16 纹理本身
  （assets/tasks/）。尺寸收在 560px —— 方形格子铺满整屏会大得离谱。
*/

.boardcard {
  max-width: 560px;
  margin: 30px auto 0;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35);
}

.boardcard__bar {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 11px 14px;
  background: var(--panel-2);
  border-bottom: 1px solid var(--line);
  font-size: 12px;
  color: var(--dim);
}
.dot { width: 8px; height: 8px; border-radius: 50%; background: #33333a; }
.boardcard__title { margin-left: 8px; letter-spacing: 0.08em; }
.boardcard__count {
  margin-left: auto;
  font-family: var(--mono);
  color: var(--gold);
}

.board {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 5px;
  padding: 10px;
}

.cell {
  --art: 32px;                /* 图标边长；角标与数字都按它算，改一处就整体缩放 */
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  aspect-ratio: 1 / 1;        /* 方形 —— 游戏里的槽位是方的，扁格子一眼不像 */
  padding: 5px 4px;
  background: #1a1a1e;
  border: 1px solid #2a2a31;
  border-radius: 4px;
  box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.5),
              inset -1px -1px 0 rgba(255, 255, 255, 0.045);
  text-align: center;
  overflow: hidden;
  transition: background 200ms ease, border-color 200ms ease, transform 200ms ease;
}

/* 图标位：角标与数字都相对**它**定位 —— 相对整格定位的话，下面名字占的那行
   会把角标推到格子外面去（这是照着游戏截图做时最容易错的一处）。 */
.cell__art {
  position: relative;
  width: var(--art);
  height: var(--art);
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
}

.cell__icon {
  width: var(--art);
  height: var(--art);
  /* 16x16 放大到 32px：必须关掉插值，否则像素糊成一团（像素风的关键一条） */
  image-rendering: pixelated;
}

/* 【没有图标的任务】这些格子没有图标，是**图确实找不到**，共 10 条
   （生成器每次都会把它们列出来）：
     · 床 / 箱子 / 旗帜 / 头颅 / 龙首：在游戏里是 **3D 模型渲染**的，
       从来没有平面贴图 —— 谁都拿不出图来；
     · 测重压力板：那张贴图本来有，是 loom 缓存里那份客户端 jar 不全
       （翻遍它，一张 pressure_plate 都没有）。
   这不是"图没加载出来"，所以**不该画成破图的样子**。

   做法：拿掉虚线框（挖个空洞看着就像坏了 —— 实测截图反馈），
   但保留 32px 的图示位、只是变透明 —— 名字才与别的格子对齐，
   击杀/数量角标也还落在原处。 */
.cell.is-noicon .cell__art {
  background: none;
  border: 0;
}
.cell.is-noicon .cell__name { color: var(--text); }   /* 比别的格子亮一档，免得像"禁用" */

/* 角标：与游戏内一致 —— 击杀=左上角钻石剑、死亡=左上角骷髅头、繁殖=右上角爱心 */
.cell__badge {
  position: absolute;
  top: -2px;
  left: -2px;
  font-size: 11px;
  line-height: 1;
  color: #d4d4d8;             /* 骷髅头字符：浅灰，与游戏里那枚骨头色接近 */
}
.cell__badge img { display: block; width: 13px; height: 13px; image-rendering: pixelated; }
.cell__heart {
  position: absolute;
  top: -2px;
  right: -2px;
  font-size: 11px;
  line-height: 1;
  color: #ff5555;             /* 与游戏内一致：红心 */
}

/* 数量角标：右下角的白字（游戏里也是白字带阴影） */
.cell__count {
  position: absolute;
  right: -2px;
  bottom: -3px;
  font-family: var(--mono);
  font-size: 10px;
  line-height: 1;
  color: #fff;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.85);
}

.cell__name {
  font-size: 10.5px;
  line-height: 1.25;
  color: var(--dim);
  /* 最多两行（与游戏一致）；名字在 HTML 里是完整的，只是显示不下就裁掉 */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* 已完成：金色底 + 左上角一个小方块（与品牌标记的"像素格"呼应，不用图标字体） */
.cell.is-done {
  background: var(--gold-dim);
  border-color: rgba(255, 216, 102, 0.32);
}
.cell.is-done .cell__name { color: var(--gold); }
.cell.is-done::after {
  content: "";
  position: absolute;
  left: 3px;
  top: 3px;
  width: 3px;
  height: 3px;
  background: var(--gold);
}

/* 当前目标：只提亮描边。刻意不做"持续闪烁"——
   那种动效在截图里好看，真盯着看一分钟就只剩烦。 */
.cell.is-next {
  border-color: rgba(255, 255, 255, 0.42);
}
.cell.is-next .cell__name { color: var(--title); }

/* 轮换与完成时的动效。整块包在 no-preference 里：系统里开了"减少动效"就一帧都不播
   （页尾脚本也会因此不启动定时器，卡板停在 HTML 里那份静态内容上）。 */
@media (prefers-reduced-motion: no-preference) {
  .cell.is-swap .cell__icon,
  .cell.is-swap .cell__name {
    animation: cell-in 320ms ease both;
  }
  .cell.is-done {
    animation: cell-done 420ms ease;
  }
  @keyframes cell-in {
    from { opacity: 0; transform: translateY(4px) scale(0.9); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes cell-done {
    0%   { transform: scale(1); }
    45%  { transform: scale(1.05); }
    100% { transform: scale(1); }
  }
}

@media (max-width: 420px) {
  .cell { gap: 3px; padding: 3px; }
  .cell__icon { width: 22px; height: 22px; }
  .cell__name { font-size: 9px; }
}

/* ============================ 分区 ============================ */

.section { padding: 76px 0; border-bottom: 1px solid var(--line); }
.section--alt { background: var(--bg-alt); }

.section__title {
  margin: 0 0 12px;
  font-size: 28px;
  letter-spacing: -0.01em;
  color: var(--title);
}
.section__lead { margin: 0 0 30px; color: var(--dim); }

/* ============================ 宣言段（模组简介） ============================ */

/* 居中的一整段话，关键词用强调色 —— 参考站首屏下面那一块就是这个形态。
   它承担"这是什么、为什么值得玩"，所以字号明显大于正文（clamp 跟着视口走），
   但也不能做成大标题：目标是让读者**读进去**，不是扫一眼。 */
.statement-band {
  padding: 92px 0;
  border-bottom: 1px solid var(--line);
}
.statement {
  margin: 0 auto;
  max-width: 1020px;
  font-size: clamp(19px, 1.7vw, 28px);
  line-height: 1.6;
  color: var(--text);
}
.statement b { color: var(--title); }
.statement em { font-style: normal; font-weight: 600; color: var(--gold); }

/* ============================ 双栏特性区 ============================ */

/* 左右各一栏：文字 + 一张"游戏内 UI 假图"。窄屏自动堆叠（文字在上）。
   两栏的行数天生不等，所以用 align-items:center 让视觉那一栏与文字块垂直居中。 */
.feature-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 40px;
  align-items: center;
}
@media (min-width: 900px) {
  .feature-row { grid-template-columns: 1fr 1fr; gap: 68px; }
}

.feature-title {
  margin: 0 0 14px;
  font-size: clamp(26px, 2.6vw, 40px);
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--title);
}
.feature-sub {
  margin: 0 0 24px;
  font-size: 17px;
  line-height: 1.65;
  color: var(--dim);
}

/* 项目符号列表：小方块而不是圆点，与像素标记同一套语言 */
.bullets {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 13px;
}
.bullets li {
  position: relative;
  padding-left: 20px;
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--text);
}
.bullets li::before {
  content: "";
  position: absolute;
  left: 1px;
  top: 0.62em;
  width: 5px;
  height: 5px;
  background: var(--gold);
}

/* 镜像行：视觉在左、文字在右（参考站就是一行一换边，避免整页节奏一样平） */
@media (min-width: 900px) {
  .feature-row--flip .feature-copy { order: 2; }
}

.feature-visual { min-width: 0; }
/* 卡板在双栏里要占满自己那一栏，不能再沿用"居中限宽 620" */
.feature-visual .boardcard { max-width: none; margin: 0; }

/* ============================ 游戏内 UI 假图（房间设置） ============================ */

/* 「自定义模式」那块是**CSS 画的游戏内界面**（房间设置面板），不是截图：
   参考站在这个位置放的是实机截图，我们没有可直接使用的素材，
   而画出来反而更准 —— 每个选项名、每句说明都与游戏里逐字一致，
   配色与行距也照 CustomRoomSettingsScreen 来（见 index.html 那段的注释）。

   **底色是平底，不铺照片**：游戏里这个界面后面是模糊的世界，但搬到站点上，
   一张照片底会把这块从其它卡片里摘出去（卡板 / 段位 / 下载卡全是平底）。
   所以外层就用站内那套卡片壳，只有"面板 + 文字 + 滚动条"是游戏的样子。 */
.shot {
  position: relative;
  height: 350px;
  overflow: hidden;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35);
}

/* 窄屏：栏目变宽、说明文字开始折行，行都变高了 ——
   面板跟着长高一点，才不至于一屏只看得到三行半 */
@media (max-width: 560px) {
  .shot { height: 390px; }
  .shot__desc { font-size: 11px; }
}

.shot__screen {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding: 14px 18px 12px;
}

.shot__title {
  margin: 0 0 10px;
  text-align: center;
  font-size: 14px;
  font-weight: 600;
  color: #fff;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.7);
}

/* 面板：游戏里是 left=40 / 宽=屏宽-80 的一块亮边盒子。
   内容比面板高 → 里面的设置会"跟着正在被改的那一行"上下滚（页尾脚本负责）。

   平底之后这块"屏幕区"得自己压深一档，否则它会和卡片底连成一片、看不出边界。
   游戏里这里是**透出世界**的，所以是压深（不是提亮）才像。 */
.shot__panel {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  border: 1px solid var(--line-2);
  background: rgba(0, 0, 0, 0.28);
}

.shot__list {
  padding: 6px 10px 8px;
  transition: transform 620ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* 分区标题：金色（0xFFD8B26A）+ 下面压一条 1px 分隔线 —— 与游戏里一模一样 */
.shot__section {
  margin: 10px 0 0;
  padding-bottom: 9px;
  font-size: 12.5px;
  font-weight: 600;
  color: #d8b26a;
  border-bottom: 1px solid rgba(255, 255, 255, 0.33);
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.7);
}
.shot__section:first-child { margin-top: 0; }

/* 一行设置：名称（白）在左、值（绿）靠右，两者基线对齐；有说明的再占满一行灰字。
   缩进照游戏：选项比分区标题往右 16 GUI px，说明与名称同一条竖线。 */
.shot__row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 10px;
  padding: 5px 12px 5px 20px;
  transition: background 200ms ease;
}
.shot__row[hidden] { display: none; }
/* 0x22FFFFFF：游戏里鼠标停在（或点中）那一行时的底色。
   在这里它表示"这一行正在被改"—— 换档时移到下一行。 */
.shot__row.is-active { background: rgba(255, 255, 255, 0.13); }

.shot__label {
  flex: 1 1 auto;
  font-size: 13px;
  color: #fff;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.75);
}

.shot__value {
  flex: none;
  font-family: var(--mono);
  font-size: 12.5px;
  color: #7fd37f;             /* 0xFF7FD37F：游戏里"值"就是这抹绿 */
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.75);
}

.shot__desc {
  flex: 1 0 100%;
  margin-top: 2px;
  font-size: 11.5px;
  line-height: 1.45;
  color: #999;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.6);
}

/* 换一档时值的那下"啪"：与卡板那格 is-swap 是同一套写法（摘类 → 回流 → 加回）。
   游戏里点一下就是值直接换掉，这里只给它 320ms 的淡入，不做花活。 */
.shot__value.is-swap { animation: rs-in 320ms ease both; }
@keyframes rs-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}

/* 滚动条：游戏里 3px 宽、贴右边 4px，轨道 0x33FFFFFF、滑钮 0xAAFFFFFF。
   滑钮的高度与位置由页尾脚本按**真实滚动量**写进 --rs-h / --rs-y —— 它是真指示，不是装饰。 */
.shot__bar {
  position: absolute;
  top: 2px;
  bottom: 2px;
  right: 3px;
  width: 3px;
  background: rgba(255, 255, 255, 0.2);
}
.shot__knob {
  position: absolute;
  left: 0;
  right: 0;
  top: var(--rs-y, 0%);
  height: var(--rs-h, 40%);
  background: rgba(255, 255, 255, 0.67);
}

/* 右下角「完成设置」：黑底 + 1px 白边 + 白字（BoardRaidButton 的画法）。
   整块都是示意图，它是个 span 不是 button —— 做成按钮会让键盘用户白点一次。 */
.shot__foot {
  display: flex;
  justify-content: flex-end;
  padding-top: 12px;
}
.shot__btn {
  min-width: 96px;
  padding: 6px 14px;
  text-align: center;
  font-size: 12.5px;
  color: #fff;
  background: rgba(0, 0, 0, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.56);
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.75);
}

/* ============================ 段位阶梯 ============================ */

/* 与游戏内「段位详情」是同一张表：13 行、每 100 分一个小段、2200 起进苍穹。
   数字来自 Rank.java 的枚举（改段位规则时同步那里），**图标与配色也照抄它**
   —— 那五张图就是游戏内用的同一批文件（assets/ranks/），颜色取自枚举里的 ARGB。
   所以这一块在网页上看和在游戏里看，是同一个东西。 */

.ranks {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35);
}

.ranks__bar {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 11px 14px;
  background: var(--panel-2);
  border-bottom: 1px solid var(--line);
  font-size: 12px;
  color: var(--dim);
}
.ranks__now { margin-left: auto; }
.ranks__now b { font-weight: 600; }

.ladder {
  margin: 0;
  padding: 6px;
  list-style: none;
}

.ladder__row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 10px;
  border-radius: 5px;
  font-size: 14.5px;
  /* opacity 也要在里面：首页那条梯子会自己往上爬，而"当前行以下压暗"
     是靠 opacity 实现的 —— 少了它，每爬一格下面那几行就是硬跳一下 */
  transition: background 260ms ease, color 260ms ease, opacity 260ms ease;
}
.ladder__icon { width: 18px; height: 18px; flex: none; image-rendering: pixelated; }
.ladder__name { font-weight: 600; color: inherit; }
.ladder__range {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--dim);
}

/* 大段配色：**照抄 Rank.java 里的 ARGB**（当初就是为深色界面挑的暗色调） */
.tier--spark  { color: #8c8c8c; }
.tier--lunar  { color: #9aacbe; }
.tier--astra  { color: #6b87ae; }
.tier--nova   { color: #b8963f; }
.tier--zenith { color: #8e6bb0; }

/* 【当前段位 = 白色一行】与游戏内那张表一致：当前行白底黑字，一眼就能在整条梯子上
   找到自己；深色站点里它也是最亮的一块，天生是焦点。
   排在它**下面**的行（还没打到的）整体压暗 —— 于是"爬到哪了"不看文字也知道。 */
.ladder__row.is-current {
  background: #f4f4f5;
  color: #17171a;
}
.ladder__row.is-current .ladder__range { color: #52525b; }
.ladder__row.is-current ~ .ladder__row { opacity: 0.4; }

/* （这里原先有一组 .orow —— 「自定义模式」那块改画成游戏内的房间设置界面之后，
    它成了全站唯一的使用者，已随那次改写一起删掉。见上面"游戏内 UI 假图"一节。） */

/* ============================ 下载页：首屏与路线选择 ============================ */

/* 【只作用于下载页】共用组件的节奏在这一页整体收紧、字号整体放大：
   段留白 76→56、段标题 28→clamp(24,2.4vw,36)、导语加大。
   主页 / 排行榜 / 查询玩家共用 .section 与 .section__title，
   用 body[data-page] 限定，改这一页不动其它页。 */
body[data-page="download"] .section { padding: 56px 0; }
body[data-page="download"] .section__title {
  font-size: clamp(24px, 2.4vw, 36px);
}
body[data-page="download"] .section__lead {
  margin: 0 0 24px;
  font-size: 16.5px;
}

/* 【只作用于文档页】法律与规则页的大标题大一档。
   这几页标题下面没有引导语、没有按钮，标题就是全页唯一的视觉支点，
   28px 与它们后面动辄几十行的正文比，撑不住层级（来自反馈）。
   排行榜那类页面不改：它们的标题下面紧跟着内容，放大反而会把人推远。 */
body[data-page="privacy"] .section__title,
body[data-page="licenses"] .section__title,
body[data-page="rules"] .section__title,
body[data-page="thanks"] .section__title {
  font-size: clamp(32px, 3.4vw, 44px);
}

/* 下载页首屏：与主页首屏同一套语言（照片底 + 压暗遮罩 + 方框标签 + 大标题 + 按钮），
   但**不占满整屏**（主页是 min-height:100vh，这里只按内容撑高 + 上下留白）。
   下载页的第一诉求是"把按钮递到手里"，首屏越矮，读者越早碰到向导。 */
.pagehero {
  position: relative;
  overflow: hidden;
  text-align: center;
  padding: 84px 0 72px;
  border-bottom: 1px solid var(--line);
}
.pagehero__inner { position: relative; }

.pagehero__title {
  margin: 0 0 14px;
  font-size: clamp(32px, 4vw, 56px);
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--title);
}
.pagehero__sub {
  margin: 0 auto;
  max-width: 640px;
  font-size: clamp(16px, 1.35vw, 19px);
  line-height: 1.7;
  color: var(--text);
}
.pagehero__sub strong { color: var(--gold); font-weight: 600; }

.pagehero__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
  margin-top: 32px;
}
/* 路线选择：两张卡并排就是"二选一"。卡片不是链接（里面有两个动作：
   下载启动器 / 跳去导入步骤），所以用 div，避免嵌套 <a>。 */
.paths {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}
.path {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 22px 24px;
  background: var(--panel);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
}
.path__name { font-size: 19px; font-weight: 600; color: var(--title); }
.path__actions { display: flex; align-items: center; gap: 14px; margin-top: 10px; }
.path__link { font-size: 14px; font-weight: 600; }

/* 常见问题：用原生 <details>，零 JS —— 键盘（Enter / Space）与读屏都自带支持，
   这种"点开才展开"的东西不该再引一段脚本来做。
   展开标记换成站点自己的那套（等宽 + 金），不用浏览器默认的三角：
   那个三角各家长得都不一样，也和这一页其它标记对不上。 */
.faq { display: grid; gap: 10px; margin-top: 6px; }

.qa {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;          /* 展开的内容不会把圆角顶破 */
}

.qa > summary {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 15px 18px;
  font-size: 15.5px;
  font-weight: 600;
  color: var(--title);
  cursor: pointer;
  list-style: none;          /* Firefox 的默认三角 */
  transition: background 160ms ease;
}
.qa > summary::-webkit-details-marker { display: none; }   /* Chrome / Safari 的默认三角 */
.qa > summary:hover { background: var(--panel-2); }

/* 收起是 "+"、展开是 "−"。用等宽字，两种状态一样宽，切换时整行不会抖一下。 */
.qa > summary::before {
  content: "+";
  flex: none;
  width: 1em;
  font-family: var(--mono);
  font-weight: 700;
  color: var(--gold);
}
.qa[open] > summary::before { content: "\2212"; }          /* 减号，不是连字符 */
.qa[open] > summary { border-bottom: 1px solid var(--line); }

.qa__body {
  padding: 14px 18px 16px 44px;   /* 左缩进对齐的是标题文字，不是那个标记 */
  font-size: 15px;
  line-height: 1.7;
  color: var(--text);
}
.qa__body p { margin: 0 0 10px; }
.qa__body p:last-child { margin-bottom: 0; }
.qa__body strong { color: var(--title); font-weight: 600; }
.qa__note { font-size: 13.5px; color: var(--dim); }

/* 安装向导：一步 = 左边一句"点哪里"，右边一张截图。
   刻意**不左右交替** —— 照着做的页面，每一步的位置固定，眼睛才知道该往哪儿落。
   间距在 2026-09-16 重排时整体收紧（gap 36→22、栏距 34→30）：旧值让每一步
   之间空出一大段，四步排下来整页拉到三千多像素，读起来"一格一格隔得太远"。 */
.guide {
  margin: 24px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 22px;
}

.step { display: grid; gap: 16px; }
.step > * { min-width: 0; }   /* grid 子项默认 min-width:auto，宽截图会把列撑破 */
@media (min-width: 900px) {
  /* 文字栏略窄、截图栏略宽：截图是"看哪里点"的主角，文字只要够读。
     顶端对齐（不是居中）：文字比截图矮得多，居中会在序号上方空出一个大洞，
     顶对齐后序号沿着截图顶边一格一格往下走，才像一份步骤清单。 */
  .step { grid-template-columns: 5fr 6fr; gap: 30px; align-items: start; }
}

/* 第一步配的是那张 zip 图标（现为 245×235 的抗锯齿抠图），不能按截图那套摆：
   按固定小尺寸放在文字左边，像一枚"文件"标签 —— 一行就说完，不占一屏的高度。
   源图比显示尺寸大得多（84px 显示是"缩小"），所以字是清楚的；不要描边、不要底色。 */
.step--file { grid-template-columns: auto 1fr; align-items: center; gap: 18px; }
.step--file .step__shot { order: -1; }
.step--file .step__shot img { max-width: 84px; border: 0; }

.step__text { display: grid; justify-items: start; gap: 10px; }
.step__text p { margin: 0; font-size: 17px; line-height: 1.65; color: var(--text); }
.step__text strong { color: var(--title); }

.step__num {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 6px;
  background: var(--gold-dim);
  color: var(--gold);
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
}

/* 截图统一套一层描边：PCL / MultiMC 都是浅色界面，直接摊在暗底上会晃眼。
   `border-radius` 顺带把窗口截图四角那点黑弧剪掉（截图的黑边已裁过，
   只剩圆角处很小的一点）。

   【不要写 width:100%】那张 zip 图标会被拉成一坨糊的。
   max-width 配原始尺寸：宽截图照样铺满这一栏，小图保持原样。

   截图外面包了一层 <a>（点开看原图）：页面上摆小一点不损失信息，
   要看清箭头指的小字就点一下。悬停给一圈亮边暗示"可点"。 */
.step__shot { display: block; cursor: zoom-in; }
.step__shot img {
  display: block;
  width: auto;
  max-width: 100%;
  height: auto;
  border: 1px solid var(--line-2);
  border-radius: 10px;
  transition: border-color 160ms ease;
}
a.step__shot:hover img { border-color: rgba(255, 255, 255, 0.4); }

/* ============================ 下载卡 ============================ */
/*
  【当前没有任何页面在用这一组】—— .download / .meta / .checksum / .reqs /
  .side__title / .fineprint / .steps。它们是旧下载页那套（下载卡 + 元数据表 +
  校验值 + 前置条件 + 四步安装），下载页在 2026-09-16 按新的四段结构重写后不再引用。
  先留着（仓库没有 git 兜底，删了不好回退）：确认不再需要时整段删掉即可 ——
  连同 assets/app.js 一起（那个脚本只服务这一组，现在也没有页面引它了）。
*/

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
}

.download {
  display: grid;
  grid-template-columns: 1fr;
  overflow: hidden;
}
@media (min-width: 820px) {
  .download { grid-template-columns: 1.6fr 1fr; }
}

.download__main { padding: 28px; }
.download__side {
  padding: 28px;
  background: var(--panel-2);
  border-top: 1px solid var(--line);
}
@media (min-width: 820px) {
  .download__side { border-top: 0; border-left: 1px solid var(--line); }
}

.download__head { display: flex; align-items: center; gap: 12px; }
.download__version {
  margin: 0;
  font-family: var(--mono);
  font-size: 26px;
  color: var(--title);
}
.download__note { margin: 10px 0 22px; color: var(--dim); font-size: 14px; }

.meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 14px 18px;
  margin: 0 0 24px;
}
.meta dt {
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dim);
}
.meta dd { margin: 3px 0 0; font-family: var(--mono); color: var(--title); }

.download__actions { display: flex; flex-wrap: wrap; gap: 12px; }

.checksum {
  margin-top: 22px;
  padding: 12px 14px;
  background: rgba(0, 0, 0, 0.28);
  border: 1px solid var(--line);
  border-radius: 10px;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.checksum__label {
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dim);
}
.checksum__value {
  flex: 1 1 260px;
  overflow-wrap: anywhere;
  white-space: normal;
  font-size: 12px;
  color: var(--text);
  background: none;
  border: 0;
  padding: 0;
}

.side__title {
  margin: 0 0 12px;
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dim);
  font-weight: 600;
}
.reqs { margin: 0 0 16px; padding-left: 18px; font-size: 14.5px; }
.reqs li { margin-bottom: 7px; }
.reqs strong { color: var(--title); }
.fineprint { margin: 0; font-size: 13px; color: var(--dim); }

/* ============================ 安装步骤 ============================ */

.steps {
  list-style: none;
  counter-reset: step;
  margin: 26px 0 0;
  padding: 0;
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}
.steps li {
  position: relative;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px 22px 20px;
}
.steps li::before {
  counter-increment: step;
  content: counter(step, decimal-leading-zero);
  display: block;
  margin-bottom: 12px;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--gold);
}
.steps h3 { margin: 0 0 8px; font-size: 16px; color: var(--title); }
.steps p { margin: 0; font-size: 14.5px; color: var(--text); }

/* ============================ 服务状态 ============================ */

.statgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 14px;
  margin: 26px 0 16px;
}
.stat {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 20px;
}
.stat__label {
  display: block;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dim);
}
.stat__value {
  display: block;
  margin-top: 6px;
  font-family: var(--mono);
  font-size: 28px;
  font-weight: 700;
  color: var(--gold);
}

/* ============================ 页脚 ============================ */

.footer { padding: 44px 0 56px; }
.footer__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  /* 联系方式跟在品牌名后面：窄屏放不下时换行，而不是把页脚横向撑破 */
  flex-wrap: wrap;
  margin-bottom: 16px;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: 0.08em;
  color: var(--dim);
}
.footer__cn { color: var(--text); font-weight: 500; letter-spacing: 0.1em; }

/* 联系方式（QQ 群 / Oopz）：与品牌名之间用一条细竖线隔开，
   它是"另一个东西"，不该读成品牌名的一部分。
   字号字距都从 .footer__brand 那套 700 / 0.08em 里重置回来 ——
   粗体加宽字距套在一串数字上会又笨又散，反而不像一个"号"。 */
.footer__contact {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 18px;
  margin-left: 10px;
  padding-left: 16px;
  border-left: 1px solid var(--line);
}
.contact {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0;
}
.contact__logo { display: block; width: 16px; height: 16px; border-radius: 4px; }
.contact__label { color: var(--dim); }
.contact__value {
  font-family: var(--mono);
  color: var(--text);
  /* 点一下就把整串号选中：玩家不必手动拖着选八个数字 */
  -webkit-user-select: all;
  user-select: all;
}
.footer__legal { margin: 0 0 16px; max-width: 700px; font-size: 13px; color: var(--dim); }
.footer__legal strong { color: var(--text); }
.footer__links { margin: 0; display: flex; flex-wrap: wrap; gap: 20px; font-size: 13px; }

/* ============================ 文档页（隐私政策 / OSS 许可证） ============================ */

/* 这类页是纯文字，唯一的目标是"读得下去"：
   每节上面压一条 1px 线、标题带序号，与参考站那种分节式法律页同一个形状，
   顺序号是有用的：说"第 6 条"时，双方指的是同一条。

   【栏宽】曾经收在 68ch —— 那是"一栏只放一行字"的读法，可它左对齐，
   在大屏上就变成"左边窄窄一条、右边一大片空地"（1920 宽的屏上正文只占 1/3）。
   现在让它铺满 wrap 的宽度；wrap 本身封顶 1120px，所以超宽屏也不会拉成一行看不到头。
   栏宽放大之后，字号与行高跟着抬一档，长行才不会显得又小又挤。 */
.doc { max-width: none; }
.doc__meta { margin: 0 0 26px; font-family: var(--mono); font-size: 13.5px; color: var(--dim); }

.doc h2 {
  margin: 34px 0 13px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  font-size: 18px;
  color: var(--title);
}
.doc p { margin: 0 0 13px; font-size: 16px; line-height: 1.85; }
.doc ul { margin: 0 0 15px; padding-left: 22px; }
.doc li { margin: 0 0 7px; font-size: 16px; line-height: 1.8; }
.doc strong { color: var(--title); }
.doc__note { font-size: 13.5px; color: var(--dim); }

/* 规则页开头的目录：编号 + 小节名，点进去跳到对应小节。
   编号与正文 h2 一致，"见第 4 节"这类指代才落得下脚。 */
.toc {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 22px;
  margin: 0 0 10px;
  padding: 0;
  list-style: none;
}
.toc a { font-size: 14.5px; color: var(--text); }
.toc a:hover { color: var(--gold); }
.toc__num { margin-right: 7px; font-family: var(--mono); font-size: 12.5px; color: var(--gold); }

/* 落款（致谢页末尾）：右对齐、压暗，像一封写完的信 */
.doc__sign {
  margin: 28px 0 0;
  text-align: right;
  font-size: 14px;
  color: var(--dim);
}

/* 组件清单：一行一个组件（名称 → 版本 → 许可证 → 出处链接），与参考站一样。
   用列表而不是表格：这种条目本来就细，窄屏下表格要么横着滚、要么挤成一团。 */
.oss { margin: 0 0 18px; padding: 0; list-style: none; }
.oss__item { padding: 0 0 14px; margin: 0 0 14px; border-bottom: 1px solid var(--line); }
.oss__item:last-child { padding-bottom: 0; margin-bottom: 0; border-bottom: 0; }
.oss__name { font-size: 15.5px; font-weight: 600; color: var(--title); }
.oss__ver { margin-left: 8px; font-family: var(--mono); font-size: 13px; color: var(--dim); }
.oss__lic { margin: 3px 0 6px; font-size: 14px; color: var(--text); }
.oss__links { display: flex; flex-wrap: wrap; gap: 16px; font-size: 13.5px; }
.oss__none { font-size: 13.5px; color: var(--dim); }

/* ============================ 数据页（排行榜 / 玩家查询） ============================ */

/* 榜单是一张【卡片】，不是贴在页面上的裸表格 —— 站点里其它成块内容
   （.notice / .playerhead / 下载卡）都是 panel 底 + 1px 边 + 12px 圆角，
   榜单跟着走，整页才不像两套设计拼起来的。 */
.ranktable {
  width: 100%;
  /* separate 而不是 collapse：collapse 下 td 的 inset box-shadow 会被相邻单元格
     的边框画掉一半，左侧那道名次竖条就断成虚线。 */
  border-collapse: separate;
  border-spacing: 0;
  margin: 22px 0 12px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: 14.5px;
}
/* 【圆角靠四个角单元格做，不用 overflow: clip】
   overflow: clip / hidden 会把表头钉住的滚动容器换成表格自己，
   position: sticky 立刻失效（表头跟着滚走）。 */
.ranktable thead th:first-child { border-top-left-radius: calc(var(--radius) - 1px); }
.ranktable thead th:last-child { border-top-right-radius: calc(var(--radius) - 1px); }
.ranktable tbody tr:last-child td { border-bottom: 0; }
.ranktable tbody tr:last-child td:first-child { border-bottom-left-radius: calc(var(--radius) - 1px); }
.ranktable tbody tr:last-child td:last-child { border-bottom-right-radius: calc(var(--radius) - 1px); }

/* 表头随滚动钉在顶栏下方：100 行的榜单滚到中段时，
   没有表头就只能靠猜"这一列是胜率还是连胜"。top 取 --topbar-h 而不是 0，
   否则会钻到 sticky 顶栏底下去（顶栏有模糊，透出来是一层脏字）。 */
.ranktable th {
  position: sticky;
  top: var(--topbar-h);
  z-index: 5;
  /* 底色必须不透明：表头是浮在行上方的，半透明会让滚过去的数字透出来叠字 */
  background: var(--panel);
  text-align: left;
  padding: 12px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  /* --dim(#71717a) 在 --panel 上只有 3.84:1，不到 AA 的 4.5:1；
     抬到 #8e8e96 才刚好够读，同时仍比正文弱一档（表头不该抢行内容的视线）。 */
  color: #8e8e96;
  border-bottom: 1px solid var(--line-2);
}
.ranktable th.is-right { text-align: right; }

.ranktable td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
  /* 数字列必须等宽对齐：不等宽时 "1204" 和 "986" 的个位不在一条竖线上，
     一整列看下来是锯齿的，比大小反而更慢。 */
  font-variant-numeric: tabular-nums;
}
/* 名次列：固定窄列右对齐，让"1 / 2 / 10 / 100"的末位对齐成一竖线。
   【只限排行榜页】玩家页复用 .ranktable 画"最近对局"，它的第一列是日期时间，
   压进 56px 会折成三行。 */
body[data-page="leaderboard"] .ranktable th:first-child,
body[data-page="leaderboard"] .ranktable td:first-child { width: 56px; }

/* 行底色的三层，顺序是【斑马 → 名次台 → 悬停】：
   三条规则特异度相同，谁在后面谁生效，所以越"临时"的状态排越后。 */
.ranktable tbody tr:nth-child(even) { background: rgba(255, 255, 255, 0.015); }

/* 前三名：每行挂一个 --pod 颜色，行底提亮一档，名次格左侧画一道竖条。
   用自定义属性而不是三份重复规则 —— 竖条、名次字色、悬停竖条都要读同一个值，
   分成三条规则写会出现"改金银铜要改三处"的隐患。
   【只限排行榜页】玩家页的"最近对局"复用 .ranktable，头三行不是名次台。 */
body[data-page="leaderboard"] .ranktable tbody tr:nth-child(1) { --pod: var(--gold); background: rgba(255, 255, 255, 0.05); }
body[data-page="leaderboard"] .ranktable tbody tr:nth-child(2) { --pod: #cfd4dc;   background: rgba(255, 255, 255, 0.035); }
body[data-page="leaderboard"] .ranktable tbody tr:nth-child(3) { --pod: #d8a06a;   background: rgba(255, 255, 255, 0.025); }
body[data-page="leaderboard"] .ranktable tbody td:first-child {
  color: var(--pod, var(--title));
  font-weight: 600;
  box-shadow: inset 2px 0 0 var(--pod, transparent);
}

/* 榜单行：底色渐变过来，鼠标沿着列表往下扫时才连得成一条，而不是一格一格地闪 */
.ranktable tbody tr { transition: background 180ms ease; }
/* 【悬停态只给真指针】触摸屏上 :hover 会在点完之后粘在那一行不走，
   留下一行擦不掉的高亮；用 hover+pointer 双条件把触摸设备排除掉。 */
@media (hover: hover) and (pointer: fine) {
  .ranktable tbody tr:hover { background: rgba(255, 255, 255, 0.05); }
  /* 悬停时竖条亮起：行本身不变色（前三名的底色被 hover 覆盖了），
     没有这道竖条，"这一行被选中了"就只剩背景一点点变化，手感很钝。 */
  .ranktable tbody tr:hover td:first-child { box-shadow: inset 2px 0 0 var(--pod, var(--gold)); }
}

/* 积分列（第 3 列）是这一页真正要读的东西：加一档字重与字号，
   让眼睛横扫时先落到分数上，再看名字。（玩家页的第 3 列是"胜 / 负"，不吃这条。） */
body[data-page="leaderboard"] .ranktable td:nth-child(3) { font-weight: 600; font-size: 15px; }

.ranktable a { color: var(--title); }
.ranktable a:hover { color: var(--gold); }
/* 键盘玩家：Tab 走到玩家名时必须有可见焦点环，否则焦点在哪一行完全看不出来 */
.ranktable a:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

/* 窄屏砍列：两张表共用 .ranktable 但列义不同，各自砍"最不影响判断"的两列。
   排行榜留 名次/玩家/积分/胜率；对局表留 时间/对手/结果/比分。
   六列挤在 390px 里每列只剩三十几像素，数字会折行、整张表会横向滚。 */
@media (max-width: 720px) {
  body[data-page="leaderboard"] .ranktable th:nth-child(4),
  body[data-page="leaderboard"] .ranktable td:nth-child(4),
  body[data-page="leaderboard"] .ranktable th:nth-child(6),
  body[data-page="leaderboard"] .ranktable td:nth-child(6),
  body[data-page="player"] .ranktable th:nth-child(5),
  body[data-page="player"] .ranktable td:nth-child(5),
  body[data-page="player"] .ranktable th:nth-child(6),
  body[data-page="player"] .ranktable td:nth-child(6) { display: none; }
}

/* 表格下方那行统计说明：贴着卡片左边缘对齐，别和卡片之间空出一大截 */
#board > p.muted { margin: 10px 2px 0; font-size: 13px; }

.is-right { text-align: right; }
.mono { font-family: var(--mono); }
.gold { color: var(--gold); }
.win { color: #8fdc9f; }
.lose { color: #e0836f; }

/* 空态 / 出错 / 搜索框：三者用同一个"提示卡"外观，玩家一眼就知道这是界面状态而不是内容 */
.notice {
  margin: 26px 0;
  padding: 20px 22px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 2px solid var(--gold);
  border-radius: var(--radius);
}
.notice strong { display: block; margin-bottom: 6px; font-size: 16px; color: var(--title); }
.notice p { margin: 0; font-size: 14px; }

.searchbar { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 16px; }
.searchbar input {
  flex: 1 1 220px;
  min-width: 0;
  padding: 11px 14px;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid var(--line-2);
  border-radius: 10px;
  color: var(--title);
  font: inherit;
}
.searchbar input:focus { outline: none; border-color: var(--gold); }

.playerhead { margin: 26px 0 8px; }
.playerhead__name { margin: 0 0 18px; font-size: 24px; color: var(--title); }
.subhead {
  margin: 36px 0 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
}

/* ============================ 玩家头像 ============================ */
/*
  头像是**服务端**给的（`/api/head?name=`），不是第三方皮肤站 —— 引外站等于把
  每个玩家的昵称都发给别人，与 privacy.html 里"浏览器只跟自己服务器说话"冲突。
  像素材是 8x8 像素图，放大走 pixelated 才像游戏里那样；服务端没做这个接口时
  data.js 会把它换成一个色块，不会出现破图。
*/
.head {
  flex: none;
  display: inline-block;
  vertical-align: middle;
  image-rendering: pixelated;
  background: rgba(255, 255, 255, 0.06);
  border-radius: 3px;
}
.head--fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1;
  color: rgba(255, 255, 255, 0.72);
}
/* 榜单"玩家"列：头像与昵称同格（不新增列 —— 窄屏砍列是按列号写的） */
.pcell { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }

/* 档案页头卡：头像是头像，段位只在昵称旁留一枚 14px 小徽章 */
.pc .head { width: 44px; height: 44px; border-radius: 4px; }
.pc__badge { flex: none; width: 14px; height: 14px; image-rendering: pixelated; }

/* 对局列表的对手列：头像 + 名字，省略号由里层的 .nm 负责。
   选择器带上 .mlist 是为了压过档案页那节里的 .mrow__opp（那条写在后面，
   同特异度会被它盖掉）—— 改这里时别把它简化回 .mrow__opp。 */
.mlist .mrow__opp { display: flex; align-items: center; gap: 7px; overflow: visible; }
.mlist .mrow__opp .nm {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* ============================ 玩家档案页 ============================ */
/*
  版式参考 MCSR Ranked / DRAFTOUT / tracker.gg 那类"战绩档案"页，只取三件事：

    1. 头部一张卡：段位图标 + 昵称 + 大号积分 + 段位进度（"距 皎月 III 还差 38 分"）；
    2. 指标条：一行紧凑的「指标 / 数值」，扫一眼就知道这人什么水平 ——
       不做成七张大卡（那是 tracker 首页的做法，放进档案页会喧宾夺主，
       而档案页要让人先看到"他强不强"，再看细节）；
    3. 左列表 + 右图表：对局列表整行可点，选中一局后右边给该局详情、图上钉一根竖线。
       列表与走势图是同一份数据的两种看法，不该各说各话。

  【段位配色不在这里重复定义】：进度条、走势图分带、段位名一律用既有的
  .tier--spark / lunar / astra / nova / zenith（那五个色值照抄 Rank.java），
  SVG 里靠 fill: currentColor 取到 —— 段位改色只改那一处。
*/

/* ---------------------------- 头部卡 ---------------------------- */

.pc {
  margin: 26px 0 14px;
  padding: 20px 22px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.pc__top { display: flex; align-items: flex-start; flex-wrap: wrap; gap: 16px 26px; }
.pc__who { display: flex; align-items: center; gap: 14px; min-width: 0; }
.pc__icon { flex: none; width: 44px; height: 44px; image-rendering: pixelated; }
.pc__whoText { min-width: 0; }
.pc__name { margin: 0; font-size: 24px; line-height: 1.2; color: var(--title); }
.pc__tierline {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 5px;
  font-size: 13px;
  color: var(--text);
}
.pc__tier { font-weight: 600; }
.pc__sep { color: var(--dim); }
.pc__other { display: inline-block; margin-top: 8px; font-size: 12px; color: var(--dim); }
.pc__other:hover { color: var(--gold); }

/* 积分块：右对齐、字号最大 —— 这一页第一个该被看到的数字 */
.pc__scoreBox { margin-left: auto; text-align: right; }
.pc__scoreNum {
  display: block;
  font-family: var(--mono);
  font-size: 42px;
  font-weight: 700;
  line-height: 1;
  color: var(--title);
}
.pc__scoreLabel {
  display: block;
  margin-top: 4px;
  font-size: 11px;
  letter-spacing: 0.12em;
  color: var(--dim);
}

.pc__prog { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line); }
.pc__progHead {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 12px;
  color: var(--dim);
}
.pc__need { color: var(--text); }
.pc__track {
  height: 6px;
  margin-top: 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.06);
  overflow: hidden;
}
/* 进度条取 currentColor：挂上 .tier--x 就自动是那一段的颜色。
   小段固定 100 分，所以条形长度永远是"本段内走了多少"，不会把满条当成顶尖。 */
.pc__fill { height: 100%; border-radius: 999px; background: currentColor; color: var(--gold); }

/* ---------------------------- 指标条 ---------------------------- */

.pstats {
  display: flex;
  flex-wrap: wrap;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.pstat { flex: 1 1 118px; padding: 12px 16px; border-left: 1px solid var(--line); }
.pstat:first-child { border-left: 0; }
.pstat__k { display: block; font-size: 11px; letter-spacing: 0.1em; color: var(--dim); }
.pstat__v {
  display: block;
  margin-top: 4px;
  font-family: var(--mono);
  font-size: 19px;
  font-weight: 600;
  color: var(--title);
}

/* ---------------------------- 两栏 ---------------------------- */

.pgrid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 18px;
  margin-top: 18px;
  align-items: start;
}
.pgrid__col { min-width: 0; }
@media (max-width: 900px) {
  .pgrid { grid-template-columns: 1fr; }
}

/* ---------------------------- 对局列表 ---------------------------- */

.mlist {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.mlist__head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
}
.mlist__title {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
}
.mlist__count { font-size: 12px; }
.filters { display: flex; gap: 6px; margin-left: auto; }
.fchip {
  padding: 4px 10px;
  font: inherit;
  font-size: 12px;
  color: var(--text);
  background: transparent;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  cursor: pointer;
}
.fchip:hover { color: var(--title); border-color: var(--gold); }
.fchip.is-on { color: #17171a; background: var(--gold); border-color: var(--gold); font-weight: 600; }
.fchip:focus-visible,
.mrow:focus-visible { outline: 2px solid var(--gold); outline-offset: -2px; }

/* 列表自身滚动：一页最多 20 局，滚列表而不是把页面拉长 */
.mlist__body { max-height: 470px; overflow-y: auto; }

/* 一行 = 一个 <button>：键盘 Tab 就能逐行走，回车即选中（不用自己造焦点管理）。
   用 flex 而不是 grid：自定义局会多一个小标签，flex 下自然排下去，
   grid 里多一个子元素会直接换行。 */
.mrow {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 16px;
  font: inherit;
  font-size: 13px;
  text-align: left;
  color: var(--text);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  transition: background 150ms ease;
}
.mrow:last-child { border-bottom: 0; }
.mrow:hover { background: rgba(255, 255, 255, 0.04); }
.mrow.is-sel { background: var(--gold-dim); box-shadow: inset 2px 0 0 var(--gold); }
.mrow__res { flex: none; width: 26px; font-weight: 600; }
.mrow__opp {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--title);
}
.mrow__score,
.mrow__time,
.mrow__delta {
  flex: none;
  width: 70px;
  font-family: var(--mono);
  text-align: right;
}
.mrow__time { width: 52px; }
.mrow__delta { width: 54px; color: var(--dim); }
.mrow__ago { flex: none; width: 76px; font-size: 12px; text-align: right; color: var(--dim); }
.mrow__tag {
  flex: none;
  padding: 1px 5px;
  font-size: 11px;
  color: var(--dim);
  border: 1px solid var(--line-2);
  border-radius: 4px;
}

/* ---------------------------- 积分走势图 ---------------------------- */

.chart {
  padding: 14px 16px 12px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.chart__head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.chart__title {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--dim);
}
.chart__note { font-size: 12px; color: var(--dim); }

.chart__plot { position: relative; height: 230px; margin: 12px 0 20px; }
/* 左右各留 8px：折线的首尾点就落在图的边界上，不留这点空，
   最后一局的圆点会被切掉半个。

   【宽高都必须写死】<svg> 是"有固有宽高比"的元素（viewBox 1000:260）。
   只给 height:100% + width:auto 的话，浏览器会按 1000/260 反推宽度 ——
   面板多宽都不管，直接画成一个 884px 宽的框伸到面板外面去，
   真机上的表现是整页多出一条横向滚动条（探针实测：面板 808px、图 885px）。
   图里的 HTML 覆盖层仍按整个 plot 的百分比定位，因此最多差这 8px —— 已知且可接受。 */
.chart__svg { position: absolute; inset: 0 8px; width: calc(100% - 16px); height: 100%; }

/* 段位分带：fill 取 currentColor，色值来自 .tier--x（不在 SVG 里再写一遍） */
.chart__band { fill: currentColor; opacity: 0.07; }
.chart__area { fill: var(--gold); opacity: 0.10; }
/* viewBox 被非等比拉伸，线宽必须靠 non-scaling-stroke 固定住，否则窄屏上会变成一条粗带 */
.chart__line {
  fill: none;
  stroke: var(--gold);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.chart__peak { fill: var(--title); stroke: var(--panel); stroke-width: 2; vector-effect: non-scaling-stroke; }
.chart__sel {
  stroke: var(--gold);
  stroke-width: 1;
  stroke-dasharray: 3 3;
  vector-effect: non-scaling-stroke;
}
.chart__seldot { fill: var(--gold); stroke: var(--panel); stroke-width: 2; vector-effect: non-scaling-stroke; }

/* 图上的字全部是 HTML 覆盖层（SVG 里的 <text> 会被非等比缩放拉变形）。
   压在折线上也要读得出来，所以都垫了一层半透明底。 */
.chart__ylab {
  position: absolute;
  left: 0;
  transform: translateY(-50%);
  padding: 1px 6px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--dim);
  background: rgba(19, 19, 22, 0.8);
  border-radius: 4px;
}
/* 段位名标在带子正中（top 由 data.js 算），所以这里按自身高度居中 */
.chart__tierlab {
  position: absolute;
  right: 0;
  transform: translateY(-50%);
  padding: 1px 5px;
  font-size: 11px;
  font-weight: 600;
  background: rgba(19, 19, 22, 0.8);
  border-radius: 4px;
}
.chart__peaklab {
  position: absolute;
  transform: translate(-50%, -150%);
  padding: 1px 6px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--title);
  background: rgba(19, 19, 22, 0.85);
  border-radius: 4px;
}
/* 峰值靠边时改锚点，把标签收回图内（data.js 按峰值位置加这两个类） */
.chart__peaklab.is-right { transform: translate(-100%, -150%); }
.chart__peaklab.is-left { transform: translate(0, -150%); }
.chart__xaxis {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -18px;
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  color: var(--dim);
}

/* ---------------------------- 选中那一局的详情 ---------------------------- */

.mdet {
  margin-top: 18px;
  padding: 16px 18px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.mdet__head { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
.mdet__res { font-weight: 700; }
.mdet__vs { color: var(--title); font-weight: 600; }
.mdet__mode {
  margin-left: auto;
  padding: 2px 8px;
  font-size: 11px;
  letter-spacing: 0.1em;
  color: var(--dim);
  border: 1px solid var(--line-2);
  border-radius: 999px;
}
.mdet__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
  gap: 12px 18px;
  margin-top: 14px;
}
.mdet__k { display: block; font-size: 11px; letter-spacing: 0.08em; color: var(--dim); }
.mdet__v { display: block; margin-top: 3px; font-size: 15px; color: var(--title); }
.mdet__link { display: inline-block; margin-top: 14px; font-size: 13px; }

/* ============================ 过渡与滚动动效 ============================ */
/*
  这一整节都是**纯增强**，全部挂在 html.js 之下 —— 那个类只由 assets/motion.js 添加。
  没有 JS（脚本被拦、加载失败、老浏览器）→ 这一节一条都不生效，
  页面是"静态但完整"的原样，与加这一节之前一模一样。

  两条不要破的取舍：

  1. 位移一律小（≤ 22px）、时长一律短（≤ 620ms）、缓动一律"快起慢收"。
     暗底极简站点的动效只要夸张一点就显得廉价；这一节的目的只是
     "上下翻页时不硌人"，不是让人注意到有动画。
  2. 动的只有 transform / opacity（合成器直接处理），不碰 height / margin / top ——
     后者每帧都要重排，长页面滚起来就是肉眼可见的卡。
*/

/* 锚点滚动交给 motion.js 的自定义缓动接管：两套平滑同时生效会互相打断，
   表现为"滚一下顿一下"。没有 JS 时上面那条 smooth 照旧生效。 */
html.js { scroll-behavior: auto; }

/* ---------------------------- 分区进场 ---------------------------- */

/* 待进场：藏起来 + 往下沉一点。
   --rx / --ry 决定从哪个方向来、--reveal-delay 是同批兄弟之间的交错，
   两个都由 motion.js 写进内联样式（CSS 这边只负责"怎么动"）。 */
html.js .reveal {
  opacity: 0;
  transform: translate3d(var(--rx, 0px), var(--ry, 20px), 0);
  transition:
    opacity 620ms cubic-bezier(0.22, 0.61, 0.36, 1),
    transform 620ms cubic-bezier(0.22, 0.61, 0.36, 1);
  transition-delay: var(--reveal-delay, 0ms);
}
html.js .reveal.is-in { opacity: 1; transform: none; }

/* 双栏那几段按"文字从内往外、图从外往内"进来，镜像行自动对调 ——
   与页面本身一行一换边的节奏是同一个方向感。
   窄屏堆叠时不做横向位移：屏幕本来就窄，横着滑进来只会撞到边。 */
@media (min-width: 900px) {
  html.js .feature-copy   { --rx: -22px; --ry: 0px; }
  html.js .feature-visual { --rx:  22px; --ry: 0px; }
  html.js .feature-row--flip .feature-copy   { --rx:  22px; }
  html.js .feature-row--flip .feature-visual { --rx: -22px; }
}

/* ---------------------------- 首屏 ---------------------------- */

@media (prefers-reduced-motion: no-preference) {
  /* 入场：背景先淡进来，然后标签 → 字标 → 中文名 → 按钮 → 滚动提示依次抬起。
     这五层本来就有从上到下的视觉顺序，让它按同一个顺序出现，
     首屏就有了"开机"的感觉，而不是一次性糊在脸上。
     fill 用 backwards 而不是 both：动画一结束属性就回到基础值，
     不留一层永久生效的动画白占合成层。 */
  html.js .hero__photo { animation: br-photo-in 900ms ease-out backwards; }
  html.js .hero__inner > * {
    animation: br-hero-in 720ms cubic-bezier(0.16, 0.84, 0.44, 1) backwards;
  }
  html.js .hero__inner > .labelbox      { animation-delay:  60ms; }
  html.js .hero__inner > .wordmark      { animation-delay: 150ms; }
  html.js .hero__inner > .wordmark__cn  { animation-delay: 240ms; }
  html.js .hero__inner > .hero__actions { animation-delay: 340ms; }
  html.js .hero__inner > .scrollhint    { animation-delay: 460ms; }

  /* 视差：滚动时背景比内容走得慢一点，首屏与下面那段宣言之间就有了纵深，
     "翻页"的那一下不再是一条硬边界划过屏幕。

     用 translate 这个**独立属性**而不是 transform：transform 已经交给入场动画了，
     两个属性各自生效再合成；挤在同一个属性里的话，动画结束时的填充值会把
     滚动算出来的位移压掉 —— 表现为"滚两下就不动了"。 */
  html.js .hero__photo {
    translate: 0 calc(var(--hero-p, 0) * 68px);
    will-change: transform, translate;
  }
  html.js .hero__inner {
    opacity: calc(1 - var(--hero-p, 0) * 0.85);
    translate: 0 calc(var(--hero-p, 0) * -30px);
    will-change: opacity, translate;
  }
}
@keyframes br-photo-in { from { opacity: 0; transform: scale(1.2); } }
@keyframes br-hero-in  { from { opacity: 0; transform: translateY(14px); } }

/* ---------------------------- 顶栏：阅读进度 + 贴顶态 ---------------------------- */

/* 那条金线就是阅读进度：宽 = 已读比例，motion.js 每帧写一次 --read（0~1）。
   刻意画在顶栏的下沿，而不是页面顶部单独悬一条 —— 顶栏已经在那儿了，
   多一个悬浮元素只会把首屏的干净感打折。 */
html.js .topbar::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: linear-gradient(90deg, var(--gold-2), var(--gold));
  transform: scaleX(var(--read, 0));
  transform-origin: 0 50%;
}

/* 滚起来之后顶栏才需要"压得住"下面的内容：底色加深一档、边线亮一档、落一点阴影。
   没滚的时候它是首屏的一部分，不该有阴影。 */
html.js .topbar.is-stuck {
  background: rgba(19, 19, 22, 0.95);
  border-bottom-color: var(--line-2);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.34);
}

/* ---------------------------- 回到顶部 ---------------------------- */

/* 按钮由 motion.js 造出来，HTML 里没有它：没有 JS 时它就不该存在 ——
   一个点了没反应的按钮比没有按钮更糟。滚过一屏才出现，短页面永远不出现。
   位移同样用 translate，把 transform 让给悬停态。 */
.totop {
  position: fixed;
  right: 22px;
  bottom: 22px;
  z-index: 30;
  width: 42px;
  height: 42px;
  display: grid;
  place-items: center;
  padding: 0;
  background: rgba(28, 28, 32, 0.92);
  border: 1px solid var(--line-2);
  border-radius: 10px;
  color: var(--gold);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  translate: 0 10px;
  backdrop-filter: blur(8px);
  transition: opacity 220ms ease, translate 220ms ease,
              background 160ms ease, border-color 160ms ease, color 160ms ease;
}
.totop.is-on { opacity: 1; pointer-events: auto; translate: 0 0; }
.totop:hover { background: var(--gold); border-color: var(--gold); color: #1a1405; }
.totop .ic { width: 18px; height: 18px; }
@media (max-width: 760px) {
  .totop { right: 14px; bottom: 14px; }
}

/* ---------------------------- 翻页（页面与页面之间） ---------------------------- */

/* 支持跨文档 View Transitions 的浏览器（Chrome / Edge 126+）：换页时做一次交叉淡入，
   而顶栏因为单独取了名字，会被当成"两页共有的元素"原地保留 ——
   于是换页看起来像"框架没动、里面的内容换了"，正是翻页该有的样子。
   不支持的浏览器整段忽略，退化成普通跳转 + 下面 main 的入场，一样不生硬。
   （各页面共用这一份 CSS，所以换页的两端都算"开启了"，这是它能生效的前提。） */
@view-transition { navigation: auto; }
.topbar { view-transition-name: br-topbar; }

::view-transition-group(root) {
  animation-duration: 260ms;
  animation-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1);
}
::view-transition-old(root) { animation: 150ms ease-out both br-vt-out; }
::view-transition-new(root) { animation: 260ms cubic-bezier(0.22, 0.61, 0.36, 1) both br-vt-in; }
@keyframes br-vt-out { to   { opacity: 0; } }
@keyframes br-vt-in  { from { opacity: 0; transform: translateY(8px); } }

/* 内容区的入场：不支持上面那套的浏览器靠它，换页至少不是"啪"地整屏换掉 */
@media (prefers-reduced-motion: no-preference) {
  html.js main { animation: br-page-in 300ms ease-out backwards; }
}
@keyframes br-page-in { from { opacity: 0; transform: translateY(6px); } }

/* ---------------------------- 排版 ---------------------------- */

/* 标题按"平衡断行"排：这几行标题都是 1~3 行，浏览器自己会把每行拉齐，
   不会出现"上一行挤满、下一行只剩两个字"。正文用 pretty（避免段末孤字）。
   两条都是新属性，不支持的浏览器直接忽略，不影响原有排版。 */
.section__title,
.feature-title,
.playerhead__name { text-wrap: balance; }
.statement,
.section__lead,
.feature-sub { text-wrap: pretty; }

/* ============================ 减少动效 ============================ */

/* 尊重系统的"减少动效"设置：动效只是锦上添花 */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .btn { transition: none; }
  .btn:hover { transform: none; }
  .scrollhint__chev { animation: none; }
  .nav a::after { transition: none; }
  .ranktable tbody tr,
  .mrow { transition: none; }
  .totop { transition: none; translate: none; }

  /* 下面这几条是"宁可不动，不可看不见"的最后一道闸。
     motion.js 在减少动效时本来就不会藏元素，但**运行途中**才改设置、
     或者脚本与系统设置不同步时，这里的 !important 保证内容一定露出来 ——
     半透明的正文停在屏幕上，比没有动效严重得多。 */
  html.js .reveal {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  html.js .hero__inner,
  html.js .hero__inner > *,
  html.js main {
    animation: none !important;
    opacity: 1 !important;
    translate: none !important;
  }
  html.js .hero__photo {
    animation: none !important;
    opacity: 1 !important;
    translate: none !important;
    transform: scale(1.1) !important;   /* 这是它的基础值，别顺手抹成 1（会露出模糊边） */
  }

  /* 跨页过渡也按平：留 0.01ms 而不是删规则，是让那套 keyframes 立刻跑完 */
  ::view-transition-group(root),
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}
